Import Cobalt 19.lts.3.194115

Signed-off-by: Andrew Top <aabtop@google.com>
diff --git a/src/base/bind_unittest.cc b/src/base/bind_unittest.cc
index 0d24dcb..fee9d45 100644
--- a/src/base/bind_unittest.cc
+++ b/src/base/bind_unittest.cc
@@ -16,7 +16,6 @@
 using ::testing::StrictMock;
 
 namespace base {
-namespace {
 
 class IncompleteType;
 
@@ -810,5 +809,4 @@
 #endif  // (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) &&
         //     GTEST_HAS_DEATH_TEST
 
-}  // namespace
 }  // namespace base
diff --git a/src/base/threading/post_task_and_reply_impl.cc b/src/base/threading/post_task_and_reply_impl.cc
index 192198b..855364f 100644
--- a/src/base/threading/post_task_and_reply_impl.cc
+++ b/src/base/threading/post_task_and_reply_impl.cc
@@ -5,6 +5,7 @@
 #include "base/threading/post_task_and_reply_impl.h"
 
 #include "base/bind.h"
+#include "base/debug/leak_annotations.h"
 #include "base/location.h"
 #include "base/message_loop_proxy.h"
 
@@ -74,6 +75,11 @@
     const tracked_objects::Location& from_here,
     const Closure& task,
     const Closure& reply) {
+  // As mentioned in a comment above, this code is prepared to leak in the case
+  // that the original calling message loop goes away while the task is being
+  // processed.  Therefore, explicitly recognize this possibility by allowing
+  // memory leaks here.
+  ANNOTATE_SCOPED_MEMORY_LEAK;
   PostTaskAndReplyRelay* relay =
       new PostTaskAndReplyRelay(from_here, task, reply);
   if (!PostTask(from_here, Bind(&PostTaskAndReplyRelay::Run,
diff --git a/src/cobalt/black_box_tests/black_box_tests.py b/src/cobalt/black_box_tests/black_box_tests.py
index a5c9897..a4000e0 100644
--- a/src/cobalt/black_box_tests/black_box_tests.py
+++ b/src/cobalt/black_box_tests/black_box_tests.py
@@ -26,8 +26,7 @@
 ]
 # These tests only need app launchers with webdriver.
 _TESTS_NO_SIGNAL = [
-    # TODO: Re-enable cookie test after its flakiness is resovled.
-    # 'persistent_cookie',
+    'persistent_cookie',
     'allow_eval',
     'disable_eval_with_csp',
 ]
@@ -58,9 +57,12 @@
   def tearDownClass(cls):
     print('Done ' + cls.__name__)
 
-  def CreateCobaltRunner(self, url, target_params=None):
+  def CreateCobaltRunner(self, url, target_params=[]):
+    all_target_params = target_params
+    if _device_params.target_params is not None:
+      all_target_params += _device_params.target_params
     new_runner = black_box_cobalt_runner.BlackBoxCobaltRunner(
-        device_params=_device_params, url=url, target_params=target_params)
+        device_params=_device_params, url=url, target_params=all_target_params)
     return new_runner
 
 
@@ -97,11 +99,13 @@
   def Run(self):
     logging.basicConfig(level=logging.DEBUG)
     GetDeviceParams()
+
     if self.test_name:
       suite = unittest.TestLoader().loadTestsFromModule(
           importlib.import_module(_TEST_DIR_PATH + self.test_name))
     else:
-      suite = LoadTests(_device_params.platform, _device_params.config, _device_params.device_id)
+      suite = LoadTests(_device_params.platform, _device_params.config,
+                        _device_params.device_id)
     return_code = not unittest.TextTestRunner(
         verbosity=0, stream=sys.stdout).run(suite).wasSuccessful()
     return return_code
diff --git a/src/cobalt/black_box_tests/testdata/persistent_cookie.html b/src/cobalt/black_box_tests/testdata/persistent_cookie.html
index dd4c75f..d7e838f 100644
--- a/src/cobalt/black_box_tests/testdata/persistent_cookie.html
+++ b/src/cobalt/black_box_tests/testdata/persistent_cookie.html
@@ -67,8 +67,6 @@
       } else if (event.keyCode === 99) {
         thirdRun();
       }
-      // Flush local storage to ensure cookie is written before closing.
-      h5vcc.storage.flush();
       onEndTest();
     }
     setupFinished();
diff --git a/src/cobalt/browser/application.cc b/src/cobalt/browser/application.cc
index e0eb6b0..17fa2c9 100644
--- a/src/cobalt/browser/application.cc
+++ b/src/cobalt/browser/application.cc
@@ -681,10 +681,11 @@
 #endif  // SB_HAS(ON_SCREEN_KEYBOARD)
 
 #if SB_HAS(CAPTIONS)
+  on_caption_settings_changed_event_callback_ = base::Bind(
+      &Application::OnCaptionSettingsChangedEvent, base::Unretained(this));
   event_dispatcher_.AddEventCallback(
       base::AccessibilityCaptionSettingsChangedEvent::TypeId(),
-      base::Bind(&Application::OnCaptionSettingsChangedEvent,
-                 base::Unretained(this)));
+      on_caption_settings_changed_event_callback_);
 #endif  // SB_HAS(CAPTIONS)
 #if defined(ENABLE_WEBDRIVER)
 #if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
@@ -748,6 +749,26 @@
   event_dispatcher_.RemoveEventCallback(base::WindowSizeChangedEvent::TypeId(),
                                         window_size_change_event_callback_);
 #endif  // SB_API_VERSION >= 8
+#if SB_HAS(ON_SCREEN_KEYBOARD)
+  event_dispatcher_.RemoveEventCallback(
+      base::OnScreenKeyboardShownEvent::TypeId(),
+      on_screen_keyboard_shown_event_callback_);
+  event_dispatcher_.RemoveEventCallback(
+      base::OnScreenKeyboardHiddenEvent::TypeId(),
+      on_screen_keyboard_hidden_event_callback_);
+  event_dispatcher_.RemoveEventCallback(
+      base::OnScreenKeyboardFocusedEvent::TypeId(),
+      on_screen_keyboard_focused_event_callback_);
+  event_dispatcher_.RemoveEventCallback(
+      base::OnScreenKeyboardBlurredEvent::TypeId(),
+      on_screen_keyboard_blurred_event_callback_);
+#endif  // SB_HAS(ON_SCREEN_KEYBOARD)
+#if SB_HAS(CAPTIONS)
+  event_dispatcher_.RemoveEventCallback(
+      base::AccessibilityCaptionSettingsChangedEvent::TypeId(),
+      on_caption_settings_changed_event_callback_);
+#endif  // SB_HAS(CAPTIONS)
+
   app_status_ = kShutDownAppStatus;
 }
 
diff --git a/src/cobalt/browser/application.h b/src/cobalt/browser/application.h
index 6417e32..c0d0d62 100644
--- a/src/cobalt/browser/application.h
+++ b/src/cobalt/browser/application.h
@@ -110,6 +110,9 @@
   base::EventCallback on_screen_keyboard_focused_event_callback_;
   base::EventCallback on_screen_keyboard_blurred_event_callback_;
 #endif  // SB_HAS(ON_SCREEN_KEYBOARD)
+#if SB_HAS(CAPTIONS)
+  base::EventCallback on_caption_settings_changed_event_callback_;
+#endif  // SB_HAS(CAPTIONS)
 
   // Thread checkers to ensure that callbacks for network and application events
   // always occur on the same thread.
diff --git a/src/cobalt/browser/web_module.cc b/src/cobalt/browser/web_module.cc
index cb9a1ae..4a777dd 100644
--- a/src/cobalt/browser/web_module.cc
+++ b/src/cobalt/browser/web_module.cc
@@ -1040,8 +1040,13 @@
 
 void WebModule::Impl::SetSize(math::Size window_dimensions,
                               float video_pixel_ratio) {
+  // A value of 0.0 for the video pixel ratio means that the ratio could not be
+  // determined. In that case it should be assumed to be the same as the
+  // graphics resolution, which corresponds to a device pixel ratio of 1.0.
+  float device_pixel_ratio =
+      video_pixel_ratio == 0.0f ? 1.0f : video_pixel_ratio;
   window_->SetSize(window_dimensions.width(), window_dimensions.height(),
-                   video_pixel_ratio);
+                   device_pixel_ratio);
 }
 
 void WebModule::Impl::SetCamera3D(
diff --git a/src/cobalt/build/build.id b/src/cobalt/build/build.id
index ac2138c..7c34122 100644
--- a/src/cobalt/build/build.id
+++ b/src/cobalt/build/build.id
@@ -1 +1 @@
-188191
\ No newline at end of file
+194115
\ No newline at end of file
diff --git a/src/cobalt/build/cobalt_configuration.gypi b/src/cobalt/build/cobalt_configuration.gypi
index 73074d5..f84dfc0 100644
--- a/src/cobalt/build/cobalt_configuration.gypi
+++ b/src/cobalt/build/cobalt_configuration.gypi
@@ -35,6 +35,7 @@
       'cobalt_webapi_extension_source_idl_files%': [],
       'cobalt_webapi_extension_generated_header_idl_files%': [],
       'cobalt_media_source_2016%': 1,
+      'cobalt_v8_buildtime_snapshot%': "false",
     },
 
     # Whether Cobalt is being built.
@@ -228,6 +229,9 @@
     # Some platforms have difficulty linking snapshot_app_stats
     'build_snapshot_app_stats%': 1,
 
+    # Set to "true" to enable v8 snapshot generation at Cobalt build time.
+    'cobalt_v8_buildtime_snapshot%': '<(cobalt_v8_buildtime_snapshot)',
+
     # Cache parameters
 
     # The following set of parameters define how much memory is reserved for
@@ -574,6 +578,11 @@
           'COBALT_DISABLE_SPDY',
         ],
       }],
+      ['cobalt_v8_buildtime_snapshot == "true"', {
+        'defines': [
+          'COBALT_V8_BUILDTIME_SNAPSHOT=1',
+        ],
+      }]
     ],
   }, # end of target_defaults
 
diff --git a/src/cobalt/build/cobalt_configuration.py b/src/cobalt/build/cobalt_configuration.py
index 6d0a316..30f4222 100644
--- a/src/cobalt/build/cobalt_configuration.py
+++ b/src/cobalt/build/cobalt_configuration.py
@@ -44,13 +44,6 @@
 
         # Cobalt uses OpenSSL on all platforms.
         'use_openssl': 1,
-
-        # Set environmental variable to enable_vr: 'USE_VR'
-        # Terminal: `export {varname}={value}`
-        # Note: must also edit gyp_configuration.gypi per internal instructions.
-
-        # Whether to enable VR.
-        'enable_vr': int(os.environ.get('USE_VR', 0)),
     }
     logging.info('Build Number: {}'.format(variables['cobalt_version']))
     return variables
diff --git a/src/cobalt/content/ssl/certs/0a775a30.0 b/src/cobalt/content/ssl/certs/0a775a30.0
new file mode 100644
index 0000000..7d540a4
--- /dev/null
+++ b/src/cobalt/content/ssl/certs/0a775a30.0
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIICDDCCAZGgAwIBAgIQbkepx2ypcyRAiQ8DVd2NHTAKBggqhkjOPQQDAzBHMQsw
+CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
+MBIGA1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw
+MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
+Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQA
+IgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout
+736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2A
+DDL24CejQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
+DgQWBBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEAgFuk
+fCPAlaUs3L6JbyO5o91lAFJekazInXJ0glMLfalAvWhgxeG4VDvBNhcl2MG9AjEA
+njWSdIUlUfUk7GRSJFClH9voy8l27OyCbvWFGFPouOOaKaqW04MjyaR7YbPMAuhd
+-----END CERTIFICATE-----
diff --git a/src/cobalt/content/ssl/certs/1001acf7.0 b/src/cobalt/content/ssl/certs/1001acf7.0
new file mode 100644
index 0000000..5496703
--- /dev/null
+++ b/src/cobalt/content/ssl/certs/1001acf7.0
@@ -0,0 +1,31 @@
+-----BEGIN CERTIFICATE-----
+MIIFWjCCA0KgAwIBAgIQbkepxUtHDA3sM9CJuRz04TANBgkqhkiG9w0BAQwFADBH
+MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM
+QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy
+MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl
+cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEB
+AQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaM
+f/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vX
+mX7wCl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7
+zUjwTcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0P
+fyblqAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtc
+vfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4
+Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUsp
+zBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOO
+Rc92wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYW
+k70paDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+
+DVrNVjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgF
+lQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV
+HQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBADiW
+Cu49tJYeX++dnAsznyvgyv3SjgofQXSlfKqE1OXyHuY3UjKcC9FhHb8owbZEKTV1
+d5iyfNm9dKyKaOOpMQkpAWBz40d8U6iQSifvS9efk+eCNs6aaAyC58/UEBZvXw6Z
+XPYfcX3v73svfuo21pdwCxXu11xWajOl40k4DLh9+42FpLFZXvRq4d2h9mREruZR
+gyFmxhE+885H7pwoHyXa/6xmld01D1zvICxi/ZG6qcz8WpyTgYMpl0p8WnK0OdC3
+d8t5/Wk6kjftbjhlRn7pYL15iJdfOBL07q9bgsiG1eGZbYwE8na6SfZu6W0eX6Dv
+J4J2QPim01hcDyxC2kLGe4g0x8HYRZvBPsVhHdljUEn2NIVq4BjFbkerQUIpm/Zg
+DdIx02OYI5NaAIFItO/Nis3Jz5nu2Z6qNuFoS3FJFDYoOj0dzpqPJeaAcWErtXvM
++SUWgeExX6GjfhaknBZqlxi9dnKlC54dNuYvoS++cJEPqOba+MSSQGwlfnuzCdyy
+F62ARPBopY+Udf90WuioAnwMCeKpSwughQtiue+hMZL77/ZRBIls6Kl0obsXs7X9
+SQ98POyDGCBDTtWTurQ0sR8WNh8M5mQ5Fkzc4P4dyKliPUDqysU0ArSuiYgzNdws
+E3PYJ/HQcu51OyLemGhmW/HGY0dVHLqlCFF1pkgl
+-----END CERTIFICATE-----
diff --git a/src/cobalt/content/ssl/certs/2c11d503.0 b/src/cobalt/content/ssl/certs/2c11d503.0
deleted file mode 100644
index acedb11..0000000
--- a/src/cobalt/content/ssl/certs/2c11d503.0
+++ /dev/null
@@ -1,12 +0,0 @@
------BEGIN CERTIFICATE-----
-MIICITCCAaagAwIBAgISESDm+Ez8JLC+BUCs2oMbNGA/MAoGCCqGSM49BAMDMEAxCzAJBgNVBAYT
-AkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5UcnVzdCBSb290IENBIEczMB4X
-DTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAwMFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9w
-ZW5UcnVzdDEdMBsGA1UEAwwUT3BlblRydXN0IFJvb3QgQ0EgRzMwdjAQBgcqhkjOPQIBBgUrgQQA
-IgNiAARK7liuTcpm3gY6oxH84Bjwbhy6LTAMidnW7ptzg6kjFYwvWYpa3RTqnVkrQ7cG7DK2uu5B
-ta1doYXM6h0UZqNnfkbilPPntlahFVmhTzeXuSIevRHr9LIfXsMUmuXZl5mjYzBhMA4GA1UdDwEB
-/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRHd8MUi2I5DMlv4VBN0BBY3JWIbTAf
-BgNVHSMEGDAWgBRHd8MUi2I5DMlv4VBN0BBY3JWIbTAKBggqhkjOPQQDAwNpADBmAjEAj6jcnboM
-BBf6Fek9LykBl7+BFjNAk2z8+e2AcG+qj9uEwov1NcoG3GRvaBbhj5G5AjEA2Euly8LQCGzpGPta
-3U1fJAuwACEl74+nBCZx4nxp5V2a+EEfOzmTk51V6s2N8fvB
------END CERTIFICATE-----
diff --git a/src/cobalt/content/ssl/certs/451b5485.0 b/src/cobalt/content/ssl/certs/451b5485.0
deleted file mode 100644
index bf864ae..0000000
--- a/src/cobalt/content/ssl/certs/451b5485.0
+++ /dev/null
@@ -1,12 +0,0 @@
------BEGIN CERTIFICATE-----
-MIICHDCCAaKgAwIBAgISESDZkc6uo+jF5//pAq/Pc7xVMAoGCCqGSM49BAMDMD4xCzAJBgNVBAYT
-AkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMjAeFw0x
-NDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBaMD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0
-cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMjB2MBAGByqGSM49AgEGBSuBBAAiA2IA
-BM0PW1aC3/BFGtat93nwHcmsltaeTpwftEIRyoa/bfuFo8XlGVzX7qY/aWfYeOKmycTbLXku54uN
-Am8xIk0G42ByRZ0OQneezs/lf4WbGOT8zC5y0xaTTsqZY1yhBSpsBqNjMGEwDgYDVR0PAQH/BAQD
-AgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNqDYwJ5jtpMxjwjFNiPwyCrKGBZMB8GA1Ud
-IwQYMBaAFNqDYwJ5jtpMxjwjFNiPwyCrKGBZMAoGCCqGSM49BAMDA2gAMGUCMHD+sAvZ94OX7PNV
-HdTcswYO/jOYnYs5kGuUIe22113WTNchp+e/IQ8rzfcq3IUHnQIxAIYUFuXcsGXCwI4Un78kFmjl
-vPl5adytRSv3tjFzzAalU5ORGpOucGpnutee5WEaXw==
------END CERTIFICATE-----
diff --git a/src/cobalt/content/ssl/certs/608a55ad.0 b/src/cobalt/content/ssl/certs/608a55ad.0
deleted file mode 100644
index eb2e84f..0000000
--- a/src/cobalt/content/ssl/certs/608a55ad.0
+++ /dev/null
@@ -1,27 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIFbzCCA1egAwIBAgISESChaRu/vbm9UpaPI+hIvyYRMA0GCSqGSIb3DQEBDQUAMEAxCzAJBgNV
-BAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5UcnVzdCBSb290IENBIEcy
-MB4XDTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAwMFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoM
-CU9wZW5UcnVzdDEdMBsGA1UEAwwUT3BlblRydXN0IFJvb3QgQ0EgRzIwggIiMA0GCSqGSIb3DQEB
-AQUAA4ICDwAwggIKAoICAQDMtlelM5QQgTJT32F+D3Y5z1zCU3UdSXqWON2ic2rxb95eolq5cSG+
-Ntmh/LzubKh8NBpxGuga2F8ORAbtp+Dz0mEL4DKiltE48MLaARf85KxP6O6JHnSrT78eCbY2albz
-4e6WiWYkBuTNQjpK3eCasMSCRbP+yatcfD7J6xcvDH1urqWPyKwlCm/61UWY0jUJ9gNDlP7ZvyCV
-eYCYitmJNbtRG6Q3ffyZO6v/v6wNj0OxmXsWEH4db0fEFY8ElggGQgT4hNYdvJGmQr5J1WqIP7wt
-UdGejeBSzFfdNTVY27SPJIjki9/ca1TSgSuyzpJLHB9G+h3Ykst2Z7UJmQnlrBcUVXDGPKBWCgOz
-3GIZ38i1MH/1PCZ1Eb3XG7OHngevZXHloM8apwkQHZOJZlvoPGIytbU6bumFAYueQ4xncyhZW+vj
-3CzMpSZyYhK05pyDRPZRpOLAeiRXyg6lPzq1O4vldu5w5pLeFlwoW5cZJ5L+epJUzpM5ChaHvGOz
-9bGTXOBut9Dq+WIyiET7vycotjCVXRIouZW+j1MY5aIYFuJWpLIsEPUdN6b4t/bQWVyJ98LVtZR0
-0dX+G7bw5tYee9I8y6jj9RjzIR9u701oBnstXW5DiabA+aC/gh7PU3+06yzbXfZqfUAkBXKJOAGT
-y3HCOV0GEfZvePg3DTmEJwIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB
-/zAdBgNVHQ4EFgQUajn6QiL35okATV59M4PLuG53hq8wHwYDVR0jBBgwFoAUajn6QiL35okATV59
-M4PLuG53hq8wDQYJKoZIhvcNAQENBQADggIBAJjLq0A85TMCl38th6aP1F5Kr7ge57tx+4BkJamz
-Gj5oXScmp7oq4fBXgwpkTx4idBvpkF/wrM//T2h6OKQQbA2xx6R3gBi2oihEdqc0nXGEL8pZ0keI
-mUEiyTCYYW49qKgFbdEfwFFEVn8nNQLdXpgKQuswv42hm1GqO+qTRmTFAHneIWv2V6CG1wZy7HBG
-S4tz3aAhdT7cHcCP009zHIXZ/n9iyJVvttN7jLpTwm+bREx50B1ws9efAvSyB7DH5fitIw6mVskp
-EndI2S9G/Tvw/HRwkqWOOAgfZDC2t0v7NqwQjqBSM2OdAzVWxWm9xiNaJ5T2pBL4LTM8oValX9YZ
-6e18CL13zSdkzJTaTkZQh+D5wVOAHrut+0dSixv9ovneDiK3PTNZbNTe9ZUGMg1RGUFcPk8G97kr
-gCf2o6p6fAbhQ8MTOWIaNr3gKC6UAuQpLmBVrkA9sHSSXvAgZJY/X0VdiLWK2gKgW0VU3jg9CcCo
-SmVGFvyqv1ROTVu+OEO3KMqLM6oaJbolXCkvW0pujOotnCr2BXbgd5eAiN1nE28daCSLT7d0geX0
-YJ96Vdc+N9oWaz53rK4YcJUIeSkDiv7BO7M/Gg+kO14fWKGVyasvc0rQLW6aWQ9VGHgtPFGml4vm
-u7JwqkwR3v98KzfUetF3NI/n+UL3PIEMS1IK
------END CERTIFICATE-----
diff --git a/src/cobalt/content/ssl/certs/626dceaf.0 b/src/cobalt/content/ssl/certs/626dceaf.0
new file mode 100644
index 0000000..984f1d1
--- /dev/null
+++ b/src/cobalt/content/ssl/certs/626dceaf.0
@@ -0,0 +1,31 @@
+-----BEGIN CERTIFICATE-----
+MIIFWjCCA0KgAwIBAgIQbkepxlqz5yDFMJo/aFLybzANBgkqhkiG9w0BAQwFADBH
+MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM
+QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy
+MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl
+cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEB
+AQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3Lv
+CvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3Kg
+GjSY6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9Bu
+XvAuMC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOd
+re7kRXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXu
+PuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1
+mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K
+8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqj
+x5RWIr9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsR
+nTKaG73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0
+kzCqgc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9Ok
+twIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV
+HQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBALZp
+8KZ3/p7uC4Gt4cCpx/k1HUCCq+YEtN/L9x0Pg/B+E02NjO7jMyLDOfxA325BS0JT
+vhaI8dI4XsRomRyYUpOM52jtG2pzegVATX9lO9ZY8c6DR2Dj/5epnGB3GFW1fgiT
+z9D2PGcDFWEJ+YF59exTpJ/JjwGLc8R3dtyDovUMSRqodt6Sm2T4syzFJ9MHwAiA
+pJiS4wGWAqoC7o87xdFtCjMwc3i5T1QWvwsHoaRc5svJXISPD+AVdyx+Jn7axEvb
+pxZ3B7DNdehyQtaVhJ2Gg/LkkM0JR9SLA3DaWsYDQvTtN6LwG1BUSw7YhN4ZKJmB
+R64JGz9I0cNv4rBgF/XuIwKl2gBbbZCr7qLpGzvpx0QnRY5rn/WkhLx3+WuXrD5R
+RaIRpsyF7gpo8j5QOHokYh4XIDdtak23CZvJ/KRY9bb7nE4Yu5UC56GtmwfuNmsk
+0jmGwZODUNKBRqhfYlcsu2xkiAhu7xNUX90txGdj08+JN7+dIPT7eoOboB6BAFDC
+5AwiWVIQ7UNWhwD4FFKnHYuTjKJNRn8nxnGbJN7k2oaLDX5rIMHAnuFl2GqjpuiF
+izoHCBy69Y9Vmhh1fuXsgWbRIXOhNUQLgD1bnF5vKheW0YMjiGZt5obicDIvUiLn
+yOd/xCxgXS/Dr55FBcOEArf9LAhST4Ldo/DUhgkC
+-----END CERTIFICATE-----
diff --git a/src/cobalt/content/ssl/certs/773e07ad.0 b/src/cobalt/content/ssl/certs/773e07ad.0
new file mode 100644
index 0000000..4e0d8e9
--- /dev/null
+++ b/src/cobalt/content/ssl/certs/773e07ad.0
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQswCQYDVQQGEwJD
+SDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEo
+MCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRa
+Fw00MjA1MDkwOTU4MzNaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQL
+ExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh
+bCBSb290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4nieUqjFqdr
+VCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4Wp2OQ0jnUsYd4XxiWD1Ab
+NTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd
+BgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7TrYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0E
+AwMDaAAwZQIwJsdpW9zV57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtk
+AjEA2zQgMgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9
+-----END CERTIFICATE-----
diff --git a/src/cobalt/content/ssl/certs/87229d21.0 b/src/cobalt/content/ssl/certs/87229d21.0
deleted file mode 100644
index 90c8eb7..0000000
--- a/src/cobalt/content/ssl/certs/87229d21.0
+++ /dev/null
@@ -1,27 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIFbzCCA1egAwIBAgISESCzkFU5fX82bWTCp59rY45nMA0GCSqGSIb3DQEBCwUAMEAxCzAJBgNV
-BAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5UcnVzdCBSb290IENBIEcx
-MB4XDTE0MDUyNjA4NDU1MFoXDTM4MDExNTAwMDAwMFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoM
-CU9wZW5UcnVzdDEdMBsGA1UEAwwUT3BlblRydXN0IFJvb3QgQ0EgRzEwggIiMA0GCSqGSIb3DQEB
-AQUAA4ICDwAwggIKAoICAQD4eUbalsUwXopxAy1wpLuwxQjczeY1wICkES3d5oeuXT2R0odsN7fa
-Yp6bwiTXj/HbpqbfRm9RpnHLPhsxZ2L3EVs0J9V5ToybWL0iEA1cJwzdMOWo010hOHQX/uMftk87
-ay3bfWAfjH1MBcLrARYVmBSO0ZB3Ij/swjm4eTrwSSTilZHcYTSSjFR077F9jAHiOH3BX2pfJLKO
-YheteSCtqx234LSWSE9mQxAGFiQD4eCcjsZGT44ameGPuY4zbGneWK2gDqdkVBFpRGZPTBKnjix9
-xNRbxQA0MMHZmf4yzgeEtE7NCv82TWLxp2NX5Ntqp66/K7nJ5rInieV+mhxNaMbBGN4zK1FGSxyO
-9z0M+Yo0FMT7MzUj8czxKselu7Cizv5Ta01BG2Yospb6p64KTrk5M0ScdMGTHPjgniQlQ/GbI4Kq
-3ywgsNw2TgOzfALU5nsaqocTvz6hdLubDuHAk5/XpGbKuxs74zD0M1mKB3IDVedzagMxbm+WG+Oi
-n6+Sx+31QrclTDsTBM8clq8cIqPQqwWyTBIjUtz9GVsnnB47ev1CI9sjgBPwvFEVVJSmdz7QdFG9
-URQIOTfLHzSpMJ1ShC5VkLG631UAC9hWLbFJSXKAqWLXwPYYEQRVzXR7z2FwefR7LFxckvzluFqr
-TJOVoSfupb7PcSNCupt2LQIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB
-/zAdBgNVHQ4EFgQUl0YhVyE12jZVx/PxN3DlCPaTKbYwHwYDVR0jBBgwFoAUl0YhVyE12jZVx/Px
-N3DlCPaTKbYwDQYJKoZIhvcNAQELBQADggIBAB3dAmB84DWn5ph76kTOZ0BP8pNuZtQ5iSas000E
-PLuHIT839HEl2ku6q5aCgZG27dmxpGWX4m9kWaSW7mDKHyP7Rbr/jyTwyqkxf3kfgLMtMrpkZ2Cv
-uVnN35pJ06iCsfmYlIrM4LvgBBuZYLFGZdwIorJGnkSI6pN+VxbSFXJfLkur1J1juONI5f6ELlgK
-n0Md/rcYkoZDSw6cMoYsYPXpSOqV7XAp8dUv/TW0V8/bhUiZucJvbI/NeJWsZCj9VrDDb8O+WVLh
-X4SPgPL0DTatdrOjteFkdjpY3H1PXlZs5VVZV6Xf8YpmMIzUUmI4d7S+KNfKNsSbBfD4Fdvb8e80
-nR14SohWZ25g/4/Ii+GOvUKpMwpZQhISKvqxnUOOBZuZ2mKtVzazHbYNeS2WuOvyDEsMpZTGMKcm
-GS3tTAZQMPH9WD25SxdfGbRqhFS0OE85og2WaMMolP3tLR9Ka0OWLpABEPs4poEL0L9109S5zvE/
-bw4cHjdx5RiHdRk/ULlepEU0rbDK5uUTdg8xFKmOLZTW1YVNcxVPS/KyPu1svf0OnWZzsD2097+o
-4BGkxK51CUpjAEggpsadCwmKtODmzj7HPiY46SvepghJAwSQiumPv+i2tCqjI40cHLI5kqiPAlxA
-OXXUc0ECd97N4EOH1uS6SsNsEn/+KuYj1oxx
------END CERTIFICATE-----
diff --git a/src/cobalt/content/ssl/certs/9168f543.0 b/src/cobalt/content/ssl/certs/9168f543.0
deleted file mode 100644
index c037748..0000000
--- a/src/cobalt/content/ssl/certs/9168f543.0
+++ /dev/null
@@ -1,27 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIFazCCA1OgAwIBAgISESBVg+QtPlRWhS2DN7cs3EYRMA0GCSqGSIb3DQEBDQUAMD4xCzAJBgNV
-BAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMTAe
-Fw0xNDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBaMD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhD
-ZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMTCCAiIwDQYJKoZIhvcNAQEBBQAD
-ggIPADCCAgoCggIBANpQh7bauKk+nWT6VjOaVj0W5QOVsjQcmm1iBdTYj+eJZJ+622SLZOZ5KmHN
-r49aiZFluVj8tANfkT8tEBXgfs+8/H9DZ6itXjYj2JizTfNDnjl8KvzsiNWI7nC9hRYt6kuJPKNx
-Qv4c/dMcLRC4hlTqQ7jbxofaqK6AJc96Jh2qkbBIb6613p7Y1/oA/caP0FG7Yn2ksYyy/yARujVj
-BYZHYEMzkPZHogNPlk2dT8Hq6pyi/jQu3rfKG3akt62f6ajUeD94/vI4CTYd0hYCyOwqaK/1jpTv
-LRN6HkJKHRUxrgwEV/xhc/MxVoYxgKDEEW4wduOU8F8ExKyHcomYxZ3MVwia9Az8fXoFOvpHgDm2
-z4QTd28n6v+WZxcIbekN1iNQMLAVdBM+5S//Ds3EC0pd8NgAM0lm66EYfFkuPSi5YXHLtaW6uOrc
-4nBvCGrch2c0798wct3zyT8j/zXhviEpIDCB5BmlIOklynMxdCm+4kLV87ImZsdo/Rmz5yCTmehd
-4F6H50boJZwKKSTUzViGUkAksnsPmBIgJPaQbEfIDbsYIC7Z/fyL8inqh3SV4EJQeIQEQWGw9CEj
-jy3LKCHyamz0GqbFFLQ3ZU+V/YDI+HLlJWvEYLF7bY5KinPOWftwenMGE9nTdDckQQoRb5fc5+R+
-ob0V8rqHDz1oihYHAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0G
-A1UdDgQWBBSowcCbkahDFXxdBie0KlHYlwuBsTAfBgNVHSMEGDAWgBSowcCbkahDFXxdBie0KlHY
-lwuBsTANBgkqhkiG9w0BAQ0FAAOCAgEAnFZvAX7RvUz1isbwJh/k4DgYzDLDKTudQSk0YcbX8ACh
-66Ryj5QXvBMsdbRX7gp8CXrc1cqh0DQT+Hern+X+2B50ioUHj3/MeXrKls3N/U/7/SMNkPX0XtPG
-YX2eEeAC7gkE2Qfdpoq3DIMku4NQkv5gdRE+2J2winq14J2by5BSS7CTKtQ+FjPlnsZlFT5kOwQ/
-2wyPX1wdaR+v8+khjPPvl/aatxm2hHSco1S1cE5j2FddUyGbQJJD+tZ3VTNPZNX70Cxqjm0lpu+F
-6ALEUz65noe8zDUa3qHpimOHZR4RKttjd5cUvpoUmRGywO6wT/gUITJDT5+rosuoD6o7BlXGEilX
-CNQ314cnrUlZp5GrRHpejXDbl85IULFzk/bwg2D5zfHhMf1bfHEhYxQUqq/F3pN+aLHsIqKqkHWe
-tUNy6mSjhEv9DKgma3GX7lZjZuhCVPnHHd/Qj1vfyDBviP4NxDMcU6ij/UgQ8uQKTuEVV/xuZDDC
-VRHc6qnNSlSsKWNEz0pAoNZoWRsz+e86i9sgktxChL8Bq4fA1SCC28a5g4VCXA9DO2pJNdWY9BW/
-+mGBDAkgGNLQFwzLSABQ6XaCjGTXOqAHVcweMcDvOrRl++O/QmueD6i9a5jc2NvLi6Td11n0bt3+
-qsOR0C5CB8AMTVPNJLFMWx5R9N/pkvo=
------END CERTIFICATE-----
diff --git a/src/cobalt/content/ssl/certs/9ffb46dd.0 b/src/cobalt/content/ssl/certs/9ffb46dd.0
new file mode 100644
index 0000000..a041a76
--- /dev/null
+++ b/src/cobalt/content/ssl/certs/9ffb46dd.0
@@ -0,0 +1,14 @@
+-----BEGIN CERTIFICATE-----
+MIICMzCCAbmgAwIBAgIOSBtqCfT5YHE6/oHMht0wCgYIKoZIzj0EAwMwXDELMAkG
+A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
+b3QgQ0ExIDAeBgNVBAMTF0dsb2JhbFNpZ24gUm9vdCBDQSAtIFI4MB4XDTE2MDYx
+NTAwMDAwMFoXDTM2MDYxNTAwMDAwMFowXDELMAkGA1UEBhMCQkUxGTAXBgNVBAoT
+EEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExIDAeBgNVBAMTF0ds
+b2JhbFNpZ24gUm9vdCBDQSAtIFI4MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEuO58
+MIfYlB9Ua22Ynfx1+1uIq0K6jX05ft1EPTk84QWhSmRgrDemc7D5yUVLCwbQOuDx
+bV/6XltaUrV240bb1R6MdHpCyUE1T8bU4ihgqzSKzrFAI0alrhkkUnyQVUTOo0Iw
+QDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQULzoS
+JoDoisJQeG0GxDR+4kk5V3YwCgYIKoZIzj0EAwMDaAAwZQIxAMehPbKSkPrKXeAn
+hII7Icz0jfiUVvIgXxHArLxfFaULyBZDp/jFf40goH9e/BYcJwIwHoz1Vr8425zm
+pteEKebfDVMu6CsBt30JPLEyahqauArq6K0I8nQ51SsiNtzvRmbY
+-----END CERTIFICATE-----
diff --git a/src/cobalt/content/ssl/certs/a3418fda.0 b/src/cobalt/content/ssl/certs/a3418fda.0
new file mode 100644
index 0000000..07372d3
--- /dev/null
+++ b/src/cobalt/content/ssl/certs/a3418fda.0
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIICCjCCAZGgAwIBAgIQbkepyIuUtui7OyrYorLBmTAKBggqhkjOPQQDAzBHMQsw
+CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
+MBIGA1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw
+MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
+Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQA
+IgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzu
+hXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/l
+xKvRHYqjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
+DgQWBBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNnADBkAjBqUFJ0
+CMRw3J5QdCHojXohw0+WbhXRIjVhLfoIN+4Zba3bssx9BzT1YBkstTTZbyACMANx
+sbqjYAuG7ZoIapVon+Kz4ZNkfF6Tpt95LY2F45TPI11xzPKwTdb+mciUqXWi4w==
+-----END CERTIFICATE-----
diff --git a/src/cobalt/content/ssl/certs/dc4d6a89.0 b/src/cobalt/content/ssl/certs/dc4d6a89.0
new file mode 100644
index 0000000..097abc0
--- /dev/null
+++ b/src/cobalt/content/ssl/certs/dc4d6a89.0
@@ -0,0 +1,27 @@
+-----BEGIN CERTIFICATE-----
+MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEgMB4GA1UECxMX
+R2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds
+b2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQxMjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9i
+YWxTaWduIFJvb3QgQ0EgLSBSNjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFs
+U2lnbjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQss
+grRIxutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1kZguSgMpE
+3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxDaNc9PIrFsmbVkJq3MQbF
+vuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJwLnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqM
+PKq0pPbzlUoSB239jLKJz9CgYXfIWHSw1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+
+azayOeSsJDa38O+2HBNXk7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05O
+WgtH8wY2SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/hbguy
+CLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4nWUx2OVvq+aWh2IMP
+0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpYrZxCRXluDocZXFSxZba/jJvcE+kN
+b7gu3GduyYsRtYQUigAZcIN5kZeR1BonvzceMgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQE
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNV
+HSMEGDAWgBSubAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN
+nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGtIxg93eFyRJa0
+lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr6155wsTLxDKZmOMNOsIeDjHfrY
+BzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLjvUYAGm0CuiVdjaExUd1URhxN25mW7xocBFym
+Fe944Hn+Xds+qkxV/ZoVqW/hpvvfcDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr
+3TsTjxKM4kEaSHpzoHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB1
+0jZpnOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfspA9MRf/T
+uTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+vJJUEeKgDu+6B5dpffItK
+oZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+t
+JDfLRVpOoERIyNiwmcUVhAn21klJwGW45hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA=
+-----END CERTIFICATE-----
diff --git a/src/cobalt/dom/dom.gyp b/src/cobalt/dom/dom.gyp
index dbc0a88..28de740 100644
--- a/src/cobalt/dom/dom.gyp
+++ b/src/cobalt/dom/dom.gyp
@@ -240,8 +240,6 @@
         'screenshot.h',
         'screenshot_manager.cc',
         'screenshot_manager.h',
-        'script_event_log.cc',
-        'script_event_log.h',
         'security_policy_violation_event.cc',
         'security_policy_violation_event.h',
         'serializer.cc',
diff --git a/src/cobalt/dom/eme/media_keys.h b/src/cobalt/dom/eme/media_keys.h
index fcd5566..56c122c 100644
--- a/src/cobalt/dom/eme/media_keys.h
+++ b/src/cobalt/dom/eme/media_keys.h
@@ -45,7 +45,7 @@
   MediaKeys(const std::string& key_system,
             script::ScriptValueFactory* script_value_factory);
 
-  media::DrmSystem* drm_system() const { return drm_system_.get(); }
+  scoped_refptr<media::DrmSystem> drm_system() const { return drm_system_; }
 
   // Web API: MediaKeys.
 
diff --git a/src/cobalt/dom/generic_event_handler_reference.cc b/src/cobalt/dom/generic_event_handler_reference.cc
index 65ca43f..6f89eb9 100644
--- a/src/cobalt/dom/generic_event_handler_reference.cc
+++ b/src/cobalt/dom/generic_event_handler_reference.cc
@@ -17,7 +17,6 @@
 #include "base/debug/trace_event.h"
 #include "cobalt/dom/event.h"
 #include "cobalt/dom/event_target.h"
-#include "cobalt/dom/script_event_log.h"
 
 namespace cobalt {
 namespace dom {
@@ -59,8 +58,6 @@
     bool unpack_error_event) {
   TRACE_EVENT1("cobalt::dom", "GenericEventHandlerReference::HandleEvent",
                "Event Name", TRACE_STR_COPY(event->type().c_str()));
-  script_event_log.Get().PushEvent(event);
-
   bool had_exception;
   base::optional<bool> result;
 
@@ -77,8 +74,6 @@
     had_exception = true;
   }
 
-  script_event_log.Get().PopEvent();
-
   if (had_exception) {
     return;
   }
diff --git a/src/cobalt/dom/html_media_element.cc b/src/cobalt/dom/html_media_element.cc
index ba28f7b..f05da17 100644
--- a/src/cobalt/dom/html_media_element.cc
+++ b/src/cobalt/dom/html_media_element.cc
@@ -278,20 +278,13 @@
   DLOG_IF(ERROR, !key_system.empty())
       << "CanPlayType() only accepts one parameter but (" << key_system
       << ") is passed as a second parameter.";
+#endif  // defined(COBALT_MEDIA_SOURCE_2016)
   std::string result =
-      html_element_context()->can_play_type_handler()->CanPlayType(mime_type,
-                                                                   "");
-  MLOG() << "(" << mime_type << ") => " << result;
-  LOG(INFO) << "HTMLMediaElement::canPlayType(" << mime_type << ") -> "
-            << result;
-#else   // defined(COBALT_MEDIA_SOURCE_2016)
-  std::string result =
-      html_element_context()->can_play_type_handler()->CanPlayType(mime_type,
-                                                                   key_system);
+      html_element_context()->can_play_type_handler()->CanPlayType(
+          true, mime_type, key_system);
   MLOG() << "(" << mime_type << ", " << key_system << ") => " << result;
   LOG(INFO) << "HTMLMediaElement::canPlayType(" << mime_type << ", "
             << key_system << ") -> " << result;
-#endif  // defined(COBALT_MEDIA_SOURCE_2016)
   return result;
 }
 
diff --git a/src/cobalt/dom/media_source.cc b/src/cobalt/dom/media_source.cc
index ffd1ed6..c1908a5 100644
--- a/src/cobalt/dom/media_source.cc
+++ b/src/cobalt/dom/media_source.cc
@@ -223,7 +223,7 @@
   DCHECK(dom_settings);
   media::CanPlayTypeHandler* handler = dom_settings->can_play_type_handler();
   DCHECK(handler);
-  std::string result = handler->CanPlayType(type, "");
+  std::string result = handler->CanPlayType(false, type, "");
   DLOG(INFO) << "MediaSource::IsTypeSupported(" << type << ") -> " << result;
   return result == "probably";
 }
diff --git a/src/cobalt/dom/on_error_event_listener.cc b/src/cobalt/dom/on_error_event_listener.cc
index 1401531..fb9daf0 100644
--- a/src/cobalt/dom/on_error_event_listener.cc
+++ b/src/cobalt/dom/on_error_event_listener.cc
@@ -21,7 +21,6 @@
 #include "cobalt/base/polymorphic_downcast.h"
 #include "cobalt/dom/error_event.h"
 #include "cobalt/dom/event_target.h"
-#include "cobalt/dom/script_event_log.h"
 
 namespace cobalt {
 namespace dom {
diff --git a/src/cobalt/dom/script_event_log.cc b/src/cobalt/dom/script_event_log.cc
deleted file mode 100644
index 9ede256..0000000
--- a/src/cobalt/dom/script_event_log.cc
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2018 The Cobalt Authors. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "cobalt/dom/script_event_log.h"
-
-#include "cobalt/dom/event_target.h"
-
-namespace cobalt {
-namespace dom {
-
-ScriptEventLog::ScriptEventLog() : current_stack_depth_(0) {
-  base::UserLog::Register(base::UserLog::kEventStackLevelCountIndex,
-                          "EventLevelCnt", &current_stack_depth_,
-                          sizeof(current_stack_depth_));
-
-  memset(event_log_stack_, 0, sizeof(event_log_stack_));
-  const int kLogNameBufferSize = 16;
-  char log_name_buffer[kLogNameBufferSize];
-  for (int i = 0; i < base::UserLog::kEventStackMaxDepth; i++) {
-    snprintf(log_name_buffer, kLogNameBufferSize, "EventLevel%d", i);
-    base::UserLog::Register(static_cast<base::UserLog::Index>(
-                                base::UserLog::kEventStackMinLevelIndex + i),
-                            log_name_buffer, event_log_stack_[i],
-                            kLogEntryMaxLength);
-  }
-}
-
-ScriptEventLog::~ScriptEventLog() {
-  base::UserLog::Deregister(base::UserLog::kEventStackLevelCountIndex);
-  for (int i = 0; i < base::UserLog::kEventStackMaxDepth; i++) {
-    base::UserLog::Deregister(static_cast<base::UserLog::Index>(
-        base::UserLog::kEventStackMinLevelIndex + i));
-  }
-}
-
-void ScriptEventLog::PushEvent(Event* event) {
-  if (current_stack_depth_ < base::UserLog::kEventStackMaxDepth) {
-    snprintf(event_log_stack_[current_stack_depth_], kLogEntryMaxLength,
-             "%s@%s", event->type().c_str(),
-             event->current_target()->GetDebugName().c_str());
-  } else if (current_stack_depth_ == base::UserLog::kEventStackMaxDepth) {
-    DLOG(WARNING) << "Reached maximum depth of " << kLogEntryMaxLength
-                  << ". Subsequent events will not be logged.";
-  }
-  current_stack_depth_++;
-}
-
-void ScriptEventLog::PopEvent() {
-  DCHECK(current_stack_depth_);
-  current_stack_depth_--;
-  if (current_stack_depth_ < base::UserLog::kEventStackMaxDepth) {
-    memset(event_log_stack_[current_stack_depth_], 0, kLogEntryMaxLength);
-  }
-}
-
-base::LazyInstance<ScriptEventLog> script_event_log = LAZY_INSTANCE_INITIALIZER;
-
-}  // namespace dom
-}  // namespace cobalt
diff --git a/src/cobalt/dom/script_event_log.h b/src/cobalt/dom/script_event_log.h
deleted file mode 100644
index 3d77748..0000000
--- a/src/cobalt/dom/script_event_log.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2018 The Cobalt Authors. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef COBALT_DOM_SCRIPT_EVENT_LOG_H_
-#define COBALT_DOM_SCRIPT_EVENT_LOG_H_
-
-#include "base/lazy_instance.h"
-#include "cobalt/base/user_log.h"
-#include "cobalt/dom/event.h"
-
-namespace cobalt {
-namespace dom {
-
-// This class records the nested events and manages the user log information.
-class ScriptEventLog {
- public:
-  ScriptEventLog();
-  ~ScriptEventLog();
-  void PushEvent(Event* event);
-  void PopEvent();
-
- private:
-  static const size_t kLogEntryMaxLength = 64;
-  int current_stack_depth_;
-  char event_log_stack_[base::UserLog::kEventStackMaxDepth][kLogEntryMaxLength];
-
-  DISALLOW_COPY_AND_ASSIGN(ScriptEventLog);
-};
-
-extern base::LazyInstance<ScriptEventLog> script_event_log;
-
-}  // namespace dom
-}  // namespace cobalt
-
-#endif  // COBALT_DOM_SCRIPT_EVENT_LOG_H_
diff --git a/src/cobalt/h5vcc/h5vcc_accessibility.cc b/src/cobalt/h5vcc/h5vcc_accessibility.cc
index 948f3f8..9255ce9 100644
--- a/src/cobalt/h5vcc/h5vcc_accessibility.cc
+++ b/src/cobalt/h5vcc/h5vcc_accessibility.cc
@@ -62,10 +62,11 @@
     dom::MutationObserverTaskManager* mutation_observer_task_manager)
     : event_dispatcher_(event_dispatcher) {
   message_loop_proxy_ = base::MessageLoopProxy::current();
+  on_application_event_callback_ = base::Bind(
+      &H5vccAccessibility::OnApplicationEvent, base::Unretained(this));
   event_dispatcher_->AddEventCallback(
       base::AccessibilitySettingsChangedEvent::TypeId(),
-      base::Bind(&H5vccAccessibility::OnApplicationEvent,
-                 base::Unretained(this)));
+      on_application_event_callback_);
   if (ShouldForceTextToSpeech()) {
 #if SB_HAS(SPEECH_SYNTHESIS)
     // Create a StarboardTTSEngine if the platform has speech synthesis.
@@ -88,6 +89,12 @@
   }
 }
 
+H5vccAccessibility::~H5vccAccessibility() {
+  event_dispatcher_->RemoveEventCallback(
+      base::AccessibilitySettingsChangedEvent::TypeId(),
+      on_application_event_callback_);
+}
+
 bool H5vccAccessibility::built_in_screen_reader() const {
   return screen_reader_ && screen_reader_->enabled();
 }
diff --git a/src/cobalt/h5vcc/h5vcc_accessibility.h b/src/cobalt/h5vcc/h5vcc_accessibility.h
index 50dce1a..eefccd4 100644
--- a/src/cobalt/h5vcc/h5vcc_accessibility.h
+++ b/src/cobalt/h5vcc/h5vcc_accessibility.h
@@ -37,6 +37,7 @@
       base::EventDispatcher* event_dispatcher,
       const scoped_refptr<dom::Window>& window,
       dom::MutationObserverTaskManager* mutation_observer_task_manager);
+  ~H5vccAccessibility();
 
   bool high_contrast_text() const;
   void AddHighContrastTextListener(
@@ -58,6 +59,7 @@
 
   scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
 
+  base::EventCallback on_application_event_callback_;
   base::EventDispatcher* event_dispatcher_;
   scoped_ptr<H5vccAccessibilityCallbackReference> high_contrast_text_listener_;
   scoped_ptr<accessibility::TTSEngine> tts_engine_;
diff --git a/src/cobalt/layout/box_generator.h b/src/cobalt/layout/box_generator.h
index f03eb6f..edc6ce1 100644
--- a/src/cobalt/layout/box_generator.h
+++ b/src/cobalt/layout/box_generator.h
@@ -108,7 +108,7 @@
 
   const scoped_refptr<cssom::CSSComputedStyleDeclaration>
       parent_css_computed_style_declaration_;
-  const scoped_refptr<const web_animations::AnimationSet>& parent_animations_;
+  const scoped_refptr<const web_animations::AnimationSet> parent_animations_;
   scoped_refptr<Paragraph>* paragraph_;
   // The current element depth.
   const int dom_element_depth_;
diff --git a/src/cobalt/layout/topmost_event_target.cc b/src/cobalt/layout/topmost_event_target.cc
index 8864210..ae53426 100644
--- a/src/cobalt/layout/topmost_event_target.cc
+++ b/src/cobalt/layout/topmost_event_target.cc
@@ -331,8 +331,10 @@
         pointer_state->SetActive(pointer_event->pointer_id());
         // Implicitly capture the pointer to the active element.
         //   https://www.w3.org/TR/pointerevents/#implicit-pointer-capture
-        scoped_refptr<dom::HTMLElement> html_element =
-            view->document()->active_element()->AsHTMLElement();
+        scoped_refptr<dom::HTMLElement> html_element;
+        if (view->document()->active_element()) {
+          html_element = view->document()->active_element()->AsHTMLElement();
+        }
         if (html_element) {
           pointer_state->SetPendingPointerCaptureTargetOverride(
               pointer_event->pointer_id(), html_element);
diff --git a/src/cobalt/loader/file_fetcher.cc b/src/cobalt/loader/file_fetcher.cc
index fdcdaa7..b8d9e7d 100644
--- a/src/cobalt/loader/file_fetcher.cc
+++ b/src/cobalt/loader/file_fetcher.cc
@@ -54,6 +54,18 @@
 
 FileFetcher::~FileFetcher() {
   DCHECK(thread_checker_.CalledOnValidThread());
+
+  if (message_loop_proxy_ != base::MessageLoopProxy::current()) {
+    // In case we are currently in the middle of a fetch (in which case it will
+    // be aborted), invalidate the weak pointers to this FileFetcher object to
+    // ensure that we do not process any responses from pending file I/O, which
+    // also guarantees that no new file I/O requests will be generated after the
+    // current one (if one is currently active).
+    weak_ptr_factory_.InvalidateWeakPtrs();
+    // Then wait for any currently active file I/O to complete, after which
+    // everything will be quiet and we can shutdown safely.
+    message_loop_proxy_->WaitForFence();
+  }
   CloseFile();
 }
 
diff --git a/src/cobalt/media/can_play_type_handler.h b/src/cobalt/media/can_play_type_handler.h
index 6fed16b..868b4a2 100644
--- a/src/cobalt/media/can_play_type_handler.h
+++ b/src/cobalt/media/can_play_type_handler.h
@@ -23,7 +23,8 @@
 class CanPlayTypeHandler {
  public:
   virtual ~CanPlayTypeHandler() {}
-  virtual std::string CanPlayType(const std::string& mime_type,
+  virtual std::string CanPlayType(bool is_progressive,
+                                  const std::string& mime_type,
                                   const std::string& key_system) = 0;
 
  protected:
diff --git a/src/cobalt/media/decoder_buffer_allocator.cc b/src/cobalt/media/decoder_buffer_allocator.cc
index 246f8db..3096515 100644
--- a/src/cobalt/media/decoder_buffer_allocator.cc
+++ b/src/cobalt/media/decoder_buffer_allocator.cc
@@ -125,6 +125,9 @@
 
     if (!kEnableMultiblockAllocate || kEnableAllocationLog) {
       void* p = reuse_allocator_->Allocate(size, alignment);
+      if (!p) {
+        return Allocations();
+      }
       LOG_IF(INFO, kEnableAllocationLog)
           << "======== Media Allocation Log " << p << " " << size << " "
           << alignment << " " << context;
@@ -141,6 +144,9 @@
     void* p = reuse_allocator_->AllocateBestBlock(alignment, context,
                                                   &allocated_size);
     DCHECK_LE(allocated_size, size);
+    if (!p) {
+      return Allocations();
+    }
     if (allocated_size == size) {
       if (!UpdateAllocationRecord()) {
         // UpdateAllocationRecord may fail with non-NULL p when capacity is
@@ -160,6 +166,9 @@
       allocated_size = size;
       void* p = reuse_allocator_->AllocateBestBlock(alignment, context,
                                                     &allocated_size);
+      if (!p) {
+        return Allocations();
+      }
       if (!UpdateAllocationRecord()) {
         update_allocation_record_failed = true;
         reuse_allocator_->Free(p);
@@ -226,19 +235,21 @@
     const VideoDecoderConfig& config) {
 #if COBALT_MEDIA_BUFFER_USING_MEMORY_POOL || SB_API_VERSION >= 10
   if (using_memory_pool_) {
-    if (!reuse_allocator_) {
-      return;
-    }
-    VideoResolution resolution =
-        GetVideoResolution(config.visible_rect().size());
 #if SB_API_VERSION >= 10
     video_codec_ = MediaVideoCodecToSbMediaVideoCodec(config.codec());
     resolution_width_ = config.visible_rect().size().width();
     resolution_height_ = config.visible_rect().size().height();
     bits_per_pixel_ = config.webm_color_metadata().BitsPerChannel;
+#endif  // SB_API_VERSION >= 10
+    if (!reuse_allocator_) {
+      return;
+    }
+#if SB_API_VERSION >= 10
     reuse_allocator_->set_max_capacity(SbMediaGetMaxBufferCapacity(
         video_codec_, resolution_width_, resolution_height_, bits_per_pixel_));
 #else   // SB_API_VERSION >= 10
+    VideoResolution resolution =
+        GetVideoResolution(config.visible_rect().size());
     if (reuse_allocator_->max_capacity() &&
         resolution > kVideoResolution1080p) {
       reuse_allocator_->set_max_capacity(COBALT_MEDIA_BUFFER_MAX_CAPACITY_4K);
diff --git a/src/cobalt/media/filters/shell_demuxer.cc b/src/cobalt/media/filters/shell_demuxer.cc
index 5232d1b..aca84cb 100644
--- a/src/cobalt/media/filters/shell_demuxer.cc
+++ b/src/cobalt/media/filters/shell_demuxer.cc
@@ -36,11 +36,7 @@
 namespace media {
 
 ShellDemuxerStream::ShellDemuxerStream(ShellDemuxer* demuxer, Type type)
-    : demuxer_(demuxer),
-      type_(type),
-      last_buffer_timestamp_(kNoTimestamp),
-      stopped_(false),
-      total_buffer_size_(0) {
+    : demuxer_(demuxer), type_(type) {
   TRACE_EVENT0("media_stack", "ShellDemuxerStream::ShellDemuxerStream()");
   DCHECK(demuxer_);
 }
@@ -71,6 +67,7 @@
     } else {
       // Do not pop EOS buffers, so that subsequent read requests also get EOS
       total_buffer_size_ -= buffer->data_size();
+      --total_buffer_count_;
       buffer_queue_.pop_front();
     }
     read_cb.Run(
@@ -139,6 +136,7 @@
     buffer_queue_.push_back(buffer);
     if (!buffer->end_of_stream()) {
       total_buffer_size_ += buffer->data_size();
+      ++total_buffer_count_;
     }
   }
 }
@@ -153,6 +151,11 @@
   return total_buffer_size_;
 }
 
+size_t ShellDemuxerStream::GetTotalBufferCount() const {
+  base::AutoLock auto_lock(lock_);
+  return total_buffer_count_;
+}
+
 void ShellDemuxerStream::FlushBuffers() {
   TRACE_EVENT0("media_stack", "ShellDemuxerStream::FlushBuffers()");
   base::AutoLock auto_lock(lock_);
@@ -160,6 +163,7 @@
   DLOG_IF(WARNING, !read_queue_.empty()) << "Read requests should be empty";
   buffer_queue_.clear();
   total_buffer_size_ = 0;
+  total_buffer_count_ = 0;
   last_buffer_timestamp_ = kNoTimestamp;
 }
 
@@ -169,6 +173,7 @@
   base::AutoLock auto_lock(lock_);
   buffer_queue_.clear();
   total_buffer_size_ = 0;
+  total_buffer_count_ = 0;
   last_buffer_timestamp_ = kNoTimestamp;
   // fulfill any pending callbacks with EOS buffers set to end timestamp
   for (ReadQueue::iterator it = read_queue_.begin(); it != read_queue_.end();
@@ -368,16 +373,26 @@
   if (requested_au_) {
     size_t total_buffer_size = audio_demuxer_stream_->GetTotalBufferSize() +
                                video_demuxer_stream_->GetTotalBufferSize();
+    size_t total_buffer_count = audio_demuxer_stream_->GetTotalBufferCount() +
+                                video_demuxer_stream_->GetTotalBufferCount();
 #if SB_API_VERSION >= 10
     int progressive_budget = SbMediaGetProgressiveBufferBudget(
         MediaVideoCodecToSbMediaVideoCodec(VideoConfig().codec()),
         VideoConfig().visible_rect().size().width(),
         VideoConfig().visible_rect().size().height(),
         VideoConfig().webm_color_metadata().BitsPerChannel);
+    int progressive_duration_cap_in_seconds =
+        SbMediaGetBufferGarbageCollectionDurationThreshold() / kSbTimeSecond;
 #else   // SB_API_VERSION >= 10
     int progressive_budget = COBALT_MEDIA_BUFFER_PROGRESSIVE_BUDGET;
+    int progressive_duration_cap_in_seconds =
+        COBALT_MEDIA_SOURCE_GARBAGE_COLLECTION_DURATION_THRESHOLD_IN_SECONDS;
 #endif  // SB_API_VERSION >= 10
-    if (total_buffer_size >= progressive_budget) {
+    const int kEstimatedBufferCountPerSeconds = 70;
+    int progressive_buffer_count_cap =
+        progressive_duration_cap_in_seconds * kEstimatedBufferCountPerSeconds;
+    if (total_buffer_size >= progressive_budget ||
+        total_buffer_count > progressive_buffer_count_cap) {
       // Retry after 100 milliseconds.
       const base::TimeDelta kDelay = base::TimeDelta::FromMilliseconds(100);
       blocking_thread_.message_loop()->PostDelayedTask(
diff --git a/src/cobalt/media/filters/shell_demuxer.h b/src/cobalt/media/filters/shell_demuxer.h
index ef33f0e..a560a91 100644
--- a/src/cobalt/media/filters/shell_demuxer.h
+++ b/src/cobalt/media/filters/shell_demuxer.h
@@ -62,6 +62,7 @@
   void Stop();
   base::TimeDelta GetLastBufferTimestamp() const;
   size_t GetTotalBufferSize() const;
+  size_t GetTotalBufferCount() const;
 
  private:
   // The Ranges object doesn't offer a complement object so we rebuild
@@ -83,8 +84,8 @@
   //   1. Used with the timestamp of the current frame to calculate the
   //      buffer range.
   //   2. Used by the demuxer to deteminate what type of frame to get next.
-  base::TimeDelta last_buffer_timestamp_;
-  bool stopped_;
+  base::TimeDelta last_buffer_timestamp_ = kNoTimestamp;
+  bool stopped_ = false;
 
   typedef std::deque<scoped_refptr<DecoderBuffer> > BufferQueue;
   BufferQueue buffer_queue_;
@@ -92,7 +93,8 @@
   typedef std::deque<ReadCB> ReadQueue;
   ReadQueue read_queue_;
 
-  size_t total_buffer_size_;
+  size_t total_buffer_size_ = 0;
+  size_t total_buffer_count_ = 0;
 
   DISALLOW_COPY_AND_ASSIGN(ShellDemuxerStream);
 };
diff --git a/src/cobalt/media/filters/source_buffer_stream.cc b/src/cobalt/media/filters/source_buffer_stream.cc
index 47b30d7..a2e2b21 100644
--- a/src/cobalt/media/filters/source_buffer_stream.cc
+++ b/src/cobalt/media/filters/source_buffer_stream.cc
@@ -1545,12 +1545,6 @@
     return false;
   }
 
-  if (!audio_configs_[0].encryption_scheme().Matches(
-          config.encryption_scheme())) {
-    MEDIA_LOG(ERROR, media_log_) << "Audio encryption changes not allowed.";
-    return false;
-  }
-
   // Check to see if the new config matches an existing one.
   for (size_t i = 0; i < audio_configs_.size(); ++i) {
     if (config.Matches(audio_configs_[i])) {
@@ -1599,12 +1593,6 @@
     return false;
   }
 
-  if (!video_configs_[0].encryption_scheme().Matches(
-          config.encryption_scheme())) {
-    MEDIA_LOG(ERROR, media_log_) << "Video encryption changes not allowed.";
-    return false;
-  }
-
   // Check to see if the new config matches an existing one.
   for (size_t i = 0; i < video_configs_.size(); ++i) {
     if (config.Matches(video_configs_[i])) {
diff --git a/src/cobalt/media/media_module_starboard.cc b/src/cobalt/media/media_module_starboard.cc
index 92dc615..2d63a41 100644
--- a/src/cobalt/media/media_module_starboard.cc
+++ b/src/cobalt/media/media_module_starboard.cc
@@ -23,6 +23,7 @@
 #include "cobalt/system_window/system_window.h"
 #include "nb/memory_scope.h"
 #include "starboard/media.h"
+#include "starboard/string.h"
 #include "starboard/window.h"
 
 namespace cobalt {
@@ -32,8 +33,21 @@
 
 class CanPlayTypeHandlerStarboard : public CanPlayTypeHandler {
  public:
-  std::string CanPlayType(const std::string& mime_type,
+  std::string CanPlayType(bool is_progressive, const std::string& mime_type,
                           const std::string& key_system) override {
+    if (is_progressive) {
+      // |mime_type| is something like:
+      //   video/mp4
+      //   video/webm
+      //   video/mp4; codecs="avc1.4d401e"
+      //   video/webm; codecs="vp9"
+      // We do a rough pre-filter to ensure that only video/mp4 is supported as
+      // progressive.
+      if (SbStringFindString(mime_type.c_str(), "video/mp4") == 0 &&
+          SbStringFindString(mime_type.c_str(), "application/x-mpegURL") == 0) {
+        return "";
+      }
+    }
     SbMediaSupportType type =
         SbMediaCanPlayMimeAndKeySystem(mime_type.c_str(), key_system.c_str());
     switch (type) {
diff --git a/src/cobalt/media/player/web_media_player.h b/src/cobalt/media/player/web_media_player.h
index 3ca8eb7..f0a3238 100644
--- a/src/cobalt/media/player/web_media_player.h
+++ b/src/cobalt/media/player/web_media_player.h
@@ -193,7 +193,8 @@
   // in |WebMediaPlayerClient::EncryptedMediaInitData|.
   //
   // |drm_system| must not be NULL. The method can only be called once.
-  virtual void SetDrmSystem(DrmSystem* drm_system) = 0;
+  virtual void SetDrmSystem(
+      const scoped_refptr<media::DrmSystem>& drm_system) = 0;
 };
 
 // TODO: Add prefix "On" to all methods that handle events, such
diff --git a/src/cobalt/media/player/web_media_player_impl.cc b/src/cobalt/media/player/web_media_player_impl.cc
index 1920b76..373bb88 100644
--- a/src/cobalt/media/player/web_media_player_impl.cc
+++ b/src/cobalt/media/player/web_media_player_impl.cc
@@ -586,7 +586,8 @@
   return true;
 }
 
-void WebMediaPlayerImpl::SetDrmSystem(DrmSystem* drm_system) {
+void WebMediaPlayerImpl::SetDrmSystem(
+    const scoped_refptr<media::DrmSystem>& drm_system) {
   DCHECK_EQ(static_cast<DrmSystem*>(NULL), drm_system_);
   DCHECK_NE(static_cast<DrmSystem*>(NULL), drm_system);
 
diff --git a/src/cobalt/media/player/web_media_player_impl.h b/src/cobalt/media/player/web_media_player_impl.h
index 92fdb4a..c52a7a3 100644
--- a/src/cobalt/media/player/web_media_player_impl.h
+++ b/src/cobalt/media/player/web_media_player_impl.h
@@ -187,7 +187,7 @@
 
   bool GetDebugReportDataAddress(void** out_address, size_t* out_size) override;
 
-  void SetDrmSystem(DrmSystem* drm_system) override;
+  void SetDrmSystem(const scoped_refptr<media::DrmSystem>& drm_system) override;
   void SetDrmSystemReadyCB(const DrmSystemReadyCB& drm_system_ready_cb);
 
   void OnPipelineSeek(PipelineStatus status);
@@ -326,7 +326,7 @@
       media_time_and_seeking_state_cb_;
 
   DrmSystemReadyCB drm_system_ready_cb_;
-  DrmSystem* drm_system_;
+  scoped_refptr<DrmSystem> drm_system_;
 
   DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerImpl);
 };
diff --git a/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_texture_lookup_ellipse.glsl b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_texture_lookup_ellipse.glsl
new file mode 100644
index 0000000..ce95493
--- /dev/null
+++ b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_texture_lookup_ellipse.glsl
@@ -0,0 +1,37 @@
+#version 100
+uniform highp float u_skRTHeight;
+precision mediump float;
+uniform highp vec4 uellipse_Stage2;
+uniform highp sampler2D uTextureSampler_0_Stage1;
+varying mediump vec4 vcolor_Stage0;
+varying highp vec2 vTransformedCoords_0_Stage0;
+
+void main() {
+  highp vec2 _sktmpCoord = gl_FragCoord.xy;
+  highp vec4 sk_FragCoord = vec4(_sktmpCoord.x, u_skRTHeight - _sktmpCoord.y, 1.0, 1.0);
+  vec4 outputColor_Stage0;
+  {
+    outputColor_Stage0 = vcolor_Stage0;
+  }
+  vec4 output_Stage1;
+  {
+    output_Stage1 = texture2D(uTextureSampler_0_Stage1, vTransformedCoords_0_Stage0).wwww;
+  }
+  vec4 output_Stage2;
+  {
+    vec2 d = sk_FragCoord.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, 0.0001);
+    float approx_dist = implicit * inversesqrt(grad_dot);
+    float alpha;
+    {
+        alpha = clamp(0.5 + approx_dist, 0.0, 1.0);
+    }
+    output_Stage2 = output_Stage1 * alpha;
+  }
+  {
+    gl_FragColor = outputColor_Stage0 * output_Stage2;
+  }
+}
diff --git a/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_texture_lookup_rectangle.glsl b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_texture_lookup_rectangle.glsl
new file mode 100644
index 0000000..d0d7f54
--- /dev/null
+++ b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_texture_lookup_rectangle.glsl
@@ -0,0 +1,37 @@
+#version 100
+uniform highp float u_skRTHeight;
+precision mediump float;
+uniform vec4 uinnerRect_Stage2;
+uniform vec2 uinvRadiiXY_Stage2;
+uniform highp sampler2D uTextureSampler_0_Stage1;
+varying mediump vec4 vcolor_Stage0;
+varying highp vec2 vTransformedCoords_0_Stage0;
+
+void main() {
+  highp vec2 _sktmpCoord = gl_FragCoord.xy;
+  highp vec4 sk_FragCoord = vec4(_sktmpCoord.x, u_skRTHeight - _sktmpCoord.y, 1.0, 1.0);
+  vec4 outputColor_Stage0;
+  {
+    outputColor_Stage0 = vcolor_Stage0;
+  }
+  vec4 output_Stage1;
+  {
+    output_Stage1 = texture2D(uTextureSampler_0_Stage1, vTransformedCoords_0_Stage0).wwww;
+  }
+  vec4 output_Stage2;
+  {
+    vec2 dxy0 = uinnerRect_Stage2.xy - sk_FragCoord.xy;
+    vec2 dxy1 = sk_FragCoord.xy - uinnerRect_Stage2.zw;
+    vec2 dxy = max(max(dxy0, dxy1), 0.0);
+    vec2 Z = dxy * uinvRadiiXY_Stage2.xy;
+    float implicit = dot(Z, dxy) - 1.0;
+    float grad_dot = 4.0 * dot(Z, Z);
+    grad_dot = max(grad_dot, 0.0001);
+    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 = outputColor_Stage0 * output_Stage2;
+  }
+}
diff --git a/src/cobalt/renderer/glimp_shaders/glsl/vertex_skia_color_position_passthrough_4kx8k_texcoords.glsl b/src/cobalt/renderer/glimp_shaders/glsl/vertex_skia_color_position_passthrough_4kx8k_texcoords.glsl
new file mode 100644
index 0000000..911c25c
--- /dev/null
+++ b/src/cobalt/renderer/glimp_shaders/glsl/vertex_skia_color_position_passthrough_4kx8k_texcoords.glsl
@@ -0,0 +1,17 @@
+#version 100
+
+precision highp float;
+uniform highp vec4 urtAdjustment_Stage0;
+attribute highp vec2 inPosition;
+attribute mediump vec4 inColor;
+attribute highp vec2 inTextureCoords;
+varying mediump vec4 vinColor_Stage0;
+varying highp vec2 vTextureCoords_Stage0;
+varying highp vec2 vIntTextureCoords_Stage0;
+void main() {
+    vinColor_Stage0 = inColor;
+    vec2 pos2 = inPosition;
+    vTextureCoords_Stage0 = inTextureCoords;
+    vIntTextureCoords_Stage0 = vec2(4096.0, 8192.0) * inTextureCoords;
+    gl_Position = vec4(pos2.x * urtAdjustment_Stage0.x + urtAdjustment_Stage0.y, pos2.y * urtAdjustment_Stage0.z + urtAdjustment_Stage0.w, 0.0, 1.0);
+}
diff --git a/src/cobalt/renderer/glimp_shaders/glsl/vertex_skia_distance_field_path.glsl b/src/cobalt/renderer/glimp_shaders/glsl/vertex_skia_distance_field_path.glsl
new file mode 100644
index 0000000..d052f69
--- /dev/null
+++ b/src/cobalt/renderer/glimp_shaders/glsl/vertex_skia_distance_field_path.glsl
@@ -0,0 +1,16 @@
+#version 100

+

+precision highp float;

+uniform highp vec4 urtAdjustment_Stage0;

+uniform highp mat3 uViewM_Stage0;

+attribute highp vec2 inPosition;

+attribute mediump vec4 inColor;

+attribute mediump vec2 inTextureCoords;

+varying highp vec2 vTextureCoords_Stage0;

+varying mediump vec4 vinColor_Stage0;

+void main() {

+    vinColor_Stage0 = inColor;

+    vTextureCoords_Stage0 = inTextureCoords;

+    vec2 pos2 = (uViewM_Stage0 * vec3(inPosition, 1.0)).xy;

+    gl_Position = vec4(pos2.x * urtAdjustment_Stage0.x + urtAdjustment_Stage0.y, pos2.y * urtAdjustment_Stage0.z + urtAdjustment_Stage0.w, 0.0, 1.0);

+}

diff --git a/src/cobalt/renderer/rasterizer/pixel_test.cc b/src/cobalt/renderer/rasterizer/pixel_test.cc
index 3655b47..6d773c3 100644
--- a/src/cobalt/renderer/rasterizer/pixel_test.cc
+++ b/src/cobalt/renderer/rasterizer/pixel_test.cc
@@ -1103,6 +1103,17 @@
                                        ColorRGBA(1.0f, 0, 0, 1.0)));
 }
 
+TEST_F(PixelTest, TooManyGlyphs) {
+  // Overflow the glyph atlas to force path rendering.
+  CompositionNode::Builder builder;
+  for (char ch = 33; ch < 127; ++ch) {
+    builder.AddChild(CreateTextNodeWithinSurface(
+        GetResourceProvider(), std::string(1, ch), FontStyle(), 500,
+        ColorRGBA(0, 0, 0, 0.1)));
+  }
+  TestTree(new CompositionNode(builder));
+}
+
 TEST_F(PixelTest, ShearedText) {
   TestTree(new MatrixTransformNode(
       CreateTextNodeWithinSurface(GetResourceProvider(), "Cobalt", FontStyle(),
diff --git a/src/cobalt/renderer/rasterizer/testdata/TooManyGlyphs-expected.png b/src/cobalt/renderer/rasterizer/testdata/TooManyGlyphs-expected.png
new file mode 100644
index 0000000..4f577e3
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/TooManyGlyphs-expected.png
Binary files differ
diff --git a/src/cobalt/script/v8c/isolate_fellowship.cc b/src/cobalt/script/v8c/isolate_fellowship.cc
index 78a99e4..4cef531 100644
--- a/src/cobalt/script/v8c/isolate_fellowship.cc
+++ b/src/cobalt/script/v8c/isolate_fellowship.cc
@@ -53,7 +53,7 @@
   }
 }
 
-} // namespace
+}  // namespace
 
 IsolateFellowship::IsolateFellowship() {
   TRACE_EVENT0("cobalt::script", "IsolateFellowship::IsolateFellowship");
@@ -68,7 +68,9 @@
   // to write the snapshot data. We need to make sure all global command line
   // flags are set before that.
   V8FlagsInit();
+#if !defined(COBALT_V8_BUILDTIME_SNAPSHOT)
   InitializeStartupData();
+#endif  // !defined(COBALT_V8_BUILDTIME_SNAPSHOT)
 }
 
 IsolateFellowship::~IsolateFellowship() {
@@ -80,14 +82,17 @@
   delete array_buffer_allocator;
   array_buffer_allocator = nullptr;
 
+#if !defined(COBALT_V8_BUILDTIME_SNAPSHOT)
   // Note that both us and V8 will have created this with new[], see
   // "snapshot-common.cc".  Also note that both startup data creation failure
   // from V8 is possible, and deleting a null pointer is safe, so there is no
   // DCHECK here.
   delete[] startup_data.data;
   startup_data = {nullptr, 0};
+#endif
 }
 
+#if !defined(COBALT_V8_BUILDTIME_SNAPSHOT)
 void IsolateFellowship::InitializeStartupData() {
   TRACE_EVENT0("cobalt::script", "IsolateFellowship::InitializeStartupData");
   DCHECK(startup_data.data == nullptr);
@@ -223,6 +228,7 @@
 
   maybe_remove_cache_file();
 }
+#endif  // !defined(COBALT_V8_BUILDTIME_SNAPSHOT)
 
 }  // namespace v8c
 }  // namespace script
diff --git a/src/cobalt/script/v8c/isolate_fellowship.h b/src/cobalt/script/v8c/isolate_fellowship.h
index 6b6a631..705a126 100644
--- a/src/cobalt/script/v8c/isolate_fellowship.h
+++ b/src/cobalt/script/v8c/isolate_fellowship.h
@@ -18,8 +18,8 @@
 #include "base/memory/singleton.h"
 #include "cobalt/script/v8c/cobalt_platform.h"
 #include "v8/include/libplatform/libplatform.h"
-#include "v8/include/v8-platform.h"
 #include "v8/include/v8.h"
+#include "v8/include/v8-platform.h"
 
 namespace cobalt {
 namespace script {
@@ -28,7 +28,8 @@
 // A helper singleton to hold global state required by all V8 isolates across
 // the entire process (the fellowship).  Initialization logic for this data is
 // also handled here, most notably, the possible reading/writing of
-// |startup_data| from/to a cache file.
+// |startup_data| from/to a cache file if snapshot has not been generated at
+// build time.
 struct IsolateFellowship {
  public:
   static IsolateFellowship* GetInstance() {
@@ -38,7 +39,9 @@
 
   scoped_refptr<CobaltPlatform> platform = nullptr;
   v8::ArrayBuffer::Allocator* array_buffer_allocator = nullptr;
+#if !defined(COBALT_V8_BUILDTIME_SNAPSHOT)
   v8::StartupData startup_data = {nullptr, 0};
+#endif  // !defined(COBALT_V8_BUILDTIME_SNAPSHOT)
 
   friend struct StaticMemorySingletonTraits<IsolateFellowship>;
 
@@ -46,11 +49,13 @@
   IsolateFellowship();
   ~IsolateFellowship();
 
+#if !defined(COBALT_V8_BUILDTIME_SNAPSHOT)
   // Initialize |startup_data| by either reading it from a cache file or
   // creating it.  If creating it for the first time, then when appropriate
   // (i.e. the platform has a suitable directory) attempt to write it to a cache
   // file.
   void InitializeStartupData();
+#endif  // !defined(COBALT_V8_BUILDTIME_SNAPSHOT)
 };
 
 }  // namespace v8c
diff --git a/src/cobalt/script/v8c/v8c_engine.cc b/src/cobalt/script/v8c/v8c_engine.cc
index 25daf87..cc55ee4 100644
--- a/src/cobalt/script/v8c/v8c_engine.cc
+++ b/src/cobalt/script/v8c/v8c_engine.cc
@@ -108,6 +108,7 @@
   v8::Isolate::CreateParams create_params;
   create_params.array_buffer_allocator =
       isolate_fellowship->array_buffer_allocator;
+#if !defined(COBALT_V8_BUILDTIME_SNAPSHOT)
   auto* startup_data = &isolate_fellowship->startup_data;
   if (startup_data->data != nullptr) {
     create_params.snapshot_blob = startup_data;
@@ -117,6 +118,7 @@
     LOG(WARNING) << "Isolate fellowship startup data was null, this will "
                     "significantly slow down startup time.";
   }
+#endif  // !defined(COBALT_V8_BUILDTIME_SNAPSHOT)
 
   isolate_ = v8::Isolate::New(create_params);
   CHECK(isolate_);
diff --git a/src/cobalt/storage/store_upgrade/upgrade_test.cc b/src/cobalt/storage/store_upgrade/upgrade_test.cc
index 2c8b4fb..c64d7df 100644
--- a/src/cobalt/storage/store_upgrade/upgrade_test.cc
+++ b/src/cobalt/storage/store_upgrade/upgrade_test.cc
@@ -73,8 +73,7 @@
 
   Storage storage;
   EXPECT_TRUE(storage.ParseFromArray(buffer.data() + kStorageHeaderSize,
-                                     buffer.size()) -
-              kStorageHeaderSize);
+                                     buffer.size() - kStorageHeaderSize));
 
   if (storage.cookies(0).name() == "foo") {
     ValidateCookie(storage.cookies(0), "foo", "bar", "localhost", "/",
diff --git a/src/cobalt/tools/automated_testing/cobalt_runner.py b/src/cobalt/tools/automated_testing/cobalt_runner.py
index 46ab679..29c4326 100644
--- a/src/cobalt/tools/automated_testing/cobalt_runner.py
+++ b/src/cobalt/tools/automated_testing/cobalt_runner.py
@@ -69,6 +69,7 @@
     device_id = None
     config = None
     out_directory = None
+    target_params = None
 
   class WindowDriverCreatedTimeoutException(Exception):
     """Exception thrown when WindowDriver was not created in time."""
@@ -92,9 +93,9 @@
       url:              The intial URL to launch Cobalt on.
       log_file:         The log file's name string.
       target_params:    An array of command line arguments to launch Cobalt
-      with.
+        with.
       success_message:  Optional success message to be printed on successful
-      exit.
+        exit.
     """
 
     self.test_script_started = threading.Event()
@@ -242,15 +243,14 @@
 
   def _KillLauncher(self):
     """Kills the launcher and its attached Cobalt instance."""
-    try:
-      self.launcher.Kill()
-    except Exception as e:  # pylint: disable=broad-except
-      sys.stderr.write('Exception killing launcher:\n')
-      sys.stderr.write('{}\n'.format(str(e)))
+    self.ExecuteJavaScript('window.close();')
 
     self.runner_thread.join(COBALT_EXIT_TIMEOUT_SECONDS)
     if self.runner_thread.isAlive():
-      sys.stderr.write('***Runner thread still alive***\n')
+      sys.stderr.write(
+          '***Runner thread still alive after sending graceful shutdown command, try again by killing app***\n'
+      )
+      self.launcher.Kill()
     # Once the write end of the pipe has been closed by the launcher, the reader
     # thread will get EOF and exit.
     self.reader_thread.join(COBALT_EXIT_TIMEOUT_SECONDS)
@@ -301,16 +301,20 @@
         thread.interrupt_main()
     return 0
 
+  def ExecuteJavaScript(self, js_code):
+    return self.webdriver.execute_script(js_code)
+
   def GetCval(self, cval_name):
     """Returns the Python object represented by a JSON cval string.
 
     Args:
       cval_name: Name of the cval.
+
     Returns:
       Python object represented by the JSON cval string
     """
     javascript_code = 'return h5vcc.cVal.getValue(\'{}\')'.format(cval_name)
-    json_result = self.webdriver.execute_script(javascript_code)
+    json_result = self.ExecuteJavaScript(javascript_code)
     if json_result is None:
       return None
     else:
@@ -322,6 +326,7 @@
     Args:
       css_selector: A CSS selector
       expected_num: The expected number of the selector type to be found.
+
     Raises:
       Underlying WebDriver exceptions
     """
@@ -337,6 +342,7 @@
 
     Args:
       unique_selector: A CSS selector that will select only one element
+
     Raises:
       AssertException: the element isn't unique
     Returns:
@@ -349,6 +355,7 @@
 
     Args:
       css_selector: A CSS selector
+
     Raises:
       AssertException: the element isn't found
     """
@@ -364,6 +371,7 @@
     Args:
       css_selector: A CSS selector
       expected_num: Expected number of matching elements
+
     Raises:
       AssertException: expected_num isn't met
     Returns:
@@ -406,6 +414,7 @@
 
     Args:
       url:  URL string to be loaded by Cobalt.
+
     Raises:
       Underlying WebDriver exceptions
     """
@@ -434,5 +443,9 @@
   device_params.config = args.config
   device_params.device_id = args.device_id
   device_params.out_directory = args.out_directory
+  if args.target_params == None:
+    device_params.target_params = []
+  else:
+    device_params.target_params = [args.target_params]
 
   return device_params
diff --git a/src/cobalt/version.h b/src/cobalt/version.h
index e6a94f6..3c73b6c 100644
--- a/src/cobalt/version.h
+++ b/src/cobalt/version.h
@@ -35,6 +35,6 @@
 //                  release is cut.
 //.
 
-#define COBALT_VERSION "19.lts.2"
+#define COBALT_VERSION "19.lts.3"
 
 #endif  // COBALT_VERSION_H_
diff --git a/src/cobalt/webdriver/web_driver_module.cc b/src/cobalt/webdriver/web_driver_module.cc
index c0b24f4..993e0aa 100644
--- a/src/cobalt/webdriver/web_driver_module.cc
+++ b/src/cobalt/webdriver/web_driver_module.cc
@@ -445,8 +445,8 @@
 }  // NOLINT(readability/fn_size)
 
 WebDriverModule::~WebDriverModule() {
-  webdriver_thread_.message_loop()->PostTask(
-      FROM_HERE, base::Bind(&WebDriverModule::StopServer,
+  webdriver_thread_.message_loop()->PostBlockingTask(
+      FROM_HERE, base::Bind(&WebDriverModule::StopServerAndSession,
                             base::Unretained(this)));
   webdriver_thread_.Stop();
 }  // NOLINT(readability/fn_size)
@@ -474,8 +474,9 @@
                  base::Unretained(webdriver_dispatcher_.get()))));
 }
 
-void WebDriverModule::StopServer() {
+void WebDriverModule::StopServerAndSession() {
   webdriver_server_.reset();
+  session_.reset();
 }
 
 SessionDriver* WebDriverModule::GetSessionDriver(
diff --git a/src/cobalt/webdriver/web_driver_module.h b/src/cobalt/webdriver/web_driver_module.h
index 8d8c96f..347e3d6 100644
--- a/src/cobalt/webdriver/web_driver_module.h
+++ b/src/cobalt/webdriver/web_driver_module.h
@@ -71,7 +71,7 @@
 
  private:
   void StartServer(int server_port, const std::string& listen_ip);
-  void StopServer();
+  void StopServerAndSession();
   void GetServerStatus(
       const base::Value* parameters,
       const WebDriverDispatcher::PathVariableMap* path_variables,
diff --git a/src/nb/reuse_allocator_base.cc b/src/nb/reuse_allocator_base.cc
index 2a64b43..6a38327 100644
--- a/src/nb/reuse_allocator_base.cc
+++ b/src/nb/reuse_allocator_base.cc
@@ -329,10 +329,16 @@
   std::size_t size_to_try = 0;
   if (allocation_increment_ > size) {
     size_to_try = std::max(size, allocation_increment_);
+    if (max_capacity_ && capacity_ + size_to_try > max_capacity_) {
+      return free_blocks_.end();
+    }
     ptr = fallback_allocator_->AllocateForAlignment(&size_to_try, alignment);
   }
   if (ptr == NULL) {
     size_to_try = size;
+    if (max_capacity_ && capacity_ + size_to_try > max_capacity_) {
+      return free_blocks_.end();
+    }
     ptr = fallback_allocator_->AllocateForAlignment(&size_to_try, alignment);
   }
   if (ptr != NULL) {
@@ -350,6 +356,9 @@
   // in the hope that they are continuous and can be connect to a block that is
   // large enough to fulfill |size|.
   size_t size_difference = size - free_blocks_.rbegin()->size();
+  if (max_capacity_ && capacity_ + size_difference > max_capacity_) {
+    return free_blocks_.end();
+  }
   ptr = fallback_allocator_->AllocateForAlignment(&size_difference, alignment);
   if (ptr == NULL) {
     return free_blocks_.end();
diff --git a/src/nb/reuse_allocator_base.h b/src/nb/reuse_allocator_base.h
index cb70f0f..0e4f935 100644
--- a/src/nb/reuse_allocator_base.h
+++ b/src/nb/reuse_allocator_base.h
@@ -17,6 +17,7 @@
 #ifndef NB_REUSE_ALLOCATOR_BASE_H_
 #define NB_REUSE_ALLOCATOR_BASE_H_
 
+#include <algorithm>
 #include <map>
 #include <set>
 #include <vector>
@@ -66,7 +67,9 @@
 
   std::size_t max_capacity() const { return max_capacity_; }
   void set_max_capacity(std::size_t max_capacity) {
-    max_capacity_ = max_capacity;
+    // TODO: Properly implement decreasing the max capacity so that the
+    // capacity is not suddenly exceeded.
+    max_capacity_ = std::max(max_capacity, max_capacity_);
   }
 
  protected:
diff --git a/src/net/base/transport_security_state_unittest.cc b/src/net/base/transport_security_state_unittest.cc
index 7d7f7fe..69afef4 100644
--- a/src/net/base/transport_security_state_unittest.cc
+++ b/src/net/base/transport_security_state_unittest.cc
@@ -34,7 +34,7 @@
 #include "crypto/nss_util.h"
 #endif
 
-#if defined(__LB_SHELL__)
+#if defined(OS_STARBOARD)
 // We don't support cert pinning, so it's not compiled in.
 // Disable all tests related to cert pins.
 #define MAYBE_IsPreloaded DISABLED_IsPreloaded
diff --git a/src/net/dial/dial_udp_socket_factory.cc b/src/net/dial/dial_udp_socket_factory.cc
index 3e5e2b0..f78a8d8 100644
--- a/src/net/dial/dial_udp_socket_factory.cc
+++ b/src/net/dial/dial_udp_socket_factory.cc
@@ -70,8 +70,14 @@
 
  SetupSocketAfterCreate(s);
 
- if (!NativeBind(s, address))
+ if (!NativeBind(s, address)) {
+#if defined(OS_POSIX)
+   close(s);
+#elif defined(OS_STARBOARD)
+   SbSocketDestroy(s);
+#endif
    return NULL;
+ }
 
  SetupSocketAfterBind(s);
 
diff --git a/src/starboard/build/base_configuration.gypi b/src/starboard/build/base_configuration.gypi
index f085dfc..0853f2c 100644
--- a/src/starboard/build/base_configuration.gypi
+++ b/src/starboard/build/base_configuration.gypi
@@ -147,8 +147,6 @@
 
     'compiler_flags_host%': [],
     'compiler_flags_c_host%': [],
-    'compiler_flags_cc_host%': [],
-    'linker_flags_host%': [],
     'defines_host%': [],
 
     'platform_libraries%': [],
@@ -157,6 +155,38 @@
 
     # List of platform-specific targets that get compiled into cobalt.
     'cobalt_platform_dependencies%': [],
+
+    'conditions': [
+      ['host_os=="linux"', {
+        'conditions': [
+          ['target_arch=="arm" or target_arch=="ia32" or target_arch=="x32"\
+           or target_arch=="mips" or target_arch=="mipsel" or\
+           target_arch=="ppc"', {
+            # All the 32 bit CPU architectures v8 supports.
+            'compiler_flags_cc_host%': [
+              '-m32',
+              '--std=gnu++11',
+            ],
+            'linker_flags_host%': [
+              '-target', 'i386-unknown-linux-gnu',
+              '-pthread',
+              '-fuse-ld=lld',
+            ],
+          }, {
+            'compiler_flags_cc_host%': [
+              '--std=gnu++11',
+            ],
+            'linker_flags_host%': [
+              '-pthread',
+              '-fuse-ld=lld',
+            ],
+          }],
+        ],
+      }, {
+        'compiler_flags_cc_host%': [],
+        'linker_flags_host%': [],
+      }],
+    ],
   },
 
   'target_defaults': {
diff --git a/src/starboard/linux/shared/player_components_impl.cc b/src/starboard/linux/shared/player_components_impl.cc
index 809b7df..fe97e20 100644
--- a/src/starboard/linux/shared/player_components_impl.cc
+++ b/src/starboard/linux/shared/player_components_impl.cc
@@ -88,8 +88,12 @@
     }
 
     video_render_algorithm->reset(new VideoRenderAlgorithmImpl);
-    *video_renderer_sink = new PunchoutVideoRendererSink(
-        video_parameters.player, kVideoSinkRenderInterval);
+    if (video_parameters.output_mode == kSbPlayerOutputModeDecodeToTexture) {
+      *video_renderer_sink = NULL;
+    } else {
+      *video_renderer_sink = new PunchoutVideoRendererSink(
+          video_parameters.player, kVideoSinkRenderInterval);
+    }
   }
 
   void GetAudioRendererParams(int* max_cached_frames,
diff --git a/src/starboard/nplb/socket_join_multicast_group_test.cc b/src/starboard/nplb/socket_join_multicast_group_test.cc
index f6021b4..6b06998 100644
--- a/src/starboard/nplb/socket_join_multicast_group_test.cc
+++ b/src/starboard/nplb/socket_join_multicast_group_test.cc
@@ -14,6 +14,7 @@
 
 #include "starboard/nplb/socket_helpers.h"
 #include "starboard/socket.h"
+#include "starboard/thread.h"
 #include "starboard/time.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -79,15 +80,16 @@
   }
 
   SbSocketAddress receive_address;
-  int loop_counts = 10000;
+  SbTimeMonotonic stop_time = SbTimeGetMonotonicNow() + kSbTimeSecond;
   while (true) {
     // Breaks the case where the test will hang in a loop when
     // SbSocketReceiveFrom() always returns kSbSocketPending.
-    ASSERT_GE(loop_counts--, 0) << "Multicast timed out.";
+    ASSERT_LE(SbTimeGetMonotonicNow(), stop_time) << "Multicast timed out.";
     int received = SbSocketReceiveFrom(
         receive_socket, buf, SB_ARRAY_SIZE_INT(buf), &receive_address);
     if (received < 0 &&
         SbSocketGetLastError(receive_socket) == kSbSocketPending) {
+      SbThreadSleep(kSbTimeMillisecond);
       continue;
     }
     EXPECT_EQ(SB_ARRAY_SIZE_INT(kBuf), received);
diff --git a/src/starboard/raspi/shared/launcher.py b/src/starboard/raspi/shared/launcher.py
index 20ffbbb..75e57c6 100644
--- a/src/starboard/raspi/shared/launcher.py
+++ b/src/starboard/raspi/shared/launcher.py
@@ -35,8 +35,8 @@
   Args:
     signum: Signal number that triggered this callback.  Passed in when the
       signal handler is called by python runtime.
-    frame: Current stack frame.  Passed in when the signal handler is called
-      by python runtime.
+    frame: Current stack frame.  Passed in when the signal handler is called by
+      python runtime.
   """
   sys.exit(signum)
 
@@ -48,6 +48,7 @@
 
   _RASPI_USERNAME = 'pi'
   _RASPI_PASSWORD = 'raspberry'
+  _SSH_LOGIN_SIGNAL = 'cobalt-launcher-login-success'
 
   # pexpect times out each second to allow Kill to quickly stop a test run
   _PEXPECT_TIMEOUT = 1
@@ -101,7 +102,7 @@
     raspi_test_path = os.path.join(test_base_dir, test_file)
 
     # rsync command setup
-    options = '-avzh --exclude obj*'
+    options = '-avzLh --exclude obj/ --exclude obj.host/ --exclude gen/'
     source = test_dir_path
     destination = raspi_user_hostname + ':~/'
     self.rsync_command = 'rsync ' + options + ' ' + source + ' ' + destination
@@ -140,18 +141,26 @@
     self.pexpect_process = pexpect.spawn(
         command, timeout=Launcher._PEXPECT_TIMEOUT)
     retry_count = 0
+    expected_prompts = [
+        r'.*Are\syou\ssure.*',  # Fingerprint verification
+        r'\S+ password:',  # Password prompt
+        '.*[a-zA-Z]+.*',  # Any other text input
+    ]
     while True:
-      expected_prompts = [
-          r'.*Are\syou\ssure.*',  # Fingerprint verification
-          r'\S+ password:',  # Password prompt
-      ]
       try:
         i = self.pexpect_process.expect(expected_prompts)
         if i == 0:
           self.pexpect_process.sendline('yes')
-        else:
+        elif i == 1:
           self.pexpect_process.sendline(Launcher._RASPI_PASSWORD)
           break
+        else:
+          # If any other input comes in, maybe we've logged in with rsa key or
+          # raspi does not have password. Check if we've logged in by echoing
+          # a special sentence and expect it back.
+          self.pexpect_process.sendline('echo ' + Launcher._SSH_LOGIN_SIGNAL)
+          i = self.pexpect_process.expect([Launcher._SSH_LOGIN_SIGNAL])
+          break
       except pexpect.TIMEOUT:
         if self.shutdown_initiated.is_set():
           return
@@ -232,8 +241,7 @@
       logging.exception('pexpect encountered EOF while reading line.')
     except pexpect.TIMEOUT:
       logging.exception('pexpect timed out while reading line.')
-    # pylint: disable=W0703
-    except Exception:
+    except Exception:  # pylint: disable=broad-except
       logging.exception('Error occured while running test.')
     finally:
       self._CleanupPexpectProcess()
diff --git a/src/starboard/shared/ffmpeg/ffmpeg_video_decoder_impl.cc b/src/starboard/shared/ffmpeg/ffmpeg_video_decoder_impl.cc
index 37170aa..e60fe47 100644
--- a/src/starboard/shared/ffmpeg/ffmpeg_video_decoder_impl.cc
+++ b/src/starboard/shared/ffmpeg/ffmpeg_video_decoder_impl.cc
@@ -188,6 +188,9 @@
     TeardownCodec();
     InitializeCodec();
   }
+
+  decltype(frames_) frames;
+  frames_ = std::queue<scoped_refptr<CpuVideoFrame>>();
 }
 
 bool VideoDecoderImpl<FFMPEG>::is_valid() const {
@@ -293,29 +296,25 @@
 
   bool result = true;
   if (output_mode_ == kSbPlayerOutputModeDecodeToTexture) {
-    result = UpdateDecodeTarget(frame);
+    frames_.push(frame);
   }
 
   decoder_status_cb_(kBufferFull, frame);
 
-  return result;
+  return true;
 }
 
-bool VideoDecoderImpl<FFMPEG>::UpdateDecodeTarget(
+void VideoDecoderImpl<FFMPEG>::UpdateDecodeTarget_Locked(
     const scoped_refptr<CpuVideoFrame>& frame) {
   SbDecodeTarget decode_target = DecodeTargetCreate(
       decode_target_graphics_context_provider_, frame, decode_target_);
 
   // Lock only after the post to the renderer thread, to prevent deadlock.
-  ScopedLock lock(decode_target_mutex_);
   decode_target_ = decode_target;
 
   if (!SbDecodeTargetIsValid(decode_target)) {
     SB_LOG(ERROR) << "Could not acquire a decode target from provider.";
-    return false;
   }
-
-  return true;
 }
 
 void VideoDecoderImpl<FFMPEG>::InitializeCodec() {
@@ -397,6 +396,12 @@
   // We must take a lock here since this function can be called from a
   // separate thread.
   ScopedLock lock(decode_target_mutex_);
+  while (frames_.size() > 1 && frames_.front()->HasOneRef()) {
+    frames_.pop();
+  }
+  if (!frames_.empty()) {
+    UpdateDecodeTarget_Locked(frames_.front());
+  }
   if (SbDecodeTargetIsValid(decode_target_)) {
     // Make a disposable copy, since the state is internally reused by this
     // class (to avoid recreating GL objects).
diff --git a/src/starboard/shared/ffmpeg/ffmpeg_video_decoder_impl.h b/src/starboard/shared/ffmpeg/ffmpeg_video_decoder_impl.h
index b1b05b3..b7a55e8 100644
--- a/src/starboard/shared/ffmpeg/ffmpeg_video_decoder_impl.h
+++ b/src/starboard/shared/ffmpeg/ffmpeg_video_decoder_impl.h
@@ -15,6 +15,8 @@
 #ifndef STARBOARD_SHARED_FFMPEG_FFMPEG_VIDEO_DECODER_IMPL_H_
 #define STARBOARD_SHARED_FFMPEG_FFMPEG_VIDEO_DECODER_IMPL_H_
 
+#include <queue>
+
 #include "starboard/common/ref_counted.h"
 #include "starboard/log.h"
 #include "starboard/media.h"
@@ -114,7 +116,7 @@
   void TeardownCodec();
   SbDecodeTarget GetCurrentDecodeTarget() override;
 
-  bool UpdateDecodeTarget(const scoped_refptr<CpuVideoFrame>& frame);
+  void UpdateDecodeTarget_Locked(const scoped_refptr<CpuVideoFrame>& frame);
 
   FFMPEGDispatch* ffmpeg_;
 
@@ -158,6 +160,7 @@
 
   // int frame_last_rendered_pts_;
   // scoped_refptr<VideoFrame> frame_;
+  std::queue<scoped_refptr<CpuVideoFrame>> frames_;
 };
 
 }  // namespace ffmpeg
diff --git a/src/starboard/shared/libvpx/vpx_video_decoder.cc b/src/starboard/shared/libvpx/vpx_video_decoder.cc
index fdd2a35..b511b68 100644
--- a/src/starboard/shared/libvpx/vpx_video_decoder.cc
+++ b/src/starboard/shared/libvpx/vpx_video_decoder.cc
@@ -104,6 +104,9 @@
   stream_ended_ = false;
 
   TeardownCodec();
+
+  ScopedLock lock(decode_target_mutex_);
+  frames_ = std::queue<scoped_refptr<CpuVideoFrame>>();
 }
 
 // static
@@ -134,21 +137,17 @@
   }
 }
 
-bool VideoDecoder::UpdateDecodeTarget(
+void VideoDecoder::UpdateDecodeTarget_Locked(
     const scoped_refptr<CpuVideoFrame>& frame) {
   SbDecodeTarget decode_target = DecodeTargetCreate(
       decode_target_graphics_context_provider_, frame, decode_target_);
 
   // Lock only after the post to the renderer thread, to prevent deadlock.
-  ScopedLock lock(decode_target_mutex_);
   decode_target_ = decode_target;
 
   if (!SbDecodeTargetIsValid(decode_target)) {
     SB_LOG(ERROR) << "Could not acquire a decode target from provider.";
-    return false;
   }
-
-  return true;
 }
 
 void VideoDecoder::ReportError(const std::string& error_message) {
@@ -268,7 +267,8 @@
       vpx_image->stride[VPX_PLANE_Y], timestamp, vpx_image->planes[VPX_PLANE_Y],
       vpx_image->planes[VPX_PLANE_U], vpx_image->planes[VPX_PLANE_V]);
   if (output_mode_ == kSbPlayerOutputModeDecodeToTexture) {
-    UpdateDecodeTarget(frame);
+    ScopedLock lock(decode_target_mutex_);
+    frames_.push(frame);
   }
 
   decoder_status_cb_(kNeedMoreInput, frame);
@@ -281,6 +281,12 @@
   // We must take a lock here since this function can be called from a
   // separate thread.
   ScopedLock lock(decode_target_mutex_);
+  while (frames_.size() > 1 && frames_.front()->HasOneRef()) {
+    frames_.pop();
+  }
+  if (!frames_.empty()) {
+    UpdateDecodeTarget_Locked(frames_.front());
+  }
   if (SbDecodeTargetIsValid(decode_target_)) {
     // Make a disposable copy, since the state is internally reused by this
     // class (to avoid recreating GL objects).
diff --git a/src/starboard/shared/libvpx/vpx_video_decoder.h b/src/starboard/shared/libvpx/vpx_video_decoder.h
index 12eb6f3..5d9292f 100644
--- a/src/starboard/shared/libvpx/vpx_video_decoder.h
+++ b/src/starboard/shared/libvpx/vpx_video_decoder.h
@@ -15,6 +15,7 @@
 #ifndef STARBOARD_SHARED_LIBVPX_VPX_VIDEO_DECODER_H_
 #define STARBOARD_SHARED_LIBVPX_VPX_VIDEO_DECODER_H_
 
+#include <queue>
 #include <string>
 
 #include "starboard/common/ref_counted.h"
@@ -92,7 +93,7 @@
 
   SbDecodeTarget GetCurrentDecodeTarget() override;
 
-  bool UpdateDecodeTarget(const scoped_refptr<CpuVideoFrame>& frame);
+  void UpdateDecodeTarget_Locked(const scoped_refptr<CpuVideoFrame>& frame);
 
   // The following callbacks will be initialized in Initialize() and won't be
   // changed during the life time of this class.
@@ -126,6 +127,8 @@
   // copy of |decode_target_|), we need to safe-guard access to |decode_target_|
   // and we do so through this mutex.
   Mutex decode_target_mutex_;
+
+  std::queue<scoped_refptr<CpuVideoFrame>> frames_;
 };
 
 }  // namespace vpx
diff --git a/src/starboard/shared/linux/system_get_used_cpu_memory.cc b/src/starboard/shared/linux/system_get_used_cpu_memory.cc
index f7dca8f..0e9f2a5 100644
--- a/src/starboard/shared/linux/system_get_used_cpu_memory.cc
+++ b/src/starboard/shared/linux/system_get_used_cpu_memory.cc
@@ -26,68 +26,54 @@
 #include "starboard/string.h"
 
 // We find the current amount of used memory on Linux by opening
-// '/proc/self/status' and scan the file for its "VmRSS" entry.  Essentially,
-// we need to parse a buffer that has the following format:
+// '/proc/self/status' and scan the file for its "VmRSS" and "VmSwap" entries.
+// Essentially, we need to parse a buffer that has the following format:
 //
 // xxxxxx:       45327 kB
 // yyyyyy:          23 kB
 // VmRSS:        87432 kB
 // zzzzzz:        3213 kB
+// VmSwap:          15 kB
 // ...
 //
-// And here, we would want to return the value 87432 * 1024.
+// And here, we would want to return the value 87432 * 1024 + 15 * 1024 (i.e.
+// (VmRSS + VmSwap) * 1024).
 // See http://man7.org/linux/man-pages/man5/proc.5.html for more details.
 
-// Searches for the value of VmRSS and returns it.  Will modify |buffer| in
-// order to do so quickly and easily.
-int64_t SearchForVmRSSValue(char* buffer, size_t length) {
-  // Search for the string ""VmRSS:".
-  const char kSearchString[] = "\nVmRSS:";
-  enum State {
-    // We are currently searching for kSearchString
-    kSearchingForSearchString,
-    // We found the search string and are advancing through spaces/tabs until
-    // we see a number.
-    kAdvancingSpacesToNumber,
-    // We found the number and are now searching for the end of it.
-    kFindingEndOfNumber,
-  };
-  State state = kSearchingForSearchString;
-  const char* number_start = NULL;
-  for (size_t i = 0; i < length - sizeof(kSearchString); ++i) {
-    if (state == kSearchingForSearchString) {
-      if (SbStringCompare(&buffer[i], kSearchString,
-                          sizeof(kSearchString) - 1) == 0) {
-        // Advance until we find a number.
-        state = kAdvancingSpacesToNumber;
-        i += sizeof(kSearchString) - 2;
-      }
-    } else if (state == kAdvancingSpacesToNumber) {
-      if (buffer[i] >= '0' && buffer[i] <= '9') {
-        // We found the start of the number, record where that is and then
-        // continue searching for the end of the number.
-        number_start = &buffer[i];
-        state = kFindingEndOfNumber;
-      }
-    } else {
-      SB_DCHECK(state == kFindingEndOfNumber);
-      if (buffer[i] < '0' || buffer[i] > '9') {
-        // Drop a null at the end of the number so that we can call atoi() on
-        // it and return.
-        buffer[i] = '\0';
-        return SbStringAToI(number_start);
-      }
-    }
+// Searches for a specific value we're interested in and return it.  Will
+// modify |buffer| in order to do so quickly and easily.  Returns the memory
+// value in bytes (not kilobytes as it is presented in /proc/self/status).
+int64_t SearchForMemoryValue(
+    const char* search_key, const char* buffer) {
+  const char* found = SbStringFindString(buffer, search_key);
+  if (!found) {
+    SB_LOG(ERROR) << "Could not find '" << search_key << "' in "
+                  << "/proc/self/status.";
+    return 0;
   }
 
-  SB_LOG(ERROR) << "Could not find 'VmRSS:' in /proc/self/status.";
-  return 0;
+  while (*found != '\0' && (*found < '0' || *found > '9')) {
+    ++found;
+  }
+
+  if (*found == '\0') {
+    SB_LOG(ERROR) << "Unexpected end of string when searching for '"
+                  << search_key << "' in /proc/self/status.";
+    return 0;
+  }
+
+  // Convert the number string into an integer.
+  int64_t memory_value_in_kilobytes = 0;
+  while (*found >= '0' && *found <= '9') {
+    memory_value_in_kilobytes = memory_value_in_kilobytes * 10 + (*found - '0');
+    ++found;
+  }
+
+  return memory_value_in_kilobytes * 1024;
 }
 
 int64_t SbSystemGetUsedCPUMemory() {
   // Read our process' current physical memory usage from /proc/self/status.
-  // This requires a bit of parsing through the output to find the value for
-  // the "VmRSS" field which indicates used physical memory.
   starboard::ScopedFile status_file("/proc/self/status",
                                     kSbFileOpenOnly | kSbFileRead);
   if (!status_file.IsValid()) {
@@ -100,19 +86,15 @@
   // Read the entire file into memory.
   const int kBufferSize = 2048;
   char buffer[kBufferSize];
-  int remaining = kBufferSize;
-  char* output_pointer = buffer;
-  do {
-    int result = status_file.Read(output_pointer, remaining);
-    if (result <= 0)
-      break;
+  int bytes_read = status_file.ReadAll(buffer, kBufferSize);
 
-    remaining -= result;
-    output_pointer += result;
-  } while (remaining);
+  // Ensure that this is a null-terminated string.
+  if (bytes_read == kBufferSize) {
+    bytes_read = kBufferSize - 1;
+  }
+  buffer[bytes_read] = '\0';
 
   // Return the result, multiplied by 1024 because it is given in kilobytes.
-  return SearchForVmRSSValue(buffer,
-                             static_cast<size_t>(output_pointer - buffer)) *
-         1024;
+  return SearchForMemoryValue("VmRSS", buffer) +
+         SearchForMemoryValue("VmSwap", buffer);
 }
diff --git a/src/starboard/shared/opus/opus_audio_decoder.cc b/src/starboard/shared/opus/opus_audio_decoder.cc
new file mode 100644
index 0000000..dda6c11
--- /dev/null
+++ b/src/starboard/shared/opus/opus_audio_decoder.cc
@@ -0,0 +1,179 @@
+// Copyright 2018 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/shared/opus/opus_audio_decoder.h"
+
+#include "starboard/log.h"
+#include "starboard/memory.h"
+#include "starboard/shared/starboard/media/media_util.h"
+#include "starboard/string.h"
+
+namespace starboard {
+namespace shared {
+namespace opus {
+
+namespace {
+const int kMaxOpusFramesPerAU = 9600;
+}  // namespace
+
+OpusAudioDecoder::OpusAudioDecoder(const SbMediaAudioHeader& audio_header)
+    : audio_header_(audio_header) {
+#if SB_HAS_QUIRK(SUPPORT_INT16_AUDIO_SAMPLES)
+  working_buffer_.resize(kMaxOpusFramesPerAU *
+                         audio_header_.number_of_channels * sizeof(opus_int16));
+#else   // SB_HAS_QUIRK(SUPPORT_INT16_AUDIO_SAMPLES)
+  working_buffer_.resize(kMaxOpusFramesPerAU *
+                         audio_header_.number_of_channels * sizeof(float));
+#endif  // SB_HAS_QUIRK(SUPPORT_INT16_AUDIO_SAMPLES)
+
+  int error;
+  decoder_ = opus_decoder_create(audio_header_.samples_per_second,
+                                 audio_header_.number_of_channels, &error);
+  if (error != OPUS_OK) {
+    SB_LOG(ERROR) << "Failed to create decoder with error: "
+                  << opus_strerror(error);
+    decoder_ = NULL;
+    return;
+  }
+  SB_DCHECK(decoder_ != NULL);
+}
+
+OpusAudioDecoder::~OpusAudioDecoder() {
+  if (decoder_) {
+    opus_decoder_destroy(decoder_);
+  }
+}
+
+void OpusAudioDecoder::Initialize(const OutputCB& output_cb,
+                                  const ErrorCB& error_cb) {
+  SB_DCHECK(BelongsToCurrentThread());
+  SB_DCHECK(output_cb);
+  SB_DCHECK(!output_cb_);
+  SB_DCHECK(error_cb);
+  SB_DCHECK(!error_cb_);
+
+  output_cb_ = output_cb;
+  error_cb_ = error_cb;
+}
+
+void OpusAudioDecoder::Decode(const scoped_refptr<InputBuffer>& input_buffer,
+                              const ConsumedCB& consumed_cb) {
+  SB_DCHECK(BelongsToCurrentThread());
+  SB_DCHECK(input_buffer);
+  SB_DCHECK(output_cb_);
+
+  Schedule(consumed_cb);
+
+  if (stream_ended_) {
+    SB_LOG(ERROR) << "Decode() is called after WriteEndOfStream() is called.";
+    return;
+  }
+
+#if SB_HAS_QUIRK(SUPPORT_INT16_AUDIO_SAMPLES)
+  const char kDecodeFunctionName[] = "opus_decode";
+  int decoded_frames = opus_decode(
+      decoder_, static_cast<const unsigned char*>(input_buffer->data()),
+      input_buffer->size(),
+      reinterpret_cast<opus_int16*>(working_buffer_.data()),
+      kMaxOpusFramesPerAU, 0);
+#else   // SB_HAS_QUIRK(SUPPORT_INT16_AUDIO_SAMPLES)
+  const char kDecodeFunctionName[] = "opus_decode_float";
+  int decoded_frames = opus_decode_float(
+      decoder_, static_cast<const unsigned char*>(input_buffer->data()),
+      input_buffer->size(), reinterpret_cast<float*>(working_buffer_.data()),
+      kMaxOpusFramesPerAU, 0);
+#endif  // SB_HAS_QUIRK(SUPPORT_INT16_AUDIO_SAMPLES)
+  if (decoded_frames <= 0) {
+    // TODO: Consider fill it with silence.
+    SB_LOG(ERROR) << kDecodeFunctionName
+                  << "() failed with error code: " << decoded_frames;
+    error_cb_(kSbPlayerErrorDecode,
+              FormatString("%s() failed with error code: %d",
+                           kDecodeFunctionName, decoded_frames));
+    return;
+  }
+
+  scoped_refptr<DecodedAudio> decoded_audio = new DecodedAudio(
+      audio_header_.number_of_channels, GetSampleType(), GetStorageType(),
+      input_buffer->timestamp(),
+      audio_header_.number_of_channels * decoded_frames *
+          starboard::media::GetBytesPerSample(GetSampleType()));
+  SbMemoryCopy(decoded_audio->buffer(), working_buffer_.data(),
+               decoded_audio->size());
+  decoded_audios_.push(decoded_audio);
+  Schedule(output_cb_);
+}
+
+void OpusAudioDecoder::WriteEndOfStream() {
+  SB_DCHECK(BelongsToCurrentThread());
+  SB_DCHECK(output_cb_);
+
+  // Opus has no dependent frames so we needn't flush the decoder.  Set the
+  // flag to ensure that Decode() is not called when the stream is ended.
+  stream_ended_ = true;
+  // Put EOS into the queue.
+  decoded_audios_.push(new DecodedAudio);
+
+  Schedule(output_cb_);
+}
+
+scoped_refptr<OpusAudioDecoder::DecodedAudio> OpusAudioDecoder::Read() {
+  SB_DCHECK(BelongsToCurrentThread());
+  SB_DCHECK(output_cb_);
+  SB_DCHECK(!decoded_audios_.empty());
+
+  scoped_refptr<DecodedAudio> result;
+  if (!decoded_audios_.empty()) {
+    result = decoded_audios_.front();
+    decoded_audios_.pop();
+  }
+  return result;
+}
+
+void OpusAudioDecoder::Reset() {
+  SB_DCHECK(BelongsToCurrentThread());
+
+  stream_ended_ = false;
+  while (!decoded_audios_.empty()) {
+    decoded_audios_.pop();
+  }
+
+  CancelPendingJobs();
+}
+
+bool OpusAudioDecoder::is_valid() const {
+  return decoder_ != NULL;
+}
+
+SbMediaAudioSampleType OpusAudioDecoder::GetSampleType() const {
+  SB_DCHECK(BelongsToCurrentThread());
+#if SB_HAS_QUIRK(SUPPORT_INT16_AUDIO_SAMPLES)
+  return kSbMediaAudioSampleTypeInt16;
+#else   // SB_HAS_QUIRK(SUPPORT_INT16_AUDIO_SAMPLES)
+  return kSbMediaAudioSampleTypeFloat32;
+#endif  // SB_HAS_QUIRK(SUPPORT_INT16_AUDIO_SAMPLES)
+}
+
+SbMediaAudioFrameStorageType OpusAudioDecoder::GetStorageType() const {
+  SB_DCHECK(BelongsToCurrentThread());
+  return kSbMediaAudioFrameStorageTypeInterleaved;
+}
+
+int OpusAudioDecoder::GetSamplesPerSecond() const {
+  return audio_header_.samples_per_second;
+}
+
+}  // namespace opus
+}  // namespace shared
+}  // namespace starboard
diff --git a/src/starboard/shared/opus/opus_audio_decoder.h b/src/starboard/shared/opus/opus_audio_decoder.h
new file mode 100644
index 0000000..e20db96
--- /dev/null
+++ b/src/starboard/shared/opus/opus_audio_decoder.h
@@ -0,0 +1,68 @@
+// Copyright 2018 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef STARBOARD_SHARED_OPUS_OPUS_AUDIO_DECODER_H_
+#define STARBOARD_SHARED_OPUS_OPUS_AUDIO_DECODER_H_
+
+#include <queue>
+#include <vector>
+
+#include "starboard/common/ref_counted.h"
+#include "starboard/media.h"
+#include "starboard/shared/internal_only.h"
+#include "starboard/shared/starboard/player/decoded_audio_internal.h"
+#include "starboard/shared/starboard/player/filter/audio_decoder_internal.h"
+#include "starboard/shared/starboard/player/job_queue.h"
+#include "third_party/opus/include/opus.h"
+
+namespace starboard {
+namespace shared {
+namespace opus {
+
+class OpusAudioDecoder
+    : public ::starboard::shared::starboard::player::filter::AudioDecoder,
+      private starboard::player::JobQueue::JobOwner {
+ public:
+  explicit OpusAudioDecoder(const SbMediaAudioHeader& audio_header);
+  ~OpusAudioDecoder() override;
+
+  bool is_valid() const;
+
+  // AudioDecoder functions
+  void Initialize(const OutputCB& output_cb, const ErrorCB& error_cb) override;
+  void Decode(const scoped_refptr<InputBuffer>& input_buffer,
+              const ConsumedCB& consumed_cb) override;
+  void WriteEndOfStream() override;
+  scoped_refptr<DecodedAudio> Read() override;
+  void Reset() override;
+  SbMediaAudioSampleType GetSampleType() const override;
+  SbMediaAudioFrameStorageType GetStorageType() const override;
+  int GetSamplesPerSecond() const override;
+
+ private:
+  OutputCB output_cb_;
+  ErrorCB error_cb_;
+
+  OpusDecoder* decoder_ = NULL;
+  bool stream_ended_ = false;
+  std::queue<scoped_refptr<DecodedAudio> > decoded_audios_;
+  SbMediaAudioHeader audio_header_;
+  std::vector<uint8_t> working_buffer_;
+};
+
+}  // namespace opus
+}  // namespace shared
+}  // namespace starboard
+
+#endif  // STARBOARD_SHARED_OPUS_OPUS_AUDIO_DECODER_H_
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 e6dbcfa..c478ea2 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
@@ -34,74 +34,148 @@
 const int64_t kDefaultBitRate = 0;
 const int64_t kDefaultAudioChannels = 2;
 
-// A progressive video contains both audio and video data.  The JS app uses
-// canPlayType() like "canPlayType(video/mp4; codecs="avc1.42001E, mp4a.40.2",)"
-// to query for support on both the audio and video codecs, which is being
-// forwarded to here.
-//
-// Note that canPlayType() doesn't support extra parameters like width, height
-// and channels.
-SbMediaSupportType CanPlayProgressiveVideo(const MimeType& mime_type,
-                                           bool decode_to_texture_required) {
+bool IsSupportedAudioCodec(const MimeType& mime_type,
+                           const std::string& codec,
+                           const char* key_system) {
+  SbMediaAudioCodec audio_codec = GetAudioCodecFromString(codec.c_str());
+  if (audio_codec == kSbMediaAudioCodecNone) {
+    return false;
+  }
+  if (SbStringGetLength(key_system) != 0) {
+    if (!SbMediaIsSupported(kSbMediaVideoCodecNone, audio_codec, key_system)) {
+      return false;
+    }
+  }
+
+  int channels = mime_type.GetParamIntValue("channels", kDefaultAudioChannels);
+  if (!IsAudioOutputSupported(kSbMediaAudioCodingTypePcm, channels)) {
+    return false;
+  }
+
+  int bitrate = mime_type.GetParamIntValue("bitrate", kDefaultBitRate);
+
+  if (!SbMediaIsAudioSupported(audio_codec, bitrate)) {
+    return false;
+  }
+
+  switch (audio_codec) {
+    case kSbMediaAudioCodecNone:
+      SB_NOTREACHED();
+      return false;
+    case kSbMediaAudioCodecAac:
+      return mime_type.subtype() == "mp4";
+#if SB_HAS(AC3_AUDIO)
+    case kSbMediaAudioCodecAc3:
+      return mime_type.subtype() == "mp4";
+#endif  // SB_HAS(AC3_AUDIO)
+    case kSbMediaAudioCodecOpus:
+    case kSbMediaAudioCodecVorbis:
+      return mime_type.subtype() == "webm";
+  }
+
+  SB_NOTREACHED();
+  return false;
+}
+
+bool IsSupportedVideoCodec(const MimeType& mime_type,
+                           const std::string& codec,
+                           const char* key_system,
+                           bool decode_to_texture_required) {
 #if SB_API_VERSION < 10
   SB_UNREFERENCED_PARAMETER(decode_to_texture_required);
 #endif  // SB_API_VERSION < 10
 
-  const std::vector<std::string>& codecs = mime_type.GetCodecs();
+  SbMediaVideoCodec video_codec = GetVideoCodecFromString(codec.c_str());
+  if (video_codec == kSbMediaVideoCodecNone) {
+    return false;
+  }
 
-  SB_DCHECK(codecs.size() == 2) << codecs.size();
-
-  bool has_audio_codec = false;
-  bool has_video_codec = false;
-  for (size_t i = 0; i < codecs.size(); ++i) {
-    SbMediaAudioCodec audio_codec = GetAudioCodecFromString(codecs[i].c_str());
-    if (audio_codec != kSbMediaAudioCodecNone) {
-      if (!SbMediaIsAudioSupported(audio_codec, kDefaultBitRate)) {
-        return kSbMediaSupportTypeNotSupported;
-      }
-      has_audio_codec = true;
-      continue;
+  if (SbStringGetLength(key_system) != 0) {
+    if (!SbMediaIsSupported(video_codec, kSbMediaAudioCodecNone, key_system)) {
+      return false;
     }
-    SbMediaVideoCodec video_codec = GetVideoCodecFromString(codecs[i].c_str());
-    if (video_codec == kSbMediaVideoCodecNone) {
-      return kSbMediaSupportTypeNotSupported;
+  }
+
+  std::string eotf = mime_type.GetParamStringValue("eotf", "");
+  SbMediaTransferId transfer_id = kSbMediaTransferIdUnspecified;
+  if (!eotf.empty()) {
+    transfer_id = GetTransferIdFromString(eotf);
+    // If the eotf is not known, reject immediately - without checking with
+    // the platform.
+    if (transfer_id == kSbMediaTransferIdUnknown) {
+      return false;
     }
-
-    has_video_codec = true;
-
-    int width = 0;
-    int height = 0;
-    int fps = 0;
-
-    if (video_codec == kSbMediaVideoCodecH264) {
-      if (!ParseH264Info(codecs[i].c_str(), &width, &height, &fps)) {
-        return kSbMediaSupportTypeNotSupported;
-      }
+#if !SB_HAS(MEDIA_EOTF_CHECK_SUPPORT)
+    if (!SbMediaIsTransferCharacteristicsSupported(transfer_id)) {
+      return false;
     }
-    if (!SbMediaIsVideoSupported(video_codec, width, height, kDefaultBitRate,
-                                 fps
+#endif  // !SB_HAS(MEDIA_EOTF_CHECK_SUPPORT)
+  }
+
+  std::string cryptoblockformat =
+      mime_type.GetParamStringValue("cryptoblockformat", "");
+  if (!cryptoblockformat.empty()) {
+    if (mime_type.subtype() != "webm" || cryptoblockformat != "subsample") {
+      return false;
+    }
+  }
+
+  int width = 0;
+  int height = 0;
+  int fps = 0;
+
+  if (video_codec == kSbMediaVideoCodecH264) {
+    if (!ParseH264Info(codec.c_str(), &width, &height, &fps)) {
+      return false;
+    }
+  }
+
+  width = mime_type.GetParamIntValue("width", width);
+  height = mime_type.GetParamIntValue("height", height);
+  fps = mime_type.GetParamIntValue("framerate", fps);
+
+  int bitrate = mime_type.GetParamIntValue("bitrate", kDefaultBitRate);
+
+  if (!SbMediaIsVideoSupported(video_codec, width, height, bitrate, fps
 #if SB_API_VERSION >= 10
-                                 ,
-                                 decode_to_texture_required
+                               ,
+                               decode_to_texture_required
 #endif  // SB_API_VERSION >= 10
 #if SB_HAS(MEDIA_EOTF_CHECK_SUPPORT)
-                                 ,
-                                 kSbMediaTransferIdUnspecified
+                               ,
+                               transfer_id
 #endif  // SB_HAS(MEDIA_EOTF_CHECK_SUPPORT)
-                                 )) {
-      return kSbMediaSupportTypeNotSupported;
-    }
+                               )) {
+    return false;
   }
 
-  if (has_audio_codec && has_video_codec) {
-    return kSbMediaSupportTypeProbably;
+  switch (video_codec) {
+    case kSbMediaVideoCodecNone:
+      SB_NOTREACHED();
+      return false;
+    case kSbMediaVideoCodecH264:
+    case kSbMediaVideoCodecH265:
+      return mime_type.subtype() == "mp4";
+    case kSbMediaVideoCodecMpeg2:
+    case kSbMediaVideoCodecTheora:
+      return false;  // No associated container in YT.
+    case kSbMediaVideoCodecVc1:
+    case kSbMediaVideoCodecVp10:
+      return mime_type.subtype() == "mp4";
+    case kSbMediaVideoCodecVp8:
+    case kSbMediaVideoCodecVp9:
+      return mime_type.subtype() == "webm";
   }
 
-  return kSbMediaSupportTypeNotSupported;
+  SB_NOTREACHED();
+  return false;
 }
 
-// Calls to isTypeSupported() are redirected to this function.  Following are
-// some example inputs:
+// Calls to canPlayType() and isTypeSupported() are redirected to this function.
+// Following are some example inputs:
+//   canPlayType(video/mp4)
+//   canPlayType(video/mp4; codecs="avc1.42001E, mp4a.40.2")
+//   canPlayType(video/webm)
 //   isTypeSupported(video/webm; codecs="vp9")
 //   isTypeSupported(video/mp4; codecs="avc1.4d401e"; width=640)
 //   isTypeSupported(video/mp4; codecs="avc1.4d401e"; width=99999)
@@ -125,6 +199,10 @@
                                            const char* key_system) {
   SB_DCHECK(mime_type.is_valid());
 
+  if (mime_type.type() != "audio" && mime_type.type() != "video") {
+    return kSbMediaSupportTypeNotSupported;
+  }
+
   const std::vector<std::string>& codecs = mime_type.GetCodecs();
 
   // Pre-filter for |key_system|.
@@ -149,114 +227,48 @@
 #endif  // SB_API_VERSION >= 10
 
   if (codecs.size() == 0) {
-    // When there is no codecs listed, returns |kSbMediaSupportTypeMaybe| and
-    // reject unsupported formats when query again with valid "codecs".
-    return kSbMediaSupportTypeMaybe;
+    // This is a progressive query.  We only support "video/mp4" in this case.
+    if (mime_type.type() == "video" && mime_type.subtype() == "mp4") {
+      return kSbMediaSupportTypeMaybe;
+    }
+    return kSbMediaSupportTypeNotSupported;
   }
 
   if (codecs.size() > 2) {
     return kSbMediaSupportTypeNotSupported;
   }
 
-  if (codecs.size() == 2) {
-    SB_DCHECK(SbStringGetLength(key_system) == 0);
-    return CanPlayProgressiveVideo(mime_type, decode_to_texture_required);
-  }
-
-  SB_DCHECK(codecs.size() == 1);
-
-  if (mime_type.type() == "audio") {
-    SbMediaAudioCodec audio_codec = GetAudioCodecFromString(codecs[0].c_str());
-    if (audio_codec == kSbMediaAudioCodecNone) {
-      return kSbMediaSupportTypeNotSupported;
-    }
-
-    if (SbStringGetLength(key_system) != 0) {
-      if (!SbMediaIsSupported(kSbMediaVideoCodecNone, audio_codec,
-                              key_system)) {
+  bool has_audio_codec = false;
+  bool has_video_codec = false;
+  for (const auto& codec : codecs) {
+    if (IsSupportedAudioCodec(mime_type, codec, key_system)) {
+      if (has_audio_codec) {
+        // We don't support two audio codecs in one stream.
         return kSbMediaSupportTypeNotSupported;
       }
+      has_audio_codec = true;
+      continue;
     }
-
-    int channels =
-        mime_type.GetParamIntValue("channels", kDefaultAudioChannels);
-    if (!IsAudioOutputSupported(kSbMediaAudioCodingTypePcm, channels)) {
-      return kSbMediaSupportTypeNotSupported;
+    if (IsSupportedVideoCodec(mime_type, codec, key_system,
+                              decode_to_texture_required)) {
+      if (mime_type.type() != "video") {
+        // Video can only be contained in "video/*", while audio can be
+        // contained in both "audio/*" and "video/*".
+        return kSbMediaSupportTypeNotSupported;
+      }
+      if (has_video_codec) {
+        // We don't support two video codecs in one stream.
+        return kSbMediaSupportTypeNotSupported;
+      }
+      has_video_codec = true;
+      continue;
     }
-
-    int bitrate = mime_type.GetParamIntValue("bitrate", kDefaultBitRate);
-
-    if (SbMediaIsAudioSupported(audio_codec, bitrate)) {
-      return kSbMediaSupportTypeProbably;
-    }
-
     return kSbMediaSupportTypeNotSupported;
   }
 
-  if (mime_type.type() == "video") {
-    SbMediaVideoCodec video_codec = GetVideoCodecFromString(codecs[0].c_str());
-    if (video_codec == kSbMediaVideoCodecNone) {
-      return kSbMediaSupportTypeNotSupported;
-    }
-
-    if (SbStringGetLength(key_system) != 0) {
-      if (!SbMediaIsSupported(video_codec, kSbMediaAudioCodecNone,
-                              key_system)) {
-        return kSbMediaSupportTypeNotSupported;
-      }
-    }
-
-    std::string eotf = mime_type.GetParamStringValue("eotf", "");
-    SbMediaTransferId transfer_id = kSbMediaTransferIdUnspecified;
-    if (!eotf.empty()) {
-      transfer_id = GetTransferIdFromString(eotf);
-      // If the eotf is not known, reject immediately - without checking with
-      // the platform.
-      if (transfer_id == kSbMediaTransferIdUnknown) {
-        return kSbMediaSupportTypeNotSupported;
-      }
-    }
-
-    std::string cryptoblockformat =
-        mime_type.GetParamStringValue("cryptoblockformat", "");
-    if (!cryptoblockformat.empty()) {
-      if (mime_type.subtype() != "webm" || cryptoblockformat != "subsample") {
-        return kSbMediaSupportTypeNotSupported;
-      }
-    }
-
-    int width = 0;
-    int height = 0;
-    int fps = 0;
-
-    if (video_codec == kSbMediaVideoCodecH264) {
-      if (!ParseH264Info(codecs[0].c_str(), &width, &height, &fps)) {
-        return kSbMediaSupportTypeNotSupported;
-      }
-    }
-
-    width = mime_type.GetParamIntValue("width", width);
-    height = mime_type.GetParamIntValue("height", height);
-    fps = mime_type.GetParamIntValue("framerate", fps);
-
-    int bitrate = mime_type.GetParamIntValue("bitrate", kDefaultBitRate);
-
-    if (SbMediaIsVideoSupported(video_codec, width, height, bitrate, fps
-#if SB_API_VERSION >= 10
-                                ,
-                                decode_to_texture_required
-#endif  // SB_API_VERSION >= 10
-#if SB_HAS(MEDIA_EOTF_CHECK_SUPPORT)
-                                ,
-                                transfer_id
-#endif  // SB_HAS(MEDIA_EOTF_CHECK_SUPPORT)
-                                )) {
-      return kSbMediaSupportTypeProbably;
-    }
-
-    return kSbMediaSupportTypeNotSupported;
+  if (has_audio_codec || has_video_codec) {
+    return kSbMediaSupportTypeProbably;
   }
-
   return kSbMediaSupportTypeNotSupported;
 }
 
diff --git a/src/starboard/shared/starboard/net_log.cc b/src/starboard/shared/starboard/net_log.cc
index 1a27602..525cc07 100644
--- a/src/starboard/shared/starboard/net_log.cc
+++ b/src/starboard/shared/starboard/net_log.cc
@@ -62,44 +62,27 @@
 namespace starboard {
 namespace {
 
-using JoinFunction = std::function<void()>;
-using RunFunction = std::function<void(Semaphore*, atomic_bool*)>;
-using std::placeholders::_1;
-using std::placeholders::_2;
+using RunFunction = std::function<void(Semaphore*)>;
 
 class FunctionThread : public Thread {
  public:
   static scoped_ptr<Thread> Create(
       const std::string& thread_name,
-      RunFunction run_function,
-      JoinFunction on_join_called = JoinFunction()) {
-    scoped_ptr<Thread> out(
-        new FunctionThread(thread_name, run_function, on_join_called));
+      RunFunction run_function) {
+    scoped_ptr<Thread> out(new FunctionThread(thread_name, run_function));
     return out.Pass();
   }
 
-  FunctionThread(const std::string& name,
-                 RunFunction run_function,
-                 JoinFunction join_function)
-      : Thread(name),
-        run_function_(run_function),
-        join_function_(join_function) {
+  FunctionThread(const std::string& name, RunFunction run_function)
+      : Thread(name), run_function_(run_function) {
   }
 
   void Run() override {
-    run_function_(join_sema(), joined_bool());
-  }
-
-  void Join() override {
-    if (join_function_) {
-      join_function_();
-    }
-    Thread::Join();
+    run_function_(join_sema());
   }
 
  private:
   RunFunction run_function_;
-  JoinFunction join_function_;
 };
 
 std::string ToString(SbSocketError error) {
@@ -289,9 +272,8 @@
   SocketListener(Socket* listen_socket, Callback cb)
       : listen_socket_(listen_socket),
         callback_(cb) {
-    RunFunction run_cb = std::bind(&SocketListener::Run, this, _1, _2);
-    thread_ = FunctionThread::Create("NetLogSocketListener",
-                                     run_cb);
+    auto run_cb = [this](Semaphore* sema) { this->Run(sema); };
+    thread_ = FunctionThread::Create("NetLogSocketListener", run_cb);
     thread_->Start();
   }
 
@@ -300,7 +282,7 @@
   }
 
  private:
-  void Run(Semaphore* joined_sema, atomic_bool*) {
+  void Run(Semaphore* joined_sema) {
     while (!joined_sema->TakeWait(100 * kSbTimeMillisecond)) {
       scoped_ptr<Socket> client_connection(listen_socket_->Accept());
 
@@ -326,9 +308,8 @@
     ListenForClient();
 
     writer_thread_ = FunctionThread::Create(
-        "NetLogSocketWriter",
-        std::bind(&NetLogServer::WriterTask, this, _1, _2),
-        std::bind(&NetLogServer::OnWriterTaskJoined, this));
+      "NetLogSocketWriter",
+      [this](Semaphore* sema) { this->WriterTask(sema); });
     writer_thread_->Start();
   }
 
@@ -366,6 +347,8 @@
   void Close() {
     socket_listener_.reset();
     if (writer_thread_) {
+      is_joined_.store(true);
+      writer_thread_sema_.Put();
       writer_thread_->Join();
       writer_thread_.reset(nullptr);
       Flush();  // One last flush to the socket.
@@ -389,11 +372,7 @@
   }
 
  private:
-  void OnWriterTaskJoined() {
-    writer_thread_sema_.Put();
-  }
-
-  void WriterTask(Semaphore* /*joined_sema*/, atomic_bool* is_joined) {
+  void WriterTask(Semaphore* /*joined_sema*/) {
     while (true) {
       writer_thread_sema_.Take();
 
@@ -402,7 +381,7 @@
           break;  // Connection dropped.
         }
       }
-      if (is_joined->load()) {
+      if (is_joined_.load()) {
         break;
       }
     }
@@ -415,6 +394,7 @@
   scoped_ptr<SocketListener> socket_listener_;
   scoped_ptr<Thread> writer_thread_;
   Semaphore writer_thread_sema_;
+  atomic_bool is_joined_;
 
   BufferedSocketWriter buffered_socket_writer_;
 };
diff --git a/src/starboard/shared/starboard/player/filter/player_components.h b/src/starboard/shared/starboard/player/filter/player_components.h
index 976143c..a0401b7 100644
--- a/src/starboard/shared/starboard/player/filter/player_components.h
+++ b/src/starboard/shared/starboard/player/filter/player_components.h
@@ -88,7 +88,7 @@
     scoped_refptr<VideoRendererSink> video_renderer_sink;
     CreateVideoComponents(video_parameters, &video_decoder,
                           &video_render_algorithm, &video_renderer_sink);
-    if (!video_decoder || !video_render_algorithm || !video_renderer_sink) {
+    if (!video_decoder || !video_render_algorithm) {
       return scoped_ptr<VideoRenderer>();
     }
     return make_scoped_ptr(
diff --git a/src/starboard/shared/starboard/player/filter/testing/video_decoder_test.cc b/src/starboard/shared/starboard/player/filter/testing/video_decoder_test.cc
index 3f678f0..aa1cac2 100644
--- a/src/starboard/shared/starboard/player/filter/testing/video_decoder_test.cc
+++ b/src/starboard/shared/starboard/player/filter/testing/video_decoder_test.cc
@@ -122,8 +122,10 @@
                                       &video_renderer_sink_);
     ASSERT_TRUE(video_decoder_);
 
-    video_renderer_sink_->SetRenderCB(
-        std::bind(&VideoDecoderTest::Render, this, _1));
+    if (video_renderer_sink_) {
+      video_renderer_sink_->SetRenderCB(
+          std::bind(&VideoDecoderTest::Render, this, _1));
+    }
 
     video_decoder_->Initialize(
         std::bind(&VideoDecoderTest::OnDecoderStatusUpdate, this, _1, _2),
@@ -439,8 +441,10 @@
               &video_renderer_sinks[i]);
           ASSERT_TRUE(video_decoders[i]);
 
-          video_renderer_sinks[i]->SetRenderCB(
-              std::bind(&VideoDecoderTest::Render, this, _1));
+          if (video_renderer_sinks[i]) {
+            video_renderer_sinks[i]->SetRenderCB(
+                std::bind(&VideoDecoderTest::Render, this, _1));
+          }
 
           video_decoders[i]->Initialize(
               std::bind(&VideoDecoderTest::OnDecoderStatusUpdate, this, _1, _2),
diff --git a/src/starboard/shared/starboard/player/filter/video_render_algorithm.h b/src/starboard/shared/starboard/player/filter/video_render_algorithm.h
index 9bf14fb..0e21b5b 100644
--- a/src/starboard/shared/starboard/player/filter/video_render_algorithm.h
+++ b/src/starboard/shared/starboard/player/filter/video_render_algorithm.h
@@ -42,6 +42,10 @@
       VideoRendererSink;
 
   virtual ~VideoRenderAlgorithm() {}
+
+  // |draw_frame_cb| can be empty.  When it is empty, this function simply runs
+  // the frame picking algorithm without calling |draw_frame_cb| to render the
+  // frame explicitly.
   virtual void Render(MediaTimeProvider* media_time_provider,
                       std::list<scoped_refptr<VideoFrame>>* frames,
                       VideoRendererSink::DrawFrameCB draw_frame_cb) = 0;
diff --git a/src/starboard/shared/starboard/player/filter/video_render_algorithm_impl.cc b/src/starboard/shared/starboard/player/filter/video_render_algorithm_impl.cc
index b54a451..8342789 100644
--- a/src/starboard/shared/starboard/player/filter/video_render_algorithm_impl.cc
+++ b/src/starboard/shared/starboard/player/filter/video_render_algorithm_impl.cc
@@ -34,7 +34,6 @@
     VideoRendererSink::DrawFrameCB draw_frame_cb) {
   SB_DCHECK(media_time_provider);
   SB_DCHECK(frames);
-  SB_DCHECK(draw_frame_cb);
 
   if (frames->empty() || frames->front()->is_end_of_stream()) {
     return;
@@ -102,9 +101,11 @@
 
   if (!frames->front()->is_end_of_stream()) {
     last_frame_timestamp_ = frames->front()->timestamp();
-    auto status = draw_frame_cb(frames->front(), 0);
-    if (status == VideoRendererSink::kReleased) {
-      frames->pop_front();
+    if (draw_frame_cb) {
+      auto status = draw_frame_cb(frames->front(), 0);
+      if (status == VideoRendererSink::kReleased) {
+        frames->pop_front();
+      }
     }
   }
 }
diff --git a/src/starboard/shared/starboard/player/filter/video_renderer_internal.cc b/src/starboard/shared/starboard/player/filter/video_renderer_internal.cc
index 48ab311..161dd69 100644
--- a/src/starboard/shared/starboard/player/filter/video_renderer_internal.cc
+++ b/src/starboard/shared/starboard/player/filter/video_renderer_internal.cc
@@ -47,7 +47,6 @@
       number_of_frames_(0) {
   SB_DCHECK(decoder_ != NULL);
   SB_DCHECK(algorithm_ != NULL);
-  SB_DCHECK(sink_ != NULL);
   SB_DCHECK(decoder_->GetMaxNumberOfCachedFrames() > 1);
   SB_DLOG_IF(WARNING, decoder_->GetMaxNumberOfCachedFrames() < 4)
       << "VideoDecoder::GetMaxNumberOfCachedFrames() returns "
@@ -206,7 +205,9 @@
                               int y,
                               int width,
                               int height) {
-  sink_->SetBounds(z_index, x, y, width, height);
+  if (sink_) {
+    sink_->SetBounds(z_index, x, y, width, height);
+  }
 }
 
 SbDecodeTarget VideoRenderer::GetCurrentDecodeTarget() {
@@ -215,6 +216,12 @@
   // NULL inside the dtor.
   SB_DCHECK(decoder_);
 
+  // TODO: Ensure that |sink_| is NULL when decode target is used across all
+  // platforms.
+  if (!sink_) {
+    Render(VideoRendererSink::DrawFrameCB());
+  }
+
   return decoder_->GetCurrentDecodeTarget();
 }
 
diff --git a/src/third_party/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp b/src/third_party/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp
index ce19a29..db531ee 100644
--- a/src/third_party/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp
+++ b/src/third_party/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp
@@ -26,6 +26,21 @@
 #include "libANGLE/renderer/d3d/ShaderExecutableD3D.h"
 #include "libANGLE/renderer/d3d/VertexDataManager.h"
 
+#if defined(ANGLE_STD_ASYNC_WORKERS) && defined(_MSC_VER)
+#if (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) && (_MSC_VER >= 1915)
+// Starting with MSVC++ 14.15 std::future::wait() will throw an exception
+// with the message "Illegal to wait on a task in a Windows Runtime STA"
+// whenever it is invoked from the UI thread. This define signals a
+// workaround to avoid this exception by invoking future::wait() on a
+// separate thread and then immediately doing a thread join.
+#define ANGLE_MSVC_STA_EXCEPTION_WORKAROUND
+#endif
+#endif
+
+#ifdef ANGLE_MSVC_STA_EXCEPTION_WORKAROUND
+#include <thread>
+#endif
+
 using namespace angle;
 
 namespace rx
@@ -1411,7 +1426,11 @@
                                                 workerPool->postWorkerTask(&pixelTask),
                                                 workerPool->postWorkerTask(&geometryTask)}};
 
+#ifdef ANGLE_MSVC_STA_EXCEPTION_WORKAROUND
+    std::thread([&]() { WaitableEvent::WaitMany(&waitEvents); }).join();
+#else
     WaitableEvent::WaitMany(&waitEvents);
+#endif
 
     infoLog << vertexTask.getInfoLog().str();
     infoLog << pixelTask.getInfoLog().str();
diff --git a/src/third_party/icu/source/common/ucase.cpp b/src/third_party/icu/source/common/ucase.cpp
index 0f5f705..0930574 100644
--- a/src/third_party/icu/source/common/ucase.cpp
+++ b/src/third_party/icu/source/common/ucase.cpp
@@ -620,6 +620,18 @@
                 result=UCASE_LOC_LITHUANIAN;
             }
         }
+    } else if(is_e(c)) {
+        /* el or ell? */
+        c=*locale++;
+        if(is_l(c)) {
+            c=*locale++;
+            if(is_l(c)) {
+                c=*locale;
+            }
+            if(is_sep(c)) {
+                result=UCASE_LOC_GREEK;
+            }
+        }
     } else if(is_n(c)) {
         /* nl or nld? */
         c=*locale++;
diff --git a/src/third_party/icu/source/common/ucase.h b/src/third_party/icu/source/common/ucase.h
index 8f24769..12771a3 100644
--- a/src/third_party/icu/source/common/ucase.h
+++ b/src/third_party/icu/source/common/ucase.h
@@ -62,6 +62,7 @@
     UCASE_LOC_ROOT,
     UCASE_LOC_TURKISH,
     UCASE_LOC_LITHUANIAN,
+    UCASE_LOC_GREEK,
     UCASE_LOC_DUTCH
 };
 
@@ -156,7 +157,7 @@
 U_CAPI int32_t U_EXPORT2
 ucase_getType(const UCaseProps *csp, UChar32 c);
 
-/** @return same as ucase_getType(), or <0 if c is case-ignorable */
+/** @return same as ucase_getType() and set bit 2 if c is case-ignorable */
 U_CAPI int32_t U_EXPORT2
 ucase_getTypeOrIgnorable(const UCaseProps *csp, UChar32 c);
 
diff --git a/src/third_party/icu/source/common/ucasemap.cpp b/src/third_party/icu/source/common/ucasemap.cpp
index 8d5b260..48fd558 100644
--- a/src/third_party/icu/source/common/ucasemap.cpp
+++ b/src/third_party/icu/source/common/ucasemap.cpp
@@ -175,6 +175,15 @@
     return destIndex;
 }
 
+static inline int32_t
+appendUChar(uint8_t *dest, int32_t destIndex, int32_t destCapacity, UChar c) {
+    int32_t limit=destIndex+U8_LENGTH(c);
+    if(limit<destCapacity) {
+        U8_APPEND_UNSAFE(dest, destIndex, c);
+    }
+    return limit;
+}
+
 static UChar32 U_CALLCONV
 utf8_caseContextIterator(void *context, int8_t dir) {
     UCaseContext *csc=(UCaseContext *)context;
@@ -387,6 +396,141 @@
 
 #endif
 
+U_NAMESPACE_BEGIN
+namespace GreekUpper {
+
+UBool isFollowedByCasedLetter(const UCaseProps *csp, const uint8_t *s, int32_t i, int32_t length) {
+    while (i < length) {
+        UChar32 c;
+        U8_NEXT(s, i, length, c);
+        int32_t type = ucase_getTypeOrIgnorable(csp, c);
+        if ((type & UCASE_IGNORABLE) != 0) {
+            // Case-ignorable, continue with the loop.
+        } else if (type != UCASE_NONE) {
+            return TRUE;  // Followed by cased letter.
+        } else {
+            return FALSE;  // Uncased and not case-ignorable.
+        }
+    }
+    return FALSE;  // Not followed by cased letter.
+}
+
+// Keep this consistent with the UTF-16 version in ustrcase.cpp and the Java version in CaseMap.java.
+int32_t toUpper(const UCaseMap *csm,
+                uint8_t *dest, int32_t destCapacity,
+                const uint8_t *src, int32_t srcLength,
+                UErrorCode *pErrorCode) {
+    int32_t locCache = UCASE_LOC_GREEK;
+    int32_t destIndex=0;
+    uint32_t state = 0;
+    for (int32_t i = 0; i < srcLength;) {
+        int32_t nextIndex = i;
+        UChar32 c;
+        U8_NEXT(src, nextIndex, srcLength, c);
+        uint32_t nextState = 0;
+        int32_t type = ucase_getTypeOrIgnorable(csm->csp, c);
+        if ((type & UCASE_IGNORABLE) != 0) {
+            // c is case-ignorable
+            nextState |= (state & AFTER_CASED);
+        } else if (type != UCASE_NONE) {
+            // c is cased
+            nextState |= AFTER_CASED;
+        }
+        uint32_t data = getLetterData(c);
+        if (data > 0) {
+            uint32_t upper = data & UPPER_MASK;
+            // Add a dialytika to this iota or ypsilon vowel
+            // if we removed a tonos from the previous vowel,
+            // and that previous vowel did not also have (or gain) a dialytika.
+            // Adding one only to the final vowel in a longer sequence
+            // (which does not occur in normal writing) would require lookahead.
+            // Set the same flag as for preserving an existing dialytika.
+            if ((data & HAS_VOWEL) != 0 && (state & AFTER_VOWEL_WITH_ACCENT) != 0 &&
+                    (upper == 0x399 || upper == 0x3A5)) {
+                data |= HAS_DIALYTIKA;
+            }
+            int32_t numYpogegrammeni = 0;  // Map each one to a trailing, spacing, capital iota.
+            if ((data & HAS_YPOGEGRAMMENI) != 0) {
+                numYpogegrammeni = 1;
+            }
+            // Skip combining diacritics after this Greek letter.
+            int32_t nextNextIndex = nextIndex;
+            while (nextIndex < srcLength) {
+                UChar32 c2;
+                U8_NEXT(src, nextNextIndex, srcLength, c2);
+                uint32_t diacriticData = getDiacriticData(c2);
+                if (diacriticData != 0) {
+                    data |= diacriticData;
+                    if ((diacriticData & HAS_YPOGEGRAMMENI) != 0) {
+                        ++numYpogegrammeni;
+                    }
+                    nextIndex = nextNextIndex;
+                } else {
+                    break;  // not a Greek diacritic
+                }
+            }
+            if ((data & HAS_VOWEL_AND_ACCENT_AND_DIALYTIKA) == HAS_VOWEL_AND_ACCENT) {
+                nextState |= AFTER_VOWEL_WITH_ACCENT;
+            }
+            // Map according to Greek rules.
+            UBool addTonos = FALSE;
+            if (upper == 0x397 &&
+                    (data & HAS_ACCENT) != 0 &&
+                    numYpogegrammeni == 0 &&
+                    (state & AFTER_CASED) == 0 &&
+                    !isFollowedByCasedLetter(csm->csp, src, nextIndex, srcLength)) {
+                // Keep disjunctive "or" with (only) a tonos.
+                // We use the same "word boundary" conditions as for the Final_Sigma test.
+                if (i == nextIndex) {
+                    upper = 0x389;  // Preserve the precomposed form.
+                } else {
+                    addTonos = TRUE;
+                }
+            } else if ((data & HAS_DIALYTIKA) != 0) {
+                // Preserve a vowel with dialytika in precomposed form if it exists.
+                if (upper == 0x399) {
+                    upper = 0x3AA;
+                    data &= ~HAS_EITHER_DIALYTIKA;
+                } else if (upper == 0x3A5) {
+                    upper = 0x3AB;
+                    data &= ~HAS_EITHER_DIALYTIKA;
+                }
+            }
+            destIndex=appendUChar(dest, destIndex, destCapacity, (UChar)upper);
+            if ((data & HAS_EITHER_DIALYTIKA) != 0) {
+                destIndex=appendUChar(dest, destIndex, destCapacity, 0x308);  // restore or add a dialytika
+            }
+            if (addTonos) {
+                destIndex=appendUChar(dest, destIndex, destCapacity, 0x301);
+            }
+            while (numYpogegrammeni > 0) {
+                destIndex=appendUChar(dest, destIndex, destCapacity, 0x399);
+                --numYpogegrammeni;
+            }
+        } else {
+            const UChar *s;
+            UChar32 c2 = 0;
+            c=ucase_toFullUpper(csm->csp, c, NULL, NULL, &s, csm->locale, &locCache);
+            if((destIndex<destCapacity) && (c<0 ? (c2=~c)<=0x7f : UCASE_MAX_STRING_LENGTH<c && (c2=c)<=0x7f)) {
+                /* fast path version of appendResult() for ASCII results */
+                dest[destIndex++]=(uint8_t)c2;
+            } else {
+                destIndex=appendResult(dest, destIndex, destCapacity, c, s);
+            }
+        }
+        i = nextIndex;
+        state = nextState;
+    }
+
+    if(destIndex>destCapacity) {
+        *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+    }
+    return destIndex;
+}
+
+}  // namespace GreekUpper
+U_NAMESPACE_END
+
 static int32_t U_CALLCONV
 ucasemap_internalUTF8ToLower(const UCaseMap *csm,
                              uint8_t *dest, int32_t destCapacity,
@@ -407,6 +551,10 @@
                              uint8_t *dest, int32_t destCapacity,
                              const uint8_t *src, int32_t srcLength,
                              UErrorCode *pErrorCode) {
+    int32_t locCache = csm->locCache;
+    if (ucase_getCaseLocale(csm->locale, &locCache) == UCASE_LOC_GREEK) {
+        return GreekUpper::toUpper(csm, dest, destCapacity, src, srcLength, pErrorCode);
+    }
     UCaseContext csc=UCASECONTEXT_INITIALIZER;
     csc.p=(void *)src;
     csc.limit=srcLength;
diff --git a/src/third_party/icu/source/common/unicode/utf8.h b/src/third_party/icu/source/common/unicode/utf8.h
index 1198a17..808d9f2 100644
--- a/src/third_party/icu/source/common/unicode/utf8.h
+++ b/src/third_party/icu/source/common/unicode/utf8.h
@@ -431,21 +431,22 @@
  * @stable ICU 2.4
  */
 #define U8_APPEND_UNSAFE(s, i, c) { \
-    if((uint32_t)(c)<=0x7f) { \
-        (s)[(i)++]=(uint8_t)(c); \
+    uint32_t __uc=(c); \
+    if(__uc<=0x7f) { \
+        (s)[(i)++]=(uint8_t)__uc; \
     } else { \
-        if((uint32_t)(c)<=0x7ff) { \
-            (s)[(i)++]=(uint8_t)(((c)>>6)|0xc0); \
+        if(__uc<=0x7ff) { \
+            (s)[(i)++]=(uint8_t)((__uc>>6)|0xc0); \
         } else { \
-            if((uint32_t)(c)<=0xffff) { \
-                (s)[(i)++]=(uint8_t)(((c)>>12)|0xe0); \
+            if(__uc<=0xffff) { \
+                (s)[(i)++]=(uint8_t)((__uc>>12)|0xe0); \
             } else { \
-                (s)[(i)++]=(uint8_t)(((c)>>18)|0xf0); \
-                (s)[(i)++]=(uint8_t)((((c)>>12)&0x3f)|0x80); \
+                (s)[(i)++]=(uint8_t)((__uc>>18)|0xf0); \
+                (s)[(i)++]=(uint8_t)(((__uc>>12)&0x3f)|0x80); \
             } \
-            (s)[(i)++]=(uint8_t)((((c)>>6)&0x3f)|0x80); \
+            (s)[(i)++]=(uint8_t)(((__uc>>6)&0x3f)|0x80); \
         } \
-        (s)[(i)++]=(uint8_t)(((c)&0x3f)|0x80); \
+        (s)[(i)++]=(uint8_t)((__uc&0x3f)|0x80); \
     } \
 }
 
@@ -467,17 +468,23 @@
  * @stable ICU 2.4
  */
 #define U8_APPEND(s, i, capacity, c, isError) { \
-    if((uint32_t)(c)<=0x7f) { \
-        (s)[(i)++]=(uint8_t)(c); \
-    } else if((uint32_t)(c)<=0x7ff && (i)+1<(capacity)) { \
-        (s)[(i)++]=(uint8_t)(((c)>>6)|0xc0); \
-        (s)[(i)++]=(uint8_t)(((c)&0x3f)|0x80); \
-    } else if((uint32_t)(c)<=0xd7ff && (i)+2<(capacity)) { \
-        (s)[(i)++]=(uint8_t)(((c)>>12)|0xe0); \
-        (s)[(i)++]=(uint8_t)((((c)>>6)&0x3f)|0x80); \
-        (s)[(i)++]=(uint8_t)(((c)&0x3f)|0x80); \
+    uint32_t __uc=(c); \
+    if(__uc<=0x7f) { \
+        (s)[(i)++]=(uint8_t)__uc; \
+    } else if(__uc<=0x7ff && (i)+1<(capacity)) { \
+        (s)[(i)++]=(uint8_t)((__uc>>6)|0xc0); \
+        (s)[(i)++]=(uint8_t)((__uc&0x3f)|0x80); \
+    } else if((__uc<=0xd7ff || (0xe000<=__uc && __uc<=0xffff)) && (i)+2<(capacity)) { \
+        (s)[(i)++]=(uint8_t)((__uc>>12)|0xe0); \
+        (s)[(i)++]=(uint8_t)(((__uc>>6)&0x3f)|0x80); \
+        (s)[(i)++]=(uint8_t)((__uc&0x3f)|0x80); \
+    } else if(0xffff<__uc && __uc<=0x10ffff && (i)+3<(capacity)) { \
+        (s)[(i)++]=(uint8_t)((__uc>>18)|0xf0); \
+        (s)[(i)++]=(uint8_t)(((__uc>>12)&0x3f)|0x80); \
+        (s)[(i)++]=(uint8_t)(((__uc>>6)&0x3f)|0x80); \
+        (s)[(i)++]=(uint8_t)((__uc&0x3f)|0x80); \
     } else { \
-        (i)=utf8_appendCharSafeBody(s, (i), (capacity), c, &(isError)); \
+        (isError)=TRUE; \
     } \
 }
 
diff --git a/src/third_party/icu/source/common/ustr_imp.h b/src/third_party/icu/source/common/ustr_imp.h
index a746016..051292a 100644
--- a/src/third_party/icu/source/common/ustr_imp.h
+++ b/src/third_party/icu/source/common/ustr_imp.h
@@ -218,6 +218,44 @@
                  UTF8CaseMapper *stringCaseMapper,
                  UErrorCode *pErrorCode);
 
+#ifdef __cplusplus
+
+U_NAMESPACE_BEGIN
+namespace GreekUpper {
+
+// Data bits.
+static const uint32_t UPPER_MASK = 0x3ff;
+static const uint32_t HAS_VOWEL = 0x1000;
+static const uint32_t HAS_YPOGEGRAMMENI = 0x2000;
+static const uint32_t HAS_ACCENT = 0x4000;
+static const uint32_t HAS_DIALYTIKA = 0x8000;
+// Further bits during data building and processing, not stored in the data map.
+static const uint32_t HAS_COMBINING_DIALYTIKA = 0x10000;
+static const uint32_t HAS_OTHER_GREEK_DIACRITIC = 0x20000;
+
+static const uint32_t HAS_VOWEL_AND_ACCENT = HAS_VOWEL | HAS_ACCENT;
+static const uint32_t HAS_VOWEL_AND_ACCENT_AND_DIALYTIKA =
+        HAS_VOWEL_AND_ACCENT | HAS_DIALYTIKA;
+static const uint32_t HAS_EITHER_DIALYTIKA = HAS_DIALYTIKA | HAS_COMBINING_DIALYTIKA;
+
+// State bits.
+static const uint32_t AFTER_CASED = 1;
+static const uint32_t AFTER_VOWEL_WITH_ACCENT = 2;
+
+uint32_t getLetterData(UChar32 c);
+
+/**
+ * Returns a non-zero value for each of the Greek combining diacritics
+ * listed in The Unicode Standard, version 8, chapter 7.2 Greek,
+ * plus some perispomeni look-alikes.
+ */
+uint32_t getDiacriticData(UChar32 c);
+
+}  // namespace GreekUpper
+U_NAMESPACE_END
+
+#endif  // __cplusplus
+
 U_CAPI int32_t U_EXPORT2 
 ustr_hashUCharsN(const UChar *str, int32_t length);
 
diff --git a/src/third_party/icu/source/common/ustrcase.cpp b/src/third_party/icu/source/common/ustrcase.cpp
index ae3893a..5b8f8f6 100644
--- a/src/third_party/icu/source/common/ustrcase.cpp
+++ b/src/third_party/icu/source/common/ustrcase.cpp
@@ -89,6 +89,14 @@
     return destIndex;
 }
 
+static inline int32_t
+appendUChar(UChar *dest, int32_t destIndex, int32_t destCapacity, UChar c) {
+    if(destIndex<destCapacity) {
+        dest[destIndex]=c;
+    }
+    return destIndex+1;
+}
+
 static UChar32 U_CALLCONV
 utf16_caseContextIterator(void *context, int8_t dir) {
     UCaseContext *csc=(UCaseContext *)context;
@@ -295,6 +303,597 @@
 
 #endif  // !UCONFIG_NO_BREAK_ITERATION
 
+U_NAMESPACE_BEGIN
+namespace GreekUpper {
+
+// Data generated by prototype code, see
+// http://site.icu-project.org/design/case/greek-upper
+// TODO: Move this data into ucase.icu.
+static const uint16_t data0370[] = {
+    // U+0370..03FF
+    0x0370,
+    0x0370,
+    0x0372,
+    0x0372,
+    0,
+    0,
+    0x0376,
+    0x0376,
+    0,
+    0,
+    0x037A,
+    0x03FD,
+    0x03FE,
+    0x03FF,
+    0,
+    0x037F,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0x0391 | HAS_VOWEL | HAS_ACCENT,
+    0,
+    0x0395 | HAS_VOWEL | HAS_ACCENT,
+    0x0397 | HAS_VOWEL | HAS_ACCENT,
+    0x0399 | HAS_VOWEL | HAS_ACCENT,
+    0,
+    0x039F | HAS_VOWEL | HAS_ACCENT,
+    0,
+    0x03A5 | HAS_VOWEL | HAS_ACCENT,
+    0x03A9 | HAS_VOWEL | HAS_ACCENT,
+    0x0399 | HAS_VOWEL | HAS_ACCENT | HAS_DIALYTIKA,
+    0x0391 | HAS_VOWEL,
+    0x0392,
+    0x0393,
+    0x0394,
+    0x0395 | HAS_VOWEL,
+    0x0396,
+    0x0397 | HAS_VOWEL,
+    0x0398,
+    0x0399 | HAS_VOWEL,
+    0x039A,
+    0x039B,
+    0x039C,
+    0x039D,
+    0x039E,
+    0x039F | HAS_VOWEL,
+    0x03A0,
+    0x03A1,
+    0,
+    0x03A3,
+    0x03A4,
+    0x03A5 | HAS_VOWEL,
+    0x03A6,
+    0x03A7,
+    0x03A8,
+    0x03A9 | HAS_VOWEL,
+    0x0399 | HAS_VOWEL | HAS_DIALYTIKA,
+    0x03A5 | HAS_VOWEL | HAS_DIALYTIKA,
+    0x0391 | HAS_VOWEL | HAS_ACCENT,
+    0x0395 | HAS_VOWEL | HAS_ACCENT,
+    0x0397 | HAS_VOWEL | HAS_ACCENT,
+    0x0399 | HAS_VOWEL | HAS_ACCENT,
+    0x03A5 | HAS_VOWEL | HAS_ACCENT | HAS_DIALYTIKA,
+    0x0391 | HAS_VOWEL,
+    0x0392,
+    0x0393,
+    0x0394,
+    0x0395 | HAS_VOWEL,
+    0x0396,
+    0x0397 | HAS_VOWEL,
+    0x0398,
+    0x0399 | HAS_VOWEL,
+    0x039A,
+    0x039B,
+    0x039C,
+    0x039D,
+    0x039E,
+    0x039F | HAS_VOWEL,
+    0x03A0,
+    0x03A1,
+    0x03A3,
+    0x03A3,
+    0x03A4,
+    0x03A5 | HAS_VOWEL,
+    0x03A6,
+    0x03A7,
+    0x03A8,
+    0x03A9 | HAS_VOWEL,
+    0x0399 | HAS_VOWEL | HAS_DIALYTIKA,
+    0x03A5 | HAS_VOWEL | HAS_DIALYTIKA,
+    0x039F | HAS_VOWEL | HAS_ACCENT,
+    0x03A5 | HAS_VOWEL | HAS_ACCENT,
+    0x03A9 | HAS_VOWEL | HAS_ACCENT,
+    0x03CF,
+    0x0392,
+    0x0398,
+    0x03D2,
+    0x03D2 | HAS_ACCENT,
+    0x03D2 | HAS_DIALYTIKA,
+    0x03A6,
+    0x03A0,
+    0x03CF,
+    0x03D8,
+    0x03D8,
+    0x03DA,
+    0x03DA,
+    0x03DC,
+    0x03DC,
+    0x03DE,
+    0x03DE,
+    0x03E0,
+    0x03E0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0x039A,
+    0x03A1,
+    0x03F9,
+    0x037F,
+    0x03F4,
+    0x0395 | HAS_VOWEL,
+    0,
+    0x03F7,
+    0x03F7,
+    0x03F9,
+    0x03FA,
+    0x03FA,
+    0x03FC,
+    0x03FD,
+    0x03FE,
+    0x03FF,
+};
+
+static const uint16_t data1F00[] = {
+    // U+1F00..1FFF
+    0x0391 | HAS_VOWEL,
+    0x0391 | HAS_VOWEL,
+    0x0391 | HAS_VOWEL | HAS_ACCENT,
+    0x0391 | HAS_VOWEL | HAS_ACCENT,
+    0x0391 | HAS_VOWEL | HAS_ACCENT,
+    0x0391 | HAS_VOWEL | HAS_ACCENT,
+    0x0391 | HAS_VOWEL | HAS_ACCENT,
+    0x0391 | HAS_VOWEL | HAS_ACCENT,
+    0x0391 | HAS_VOWEL,
+    0x0391 | HAS_VOWEL,
+    0x0391 | HAS_VOWEL | HAS_ACCENT,
+    0x0391 | HAS_VOWEL | HAS_ACCENT,
+    0x0391 | HAS_VOWEL | HAS_ACCENT,
+    0x0391 | HAS_VOWEL | HAS_ACCENT,
+    0x0391 | HAS_VOWEL | HAS_ACCENT,
+    0x0391 | HAS_VOWEL | HAS_ACCENT,
+    0x0395 | HAS_VOWEL,
+    0x0395 | HAS_VOWEL,
+    0x0395 | HAS_VOWEL | HAS_ACCENT,
+    0x0395 | HAS_VOWEL | HAS_ACCENT,
+    0x0395 | HAS_VOWEL | HAS_ACCENT,
+    0x0395 | HAS_VOWEL | HAS_ACCENT,
+    0,
+    0,
+    0x0395 | HAS_VOWEL,
+    0x0395 | HAS_VOWEL,
+    0x0395 | HAS_VOWEL | HAS_ACCENT,
+    0x0395 | HAS_VOWEL | HAS_ACCENT,
+    0x0395 | HAS_VOWEL | HAS_ACCENT,
+    0x0395 | HAS_VOWEL | HAS_ACCENT,
+    0,
+    0,
+    0x0397 | HAS_VOWEL,
+    0x0397 | HAS_VOWEL,
+    0x0397 | HAS_VOWEL | HAS_ACCENT,
+    0x0397 | HAS_VOWEL | HAS_ACCENT,
+    0x0397 | HAS_VOWEL | HAS_ACCENT,
+    0x0397 | HAS_VOWEL | HAS_ACCENT,
+    0x0397 | HAS_VOWEL | HAS_ACCENT,
+    0x0397 | HAS_VOWEL | HAS_ACCENT,
+    0x0397 | HAS_VOWEL,
+    0x0397 | HAS_VOWEL,
+    0x0397 | HAS_VOWEL | HAS_ACCENT,
+    0x0397 | HAS_VOWEL | HAS_ACCENT,
+    0x0397 | HAS_VOWEL | HAS_ACCENT,
+    0x0397 | HAS_VOWEL | HAS_ACCENT,
+    0x0397 | HAS_VOWEL | HAS_ACCENT,
+    0x0397 | HAS_VOWEL | HAS_ACCENT,
+    0x0399 | HAS_VOWEL,
+    0x0399 | HAS_VOWEL,
+    0x0399 | HAS_VOWEL | HAS_ACCENT,
+    0x0399 | HAS_VOWEL | HAS_ACCENT,
+    0x0399 | HAS_VOWEL | HAS_ACCENT,
+    0x0399 | HAS_VOWEL | HAS_ACCENT,
+    0x0399 | HAS_VOWEL | HAS_ACCENT,
+    0x0399 | HAS_VOWEL | HAS_ACCENT,
+    0x0399 | HAS_VOWEL,
+    0x0399 | HAS_VOWEL,
+    0x0399 | HAS_VOWEL | HAS_ACCENT,
+    0x0399 | HAS_VOWEL | HAS_ACCENT,
+    0x0399 | HAS_VOWEL | HAS_ACCENT,
+    0x0399 | HAS_VOWEL | HAS_ACCENT,
+    0x0399 | HAS_VOWEL | HAS_ACCENT,
+    0x0399 | HAS_VOWEL | HAS_ACCENT,
+    0x039F | HAS_VOWEL,
+    0x039F | HAS_VOWEL,
+    0x039F | HAS_VOWEL | HAS_ACCENT,
+    0x039F | HAS_VOWEL | HAS_ACCENT,
+    0x039F | HAS_VOWEL | HAS_ACCENT,
+    0x039F | HAS_VOWEL | HAS_ACCENT,
+    0,
+    0,
+    0x039F | HAS_VOWEL,
+    0x039F | HAS_VOWEL,
+    0x039F | HAS_VOWEL | HAS_ACCENT,
+    0x039F | HAS_VOWEL | HAS_ACCENT,
+    0x039F | HAS_VOWEL | HAS_ACCENT,
+    0x039F | HAS_VOWEL | HAS_ACCENT,
+    0,
+    0,
+    0x03A5 | HAS_VOWEL,
+    0x03A5 | HAS_VOWEL,
+    0x03A5 | HAS_VOWEL | HAS_ACCENT,
+    0x03A5 | HAS_VOWEL | HAS_ACCENT,
+    0x03A5 | HAS_VOWEL | HAS_ACCENT,
+    0x03A5 | HAS_VOWEL | HAS_ACCENT,
+    0x03A5 | HAS_VOWEL | HAS_ACCENT,
+    0x03A5 | HAS_VOWEL | HAS_ACCENT,
+    0,
+    0x03A5 | HAS_VOWEL,
+    0,
+    0x03A5 | HAS_VOWEL | HAS_ACCENT,
+    0,
+    0x03A5 | HAS_VOWEL | HAS_ACCENT,
+    0,
+    0x03A5 | HAS_VOWEL | HAS_ACCENT,
+    0x03A9 | HAS_VOWEL,
+    0x03A9 | HAS_VOWEL,
+    0x03A9 | HAS_VOWEL | HAS_ACCENT,
+    0x03A9 | HAS_VOWEL | HAS_ACCENT,
+    0x03A9 | HAS_VOWEL | HAS_ACCENT,
+    0x03A9 | HAS_VOWEL | HAS_ACCENT,
+    0x03A9 | HAS_VOWEL | HAS_ACCENT,
+    0x03A9 | HAS_VOWEL | HAS_ACCENT,
+    0x03A9 | HAS_VOWEL,
+    0x03A9 | HAS_VOWEL,
+    0x03A9 | HAS_VOWEL | HAS_ACCENT,
+    0x03A9 | HAS_VOWEL | HAS_ACCENT,
+    0x03A9 | HAS_VOWEL | HAS_ACCENT,
+    0x03A9 | HAS_VOWEL | HAS_ACCENT,
+    0x03A9 | HAS_VOWEL | HAS_ACCENT,
+    0x03A9 | HAS_VOWEL | HAS_ACCENT,
+    0x0391 | HAS_VOWEL | HAS_ACCENT,
+    0x0391 | HAS_VOWEL | HAS_ACCENT,
+    0x0395 | HAS_VOWEL | HAS_ACCENT,
+    0x0395 | HAS_VOWEL | HAS_ACCENT,
+    0x0397 | HAS_VOWEL | HAS_ACCENT,
+    0x0397 | HAS_VOWEL | HAS_ACCENT,
+    0x0399 | HAS_VOWEL | HAS_ACCENT,
+    0x0399 | HAS_VOWEL | HAS_ACCENT,
+    0x039F | HAS_VOWEL | HAS_ACCENT,
+    0x039F | HAS_VOWEL | HAS_ACCENT,
+    0x03A5 | HAS_VOWEL | HAS_ACCENT,
+    0x03A5 | HAS_VOWEL | HAS_ACCENT,
+    0x03A9 | HAS_VOWEL | HAS_ACCENT,
+    0x03A9 | HAS_VOWEL | HAS_ACCENT,
+    0,
+    0,
+    0x0391 | HAS_VOWEL | HAS_YPOGEGRAMMENI,
+    0x0391 | HAS_VOWEL | HAS_YPOGEGRAMMENI,
+    0x0391 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x0391 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x0391 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x0391 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x0391 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x0391 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x0391 | HAS_VOWEL | HAS_YPOGEGRAMMENI,
+    0x0391 | HAS_VOWEL | HAS_YPOGEGRAMMENI,
+    0x0391 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x0391 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x0391 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x0391 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x0391 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x0391 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x0397 | HAS_VOWEL | HAS_YPOGEGRAMMENI,
+    0x0397 | HAS_VOWEL | HAS_YPOGEGRAMMENI,
+    0x0397 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x0397 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x0397 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x0397 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x0397 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x0397 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x0397 | HAS_VOWEL | HAS_YPOGEGRAMMENI,
+    0x0397 | HAS_VOWEL | HAS_YPOGEGRAMMENI,
+    0x0397 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x0397 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x0397 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x0397 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x0397 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x0397 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x03A9 | HAS_VOWEL | HAS_YPOGEGRAMMENI,
+    0x03A9 | HAS_VOWEL | HAS_YPOGEGRAMMENI,
+    0x03A9 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x03A9 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x03A9 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x03A9 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x03A9 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x03A9 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x03A9 | HAS_VOWEL | HAS_YPOGEGRAMMENI,
+    0x03A9 | HAS_VOWEL | HAS_YPOGEGRAMMENI,
+    0x03A9 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x03A9 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x03A9 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x03A9 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x03A9 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x03A9 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x0391 | HAS_VOWEL,
+    0x0391 | HAS_VOWEL,
+    0x0391 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x0391 | HAS_VOWEL | HAS_YPOGEGRAMMENI,
+    0x0391 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0,
+    0x0391 | HAS_VOWEL | HAS_ACCENT,
+    0x0391 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x0391 | HAS_VOWEL,
+    0x0391 | HAS_VOWEL,
+    0x0391 | HAS_VOWEL | HAS_ACCENT,
+    0x0391 | HAS_VOWEL | HAS_ACCENT,
+    0x0391 | HAS_VOWEL | HAS_YPOGEGRAMMENI,
+    0,
+    0x0399 | HAS_VOWEL,
+    0,
+    0,
+    0,
+    0x0397 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x0397 | HAS_VOWEL | HAS_YPOGEGRAMMENI,
+    0x0397 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0,
+    0x0397 | HAS_VOWEL | HAS_ACCENT,
+    0x0397 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x0395 | HAS_VOWEL | HAS_ACCENT,
+    0x0395 | HAS_VOWEL | HAS_ACCENT,
+    0x0397 | HAS_VOWEL | HAS_ACCENT,
+    0x0397 | HAS_VOWEL | HAS_ACCENT,
+    0x0397 | HAS_VOWEL | HAS_YPOGEGRAMMENI,
+    0,
+    0,
+    0,
+    0x0399 | HAS_VOWEL,
+    0x0399 | HAS_VOWEL,
+    0x0399 | HAS_VOWEL | HAS_ACCENT | HAS_DIALYTIKA,
+    0x0399 | HAS_VOWEL | HAS_ACCENT | HAS_DIALYTIKA,
+    0,
+    0,
+    0x0399 | HAS_VOWEL | HAS_ACCENT,
+    0x0399 | HAS_VOWEL | HAS_ACCENT | HAS_DIALYTIKA,
+    0x0399 | HAS_VOWEL,
+    0x0399 | HAS_VOWEL,
+    0x0399 | HAS_VOWEL | HAS_ACCENT,
+    0x0399 | HAS_VOWEL | HAS_ACCENT,
+    0,
+    0,
+    0,
+    0,
+    0x03A5 | HAS_VOWEL,
+    0x03A5 | HAS_VOWEL,
+    0x03A5 | HAS_VOWEL | HAS_ACCENT | HAS_DIALYTIKA,
+    0x03A5 | HAS_VOWEL | HAS_ACCENT | HAS_DIALYTIKA,
+    0x03A1,
+    0x03A1,
+    0x03A5 | HAS_VOWEL | HAS_ACCENT,
+    0x03A5 | HAS_VOWEL | HAS_ACCENT | HAS_DIALYTIKA,
+    0x03A5 | HAS_VOWEL,
+    0x03A5 | HAS_VOWEL,
+    0x03A5 | HAS_VOWEL | HAS_ACCENT,
+    0x03A5 | HAS_VOWEL | HAS_ACCENT,
+    0x03A1,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0x03A9 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x03A9 | HAS_VOWEL | HAS_YPOGEGRAMMENI,
+    0x03A9 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0,
+    0x03A9 | HAS_VOWEL | HAS_ACCENT,
+    0x03A9 | HAS_VOWEL | HAS_YPOGEGRAMMENI | HAS_ACCENT,
+    0x039F | HAS_VOWEL | HAS_ACCENT,
+    0x039F | HAS_VOWEL | HAS_ACCENT,
+    0x03A9 | HAS_VOWEL | HAS_ACCENT,
+    0x03A9 | HAS_VOWEL | HAS_ACCENT,
+    0x03A9 | HAS_VOWEL | HAS_YPOGEGRAMMENI,
+    0,
+    0,
+    0,
+};
+
+// U+2126 Ohm sign
+static const uint16_t data2126 = 0x03A9 | HAS_VOWEL;
+
+uint32_t getLetterData(UChar32 c) {
+    if (c < 0x370 || 0x2126 < c || (0x3ff < c && c < 0x1f00)) {
+        return 0;
+    } else if (c <= 0x3ff) {
+        return data0370[c - 0x370];
+    } else if (c <= 0x1fff) {
+        return data1F00[c - 0x1f00];
+    } else if (c == 0x2126) {
+        return data2126;
+    } else {
+        return 0;
+    }
+}
+
+uint32_t getDiacriticData(UChar32 c) {
+    switch (c) {
+    case 0x0300:  // varia
+    case 0x0301:  // tonos = oxia
+    case 0x0342:  // perispomeni
+    case 0x0302:  // circumflex can look like perispomeni
+    case 0x0303:  // tilde can look like perispomeni
+    case 0x0311:  // inverted breve can look like perispomeni
+        return HAS_ACCENT;
+    case 0x0308:  // dialytika = diaeresis
+        return HAS_COMBINING_DIALYTIKA;
+    case 0x0344:  // dialytika tonos
+        return HAS_COMBINING_DIALYTIKA | HAS_ACCENT;
+    case 0x0345:  // ypogegrammeni = iota subscript
+        return HAS_YPOGEGRAMMENI;
+    case 0x0304:  // macron
+    case 0x0306:  // breve
+    case 0x0313:  // comma above
+    case 0x0314:  // reversed comma above
+    case 0x0343:  // koronis
+        return HAS_OTHER_GREEK_DIACRITIC;
+    default:
+        return 0;
+    }
+}
+
+UBool isFollowedByCasedLetter(const UCaseProps *csp, const UChar *s, int32_t i, int32_t length) {
+    while (i < length) {
+        UChar32 c;
+        U16_NEXT(s, i, length, c);
+        int32_t type = ucase_getTypeOrIgnorable(csp, c);
+        if ((type & UCASE_IGNORABLE) != 0) {
+            // Case-ignorable, continue with the loop.
+        } else if (type != UCASE_NONE) {
+            return TRUE;  // Followed by cased letter.
+        } else {
+            return FALSE;  // Uncased and not case-ignorable.
+        }
+    }
+    return FALSE;  // Not followed by cased letter.
+}
+
+/**
+ * Greek string uppercasing with a state machine.
+ * Probably simpler than a stateless function that has to figure out complex context-before
+ * for each character.
+ * TODO: Try to re-consolidate one way or another with the non-Greek function.
+ */
+int32_t toUpper(const UCaseMap *csm,
+                UChar *dest, int32_t destCapacity,
+                const UChar *src, int32_t srcLength,
+                UErrorCode *pErrorCode) {
+    int32_t locCache = UCASE_LOC_GREEK;
+    int32_t destIndex=0;
+    uint32_t state = 0;
+    for (int32_t i = 0; i < srcLength;) {
+        int32_t nextIndex = i;
+        UChar32 c;
+        U16_NEXT(src, nextIndex, srcLength, c);
+        uint32_t nextState = 0;
+        int32_t type = ucase_getTypeOrIgnorable(csm->csp, c);
+        if ((type & UCASE_IGNORABLE) != 0) {
+            // c is case-ignorable
+            nextState |= (state & AFTER_CASED);
+        } else if (type != UCASE_NONE) {
+            // c is cased
+            nextState |= AFTER_CASED;
+        }
+        uint32_t data = getLetterData(c);
+        if (data > 0) {
+            uint32_t upper = data & UPPER_MASK;
+            // Add a dialytika to this iota or ypsilon vowel
+            // if we removed a tonos from the previous vowel,
+            // and that previous vowel did not also have (or gain) a dialytika.
+            // Adding one only to the final vowel in a longer sequence
+            // (which does not occur in normal writing) would require lookahead.
+            // Set the same flag as for preserving an existing dialytika.
+            if ((data & HAS_VOWEL) != 0 && (state & AFTER_VOWEL_WITH_ACCENT) != 0 &&
+                    (upper == 0x399 || upper == 0x3A5)) {
+                data |= HAS_DIALYTIKA;
+            }
+            int32_t numYpogegrammeni = 0;  // Map each one to a trailing, spacing, capital iota.
+            if ((data & HAS_YPOGEGRAMMENI) != 0) {
+                numYpogegrammeni = 1;
+            }
+            // Skip combining diacritics after this Greek letter.
+            while (nextIndex < srcLength) {
+                uint32_t diacriticData = getDiacriticData(src[nextIndex]);
+                if (diacriticData != 0) {
+                    data |= diacriticData;
+                    if ((diacriticData & HAS_YPOGEGRAMMENI) != 0) {
+                        ++numYpogegrammeni;
+                    }
+                    ++nextIndex;
+                } else {
+                    break;  // not a Greek diacritic
+                }
+            }
+            if ((data & HAS_VOWEL_AND_ACCENT_AND_DIALYTIKA) == HAS_VOWEL_AND_ACCENT) {
+                nextState |= AFTER_VOWEL_WITH_ACCENT;
+            }
+            // Map according to Greek rules.
+            UBool addTonos = FALSE;
+            if (upper == 0x397 &&
+                    (data & HAS_ACCENT) != 0 &&
+                    numYpogegrammeni == 0 &&
+                    (state & AFTER_CASED) == 0 &&
+                    !isFollowedByCasedLetter(csm->csp, src, nextIndex, srcLength)) {
+                // Keep disjunctive "or" with (only) a tonos.
+                // We use the same "word boundary" conditions as for the Final_Sigma test.
+                if (i == nextIndex) {
+                    upper = 0x389;  // Preserve the precomposed form.
+                } else {
+                    addTonos = TRUE;
+                }
+            } else if ((data & HAS_DIALYTIKA) != 0) {
+                // Preserve a vowel with dialytika in precomposed form if it exists.
+                if (upper == 0x399) {
+                    upper = 0x3AA;
+                    data &= ~HAS_EITHER_DIALYTIKA;
+                } else if (upper == 0x3A5) {
+                    upper = 0x3AB;
+                    data &= ~HAS_EITHER_DIALYTIKA;
+                }
+            }
+            destIndex=appendUChar(dest, destIndex, destCapacity, (UChar)upper);
+            if ((data & HAS_EITHER_DIALYTIKA) != 0) {
+                destIndex=appendUChar(dest, destIndex, destCapacity, 0x308);  // restore or add a dialytika
+            }
+            if (addTonos) {
+                destIndex=appendUChar(dest, destIndex, destCapacity, 0x301);
+            }
+            while (numYpogegrammeni > 0) {
+                destIndex=appendUChar(dest, destIndex, destCapacity, 0x399);
+                --numYpogegrammeni;
+            }
+        } else {
+            const UChar *s;
+            UChar32 c2 = 0;
+            c=ucase_toFullUpper(csm->csp, c, NULL, NULL, &s, csm->locale, &locCache);
+            if((destIndex<destCapacity) && (c<0 ? (c2=~c)<=0xffff : UCASE_MAX_STRING_LENGTH<c && (c2=c)<=0xffff)) {
+                /* fast path version of appendResult() for BMP results */
+                dest[destIndex++]=(UChar)c2;
+            } else {
+                destIndex=appendResult(dest, destIndex, destCapacity, c, s);
+            }
+        }
+        i = nextIndex;
+        state = nextState;
+    }
+
+    if(destIndex>destCapacity) {
+        *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+    }
+    return destIndex;
+}
+
+}  // namespace GreekUpper
+U_NAMESPACE_END
+
 /* functions available in the common library (for unistr_case.cpp) */
 
 U_CFUNC int32_t U_CALLCONV
@@ -317,6 +916,10 @@
                          UChar *dest, int32_t destCapacity,
                          const UChar *src, int32_t srcLength,
                          UErrorCode *pErrorCode) {
+    int32_t locCache = csm->locCache;
+    if (ucase_getCaseLocale(csm->locale, &locCache) == UCASE_LOC_GREEK) {
+        return GreekUpper::toUpper(csm, dest, destCapacity, src, srcLength, pErrorCode);
+    }
     UCaseContext csc=UCASECONTEXT_INITIALIZER;
     csc.p=(void *)src;
     csc.limit=srcLength;
diff --git a/src/third_party/icu/source/test/intltest/strcase.cpp b/src/third_party/icu/source/test/intltest/strcase.cpp
index 01d8db9..124841e 100644
--- a/src/third_party/icu/source/test/intltest/strcase.cpp
+++ b/src/third_party/icu/source/test/intltest/strcase.cpp
@@ -16,6 +16,7 @@
 *   Test file for string casing C++ API functions.
 */
 
+#include "unicode/std_string.h"
 #include "unicode/uchar.h"
 #include "unicode/ures.h"
 #include "unicode/uloc.h"
@@ -28,6 +29,8 @@
 #include "unicode/tstdtmod.h"
 #include "cmemory.h"
 
+StringCaseTest::StringCaseTest() : GREEK_LOCALE_("el") {}
+
 StringCaseTest::~StringCaseTest() {}
 
 void
@@ -41,6 +44,7 @@
     TESTCASE_AUTO(TestCasing);
 #endif
     TESTCASE_AUTO(TestFullCaseFoldingIterator);
+    TESTCASE_AUTO(TestGreekUpper);
     TESTCASE_AUTO_END;
 }
 
@@ -571,3 +575,113 @@
         errln("error: FullCaseFoldingIterator yielded only %d (cp, full) pairs", (int)count);
     }
 }
+
+void
+StringCaseTest::assertGreekUpper(const char *s, const char *expected) {
+    UnicodeString s16 = UnicodeString(s).unescape();
+    UnicodeString expected16 = UnicodeString(expected).unescape();
+    UnicodeString msg = UnicodeString("UnicodeString::toUpper/Greek(\"") + s16 + "\")";
+    UnicodeString result16(s16);
+    result16.toUpper(GREEK_LOCALE_);
+    assertEquals(msg, expected16, result16);
+
+#if U_HAVE_STD_STRING
+    UErrorCode errorCode = U_ZERO_ERROR;
+    LocalUCaseMapPointer csm(ucasemap_open("el", 0, &errorCode));
+    assertSuccess("ucasemap_open", errorCode);
+    std::string s8;
+    s16.toUTF8String(s8);
+    msg = UnicodeString("ucasemap_utf8ToUpper/Greek(\"") + s16 + "\")";
+    char dest[1000];
+    int32_t length = ucasemap_utf8ToUpper(csm.getAlias(), dest, UPRV_LENGTHOF(dest),
+                                          s8.data(), s8.length(), &errorCode);
+    assertSuccess("ucasemap_utf8ToUpper", errorCode);
+    StringPiece result8(dest, length);
+    UnicodeString result16From8 = UnicodeString::fromUTF8(result8);
+    assertEquals(msg, expected16, result16From8);
+#endif
+}
+
+void
+StringCaseTest::TestGreekUpper() {
+    // See UCharacterCaseTest.java for human-readable strings.
+
+    // http://bugs.icu-project.org/trac/ticket/5456
+    assertGreekUpper("\\u03AC\\u03B4\\u03B9\\u03BA\\u03BF\\u03C2, "
+                     "\\u03BA\\u03B5\\u03AF\\u03BC\\u03B5\\u03BD\\u03BF, "
+                     "\\u03AF\\u03C1\\u03B9\\u03B4\\u03B1",
+                     "\\u0391\\u0394\\u0399\\u039A\\u039F\\u03A3, "
+                     "\\u039A\\u0395\\u0399\\u039C\\u0395\\u039D\\u039F, "
+                     "\\u0399\\u03A1\\u0399\\u0394\\u0391");
+    // https://bugzilla.mozilla.org/show_bug.cgi?id=307039
+    // https://bug307039.bmoattachments.org/attachment.cgi?id=194893
+    assertGreekUpper("\\u03A0\\u03B1\\u03C4\\u03AC\\u03C4\\u03B1",
+                     "\\u03A0\\u0391\\u03A4\\u0391\\u03A4\\u0391");
+    assertGreekUpper("\\u0391\\u03AD\\u03C1\\u03B1\\u03C2, "
+                     "\\u039C\\u03C5\\u03C3\\u03C4\\u03AE\\u03C1\\u03B9\\u03BF, "
+                     "\\u03A9\\u03C1\\u03B1\\u03AF\\u03BF",
+                     "\\u0391\\u0395\\u03A1\\u0391\\u03A3, "
+                     "\\u039C\\u03A5\\u03A3\\u03A4\\u0397\\u03A1\\u0399\\u039F, "
+                     "\\u03A9\\u03A1\\u0391\\u0399\\u039F");
+    assertGreekUpper("\\u039C\\u03B1\\u0390\\u03BF\\u03C5, \\u03A0\\u03CC\\u03C1\\u03BF\\u03C2, "
+                     "\\u03A1\\u03CD\\u03B8\\u03BC\\u03B9\\u03C3\\u03B7",
+                     "\\u039C\\u0391\\u03AA\\u039F\\u03A5, \\u03A0\\u039F\\u03A1\\u039F\\u03A3, "
+                     "\\u03A1\\u03A5\\u0398\\u039C\\u0399\\u03A3\\u0397");
+    assertGreekUpper("\\u03B0, \\u03A4\\u03B7\\u03C1\\u03CE, \\u039C\\u03AC\\u03B9\\u03BF\\u03C2",
+                     "\\u03AB, \\u03A4\\u0397\\u03A1\\u03A9, \\u039C\\u0391\\u03AA\\u039F\\u03A3");
+    assertGreekUpper("\\u03AC\\u03C5\\u03BB\\u03BF\\u03C2",
+                     "\\u0391\\u03AB\\u039B\\u039F\\u03A3");
+    assertGreekUpper("\\u0391\\u03AB\\u039B\\u039F\\u03A3",
+                     "\\u0391\\u03AB\\u039B\\u039F\\u03A3");
+    assertGreekUpper("\\u0386\\u03BA\\u03BB\\u03B9\\u03C4\\u03B1 "
+                     "\\u03C1\\u03AE\\u03BC\\u03B1\\u03C4\\u03B1 \\u03AE "
+                     "\\u03AC\\u03BA\\u03BB\\u03B9\\u03C4\\u03B5\\u03C2 "
+                     "\\u03BC\\u03B5\\u03C4\\u03BF\\u03C7\\u03AD\\u03C2",
+                     "\\u0391\\u039A\\u039B\\u0399\\u03A4\\u0391 "
+                     "\\u03A1\\u0397\\u039C\\u0391\\u03A4\\u0391 \\u0397\\u0301 "
+                     "\\u0391\\u039A\\u039B\\u0399\\u03A4\\u0395\\u03A3 "
+                     "\\u039C\\u0395\\u03A4\\u039F\\u03A7\\u0395\\u03A3");
+    // http://www.unicode.org/udhr/d/udhr_ell_monotonic.html
+    assertGreekUpper("\\u0395\\u03C0\\u03B5\\u03B9\\u03B4\\u03AE \\u03B7 "
+                     "\\u03B1\\u03BD\\u03B1\\u03B3\\u03BD\\u03CE\\u03C1\\u03B9\\u03C3\\u03B7 "
+                     "\\u03C4\\u03B7\\u03C2 \\u03B1\\u03BE\\u03B9\\u03BF\\u03C0\\u03C1\\u03AD"
+                     "\\u03C0\\u03B5\\u03B9\\u03B1\\u03C2",
+                     "\\u0395\\u03A0\\u0395\\u0399\\u0394\\u0397 \\u0397 "
+                     "\\u0391\\u039D\\u0391\\u0393\\u039D\\u03A9\\u03A1\\u0399\\u03A3\\u0397 "
+                     "\\u03A4\\u0397\\u03A3 \\u0391\\u039E\\u0399\\u039F\\u03A0\\u03A1\\u0395"
+                     "\\u03A0\\u0395\\u0399\\u0391\\u03A3");
+    assertGreekUpper("\\u03BD\\u03BF\\u03BC\\u03B9\\u03BA\\u03BF\\u03CD \\u03AE "
+                     "\\u03B4\\u03B9\\u03B5\\u03B8\\u03BD\\u03BF\\u03CD\\u03C2",
+                     "\\u039D\\u039F\\u039C\\u0399\\u039A\\u039F\\u03A5 \\u0397\\u0301 "
+                     "\\u0394\\u0399\\u0395\\u0398\\u039D\\u039F\\u03A5\\u03A3");
+    // http://unicode.org/udhr/d/udhr_ell_polytonic.html
+    assertGreekUpper("\\u1F18\\u03C0\\u03B5\\u03B9\\u03B4\\u1F74 \\u1F21 "
+                     "\\u1F00\\u03BD\\u03B1\\u03B3\\u03BD\\u1F7D\\u03C1\\u03B9\\u03C3\\u03B7",
+                     "\\u0395\\u03A0\\u0395\\u0399\\u0394\\u0397 \\u0397 "
+                     "\\u0391\\u039D\\u0391\\u0393\\u039D\\u03A9\\u03A1\\u0399\\u03A3\\u0397");
+    assertGreekUpper("\\u03BD\\u03BF\\u03BC\\u03B9\\u03BA\\u03BF\\u1FE6 \\u1F22 "
+                     "\\u03B4\\u03B9\\u03B5\\u03B8\\u03BD\\u03BF\\u1FE6\\u03C2",
+                     "\\u039D\\u039F\\u039C\\u0399\\u039A\\u039F\\u03A5 \\u0397\\u0301 "
+                     "\\u0394\\u0399\\u0395\\u0398\\u039D\\u039F\\u03A5\\u03A3");
+    // From Google bug report
+    assertGreekUpper("\\u039D\\u03AD\\u03BF, "
+                     "\\u0394\\u03B7\\u03BC\\u03B9\\u03BF\\u03C5\\u03C1\\u03B3\\u03AF\\u03B1",
+                     "\\u039D\\u0395\\u039F, "
+                     "\\u0394\\u0397\\u039C\\u0399\\u039F\\u03A5\\u03A1\\u0393\\u0399\\u0391");
+    // http://crbug.com/234797
+    assertGreekUpper("\\u0395\\u03BB\\u03AC\\u03C4\\u03B5 \\u03BD\\u03B1 \\u03C6\\u03AC\\u03C4\\u03B5 "
+                     "\\u03C4\\u03B1 \\u03BA\\u03B1\\u03BB\\u03CD\\u03C4\\u03B5\\u03C1\\u03B1 "
+                     "\\u03C0\\u03B1\\u03CA\\u03B4\\u03AC\\u03BA\\u03B9\\u03B1!",
+                     "\\u0395\\u039B\\u0391\\u03A4\\u0395 \\u039D\\u0391 \\u03A6\\u0391\\u03A4\\u0395 "
+                     "\\u03A4\\u0391 \\u039A\\u0391\\u039B\\u03A5\\u03A4\\u0395\\u03A1\\u0391 "
+                     "\\u03A0\\u0391\\u03AA\\u0394\\u0391\\u039A\\u0399\\u0391!");
+    assertGreekUpper("\\u039C\\u03B1\\u0390\\u03BF\\u03C5, \\u03C4\\u03C1\\u03CC\\u03BB\\u03B5\\u03CA",
+                     "\\u039C\\u0391\\u03AA\\u039F\\u03A5, \\u03A4\\u03A1\\u039F\\u039B\\u0395\\u03AA");
+    assertGreekUpper("\\u03A4\\u03BF \\u03AD\\u03BD\\u03B1 \\u03AE \\u03C4\\u03BF "
+                     "\\u03AC\\u03BB\\u03BB\\u03BF.",
+                     "\\u03A4\\u039F \\u0395\\u039D\\u0391 \\u0397\\u0301 \\u03A4\\u039F "
+                     "\\u0391\\u039B\\u039B\\u039F.");
+    // http://multilingualtypesetting.co.uk/blog/greek-typesetting-tips/
+    assertGreekUpper("\\u03C1\\u03C9\\u03BC\\u03AD\\u03B9\\u03BA\\u03B1",
+                     "\\u03A1\\u03A9\\u039C\\u0395\\u03AA\\u039A\\u0391");
+}
diff --git a/src/third_party/icu/source/test/intltest/ustrtest.h b/src/third_party/icu/source/test/intltest/ustrtest.h
index 655af1c..b9be294 100644
--- a/src/third_party/icu/source/test/intltest/ustrtest.h
+++ b/src/third_party/icu/source/test/intltest/ustrtest.h
@@ -7,6 +7,7 @@
 #ifndef UNICODESTRINGTEST_H
 #define UNICODESTRINGTEST_H
 
+#include "unicode/locid.h"
 #include "unicode/unistr.h"
 #include "intltest.h"
 
@@ -93,7 +94,7 @@
 
 class StringCaseTest: public IntlTest {
 public:
-    StringCaseTest() {}
+    StringCaseTest();
     virtual ~StringCaseTest();
 
     void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par=0);
@@ -106,6 +107,12 @@
                         void *iter, const char *localeID, uint32_t options);
     void TestCasing();
     void TestFullCaseFoldingIterator();
+    void TestGreekUpper();
+
+private:
+    void assertGreekUpper(const char *s, const char *expected);
+
+    Locale GREEK_LOCALE_;
 };
 
 #endif
diff --git a/src/third_party/mozjs-45/mozjs-45.gyp b/src/third_party/mozjs-45/mozjs-45.gyp
index 7641497..46c5b23 100644
--- a/src/third_party/mozjs-45/mozjs-45.gyp
+++ b/src/third_party/mozjs-45/mozjs-45.gyp
@@ -176,6 +176,13 @@
       'target_name': 'mozjs-45_lib',
       'type': 'static_library',
       'cflags': ['<@(common_cflags)'],
+      # Dependent targets may need the headers from 'build_include_directory'
+      # as well. Although 'build_include_directory' specifies hard_dependency,
+      # that only prevents direct dependents from building in parallel -- it
+      # apparently does not prevent indirect dependents. So specifying this as
+      # a hard_dependency should ensure 'build_include_directory' is done for
+      # targets which depend on this.
+      'hard_dependency': 1,
       'dependencies': [
         'build_include_directory',
         '<(DEPTH)/starboard/client_porting/pr_starboard/pr_starboard.gyp:pr_starboard',
@@ -188,9 +195,6 @@
         'cflags': ['<@(common_cflags)'],
         'defines': ['<@(common_defines)'],
       },
-      'export_dependent_settings': [
-        'build_include_directory',
-      ],
       'include_dirs': [
         '<(DEPTH)/third_party/mozjs-45/js/src',
         '<@(common_include_dirs)',
diff --git a/src/third_party/protobuf/src/google/protobuf/stubs/port.h b/src/third_party/protobuf/src/google/protobuf/stubs/port.h
index de90064..49d208e 100644
--- a/src/third_party/protobuf/src/google/protobuf/stubs/port.h
+++ b/src/third_party/protobuf/src/google/protobuf/stubs/port.h
@@ -49,17 +49,18 @@
 #include "starboard/memory.h"
 #include "starboard/types.h"
 // This workaround is for protoc auto-generated files which use memset.
-#ifndef memset
-#define memset SbMemorySet
 #if SB_HAS_QUIRK(MEMSET_IN_SYSTEM_HEADERS)
   namespace std {
     inline namespace _LIBCPP_NAMESPACE {
       inline void *SbMemorySet(void* destination, int byte_value,
                                size_t count) {
-        return ::SbMemorySet(destination, byte_value, count);
+        return::SbMemorySet(destination, byte_value, count);
       }
     }
   }
+#else
+#ifndef memset
+#define memset SbMemorySet
 #endif  // SB_HAS_QUIRK(MEMSET_IN_SYSTEM_HEADERS)
 #endif  // memset
 #endif
diff --git a/src/v8/src/base/atomicops.h b/src/v8/src/base/atomicops.h
index c5ec1ea..9894dc4 100644
--- a/src/v8/src/base/atomicops.h
+++ b/src/v8/src/base/atomicops.h
@@ -38,11 +38,11 @@
 
 #if defined(V8_OS_STARBOARD)
 #include "starboard/atomic.h"
-#endif
 
 #if SB_API_VERSION < 10
 #error Your version of Starboard must support SbAtomic8 in order to use V8.
-#endif
+#endif  // SB_API_VERSION < 10
+#endif  // V8_OS_STARBOARD
 
 namespace v8 {
 namespace base {
diff --git a/src/v8/src/base/platform/platform-win32.cc b/src/v8/src/base/platform/platform-win32.cc
index 22580cc..a3f4199 100644
--- a/src/v8/src/base/platform/platform-win32.cc
+++ b/src/v8/src/base/platform/platform-win32.cc
@@ -642,7 +642,14 @@
 
 
 int OS::VSNPrintF(char* str, int length, const char* format, va_list args) {
+#if defined(COBALT)
+  // In testing, _vsnprintf_s can fill result's tail with unexpected
+  // characters if strlen(str) < length. Switching to vsnprintf is what Cobalt
+  // uses for msvs platforms currently.
+  int n = vsnprintf(str, length, format, args);
+#else
   int n = _vsnprintf_s(str, length, _TRUNCATE, format, args);
+#endif
   // Make sure to zero-terminate the string if the output was
   // truncated or if there was an error.
   if (n < 0 || n >= length) {
diff --git a/src/v8/src/ostreams.cc b/src/v8/src/ostreams.cc
index 66b5702..4d787a4 100644
--- a/src/v8/src/ostreams.cc
+++ b/src/v8/src/ostreams.cc
@@ -15,6 +15,7 @@
 namespace v8 {
 namespace internal {
 
+#if !defined(COBALT)
 OFStreamBase::OFStreamBase(FILE* f) : f_(f) {}
 
 
@@ -42,6 +43,9 @@
   DCHECK_NOT_NULL(f);
   rdbuf(&buf_);
 }
+#else
+OFStream::OFStream(FILE* f) : std::ostream(nullptr) {}
+#endif  // !defined(COBALT)
 
 
 OFStream::~OFStream() {}
diff --git a/src/v8/src/ostreams.h b/src/v8/src/ostreams.h
index f2f961e..3dc73d9 100644
--- a/src/v8/src/ostreams.h
+++ b/src/v8/src/ostreams.h
@@ -18,7 +18,7 @@
 namespace v8 {
 namespace internal {
 
-
+#if !defined(COBALT)
 class OFStreamBase : public std::streambuf {
  public:
   explicit OFStreamBase(FILE* f);
@@ -31,6 +31,7 @@
   virtual int_type overflow(int_type c);
   virtual std::streamsize xsputn(const char* s, std::streamsize n);
 };
+#endif  // !defined(COBALT)
 
 
 // An output stream writing to a file.
@@ -40,7 +41,9 @@
   virtual ~OFStream();
 
  private:
+#if !defined(COBALT)
   OFStreamBase buf_;
+#endif  // !defined(COBALT)
 };
 
 
diff --git a/src/v8/src/runtime/runtime-atomics.cc b/src/v8/src/runtime/runtime-atomics.cc
index cca1df9..de5d2b1 100644
--- a/src/v8/src/runtime/runtime-atomics.cc
+++ b/src/v8/src/runtime/runtime-atomics.cc
@@ -10,7 +10,9 @@
 #include "src/conversions-inl.h"
 #include "src/factory.h"
 
+#if defined(V8_OS_STARBOARD)
 #include "starboard/log.h"
+#endif  // V8_OS_STARBOARD
 
 // Implement Atomic accesses to SharedArrayBuffers as defined in the
 // SharedArrayBuffer draft spec, found here
@@ -21,7 +23,7 @@
 
 namespace {
 
-#if defined(STARBOARD)
+#if defined(V8_OS_STARBOARD)
 
 template <typename T>
 inline T ExchangeSeqCst(T* p, T value) {
@@ -171,7 +173,7 @@
 
 #error Unsupported platform!
 
-#endif
+#endif  // V8_OS_STARBOARD
 
 template <typename T>
 T FromObject(Handle<Object> number);
diff --git a/src/v8/src/trap-handler/trap-handler.h b/src/v8/src/trap-handler/trap-handler.h
index b927818..4bfeef5 100644
--- a/src/v8/src/trap-handler/trap-handler.h
+++ b/src/v8/src/trap-handler/trap-handler.h
@@ -13,7 +13,9 @@
 #include "src/flags.h"
 #include "src/globals.h"
 
+#if V8_OS_STARBOARD
 #include "starboard/log.h"
+#endif  //V8_OS_STARBOARD
 
 #if V8_OS_LINUX
 #include <ucontext.h>
@@ -74,7 +76,7 @@
   return FLAG_wasm_trap_handler && V8_TRAP_HANDLER_SUPPORTED;
 }
 
-#if defined(STARBOARD)
+#if defined(V8_OS_STARBOARD)
 inline bool IsThreadInWasm() {
   SB_NOTREACHED();
   return false;
@@ -85,7 +87,6 @@
 extern THREAD_LOCAL int g_thread_in_wasm_code;
 
 inline bool IsThreadInWasm() {
-  SB_NOTIMPLEMENTED();
   return g_thread_in_wasm_code;
 }
 
@@ -102,7 +103,7 @@
     g_thread_in_wasm_code = false;
   }
 }
-#endif
+#endif  // V8_OS_STARBOARD
 
 bool RegisterDefaultSignalHandler();
 V8_EXPORT_PRIVATE void RestoreOriginalSignalHandler();
diff --git a/src/v8/src/v8.gyp b/src/v8/src/v8.gyp
index 6a64c48..b40af6c 100644
--- a/src/v8/src/v8.gyp
+++ b/src/v8/src/v8.gyp
@@ -37,16 +37,13 @@
     'mksnapshot_exec': '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)mksnapshot<(EXECUTABLE_SUFFIX)',
     'v8_os_page_size%': 0,
 
-    'v8_use_snapshot': 0,
+    'v8_use_snapshot': '<(cobalt_v8_buildtime_snapshot)',
     'v8_optimized_debug': 0,
     'v8_use_external_startup_data': 0,
     # TODO: Enable i18n support.
     'v8_enable_i18n_support': 0,
   },
   'target_defaults': {
-    'defines': [
-      'V8_OS_STARBOARD=1',
-    ],
     'msvs_disabled_warnings': [4267, 4312, 4351, 4355, 4800, 4838],
     'conditions': [
       ['cobalt_config == "debug"', {
@@ -181,6 +178,11 @@
           'toolsets': ['target'],
         }],
       ],
+      'target_conditions': [
+        ['_toolset=="target"', {
+          'defines': ['V8_OS_STARBOARD=1'],
+        }],
+      ],
     },
     {
       'target_name': 'v8_initializers',
@@ -312,6 +314,11 @@
           ],
         }],
       ],
+      'target_conditions': [
+        ['_toolset=="target"', {
+          'defines': ['V8_OS_STARBOARD=1'],
+        }],
+      ],
     },
     {
       'target_name': 'v8_snapshot',
@@ -426,7 +433,12 @@
             'BUILDING_V8_SHARED',
           ],
         }],
-      ]
+      ],
+      'target_conditions': [
+        ['_toolset=="target"', {
+          'defines': ['V8_OS_STARBOARD=1'],
+        }],
+      ],
     },
     {
       'target_name': 'v8_external_snapshot',
@@ -1893,6 +1905,17 @@
           ],
         }],
       ],
+      'target_conditions': [
+        ['_toolset=="target"', {
+          'defines': ['V8_OS_STARBOARD=1'],
+        }, {
+          'conditions': [
+            ['v8_target_arch=="x64" and host_os=="linux"', {
+              'sources': ['trap-handler/handler-inside.cc']
+            }],
+          ],
+        }],
+      ],
     },
     {
       'target_name': 'v8_libbase',
@@ -1975,6 +1998,9 @@
             'src/common/android/include',
           ],
         }],
+        ['_toolset=="target"', {
+          'defines': ['V8_OS_STARBOARD=1'],
+        }],
       ],
       'conditions': [
         ['want_separate_host_toolset==1', {
@@ -2010,9 +2036,49 @@
           }
         ],
         ['OS=="starboard"', {
-          'sources': [
-            'base/debug/stack_trace_starboard.cc',
-            'base/platform/platform-starboard.cc',
+          'target_conditions': [
+            ['_toolset=="host"', {
+              # if _toolset="host", we use the native host build which does not
+              # involve Starboard at all.
+              'target_conditions': [
+                ['host_os=="linux"', {
+                  'ldflags_host': [
+                    '-ldl',
+                    '-lrt'
+                  ],
+                  'sources': [
+                    'base/debug/stack_trace_posix.cc',
+                    'base/platform/platform-linux.cc',
+                    'base/platform/platform-posix.h',
+                    'base/platform/platform-posix.cc',
+                    'base/platform/platform-posix-time.h',
+                    'base/platform/platform-posix-time.cc',
+                  ],
+                }],
+                ['host_os=="win"', {
+                  # Most of the following codes are copied from 'OS="win"'
+                  # section.
+                  'defines': [
+                    '_CRT_RAND_S'  # for rand_s()
+                  ],
+                  'variables': {
+                    'gyp_generators': '<!(echo $GYP_GENERATORS)',
+                  },
+                  'sources': [
+                    'base/debug/stack_trace_win.cc',
+                    'base/platform/platform-win32.cc',
+                    'base/win32-headers.h',
+                  ],
+                  'msvs_disabled_warnings': [4351, 4355, 4800],
+                }],
+              ],
+            }, {
+              # If _toolset=="target", build with target platform's Starboard.
+              'sources': [
+                'base/debug/stack_trace_starboard.cc',
+                'base/platform/platform-starboard.cc',
+              ],
+            }],
           ],
         }],
         ['OS=="android"', {
@@ -2282,6 +2348,11 @@
           'defines': [ 'BUILDING_V8_PLATFORM_SHARED' ],
         }]
       ],
+      'target_conditions': [
+        ['_toolset=="target"', {
+          'defines': ['V8_OS_STARBOARD=1'],
+        }],
+      ],
       'direct_dependent_settings': {
         'include_dirs': [
           '../include',
@@ -2312,6 +2383,11 @@
           'toolsets': ['target'],
         }],
       ],
+      'target_conditions': [
+        ['_toolset=="target"', {
+          'defines': ['V8_OS_STARBOARD=1'],
+        }],
+      ],
       'direct_dependent_settings': {
         'include_dirs': [
           '../include',
@@ -2373,7 +2449,12 @@
         }, {
           'toolsets': ['target'],
         }],
-      ]
+      ],
+      'target_conditions': [
+        ['_toolset=="target"', {
+          'defines': ['V8_OS_STARBOARD=1'],
+        }],
+      ],
     },
     {
       'target_name': 'js2c',