Import Cobalt 19.master.0.185967

  Includes the following patches:
    https://cobalt-review.googlesource.com/c/cobalt/+/4730
      by linus.wang@samsung.com
    https://cobalt-review.googlesource.com/c/cobalt/+/4750
      by kaiyuan.tang@samsung.com
    https://cobalt-review.googlesource.com/c/cobalt/+/4770
      by z102.zhang@samsung.com
    https://cobalt-review.googlesource.com/c/cobalt/+/4790
      by linus.wang@samsung.com
    https://cobalt-review.googlesource.com/c/cobalt/+/4810
      by milko.leporis@mips.com

Change-Id: Icc49233549571377dcc6bd17f0024cb261d7b953
diff --git a/src/base/hash_tables.h b/src/base/hash_tables.h
index b6f40be..e905ea6 100644
--- a/src/base/hash_tables.h
+++ b/src/base/hash_tables.h
@@ -29,6 +29,16 @@
 
 #if defined(OS_STARBOARD)
 #include "starboard/configuration.h"
+#if SB_HAS(STD_UNORDERED_HASH)
+#define BASE_HASH_DEFINE_LONG_LONG_HASHES 0
+#define BASE_HASH_DEFINE_STRING_HASHES 0
+#define BASE_HASH_USE_HASH 0
+#define BASE_HASH_MAP_INCLUDE <unordered_map>
+#define BASE_HASH_NAMESPACE std
+#define BASE_HASH_SET_INCLUDE <unordered_set>
+#define BASE_HASH_USE_HASH_STRUCT
+
+#else  // SB_HAS(STD_UNORDERED_HASH)
 #define BASE_HASH_DEFINE_LONG_LONG_HASHES !SB_HAS(LONG_LONG_HASH)
 #define BASE_HASH_DEFINE_STRING_HASHES !SB_HAS(STRING_HASH)
 #define BASE_HASH_USE_HASH !SB_HAS(HASH_USING)
@@ -38,6 +48,7 @@
 #if !SB_HAS(HASH_VALUE)
 #define BASE_HASH_USE_HASH_STRUCT
 #endif
+#endif // SB_HAS(STD_UNORDERED_HASH)
 #elif defined(COMPILER_MSVC)
 #define BASE_HASH_DEFINE_LONG_LONG_HASHES 0
 #define BASE_HASH_DEFINE_STRING_HASHES 0
@@ -147,10 +158,27 @@
 #if BASE_HASH_USE_HASH
 using BASE_HASH_NAMESPACE::hash;
 #endif
+#if SB_HAS(STD_UNORDERED_HASH)
+template <class K,
+          class V,
+          class Hash = std::hash<K>,
+          class KeyEqual = std::equal_to<K>>
+using hash_map = std::unordered_map<K, V, Hash, KeyEqual>;
+template <class K,
+          class V,
+          class Hash = std::hash<K>,
+          class KeyEqual = std::equal_to<K>>
+using hash_multimap = std::unordered_multimap<K, V, Hash, KeyEqual>;
+template <class K, class Hash = std::hash<K>, class KeyEqual = std::equal_to<K>>
+using hash_multiset = std::unordered_multiset<K, Hash, KeyEqual>;
+template <class K, class Hash = std::hash<K>, class KeyEqual = std::equal_to<K>>
+using hash_set = std::unordered_set<K, Hash, KeyEqual>;
+#else  // SB_HAS(STD_UNORDERED_HASH)
 using BASE_HASH_NAMESPACE::hash_map;
 using BASE_HASH_NAMESPACE::hash_multimap;
 using BASE_HASH_NAMESPACE::hash_multiset;
 using BASE_HASH_NAMESPACE::hash_set;
+#endif  // SB_HAS(STD_UNORDERED_HASH)
 }
 
 #undef BASE_HASH_DEFINE_LONG_LONG_HASHES
diff --git a/src/base/string_piece.h b/src/base/string_piece.h
index 7881e21..67e7670 100644
--- a/src/base/string_piece.h
+++ b/src/base/string_piece.h
@@ -423,7 +423,7 @@
 #if (!defined(OS_STARBOARD) && defined(COMPILER_GCC) &&                 \
         !(defined(__LB_SHELL__) && !defined(__LB_LINUX__))) ||          \
     (defined(OS_STARBOARD) &&                                           \
-        !(defined(SB_HAS_HASH_VALUE) && SB_HAS_HASH_VALUE))
+        !SB_HAS(HASH_VALUE))
 
 template<>
 struct hash<base::StringPiece> {
@@ -441,7 +441,7 @@
 #elif (!defined(OS_STARBOARD) && \
           (defined(COMPILER_MSVC) || defined(__LB_SHELL__))) ||         \
       (defined(OS_STARBOARD) &&                                         \
-          defined(SB_HAS_HASH_VALUE) && SB_HAS_HASH_VALUE)
+          SB_HAS(HASH_VALUE))
 
 inline size_t hash_value(const base::StringPiece& sp) {
   HASH_STRING_PIECE(base::StringPiece, sp);
diff --git a/src/cobalt/CHANGELOG.md b/src/cobalt/CHANGELOG.md
index a1a4b77..464062d 100644
--- a/src/cobalt/CHANGELOG.md
+++ b/src/cobalt/CHANGELOG.md
@@ -16,11 +16,6 @@
    This was not originally supported by Cobalt, and any prior use of animated
    WebP with transparency would have resulted in visual artifacts.
 
- - **Improvements and Bug Fixes**
-   - Fix pointer/mouse events not being dispatched to JavaScript in the same
-     order that they are generated by Starboard, relative to other input events
-     like key presses.
-
  - **Storage format changed from sqlite3 to protobuf**
 
    Cobalt's internal representation for persistent storage of cookies and local
@@ -49,11 +44,23 @@
    implement voice-enabled features without relying on the platform's capability
    to perform speech recognition.
 
- - **Bison 2 deprecation**
+ - **Bison 3 required**
 
    Support for compiling with version 2.x of the GNU bison parser generator
-   has been deprecated and will be removed in this version. Please upgrade
-   to bison 3.x.
+   has been removed. Please update to version 3.x.
+
+ - **Improvements and Bug Fixes**
+  - Fix pointer/mouse events not being dispatched to JavaScript in the same
+    order that they are generated by Starboard, relative to other input events
+    like key presses.
+  - Fix issue with CSS media queries not assigning correct rule indices.
+    An issue was discovered and fixed where CSS rules defined within `@media`
+    rules would be assigned a CSS rule index relative to their position within
+    the nested `@media` rule rather than being assigned an index relative to
+    their position within the parent CSS file.  As a result, rules may have been
+    assigned incorrect precedence during CSS rule matching.
+  - Fix issue where the style attribute would not appear in the string output
+    of calls to element.outerHTML.
 
 ## Version 16
  - **Rebase libwebp to version 1.0.0**
diff --git a/src/cobalt/base/type_id.h b/src/cobalt/base/type_id.h
index 834b5d9..42e4257 100644
--- a/src/cobalt/base/type_id.h
+++ b/src/cobalt/base/type_id.h
@@ -59,7 +59,8 @@
  private:
   explicit TypeId(intptr_t value) : value_(value) {}
   intptr_t value_;
-  template <typename T> friend TypeId GetTypeId();
+  template <typename T>
+  friend TypeId GetTypeId();
 #if defined(BASE_HASH_USE_HASH_STRUCT)
   friend struct BASE_HASH_NAMESPACE::hash<TypeId>;
 #else
@@ -73,8 +74,8 @@
 // same type argument is guaranteed to return the same ID.
 template <typename T>
 TypeId GetTypeId() {
-  return
-      TypeId(reinterpret_cast<intptr_t>(&(internal::TypeIdHelper<T>::dummy_)));
+  return TypeId(
+      reinterpret_cast<intptr_t>(&(internal::TypeIdHelper<T>::dummy_)));
 }
 
 }  // namespace base
@@ -89,8 +90,8 @@
 #if defined(BASE_HASH_USE_HASH_STRUCT)
 
 // Forward declaration in case <hash_fun.h> is not #include'd.
-template <typename Key>
-struct hash;
+template <>
+struct hash<base::TypeId>;
 
 template <>
 struct hash<base::TypeId> {
@@ -128,8 +129,7 @@
     return base_hash_compare_(key.value_);
   }
 
-  bool operator()(const base::TypeId& lhs,
-                  const base::TypeId& rhs) const {
+  bool operator()(const base::TypeId& lhs, const base::TypeId& rhs) const {
     return base_hash_compare_(lhs.value_, rhs.value_);
   }
 
diff --git a/src/cobalt/browser/application.cc b/src/cobalt/browser/application.cc
index d24d7f7..7fee6c2 100644
--- a/src/cobalt/browser/application.cc
+++ b/src/cobalt/browser/application.cc
@@ -527,9 +527,12 @@
   }
   options.storage_manager_options.savegame_options.id = partition_key;
 
+
   base::optional<std::string> default_key =
       base::GetApplicationKey(GURL(kDefaultURL));
-  if (partition_key == default_key) {
+  if (command_line->HasSwitch(
+          browser::switches::kForceMigrationForStoragePartitioning) ||
+      partition_key == default_key) {
     options.storage_manager_options.savegame_options.fallback_to_default_id =
         true;
   }
diff --git a/src/cobalt/browser/switches.cc b/src/cobalt/browser/switches.cc
index 6c34f09..98fbd7a 100644
--- a/src/cobalt/browser/switches.cc
+++ b/src/cobalt/browser/switches.cc
@@ -117,7 +117,13 @@
     "Use this flag to simulate production build behavior.";
 
 const char kProxy[] = "proxy";
-const char kProxyHelp[] = "Specifies a proxy to use for network connections.";
+const char kProxyHelp[] =
+    "Specifies a proxy to use for network connections. "
+    "See comments in net::ProxyRules::ParseFromString() for more information. "
+    "If you do not explicitly provide a scheme when providing the proxy server "
+    "URL, it will default to HTTP.  So for example, for a HTTPS proxy you "
+    "would want to specify '--proxy=\"https=https://localhost:443\"' instead "
+    "of '--proxy=\"https=localhost:443\"'.";
 
 const char kRemoteDebuggingPort[] = "remote_debugging_port";
 const char kRemoteDebuggingPortHelp[] =
@@ -192,6 +198,14 @@
     "video on platforms that do not support stereoscopy natively, letting the "
     "client apply a stereo mesh projection (one that differs for each eye).";
 
+const char kForceMigrationForStoragePartitioning[] =
+    "force_migration_for_storage_partitioning";
+const char kForceMigrationForStoragePartitioningHelp[] =
+    "Overrides the default storage migration policy when upgrading to "
+    "partitioned storage and forces data migration regardless of the"
+    "initial app url. The default policy is to migrate data only for"
+    "https://www.youtube.com/tv.";
+
 // If toggled, framerate statistics will be printed to stdout after each
 // animation completes, or after a maximum number of frames has been collected.
 const char kFPSPrint[] = "fps_stdout";
@@ -366,6 +380,8 @@
 
         {kDisableJavaScriptJit, kDisableJavaScriptJitHelp},
         {kEnableMapToMeshRectanglar, kEnableMapToMeshRectanglarHelp},
+        {kForceMigrationForStoragePartitioning,
+         kForceMigrationForStoragePartitioningHelp},
         {kFPSPrint, kFPSPrintHelp}, {kFPSOverlay, kFPSOverlayHelp},
         {kHelp, kHelpHelp},
         {kImageCacheSizeInBytes, kImageCacheSizeInBytesHelp},
diff --git a/src/cobalt/browser/switches.h b/src/cobalt/browser/switches.h
index 59a45df..9c9e4fc 100644
--- a/src/cobalt/browser/switches.h
+++ b/src/cobalt/browser/switches.h
@@ -91,6 +91,7 @@
 extern const char kDisableJavaScriptJit[];
 extern const char kDisableJavaScriptJitHelp[];
 extern const char kEnableMapToMeshRectanglar[];
+extern const char kForceMigrationForStoragePartitioning[];
 extern const char kFPSPrint[];
 extern const char kFPSPrintHelp[];
 extern const char kFPSOverlay[];
diff --git a/src/cobalt/build/build.id b/src/cobalt/build/build.id
index 18204af..3450182 100644
--- a/src/cobalt/build/build.id
+++ b/src/cobalt/build/build.id
@@ -1 +1 @@
-183272
\ No newline at end of file
+185967
\ No newline at end of file
diff --git a/src/cobalt/css_parser/css_parser.gyp b/src/cobalt/css_parser/css_parser.gyp
index 1bc9100..f9bc38b 100644
--- a/src/cobalt/css_parser/css_parser.gyp
+++ b/src/cobalt/css_parser/css_parser.gyp
@@ -20,11 +20,8 @@
     'conditions': [
       ['host_os=="win"', {
         'bison_exe': '<(DEPTH)/third_party/winflexbison/bin/Release/win_bison',
-        'bison_major_version': '3'
       }, {
         'bison_exe': 'bison',
-        'bison_major_version': '<!(bison --version | '
-          'head -n 1 | sed -Ee "s/[^0-9]*([0-9]+).*/\\1/")'
       }],
     ],
   },
@@ -38,13 +35,7 @@
       'type': 'none',
       'sources': [
         'grammar.h',
-      ],
-      'conditions': [
-        ['bison_major_version==2', {
-          'sources': ['grammar-bison-2.y'],
-        }, {
-          'sources': ['grammar.y']
-        }]
+	'grammar.y'
       ],
       # Generated header files are stored in the intermediate directory
       # under their module sub-directory.
@@ -111,9 +102,6 @@
         'trivial_string_piece.h',
         'trivial_type_pairs.h',
       ],
-      'defines': [
-        'BISON_VERSION_MAJOR=<@(bison_major_version)'
-      ],
       # Scanner exposes UChar32 in a header.
       'direct_dependent_settings': {
         'include_dirs': [
@@ -138,9 +126,6 @@
         'scanner_test.cc',
         'trivial_string_piece_test.cc',
       ],
-      'defines': [
-        'BISON_VERSION_MAJOR=<@(bison_major_version)'
-      ],
       'dependencies': [
         '<(DEPTH)/cobalt/base/base.gyp:base',
         '<(DEPTH)/cobalt/test/test.gyp:run_all_unittests',
diff --git a/src/cobalt/css_parser/grammar-bison-2.y b/src/cobalt/css_parser/grammar-bison-2.y
deleted file mode 100644
index c620f85..0000000
--- a/src/cobalt/css_parser/grammar-bison-2.y
+++ /dev/null
@@ -1,6901 +0,0 @@
-// Copyright 2014 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.
-
-// This file contains a definition of CSS grammar.
-
-// A reentrant parser.
-%pure_parser
-
-// yyparse()'s first and only parameter.
-%parse-param { ParserImpl* parser_impl }
-
-%{
-// Specify how the location of an action should be calculated in terms
-// of its children.
-#define YYLLOC_DEFAULT(Current, Rhs, N)          \
-  if (N) {                                       \
-    Current.first_line   = Rhs[1].first_line;    \
-    Current.first_column = Rhs[1].first_column;  \
-    Current.line_start   = Rhs[1].line_start;    \
-  } else {                                       \
-    Current.first_line   = Rhs[0].first_line;    \
-    Current.first_column = Rhs[0].first_column;  \
-    Current.line_start   = Rhs[0].line_start;    \
-  }
-
-// yylex()'s third parameter.
-#define YYLEX_PARAM &(parser_impl->scanner())
-%}
-
-// Token values returned by a scanner.
-%union TokenValue {
-  float real;
-  int integer;
-  TrivialIntPair integer_pair;
-  TrivialStringPiece string;
-}
-
-//
-// Tokens returned by a scanner.
-//
-
-// Entry point tokens, injected by the parser in order to choose the path
-// within a grammar, never appear in the source code.
-%token kMediaListEntryPointToken
-%token kMediaQueryEntryPointToken
-%token kStyleSheetEntryPointToken
-%token kRuleEntryPointToken
-%token kStyleDeclarationListEntryPointToken
-%token kFontFaceDeclarationListEntryPointToken
-%token kPropertyValueEntryPointToken
-%token kPropertyIntoDeclarationDataEntryPointToken
-
-// Tokens without a value.
-%token kEndOfFileToken 0                // null
-%token kWhitespaceToken                 // tab, space, CR, LF
-%token kSgmlCommentDelimiterToken       // <!-- -->
-%token kCommentToken                    // /* */
-%token kImportantToken                  // !important
-
-// Property name tokens.
-// WARNING: Every time a new name token is introduced, it should be added
-//          to |identifier_token| rule below.
-%token kAllToken                              // all
-%token kAnimationDelayToken                   // animation-delay
-%token kAnimationDirectionToken               // animation-direction
-%token kAnimationDurationToken                // animation-duration
-%token kAnimationFillModeToken                // animation-fill-mode
-%token kAnimationIterationCountToken          // animation-iteration-count
-%token kAnimationNameToken                    // animation-name
-%token kAnimationTimingFunctionToken          // animation-timing-function
-%token kAnimationToken                        // animation
-%token kBackgroundColorToken                  // background-color
-%token kBackgroundImageToken                  // background-image
-%token kBackgroundPositionToken               // background-position
-%token kBackgroundRepeatToken                 // background-repeat
-%token kBackgroundSizeToken                   // background-size
-%token kBackgroundToken                       // background
-%token kBorderToken                           // border
-%token kBorderBottomLeftRadiusToken           // border-bottom-left-radius
-%token kBorderBottomRightRadiusToken          // border-bottom-right-radius
-%token kBorderBottomToken                     // border-bottom
-%token kBorderBottomColorToken                // border-bottom-color
-%token kBorderBottomStyleToken                // border-bottom-style
-%token kBorderBottomWidthToken                // border-bottom-width
-%token kBorderColorToken                      // border-color
-%token kBorderLeftToken                       // border-left
-%token kBorderLeftColorToken                  // border-left-color
-%token kBorderLeftStyleToken                  // border-left-style
-%token kBorderLeftWidthToken                  // border-left-width
-%token kBorderRadiusToken                     // border-radius
-%token kBorderRightToken                      // border-right
-%token kBorderRightColorToken                 // border-right-color
-%token kBorderRightStyleToken                 // border-right-style
-%token kBorderRightWidthToken                 // border-right-width
-%token kBorderStyleToken                      // border-style
-%token kBorderTopToken                        // border-top
-%token kBorderTopColorToken                   // border-top-color
-%token kBorderTopLeftRadiusToken              // border-top-left-radius
-%token kBorderTopRightRadiusToken             // border-top-right-radius
-%token kBorderTopStyleToken                   // border-top-style
-%token kBorderTopWidthToken                   // border-top-width
-%token kBorderWidthToken                      // border-width
-%token kBottomToken                           // bottom
-%token kBoxShadowToken                        // box-shadow
-%token kColorToken                            // color
-%token kContentToken                          // content
-%token kDisplayToken                          // display
-%token kFilterToken                           // filter
-%token kFontToken                             // font
-%token kFontFamilyToken                       // font-family
-%token kFontSizeToken                         // font-size
-%token kFontStyleToken                        // font-style
-%token kFontWeightToken                       // font-weight
-%token kHeightToken                           // height
-%token kLeftToken                             // left
-%token kLineHeightToken                       // line-height
-%token kMarginBottomToken                     // margin-bottom
-%token kMarginLeftToken                       // margin-left
-%token kMarginRightToken                      // margin-right
-%token kMarginToken                           // margin
-%token kMarginTopToken                        // margin-top
-%token kMaxHeightToken                        // max-height
-%token kMaxWidthToken                         // max-width
-%token kMinHeightToken                        // min-height
-%token kMinWidthToken                         // min-width
-%token kOpacityToken                          // opacity
-%token kOutlineToken                          // outline
-%token kOutlineColorToken                     // outline-color
-%token kOutlineStyleToken                     // outline-style
-%token kOutlineWidthToken                     // outline-width
-%token kOverflowToken                         // overflow
-%token kOverflowWrapToken                     // overflow-wrap
-%token kPaddingBottomToken                    // padding-bottom
-%token kPaddingLeftToken                      // padding-left
-%token kPaddingRightToken                     // padding-right
-%token kPaddingToken                          // padding
-%token kPaddingTopToken                       // padding-top
-%token kPointerEventsToken                    // pointer-events
-%token kPositionToken                         // position
-%token kRightToken                            // right
-%token kSrcToken                              // src
-%token kTextAlignToken                        // text-align
-%token kTextDecorationToken                   // text-decoration
-%token kTextDecorationColorToken              // text-decoration-color
-%token kTextDecorationLineToken               // text-decoration-line
-%token kTextIndentToken                       // text-indent
-%token kTextOverflowToken                     // text-overflow
-%token kTextShadowToken                       // text-shadow
-%token kTextTransformToken                    // text-transform
-%token kTopToken                              // top
-%token kTransformToken                        // transform
-%token kTransformOriginToken                  // transform-origin
-%token kTransitionDelayToken                  // transition-delay
-%token kTransitionDurationToken               // transition-duration
-%token kTransitionPropertyToken               // transition-property
-%token kTransitionTimingFunctionToken         // transition-timing-function
-%token kTransitionToken                       // transition
-%token kUnicodeRangePropertyToken             // unicode-range
-%token kVerticalAlignToken                    // vertical-align
-%token kVisibilityToken                       // visibility
-%token kWhiteSpacePropertyToken               // white-space
-%token kWidthToken                            // width
-%token kZIndexToken                           // z-index
-
-// Property value tokens.
-// WARNING: Every time a new name token is introduced, it should be added
-//          to |identifier_token| rule below.
-%token kAbsoluteToken                   // absolute
-%token kAlternateToken                  // alternate
-%token kAlternateReverseToken           // alternate-reverse
-%token kAquaToken                       // aqua
-%token kAtToken                         // at
-%token kAutoToken                       // auto
-%token kBackwardsToken                  // backwards
-%token kBaselineToken                   // baseline
-%token kBlackToken                      // black
-%token kBlockToken                      // block
-%token kBlueToken                       // blue
-%token kBoldToken                       // bold
-%token kBothToken                       // both
-%token kBreakWordToken                  // break-word
-%token kCenterToken                     // center
-%token kCircleToken                     // circle
-%token kClipToken                       // clip
-%token kClosestCornerToken              // closest-corner
-%token kClosestSideToken                // closest-side
-%token kContainToken                    // contain
-%token kCoverToken                      // cover
-%token kCursiveToken                    // cursive
-%token kEaseInOutToken                  // ease-in-out
-%token kEaseInToken                     // ease-in
-%token kEaseOutToken                    // ease-out
-%token kEaseToken                       // ease
-%token kEllipseToken                    // ellipse
-%token kEllipsisToken                   // ellipsis
-%token kEndToken                        // end
-%token kEquirectangularToken            // equirectangular
-%token kFantasyToken                    // fantasy
-%token kFarthestCornerToken             // farthest-corner
-%token kFarthestSideToken               // farthest-side
-%token kFixedToken                      // fixed
-%token kForwardsToken                   // forwards
-%token kFromToken                       // from
-%token kFuchsiaToken                    // fuchsia
-%token kGrayToken                       // gray
-%token kGreenToken                      // green
-%token kHiddenToken                     // hidden
-%token kInfiniteToken                   // infinite
-%token kInheritToken                    // inherit
-%token kInitialToken                    // initial
-%token kInlineBlockToken                // inline-block
-%token kInlineToken                     // inline
-%token kInsetToken                      // inset
-%token kItalicToken                     // italic
-%token kLimeToken                       // lime
-%token kLinearToken                     // linear
-%token kLineThroughToken                // line-through
-// %token kLeftToken                    // left - also property name token
-%token kMaroonToken                     // maroon
-%token kMiddleToken                     // middle
-%token kMonoscopicToken                 // monoscopic
-%token kMonospaceToken                  // monospace
-%token kNavyToken                       // navy
-%token kNoneToken                       // none
-%token kNoRepeatToken                   // no-repeat
-%token kNormalToken                     // normal
-%token kNoWrapToken                     // nowrap
-%token kObliqueToken                    // oblique
-%token kOliveToken                      // olive
-%token kPreToken                        // pre
-%token kPreLineToken                    // pre-line
-%token kPreWrapToken                    // pre-wrap
-%token kPurpleToken                     // purple
-%token kRectangularToken                // rectangular
-%token kRedToken                        // red
-%token kRepeatToken                     // repeat
-%token kRepeatXToken                    // repeat-x
-%token kRepeatYToken                    // repeat-y
-%token kRelativeToken                   // relative
-%token kReverseToken                    // reverse
-// %token kRightToken                   // right - also property name token
-%token kSansSerifToken                  // sans-serif
-%token kSerifToken                      // serif
-%token kSilverToken                     // silver
-%token kSolidToken                      // solid
-%token kStartToken                      // start
-%token kStaticToken                     // static
-%token kStepEndToken                    // step-end
-%token kStepStartToken                  // step-start
-%token kStereoscopicLeftRightToken      // stereoscopic-left-right
-%token kStereoscopicTopBottomToken      // stereoscopic-top-bottom
-%token kTealToken                       // teal
-%token kToToken                         // to
-// %token kTopToken                     // top - also property name token
-%token kTransparentToken                // transparent
-%token kUppercaseToken                  // uppercase
-%token kVisibleToken                    // visible
-%token kWhiteToken                      // white
-%token kYellowToken                     // yellow
-
-// Pseudo-class name tokens.
-// WARNING: Every time a new name token is introduced, it should be added
-//          to |identifier_token| rule below.
-%token kActiveToken                     // active
-%token kEmptyToken                      // empty
-%token kFocusToken                      // focus
-%token kHoverToken                      // hover
-
-// Pseudo-element name tokens.
-// WARNING: Every time a new name token is introduced, it should be added
-//          to |identifier_token| rule below.
-%token kAfterToken                      // after
-%token kBeforeToken                     // before
-
-// Attribute matching tokens.
-%token kIncludesToken                   // ~=
-%token kDashMatchToken                  // |=
-%token kBeginsWithToken                 // ^=
-%token kEndsWithToken                   // $=
-%token kContainsToken                   // *=
-
-// "Media query" mode: Operator tokens.
-%token kMediaAndToken                   // and
-%token kMediaNotToken                   // not
-%token kMediaOnlyToken                  // only
-%token kMediaMinimumToken               // min-
-%token kMediaMaximumToken               // max-
-
-// "Media query" mode: Media type tokens.
-// WARNING: Every time a new media type token is introduced, it should be added
-//          to |media_type_known| rule below.
-%token kAllMediaTypeToken              // all
-%token kTVMediaTypeToken               // tv
-%token kScreenMediaTypeToken           // screen
-
-// "Media query" mode: Media feature type tokens. These tokens represent the
-// value types of media features. The integer values of these tokens represent
-// enum MediaFeatureName.
-// WARNING: Every time a new media feature type token is introduced, it should
-//          be added to |media_type_unknown| rule below.
-
-%token <integer> kLengthMediaFeatureTypeToken             // ...px, ...em, etc.
-%token <integer> kOrientationMediaFeatureTypeToken        // portrait, landscape
-%token <integer> kRatioMediaFeatureTypeToken              // ... / ...
-%token <integer> kNonNegativeIntegerMediaFeatureTypeToken // 0, 1, 2, 3, ...
-%token <integer> kResolutionMediaFeatureTypeToken         // ...dpi, ...dpcm
-%token <integer> kScanMediaFeatureTypeToken               // progressive,
-                                                          // interlace
-%token <integer> kZeroOrOneMediaFeatureTypeToken          // 0, 1
-
-// "Media query" mode: Media feature value tokens.
-%token kInterlaceMediaFeatureKeywordValueToken   // interlace
-%token kLandscapeMediaFeatureKeywordValueToken   // landscape
-%token kPortraitMediaFeatureKeywordValueToken    // portrait
-%token kProgressiveMediaFeatureKeywordValueToken // progressive
-
-// "Supports" mode tokens.
-%token kSupportsAndToken                // and (in "supports" mode)
-%token kSupportsNotToken                // not (in "supports" mode)
-%token kSupportsOrToken                 // or (in "supports" mode)
-
-// @-tokens.
-%token kImportToken                     // @import
-%token kKeyframesToken                  // @keyframes
-%token kPageToken                       // @page
-%token kMediaToken                      // @media
-%token kFontFaceToken                   // @font-face
-%token kCharsetToken                    // @charset
-%token kNamespaceToken                  // @namespace
-%token kSupportsToken                   // @supports
-
-// Paged media tokens.
-%token kTopLeftCornerToken              // @top-left-corner
-%token kTopLeftToken                    // @top-left
-%token kTopCenterToken                  // @top-center
-%token kTopRightToken                   // @top-right
-%token kTopRightCornerToken             // @top-right-corner
-%token kBottomLeftCornerToken           // @bottom-left-corner
-%token kBottomLeftToken                 // @bottom-left
-%token kBottomCenterToken               // @bottom-center
-%token kBottomRightToken                // @bottom-right
-%token kBottomRightCornerToken          // @bottom-right-corner
-%token kLeftTopToken                    // @left-top
-%token kLeftMiddleToken                 // @left-middle
-%token kLeftBottomToken                 // @left-bottom
-%token kRightTopToken                   // @right-top
-%token kRightMiddleToken                // @right-middle
-%token kRightBottomToken                // @right-bottom
-
-// Function tokens.
-%token kCalcFunctionToken               // calc(
-%token kCubicBezierFunctionToken        // cubic-bezier(
-%token kCueFunctionToken                // cue(
-%token kFormatFunctionToken             // format(
-%token kLinearGradientFunctionToken     // linear-gradient(
-%token kLocalFunctionToken              // local(
-%token kMapToMeshFunctionToken          // map-to-mesh(
-%token kMatrixFunctionToken             // matrix(
-%token kMatrix3dFunctionToken           // matrix3d(
-%token kNotFunctionToken                // not(
-%token kNthChildFunctionToken           // nth-child(
-%token kNthLastChildFunctionToken       // nth-last-child(
-%token kNthLastOfTypeFunctionToken      // nth-last-of-type(
-%token kNthOfTypeFunctionToken          // nth-of-type(
-%token kRotateFunctionToken             // rotate(
-%token kScaleFunctionToken              // scale(
-%token kScaleXFunctionToken             // scaleX(
-%token kScaleYFunctionToken             // scaleY(
-%token kStepsFunctionToken              // steps(
-%token kTranslateFunctionToken          // translate(
-%token kTranslateXFunctionToken         // translateX(
-%token kTranslateYFunctionToken         // translateY(
-%token kTranslateZFunctionToken         // translateZ(
-%token kRadialGradientFunctionToken     // radial-gradient(
-%token kRGBFunctionToken                // rgb(
-%token kRGBAFunctionToken               // rgba(
-%token kCobaltMtmFunctionToken          // -cobalt-mtm(
-
-// Tokens with a string value.
-%token <string> kStringToken            // "...", '...'
-%token <string> kIdentifierToken        // ...
-%token <string> kNthToken               // an+b, where a, b - integers
-%token <string> kHexToken               // #...
-%token <string> kIdSelectorToken        // #...
-%token <string> kUriToken               // url(...
-%token <string> kInvalidFunctionToken   // ...(
-%token <string> kInvalidNumberToken     // ... (digits)
-%token <string> kInvalidDimensionToken  // XXyy, where XX - number,
-                                        //             yy - identifier
-%token <string> kInvalidAtBlockToken    // @... { ... }, @... ... ;
-%token <string> kOtherBrowserAtBlockToken    // @-... { ... }
-
-// Tokens with an integer value.
-// WARNING: Use |integer| rule if you want to handle the sign.
-%token <integer> kIntegerToken          // 123, for example
-
-// Tokens with a floating point value.
-// WARNING: Remember to use |maybe_sign_token| rule with these tokens.
-%token <real> kRealToken                                    // 1.23, for example
-%token <real> kPercentageToken                              // ...%
-%token <real> kRootElementFontSizesAkaRemToken              // ...rem
-%token <real> kZeroGlyphWidthsAkaChToken                    // ...ch
-%token <real> kFontSizesAkaEmToken                          // ...em
-%token <real> kXHeightsAkaExToken                           // ...ex
-%token <real> kPixelsToken                                  // ...px
-%token <real> kCentimetersToken                             // ...cm
-%token <real> kMillimetersToken                             // ...mm
-%token <real> kInchesToken                                  // ...in
-%token <real> kPointsToken                                  // ...pt
-%token <real> kPicasToken                                   // ...pc
-%token <real> kDegreesToken                                 // ...deg
-%token <real> kRadiansToken                                 // ...rad
-%token <real> kGradiansToken                                // ...grad
-%token <real> kTurnsToken                                   // ...turn
-%token <real> kMillisecondsToken                            // ...ms
-%token <real> kSecondsToken                                 // ...s
-%token <real> kHertzToken                                   // ...hz
-%token <real> kKilohertzToken                               // ...khz
-%token <real> kViewportWidthPercentsAkaVwToken              // ...vw
-%token <real> kViewportHeightPercentsAkaVhToken             // ...vh
-%token <real> kViewportSmallerSizePercentsAkaVminToken      // ...vmin
-%token <real> kViewportLargerSizePercentsAkaVmaxToken       // ...vmax
-%token <real> kDotsPerPixelToken                            // ...dppx
-%token <real> kDotsPerInchToken                             // ...dpi
-%token <real> kDotsPerCentimeterToken                       // ...dpcm
-%token <real> kFractionsToken                               // ...fr
-
-// Tokens with an integer pair value
-%token <integer_pair> kUnicodeRangeToken                    // u+..., U+...
-
-//
-// Rules and their types, sorted by type name.
-//
-
-// A top-level rule.
-%start entry_point
-
-%union { bool important; }
-%type <important> maybe_important
-
-%type <integer> integer non_negative_integer positive_integer zero_or_one
-
-%union { cssom::RGBAColorValue* color; }
-%type <color> color
-%destructor { SafeRelease($$); } <color>
-
-%union { cssom::ColorStop* color_stop; }
-%type <color_stop> color_stop
-%destructor { delete $$; } <color_stop>
-
-%union { cssom::ColorStopList* color_stop_list; }
-%type <color_stop_list> comma_separated_color_stop_list
-%destructor { delete $$; } <color_stop_list>
-
-%union { cssom::PercentageValue* percentage; }
-%type <percentage> percentage positive_percentage
-%destructor { SafeRelease($$); } <percentage>
-
-%union { cssom::LengthValue* length; }
-%type <length> length positive_length absolute_or_relative_length
-%destructor { SafeRelease($$); } <length>
-
-%union { cssom::RatioValue* ratio; }
-%type <ratio> ratio
-%destructor { SafeRelease($$); } <ratio>
-
-%union { cssom::ResolutionValue* resolution; }
-%type <resolution> resolution
-%destructor { SafeRelease($$); } <resolution>
-
-%union { cssom::StringValue* string_value; }
-%type <string_value> font_family_name_identifier_list
-                     font_family_string_name
-                     font_family_specific_name
-                     font_family_specific_name_no_single_identifier
-%destructor { SafeRelease($$); } <string_value>
-
-// base::TimeDelta's internal value.  One can construct a base::TimeDelta from
-// this value using the function base::TimeDelta::FromInternalValue().  We use
-// it instead of base::TimeDelta because base::TimeDelta does not have a
-// trivial constructor and thus cannot be used in a union.
-%union { int64 time; }
-%type <time> time time_with_units_required
-
-%union { PropertyDeclaration* property_declaration; }
-%type <property_declaration> maybe_declaration
-%destructor { delete $$; } <property_declaration>
-
-// To reduce the number of classes derived from cssom::PropertyValue, some
-// semantic actions contain a value processing (such as opacity clamping
-// or RGBA color resolution) that technically belongs to computed value
-// resolution and as such should be done by layout engine. This is harmless
-// as long as web app does not rely on literal preservation of property values
-// exposed by cssom::CSSRuleStyleDeclaration (semantics is
-// always preserved).
-%union { cssom::PropertyValue* property_value; }
-%type <property_value> animation_delay_property_value
-                       animation_direction_list_element
-                       animation_direction_property_value
-                       animation_duration_property_value
-                       animation_fill_mode_list_element
-                       animation_fill_mode_property_value
-                       animation_iteration_count_list_element
-                       animation_iteration_count_property_value
-                       animation_name_list_element
-                       animation_name_property_value
-                       animation_timing_function_property_value
-                       auto
-                       background_color_property_value
-                       background_image_property_list_element
-                       background_image_property_value
-                       background_position_property_value
-                       background_repeat_element
-                       background_repeat_property_value
-                       background_repeat_property_value_without_common_values
-                       background_size_property_list_element
-                       background_size_property_value
-                       background_size_property_value_without_common_values
-                       border_color_property_value
-                       border_radius_element
-                       border_radius_element_with_common_values
-                       border_radius_property_value
-                       border_style_property_value
-                       border_width_element
-                       border_width_element_with_common_values
-                       border_width_property_value
-                       box_shadow_property_value
-                       color_property_value
-                       common_values
-                       common_values_without_errors
-                       content_property_value
-                       display_property_value
-                       font_face_local_src
-                       font_face_src_list_element
-                       font_face_src_property_value
-                       font_face_url_src
-                       font_family_name
-                       font_family_property_value
-                       font_size_property_value
-                       font_style_exclusive_property_value
-                       font_style_property_value
-                       font_weight_exclusive_property_value
-                       font_weight_property_value
-                       height_property_value
-                       length_percent_property_value
-                       line_height_property_value
-                       line_style
-                       line_style_with_common_values
-                       linear_gradient_params
-                       margin_side_property_value
-                       margin_width
-                       max_height_property_value
-                       max_width_property_value
-                       min_height_property_value
-                       min_width_property_value
-                       maybe_background_size_property_value
-                       offset_property_value
-                       opacity_property_value
-                       orientation_media_feature_keyword_value
-                       overflow_property_value
-                       overflow_wrap_property_value
-                       padding_side_property_value
-                       pointer_events_property_value
-                       position_list_element
-                       position_property_value
-                       positive_length_percent_property_value
-                       radial_gradient_params
-                       scan_media_feature_keyword_value
-                       text_align_property_value
-                       text_decoration_line_property_value
-                       text_decoration_property_value
-                       text_indent_property_value
-                       text_overflow_property_value
-                       text_shadow_property_value
-                       text_transform_property_value
-                       time_list_property_value
-                       timing_function_list_property_value
-                       transform_property_value
-                       transform_origin_property_value
-                       transition_delay_property_value
-                       transition_duration_property_value
-                       transition_property_property_value
-                       transition_timing_function_property_value
-                       unicode_range_property_value
-                       url
-                       validated_box_shadow_list
-                       validated_text_shadow_list
-                       vertical_align_property_value
-                       visibility_property_value
-                       white_space_property_value
-                       width_property_value
-                       z_index_property_value
-                       filter_property_value
-%destructor { SafeRelease($$); } <property_value>
-
-%union { std::vector<float>* number_matrix; }
-%type <number_matrix> number_matrix
-%destructor { delete $$; } <number_matrix>
-
-%union { glm::mat4* matrix4x4; }
-%type <matrix4x4> cobalt_mtm_transform_function
-%destructor { delete $$; } <matrix4x4>
-
-%union { MarginOrPaddingShorthand* margin_or_padding_shorthand; }
-%type <margin_or_padding_shorthand> margin_property_value padding_property_value
-%destructor { delete $$; } <margin_or_padding_shorthand>
-
-%union { SingleAnimationShorthand* single_animation; }
-%type <single_animation> single_animation single_non_empty_animation
-%destructor { delete $$; } <single_animation>
-
-%union { AnimationShorthandBuilder* animation_builder; }
-%type <animation_builder> comma_separated_animation_list
-%destructor { delete $$; } <animation_builder>
-
-%union { AnimationShorthand* animation; }
-%type <animation> animation_property_value
-%destructor { delete $$; } <animation>
-
-%union { FontShorthand* font; }
-%type <font> font_property_value
-             optional_font_value_list
-             non_empty_optional_font_value_list
-%destructor { delete $$; } <font>
-
-%union { TransitionShorthand* transition; }
-%type <transition> transition_property_value
-%destructor { delete $$; } <transition>
-
-%type <real> alpha angle non_negative_number number
-
-%union { cssom::CSSStyleSheet* style_sheet; }
-%type <style_sheet> style_sheet
-%destructor { SafeRelease($$); } <style_sheet>
-
-%union { cssom::CSSRuleList* rule_list; }
-%type <rule_list> rule_list rule_list_block
-%destructor { SafeRelease($$); } <rule_list>
-
-%union { cssom::AttributeSelector::ValueMatchType attribute_match; }
-%type <attribute_match> attribute_match
-
-%union { cssom::SimpleSelector* simple_selector; }
-%type <simple_selector> attribute_selector_token
-                        class_selector_token
-                        id_selector_token
-                        pseudo_class_token
-                        pseudo_element_token
-                        simple_selector_token
-                        type_selector_token
-                        universal_selector_token
-%destructor { delete $$; } <simple_selector>
-
-%union { cssom::CompoundSelector* compound_selector; }
-%type <compound_selector> compound_selector_token
-%destructor { delete $$; } <compound_selector>
-
-%union { cssom::Combinator* combinator; }
-%type <combinator> combinator
-%destructor { delete $$; } <combinator>
-
-%union { cssom::ComplexSelector* complex_selector; }
-%type <complex_selector> complex_selector
-%destructor { delete $$; } <complex_selector>
-
-%union { cssom::Selectors* selectors; }
-%type <selectors> selector_list
-%destructor { delete $$; } <selectors>
-
-%union { cssom::LinearGradientValue::SideOrCorner side_or_corner; }
-%type <side_or_corner> side side_or_corner
-
-%union { int sign; }
-%type <sign> maybe_sign_token
-
-%type <string> identifier_token
-
-%union { cssom::PropertyKey property_key; }
-%type <property_key> animatable_property_token
-
-%union { cssom::CSSDeclaredStyleData* style_declaration_data; }
-%type <style_declaration_data> style_declaration_list
-%destructor { SafeRelease($$); } <style_declaration_data>
-
-%union { cssom::CSSRuleStyleDeclaration* style_declaration; }
-%type <style_declaration> style_declaration_block
-%destructor { SafeRelease($$); } <style_declaration>
-
-%union { cssom::CSSFontFaceRule* font_face_rule; }
-%type <font_face_rule> at_font_face_rule
-%destructor { SafeRelease($$); } <font_face_rule>
-
-%union { cssom::CSSKeyframeRule* keyframe_rule; }
-%type <keyframe_rule> keyframe_rule
-%destructor { SafeRelease($$); } <keyframe_rule>
-
-%union { cssom::CSSKeyframesRule* keyframes_rule; }
-%type <keyframes_rule> at_keyframes_rule
-%destructor { SafeRelease($$); } <keyframes_rule>
-
-%union { cssom::CSSRuleList* keyframe_rule_list; }
-%type <keyframe_rule_list> keyframe_rule_list
-%destructor { SafeRelease($$); } <keyframe_rule_list>
-
-%union { float keyframe_offset; }
-%type <keyframe_offset> keyframe_offset
-
-%union { std::vector<float>* keyframe_selector; }
-%type <keyframe_selector> keyframe_selector;
-%destructor { delete $$; } <keyframe_selector>
-
-%union { cssom::CSSFontFaceDeclarationData* font_face_declaration_data; }
-%type <font_face_declaration_data> font_face_declaration_list
-%destructor { SafeRelease($$); } <font_face_declaration_data>
-
-%union { cssom::CSSMediaRule* media_rule; }
-%type <media_rule> at_media_rule
-%destructor { SafeRelease($$); } <media_rule>
-
-%union { cssom::MediaList* media_list; }
-%type <media_list> media_list
-%destructor { SafeRelease($$); } <media_list>
-
-%union { cssom::MediaQuery* media_query; }
-%type <media_query> media_query
-%destructor { SafeRelease($$); } <media_query>
-
-%union { bool evaluated_media_type; }
-%type <evaluated_media_type> evaluated_media_type media_type_specified
-
-%union { cssom::MediaFeatures* media_features; }
-%type <media_features> media_feature_list
-%destructor { delete $$; } <media_features>
-
-%union { cssom::MediaFeature* media_feature; }
-%type <media_feature> media_feature media_feature_block
-                      media_feature_with_value media_feature_without_value
-                      media_feature_allowing_operator_with_value
-
-%destructor { SafeRelease($$); } <media_feature>
-
-%union { cssom::MediaFeatureOperator media_feature_operator; }
-%type <media_feature_operator> media_feature_operator
-
-%union { cssom::CSSStyleRule* style_rule; }
-%type <style_rule> qualified_rule style_rule
-%destructor { SafeRelease($$); } <style_rule>
-
-%union { cssom::CSSRule* css_rule; }
-%type <css_rule> rule
-%destructor { SafeRelease($$); } <css_rule>
-
-%union { cssom::PropertyListValue::Builder* property_list; }
-%type <property_list> background_size_property_list
-                      border_color_property_list
-                      border_radius_property_list
-                      border_style_property_list
-                      border_width_property_list
-                      comma_separated_animation_direction_list
-                      comma_separated_animation_fill_mode_list
-                      comma_separated_animation_iteration_count_list
-                      comma_separated_animation_name_list
-                      comma_separated_background_image_list
-                      comma_separated_box_shadow_list
-                      comma_separated_font_face_src_list
-                      comma_separated_font_family_name_list
-                      comma_separated_text_shadow_list
-                      comma_separated_unicode_range_list
-                      validated_two_position_list_elements
-%destructor { delete $$; } <property_list>
-
-%union { cssom::PropertyListValue* property_list_value; }
-%type <property_list_value> at_position
-                            circle_with_positive_length
-                            ellipse_with_2_positive_length_percents
-                            maybe_at_position
-                            validated_position_property
-%destructor { SafeRelease($$); } <property_list_value>
-
-%union { cssom::TransformFunction* transform_function; }
-%type <transform_function> scale_function_parameters
-%destructor { delete $$; } <transform_function>
-
-%union { cssom::TransformFunctionListValue::Builder* transform_functions; }
-%type <transform_functions> transform_list
-%destructor { delete $$; } <transform_functions>
-
-%union { cssom::FilterFunction* filter_function; }
-%type <filter_function> cobalt_mtm_filter_function
-%type <filter_function> filter_function
-%destructor { delete $$; } <filter_function>
-
-%union { cssom::FilterFunctionListValue::Builder* cobalt_mtm_filter_functions; }
-%type <cobalt_mtm_filter_functions> filter_function_list
-%destructor { delete $$; } <cobalt_mtm_filter_functions>
-
-%union {
-  cssom::MapToMeshFunction::MeshSpec* cobalt_map_to_mesh_spec; }
-%type <cobalt_map_to_mesh_spec> cobalt_map_to_mesh_spec
-%destructor { delete $$; } <cobalt_map_to_mesh_spec>
-
-%union {
-  cssom::MapToMeshFunction::ResolutionMatchedMeshListBuilder* cobalt_mtm_resolution_matched_meshes; }
-%type <cobalt_mtm_resolution_matched_meshes> cobalt_mtm_resolution_matched_mesh_list
-%destructor { delete $$; } <cobalt_mtm_resolution_matched_meshes>
-
-%union { cssom::MapToMeshFunction::ResolutionMatchedMesh* cobalt_mtm_resolution_matched_mesh; }
-%type <cobalt_mtm_resolution_matched_mesh> cobalt_mtm_resolution_matched_mesh
-%destructor { delete $$; } <cobalt_mtm_resolution_matched_mesh>
-
-%union { cssom::KeywordValue* stereo_mode; }
-%type <stereo_mode> maybe_cobalt_mtm_stereo_mode;
-%type <stereo_mode> cobalt_mtm_stereo_mode;
-%destructor { SafeRelease($$); } <stereo_mode>
-
-%union { cssom::TimeListValue::Builder* time_list; }
-%type <time_list> comma_separated_time_list
-%destructor { delete $$; } <time_list>
-
-%union { cssom::PropertyKeyListValue::Builder* property_name_list; }
-%type <property_name_list> comma_separated_animatable_property_name_list
-%destructor { delete $$; } <property_name_list>
-
-%union {
-  cssom::SteppingTimingFunction::ValueChangeLocation
-      stepping_value_change_location;
-}
-%type <stepping_value_change_location> maybe_steps_start_or_end_parameter
-
-%union { cssom::TimingFunction* timing_function; }
-%type <timing_function> single_timing_function
-%destructor { SafeRelease($$); } <timing_function>
-
-%union {
-  cssom::TimingFunctionListValue::Builder*
-      timing_function_list;
-}
-%type <timing_function_list>
-    comma_separated_single_timing_function_list
-%destructor { delete $$; } <timing_function_list>
-
-%union { SingleTransitionShorthand* single_transition; }
-%type <single_transition> single_transition single_non_empty_transition
-%destructor { delete $$; } <single_transition>
-
-%union { TransitionShorthandBuilder* transition_builder; }
-%type <transition_builder> comma_separated_transition_list
-%destructor { delete $$; } <transition_builder>
-
-%union { BackgroundShorthandLayer* background_shorthand_layer; }
-%type <background_shorthand_layer>
-    background_position_and_size_shorthand_property_value
-    background_repeat_shorthand_property_value
-    background_position_and_repeat_combination
-    final_background_layer_without_position_and_repeat
-    final_background_layer
-    background_property_value
-%destructor { delete $$; } <background_shorthand_layer>
-
-%union { PositionParseStructure* position_structure; }
-%type <position_structure> position_list
-%destructor { delete $$; } <position_structure>
-
-%union { BorderOrOutlineShorthand* border_or_outline_shorthand; }
-%type <border_or_outline_shorthand> border_or_outline_property_value
-                                    border_or_outline_property_list
-%destructor { delete $$; } <border_or_outline_shorthand>
-
-%union { ShadowPropertyInfo* shadow_info; }
-%type <shadow_info> box_shadow_list text_shadow_list
-%destructor { delete $$; } <shadow_info>
-
-%union { cssom::RadialGradientValue::SizeKeyword size_keyword; }
-%type <size_keyword> circle_with_size_keyword
-                     maybe_ellipse_with_size_keyword size_keyword
-
-%%
-
-// WARNING: Every rule, except the ones which end with "..._token", should
-//          consume trailing whitespace.
-
-
-// ...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:.
-// Common rules used across the grammar.
-// ...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:.
-
-maybe_whitespace:
-    /* empty */
-  | maybe_whitespace kWhitespaceToken
-  ;
-
-errors:
-    error
-  | errors error
-  ;
-
-
-// ...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:.
-// @-rules.
-// ...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:.
-
-// The @font-face rule consists of the @font-face at-keyword followed by a block
-// of descriptor declarations.
-//   https://www.w3.org/TR/css3-fonts/#font-face-rule
-at_font_face_rule:
-    kFontFaceToken maybe_whitespace '{' maybe_whitespace
-        font_face_declaration_list '}' maybe_whitespace {
-    scoped_refptr<cssom::CSSFontFaceRule>
-        font_face_rule(
-            new cssom::CSSFontFaceRule(MakeScopedRefPtrAndRelease($5)));
-    if (font_face_rule->IsValid()) {
-      $$ = AddRef(font_face_rule.get());
-    } else {
-      parser_impl->LogWarning(@1, "invalid font-face");
-      $$ = NULL;
-    }
-  }
-  ;
-
-// The @media rule is a conditional group rule whose condition is a media query.
-// It consists of the at-keyword '@media' followed by a (possibly empty) media
-// query list, followed by a group rule body. The condition of the rule is the
-// result of the media query.
-//   https://www.w3.org/TR/css3-conditional/#at-media
-at_media_rule:
-  // @media expr {}
-    kMediaToken maybe_whitespace media_list rule_list_block {
-    $$ = AddRef(new cssom::CSSMediaRule(MakeScopedRefPtrAndRelease($3),
-                                        MakeScopedRefPtrAndRelease($4)));
-  }
-  ;
-
-// ...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:.
-// Media Rule, Media Query, Media Type
-//   https://www.w3.org/TR/cssom/#media-queries
-//   https://www.w3.org/TR/css3-mediaqueries/
-// ...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:.
-
-// Follow the syntax defined here:
-//   https://www.w3.org/TR/css3-mediaqueries/#syntax
-
-// Orientation value, landscale or portrait
-//   https://www.w3.org/TR/css3-mediaqueries/#orientation
-orientation_media_feature_keyword_value:
-    kLandscapeMediaFeatureKeywordValueToken maybe_whitespace {
-    $$ = AddRef(cssom::MediaFeatureKeywordValue::GetLandscape().get());
-  }
-  | kPortraitMediaFeatureKeywordValueToken maybe_whitespace {
-    $$ = AddRef(cssom::MediaFeatureKeywordValue::GetPortrait().get());
-  }
-  ;
-
-// Scan value, interlace or progressive
-//   https://www.w3.org/TR/css3-mediaqueries/#scan
-scan_media_feature_keyword_value:
-    kInterlaceMediaFeatureKeywordValueToken maybe_whitespace {
-    $$ = AddRef(cssom::MediaFeatureKeywordValue::GetInterlace().get());
-  }
-  | kProgressiveMediaFeatureKeywordValueToken maybe_whitespace {
-    $$ = AddRef(cssom::MediaFeatureKeywordValue::GetProgressive().get());
-  }
-  ;
-
-// 'min-' or 'max-' prefix for media feature name.
-media_feature_operator:
-    kMediaMinimumToken { $$ = cssom::kMinimum; }
-  | kMediaMaximumToken { $$ = cssom::kMaximum; }
-  ;
-
-// Media feature: 'feature' only.
-// (feature) will evaluate to true if (feature:x) will evaluate to true for a
-// value x other than zero or zero followed by a unit identifier.
-//   https://www.w3.org/TR/css3-mediaqueries/#media1
-media_feature_without_value:
-    kLengthMediaFeatureTypeToken maybe_whitespace {
-    $$ = AddRef(new cssom::MediaFeature($1));
-  }
-  | kOrientationMediaFeatureTypeToken maybe_whitespace {
-    $$ = AddRef(new cssom::MediaFeature($1));
-  }
-  | kRatioMediaFeatureTypeToken maybe_whitespace {
-    $$ = AddRef(new cssom::MediaFeature($1));
-  }
-  | kNonNegativeIntegerMediaFeatureTypeToken maybe_whitespace {
-    $$ = AddRef(new cssom::MediaFeature($1));
-  }
-  | kResolutionMediaFeatureTypeToken maybe_whitespace {
-    $$ = AddRef(new cssom::MediaFeature($1));
-  }
-  | kScanMediaFeatureTypeToken maybe_whitespace {
-    $$ = AddRef(new cssom::MediaFeature($1));
-  }
-  | kZeroOrOneMediaFeatureTypeToken maybe_whitespace {
-    $$ = AddRef(new cssom::MediaFeature($1));
-  }
-  ;
-
-// Media feature: 'feature:value' for features that don't allow prefixes.
-media_feature_with_value:
-    kOrientationMediaFeatureTypeToken maybe_whitespace colon
-    orientation_media_feature_keyword_value {
-    $$ = AddRef(new cssom::MediaFeature($1, $4));
-  }
-  | kScanMediaFeatureTypeToken maybe_whitespace colon
-    scan_media_feature_keyword_value {
-    $$ = AddRef(new cssom::MediaFeature($1, $4));
-  }
-  | kZeroOrOneMediaFeatureTypeToken maybe_whitespace colon zero_or_one {
-    $$ = AddRef(new cssom::MediaFeature($1, new cssom::IntegerValue($4)));
-  }
-  ;
-
-// Media feature: 'feature:value' for features that allow min/max prefixes.
-media_feature_allowing_operator_with_value:
-    kLengthMediaFeatureTypeToken maybe_whitespace colon length {
-    $$ = AddRef(new cssom::MediaFeature($1, MakeScopedRefPtrAndRelease($4)));
-  }
-  | kNonNegativeIntegerMediaFeatureTypeToken maybe_whitespace colon
-    non_negative_integer {
-    $$ = AddRef(new cssom::MediaFeature($1, new cssom::IntegerValue($4)));
-  }
-  | kRatioMediaFeatureTypeToken maybe_whitespace colon ratio {
-    $$ = AddRef(new cssom::MediaFeature($1, MakeScopedRefPtrAndRelease($4)));
-  }
-  | kResolutionMediaFeatureTypeToken maybe_whitespace colon resolution {
-    $$ = AddRef(new cssom::MediaFeature($1, MakeScopedRefPtrAndRelease($4)));
-  }
-  ;
-
-// Media feature: 'feature' or 'feature:value' or 'min-feature:value' or
-// 'max-feature:value'
-//   https://www.w3.org/TR/css3-mediaqueries/#media1
-media_feature:
-    media_feature_without_value
-  | media_feature_with_value
-  | media_feature_allowing_operator_with_value
-  | media_feature_operator media_feature_allowing_operator_with_value {
-    $$ = $2;
-    $$->set_operator($1);
-  }
-  ;
-
-// Media feature: '(name:value)'
-media_feature_block:
-    '(' maybe_whitespace media_feature ')' maybe_whitespace {
-    $$ = $3;
-  }
-  ;
-
-// Media feature list: '(name:value) [ and (name:value) ]'
-media_feature_list:
-  // (name:value)
-    media_feature_block {
-    $$ = new cssom::MediaFeatures();
-    $$->push_back(MakeScopedRefPtrAndRelease($1));
-  }
-  // ... and (name:value)
-  | media_feature_list kMediaAndToken maybe_whitespace media_feature_block {
-    $$ = $1;
-    $$->push_back(MakeScopedRefPtrAndRelease($4));
-  }
-  ;
-
-// All tokens representing unknown media types.
-media_type_unknown:
-    kIdentifierToken
-  // "Media query" mode operator names.
-  | kMediaAndToken
-  | kMediaMinimumToken
-  | kMediaMaximumToken
-  // "Media query" mode media feature tokens
-  | kLengthMediaFeatureTypeToken
-  | kOrientationMediaFeatureTypeToken
-  | kRatioMediaFeatureTypeToken
-  | kNonNegativeIntegerMediaFeatureTypeToken
-  | kResolutionMediaFeatureTypeToken
-  | kScanMediaFeatureTypeToken
-  | kZeroOrOneMediaFeatureTypeToken
-  ;
-
-// All tokens representing media types that are true on this platform.
-media_type_known:
-    kAllMediaTypeToken
-  | kTVMediaTypeToken
-  | kScreenMediaTypeToken
-  ;
-
-// Returns true for known specified media types, otherwise false.
-media_type_specified:
-    media_type_unknown {
-    $$ = false;
-  }
-  | media_type_known {
-    $$ = true;
-  }
-  ;
-// The names chosen for CSS media types reflect target devices for which the
-// relevant properties make sense
-//   https://www.w3.org/TR/CSS21/media.html#media-types
-//   https://www.w3.org/TR/css3-mediaqueries/#media0
-evaluated_media_type:
-  // @media [type]...
-    media_type_specified {
-    $$ = $1;
-  }
-  // @media not [type]...
-  | kMediaNotToken kWhitespaceToken media_type_specified {
-    $$ = !$3;
-  }
-  // @media only [type]...
-  | kMediaOnlyToken kWhitespaceToken media_type_specified {
-    $$ = $3;
-  }
-  // @media only not ... (special case)
-  | kMediaOnlyToken kWhitespaceToken kMediaNotToken {
-    $$ = false;
-  }
-  // @media not only ... (special case)
-  | kMediaNotToken kWhitespaceToken kMediaOnlyToken {
-    $$ = true;
-  }
-  ;
-
-// A media query consists of a media type and zero or more expressions that
-// check for the conditions of particular media features.
-//   https://www.w3.org/TR/cssom/#media-queries
-//   https://www.w3.org/TR/css3-mediaqueries/#media0
-media_query:
-  // @media  {}
-    /* empty */ {
-    $$ = AddRef(new cssom::MediaQuery(true));
-  }
-  // @media (name:value)... {}
-  | media_feature_list {
-    scoped_ptr<cssom::MediaFeatures> media_features($1);
-    $$ = AddRef(new cssom::MediaQuery(true, media_features.Pass()));
-  }
-  // @media mediatype {}
-  | evaluated_media_type maybe_whitespace {
-    $$ = AddRef(new cssom::MediaQuery($1));
-  }
-  // @media mediatype and (name:value)... {}
-  | evaluated_media_type maybe_whitespace kMediaAndToken maybe_whitespace
-    media_feature_list {
-    scoped_ptr<cssom::MediaFeatures> media_features($5);
-    $$ = AddRef(new cssom::MediaQuery($1, media_features.Pass()));
-  }
-  // When an unknown media feature, an unknown media feature value, a malformed
-  // media query, or unexpected tokens is found, the media query must be
-  // represented as 'not all'.
-  //   https://www.w3.org/TR/css3-mediaqueries/#error-handling
-  | errors {
-    $$ = AddRef(new cssom::MediaQuery(true));
-  }
-  ;
-
-// Several media queries can be combined in a media query list.
-//   https://www.w3.org/TR/cssom/#medialist
-//   https://www.w3.org/TR/css3-mediaqueries/#media0
-media_list:
-    media_query {
-    $$ = AddRef(new cssom::MediaList(parser_impl->css_parser()));
-    $$->Append(MakeScopedRefPtrAndRelease($1));
-  }
-  | media_list comma media_query {
-    $$ = $1;
-    $$->Append(MakeScopedRefPtrAndRelease($3));
-  }
-  ;
-
-// ...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:.
-// Keyframe Rule and Keyframes Rule
-//   https://www.w3.org/TR/2013/WD-css3-animations-20130219/#CSSKeyframeRule-interface
-//   https://www.w3.org/TR/2013/WD-css3-animations-20130219/#CSSKeyframesRule-interface
-// ...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:.
-
-at_keyframes_rule:
-    kKeyframesToken maybe_whitespace kIdentifierToken maybe_whitespace '{'
-    maybe_whitespace keyframe_rule_list '}' maybe_whitespace {
-    $$ = $7 ? AddRef(
-        new cssom::CSSKeyframesRule($3.ToString(),
-                                    MakeScopedRefPtrAndRelease($7))) : NULL;
-  }
-  ;
-
-keyframe_rule_list:
-    keyframe_rule {
-    $$ = AddRef(new cssom::CSSRuleList());
-    $$->AppendCSSRule(MakeScopedRefPtrAndRelease($1));
-  }
-  | error {
-    // The error message is logged by |keyframe_rule|, so it is not necessary to
-    // log it again.
-    $$ = NULL;
-  }
-  | keyframe_rule_list keyframe_rule {
-    $$ = $1;
-    scoped_refptr<cssom::CSSKeyframeRule> keyframe_rule(
-        MakeScopedRefPtrAndRelease($2));
-    if ($$) {
-      $$->AppendCSSRule(keyframe_rule);
-    }
-  }
-  ;
-
-keyframe_rule:
-    keyframe_selector style_declaration_block {
-    scoped_ptr<std::vector<float> > offsets($1);
-
-    scoped_refptr<cssom::CSSRuleStyleDeclaration> style(
-        MakeScopedRefPtrAndRelease($2));
-    const cssom::CSSDeclaredStyleData::PropertyValues& property_values = style->data()->declared_property_values();
-    for (cssom::CSSDeclaredStyleData::PropertyValues::const_iterator
-             property_iterator = property_values.begin();
-             property_iterator != property_values.end();
-             ++property_iterator) {
-      if (property_iterator->second == cssom::KeywordValue::GetInherit() ||
-          property_iterator->second == cssom::KeywordValue::GetInitial()) {
-        parser_impl->LogError(
-            @2, "keyframe properties with initial or inherit are not supported");
-        YYERROR;
-      }
-    }
-
-    $$ = AddRef(new cssom::CSSKeyframeRule(*offsets, style));
-  }
-  ;
-
-keyframe_selector:
-    keyframe_offset {
-    $$ = new std::vector<float>(1, $1);
-  }
-  | keyframe_selector ',' maybe_whitespace keyframe_offset {
-    $$ = $1;
-    $$->push_back($4);
-  }
-  ;
-
-keyframe_offset:
-    kFromToken maybe_whitespace {
-    $$ = 0.0f;
-  }
-  | kToToken maybe_whitespace {
-    $$ = 1.0f;
-  }
-  | kPercentageToken maybe_whitespace {
-    $$ = $1 / 100.0f;
-  }
-  ;
-
-// ...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:.
-// Selectors.
-// ...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:.
-
-// Some identifiers such as property names or values are recognized
-// specifically by the scanner. We are merging those identifiers back together
-// to allow their use in selectors.
-identifier_token:
-    kIdentifierToken
-  // Property names.
-  | kAllToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kAllProperty));
-  }
-  | kAnimationDelayToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kAnimationDelayProperty));
-  }
-  | kAnimationDirectionToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kAnimationDirectionProperty));
-  }
-  | kAnimationDurationToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kAnimationDurationProperty));
-  }
-  | kAnimationFillModeToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kAnimationFillModeProperty));
-  }
-  | kAnimationIterationCountToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kAnimationIterationCountProperty));
-  }
-  | kAnimationNameToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kAnimationNameProperty));
-  }
-  | kAnimationTimingFunctionToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kAnimationTimingFunctionProperty));
-  }
-  | kAnimationToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kAnimationProperty));
-  }
-  | kBackgroundColorToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kBackgroundColorProperty));
-  }
-  | kBackgroundImageToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kBackgroundImageProperty));
-  }
-  | kBackgroundPositionToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kBackgroundPositionProperty));
-  }
-  | kBackgroundRepeatToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kBackgroundRepeatProperty));
-  }
-  | kBackgroundSizeToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kBackgroundSizeProperty));
-  }
-  | kBackgroundToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kBackgroundProperty));
-  }
-  | kBorderToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kBorderProperty));
-  }
-  | kBorderBottomLeftRadiusToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kBorderBottomLeftRadiusProperty));
-  }
-  | kBorderBottomRightRadiusToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kBorderBottomRightRadiusProperty));
-  }
-  | kBorderBottomToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kBorderBottomProperty));
-  }
-  | kBorderBottomColorToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kBorderBottomColorProperty));
-  }
-  | kBorderBottomStyleToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kBorderBottomStyleProperty));
-  }
-  | kBorderBottomWidthToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kBorderBottomWidthProperty));
-  }
-  | kBorderLeftToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kBorderLeftProperty));
-  }
-  | kBorderColorToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kBorderColorProperty));
-  }
-  | kBorderLeftColorToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kBorderLeftColorProperty));
-  }
-  | kBorderLeftStyleToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kBorderLeftStyleProperty));
-  }
-  | kBorderLeftWidthToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kBorderLeftWidthProperty));
-  }
-  | kBorderRadiusToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kBorderRadiusProperty));
-  }
-  | kBorderRightToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kBorderRightProperty));
-  }
-  | kBorderRightColorToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kBorderRightColorProperty));
-  }
-  | kBorderRightStyleToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kBorderRightStyleProperty));
-  }
-  | kBorderRightWidthToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kBorderRightWidthProperty));
-  }
-  | kBorderStyleToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kBorderStyleProperty));
-  }
-  | kBorderTopToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kBorderTopProperty));
-  }
-  | kBorderTopColorToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kBorderTopColorProperty));
-  }
-  | kBorderTopLeftRadiusToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kBorderTopLeftRadiusProperty));
-  }
-  | kBorderTopRightRadiusToken {
-    $$ = TrivialStringPiece::FromCString(
-          cssom::GetPropertyName(cssom::kBorderTopRightRadiusProperty));
-  }
-  | kBorderTopStyleToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kBorderTopStyleProperty));
-  }
-  | kBorderTopWidthToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kBorderTopWidthProperty));
-  }
-  | kBorderWidthToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kBorderWidthProperty));
-  }
-  | kBottomToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kBottomProperty));
-  }
-  | kBoxShadowToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kBoxShadowProperty));
-  }
-  | kColorToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kColorProperty));
-  }
-  | kContentToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kContentProperty));
-  }
-  | kDisplayToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kDisplayProperty));
-  }
-  | kFilterToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kFilterProperty));
-  }
-  | kFontToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kFontProperty));
-  }
-  | kFontFamilyToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kFontFamilyProperty));
-  }
-  | kFontSizeToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kFontSizeProperty));
-  }
-  | kFontWeightToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kFontWeightProperty));
-  }
-  | kHeightToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kHeightProperty));
-  }
-  | kLeftToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kLeftProperty));
-  }
-  | kLineHeightToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kLineHeightProperty));
-  }
-  | kMarginBottomToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kMarginBottomProperty));
-  }
-  | kMarginLeftToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kMarginLeftProperty));
-  }
-  | kMarginRightToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kMarginRightProperty));
-  }
-  | kMarginToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kMarginProperty));
-  }
-  | kMarginTopToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kMarginTopProperty));
-  }
-  | kMaxHeightToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kMaxHeightProperty));
-  }
-  | kMaxWidthToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kMaxWidthProperty));
-  }
-  | kMinHeightToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kMinHeightProperty));
-  }
-  | kMinWidthToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kMinWidthProperty));
-  }
-  | kOpacityToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kOpacityProperty));
-  }
-  | kOutlineToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kOutlineProperty));
-  }
-  | kOutlineColorToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kOutlineColorProperty));
-  }
-  | kOutlineStyleToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kOutlineStyleProperty));
-  }
-  | kOutlineWidthToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kOutlineWidthProperty));
-  }
-  | kOverflowToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kOverflowProperty));
-  }
-  | kOverflowWrapToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kOverflowWrapProperty));
-  }
-  | kPaddingBottomToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kPaddingBottomProperty));
-  }
-  | kPaddingLeftToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kPaddingLeftProperty));
-  }
-  | kPaddingRightToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kPaddingRightProperty));
-  }
-  | kPaddingToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kPaddingProperty));
-  }
-  | kPaddingTopToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kPaddingTopProperty));
-  }
-  | kPointerEventsToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kPointerEventsProperty));
-  }
-  | kPositionToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kPositionProperty));
-  }
-  | kRightToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kRightProperty));
-  }
-  | kSrcToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kSrcProperty));
-  }
-  | kTextAlignToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kTextAlignProperty));
-  }
-  | kTextDecorationToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kTextDecorationProperty));
-  }
-  | kTextDecorationColorToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kTextDecorationColorProperty));
-  }
-  | kTextDecorationLineToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kTextDecorationLineProperty));
-  }
-  | kTextIndentToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kTextIndentProperty));
-  }
-  | kTextOverflowToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kTextOverflowProperty));
-  }
-  | kTextTransformToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kTextTransformProperty));
-  }
-  | kTopToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kTopProperty));
-  }
-  | kTransformToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kTransformProperty));
-  }
-  | kTransformOriginToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kTransformOriginProperty));
-  }
-  | kTransitionDelayToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kTransitionDelayProperty));
-  }
-  | kTransitionDurationToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kTransitionDurationProperty));
-  }
-  | kTransitionPropertyToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kTransitionPropertyProperty));
-  }
-  | kTransitionTimingFunctionToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kTransitionTimingFunctionProperty));
-  }
-  | kTransitionToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kTransitionProperty));
-  }
-  | kUnicodeRangePropertyToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kUnicodeRangeProperty));
-  }
-  | kVerticalAlignToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kVerticalAlignProperty));
-  }
-  | kVisibilityToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kVisibilityProperty));
-  }
-  | kWhiteSpacePropertyToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kWhiteSpaceProperty));
-  }
-  | kWidthToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kWidthProperty));
-  }
-  | kZIndexToken {
-    $$ = TrivialStringPiece::FromCString(
-            cssom::GetPropertyName(cssom::kZIndexProperty));
-  }
-  // Property values.
-  | kAbsoluteToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kAbsoluteKeywordName);
-  }
-  | kAlternateToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kAlternateKeywordName);
-  }
-  | kAlternateReverseToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kAlternateReverseKeywordName);
-  }
-  | kAquaToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kAquaKeywordName);
-  }
-  | kAtToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kAtKeywordName);
-  }
-  | kAutoToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kAutoKeywordName);
-  }
-  | kBackwardsToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kBackwardsKeywordName);
-  }
-  | kBaselineToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kBaselineKeywordName);
-  }
-  | kBlackToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kBlackKeywordName);
-  }
-  | kBlockToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kBlockKeywordName);
-  }
-  | kBlueToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kBlueKeywordName);
-  }
-  | kBoldToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kBoldKeywordName);
-  }
-  | kBothToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kBothKeywordName);
-  }
-  // A rule for kBottomToken is already defined for the matching property name.
-  | kBreakWordToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kBreakWordKeywordName);
-  }
-  | kCenterToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kCenterKeywordName);
-  }
-  | kCircleToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kCircleKeywordName);
-  }
-  | kClipToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kClipKeywordName);
-  }
-  | kClosestCornerToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kClosestCornerKeywordName);
-  }
-  | kClosestSideToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kClosestSideKeywordName);
-  }
-  | kContainToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kContainKeywordName);
-  }
-  | kCoverToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kCoverKeywordName);
-  }
-  | kCursiveToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kCursiveKeywordName);
-  }
-  | kEaseInOutToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kEaseInOutKeywordName);
-  }
-  | kEaseInToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kEaseInKeywordName);
-  }
-  | kEaseOutToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kEaseOutKeywordName);
-  }
-  | kEaseToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kEaseKeywordName);
-  }
-  | kEllipseToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kEllipseKeywordName);
-  }
-  | kEllipsisToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kEllipsisKeywordName);
-  }
-  | kEndToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kEndKeywordName);
-  }
-  | kFantasyToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kFantasyKeywordName);
-  }
-  | kFarthestCornerToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kFarthestCornerKeywordName);
-  }
-  | kFarthestSideToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kFarthestSideKeywordName);
-  }
-  | kFixedToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kFixedKeywordName);
-  }
-  | kForwardsToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kForwardsKeywordName);
-  }
-  | kFromToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kFromKeywordName);
-  }
-  | kFuchsiaToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kFuchsiaKeywordName);
-  }
-  | kGrayToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kGrayKeywordName);
-  }
-  | kGreenToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kGreenKeywordName);
-  }
-  | kHiddenToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kHiddenKeywordName);
-  }
-  | kInfiniteToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kInfiniteKeywordName);
-  }
-  | kInheritToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kInheritKeywordName);
-  }
-  | kInitialToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kInitialKeywordName);
-  }
-  | kInlineBlockToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kInlineBlockKeywordName);
-  }
-  | kInlineToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kInlineKeywordName);
-  }
-  | kInsetToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kInsetKeywordName);
-  }
-  | kItalicToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kItalicKeywordName);
-  }
-  | kLimeToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kLimeKeywordName);
-  }
-  | kLinearToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kLinearKeywordName);
-  }
-  | kLineThroughToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kLineThroughKeywordName);
-  }
-  | kMaroonToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kMaroonKeywordName);
-  }
-  | kMiddleToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kMiddleKeywordName);
-  }
-  | kMonoscopicToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kMonoscopicKeywordName);
-  }
-  | kMonospaceToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kMonospaceKeywordName);
-  }
-  | kNavyToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kNavyKeywordName);
-  }
-  | kNoneToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kNoneKeywordName);
-  }
-  | kNoRepeatToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kNoRepeatKeywordName);
-  }
-  | kNormalToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kNormalKeywordName);
-  }
-  | kNoWrapToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kNoWrapKeywordName);
-  }
-  | kObliqueToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kObliqueKeywordName);
-  }
-  | kOliveToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kOliveKeywordName);
-  }
-  | kPreToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kPreKeywordName);
-  }
-  | kPreLineToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kPreLineKeywordName);
-  }
-  | kPreWrapToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kPreWrapKeywordName);
-  }
-  | kPurpleToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kPurpleKeywordName);
-  }
-  | kRedToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kRedKeywordName);
-  }
-  | kRepeatToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kRepeatKeywordName);
-  }
-  | kRepeatXToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kRepeatXKeywordName);
-  }
-  | kRepeatYToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kRepeatYKeywordName);
-  }
-  | kRelativeToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kRelativeKeywordName);
-  }
-  | kReverseToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kReverseKeywordName);
-  }
-  | kSansSerifToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kSansSerifKeywordName);
-  }
-  | kSerifToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kSerifKeywordName);
-  }
-  | kSilverToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kSilverKeywordName);
-  }
-  | kSolidToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kSolidKeywordName);
-  }
-  | kStartToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kStartKeywordName);
-  }
-  | kStaticToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kStaticKeywordName);
-  }
-  | kStepEndToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kStepEndKeywordName);
-  }
-  | kStepStartToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kStepStartKeywordName);
-  }
-  | kStereoscopicLeftRightToken {
-    $$ = TrivialStringPiece::FromCString(
-             cssom::kStereoscopicLeftRightKeywordName);
-  }
-  | kStereoscopicTopBottomToken {
-    $$ = TrivialStringPiece::FromCString(
-             cssom::kStereoscopicTopBottomKeywordName);
-  }
-  | kTealToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kTealKeywordName);
-  }
-  | kToToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kToKeywordName);
-  }
-  // A rule for kTopToken is already defined for the matching property name.
-  | kTransparentToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kTransparentKeywordName);
-  }
-  | kUppercaseToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kUppercaseKeywordName);
-  }
-  | kVisibleToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kVisibleKeywordName);
-  }
-  | kWhiteToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kWhiteKeywordName);
-  }
-  | kYellowToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kYellowKeywordName);
-  }
-  // Pseudo-class names.
-  | kActiveToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kActivePseudoClassName);
-  }
-  | kEmptyToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kEmptyPseudoClassName);
-  }
-  | kFocusToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kFocusPseudoClassName);
-  }
-  | kHoverToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kHoverPseudoClassName);
-  }
-  // Pseudo-element names.
-  | kAfterToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kAfterPseudoElementName);
-  }
-  | kBeforeToken {
-    $$ = TrivialStringPiece::FromCString(cssom::kBeforePseudoElementName);
-  }
-  ;
-
-// The universal selector represents an element with any name.
-//   https://www.w3.org/TR/selectors4/#universal-selector
-universal_selector_token:
-    '*' {
-    $$ = new cssom::UniversalSelector();
-  }
-  ;
-
-// A type selector represents an instance of the element type in the document
-// tree.
-//   https://www.w3.org/TR/selectors4/#type-selector
-type_selector_token:
-    identifier_token {
-    $$ = new cssom::TypeSelector($1.ToString());
-  }
-  ;
-
-attribute_match:
-    '=' maybe_whitespace {
-    $$ = cssom::AttributeSelector::kEquals;
-  }
-  | kIncludesToken maybe_whitespace {
-    $$ = cssom::AttributeSelector::kIncludes;
-  }
-  | kDashMatchToken maybe_whitespace {
-    $$ = cssom::AttributeSelector::kDashMatch;
-  }
-  | kBeginsWithToken maybe_whitespace {
-    $$ = cssom::AttributeSelector::kBeginsWith;
-  }
-  | kEndsWithToken maybe_whitespace {
-    $$ = cssom::AttributeSelector::kEndsWith;
-  }
-  | kContainsToken maybe_whitespace {
-    $$ = cssom::AttributeSelector::kContains;
-  }
-
-// An attribute selector represents an element that has an attribute that
-// matches the attribute represented by the attribute selector.
-//   https://www.w3.org/TR/selectors4/#attribute-selector
-attribute_selector_token:
-    '[' maybe_whitespace identifier_token maybe_whitespace ']' {
-    $$ = new cssom::AttributeSelector($3.ToString());
-  }
-  | '[' maybe_whitespace identifier_token maybe_whitespace
-      attribute_match kStringToken maybe_whitespace ']' {
-    $$ = new cssom::AttributeSelector($3.ToString(), $5, $6.ToString());
-  }
-  | '[' maybe_whitespace identifier_token maybe_whitespace
-      attribute_match identifier_token maybe_whitespace ']' {
-    $$ = new cssom::AttributeSelector($3.ToString(), $5, $6.ToString());
-  }
-  ;
-
-// The class selector represents an element belonging to the class identified by
-// the identifier.
-//   https://www.w3.org/TR/selectors4/#class-selector
-class_selector_token:
-    '.' identifier_token {
-    $$ = new cssom::ClassSelector($2.ToString());
-  }
-  ;
-
-// An ID selector represents an element instance that has an identifier that
-// matches the identifier in the ID selector.
-//   https://www.w3.org/TR/selectors4/#id-selector
-id_selector_token:
-    kIdSelectorToken {
-    $$ = new cssom::IdSelector($1.ToString());
-  }
-  | kHexToken {
-    if (IsAsciiDigit(*$1.begin)) {
-      YYERROR;
-    }
-    $$ = new cssom::IdSelector($1.ToString());
-  }
-  ;
-
-// The pseudo-class concept is introduced to permit selection based on
-// information that lies outside of the document tree or that can be awkward or
-// impossible to express using the other simple selectors.
-//   https://www.w3.org/TR/selectors4/#pseudo-classes
-pseudo_class_token:
-  // The :active pseudo-class applies while an element is being activated by the
-  // user. For example, between the times the user presses the mouse button and
-  // releases it. On systems with more than one mouse button, :active applies
-  // only to the primary or primary activation button (typically the "left"
-  // mouse button), and any aliases thereof.
-  //   https://www.w3.org/TR/selectors4/#active-pseudo
-    ':' kActiveToken {
-    $$ = new cssom::ActivePseudoClass();
-  }
-  // The :empty pseudo-class represents an element that has no children. In
-  // terms of the document tree, only element nodes and content nodes (such as
-  // DOM text nodes, CDATA nodes, and entity references) whose data has a
-  // non-zero length must be considered as affecting emptiness; comments,
-  // processing instructions, and other nodes must not affect whether an element
-  // is considered empty or not.
-  //   https://www.w3.org/TR/selectors4/#empty-pseudo
-  | ':' kEmptyToken {
-    $$ = new cssom::EmptyPseudoClass();
-  }
-  // The :focus pseudo-class applies while an element has the focus (accepts
-  // keyboard or mouse events, or other forms of input).
-  //   https://www.w3.org/TR/selectors4/#focus-pseudo
-  | ':' kFocusToken {
-    $$ = new cssom::FocusPseudoClass();
-  }
-  // The :hover pseudo-class applies while the user designates an element with a
-  // pointing device, but does not necessarily activate it. For example, a
-  // visual user agent could apply this pseudo-class when the cursor (mouse
-  // pointer) hovers over a box generated by the element. Interactive user
-  // agents that cannot detect hovering due to hardware limitations (e.g., a pen
-  // device that does not detect hovering) are still conforming.
-  //   https://www.w3.org/TR/selectors4/#hover-pseudo
-  | ':' kHoverToken {
-    $$ = new cssom::HoverPseudoClass();
-  }
-  // The negation pseudo-class, :not(), is a functional pseudo-class taking a
-  // selector list as an argument. It represents an element that is not
-  // represented by its argument.
-  //   https://www.w3.org/TR/selectors4/#negation-pseudo
-  | ':' kNotFunctionToken compound_selector_token ')' {
-    scoped_ptr<cssom::CompoundSelector> compound_selector($3);
-    if (compound_selector) {
-      scoped_ptr<cssom::NotPseudoClass> not_pseudo_class(new
-          cssom::NotPseudoClass());
-      not_pseudo_class->set_selector(compound_selector.Pass());
-      $$ = not_pseudo_class.release();
-    } else {
-      parser_impl->LogWarning(@1, "unsupported selector within :not()");
-      $$ = NULL;
-    }
-  }
-  | ':' kNotFunctionToken errors ')' {
-    parser_impl->LogWarning(@1, "unsupported selector within :not()");
-    $$ = NULL;
-  }
-  | ':' errors {
-    parser_impl->LogWarning(@1, "unsupported pseudo-class");
-    $$ = NULL;
-  }
-  ;
-
-// Pseudo-elements create abstractions about the document tree beyond those
-// specified by the document language.
-//   https://www.w3.org/TR/selectors4/#pseudo-elements
-pseudo_element_token:
-// Authors specify the style and location of generated content with the
-// :before and :after pseudo-elements.
-//   https://www.w3.org/TR/CSS21/generate.html#before-after-content
-// User agents must also accept the previous one-colon notation for
-// pseudo-elements introduced in CSS levels 1 and 2.
-//   https://www.w3.org/TR/selectors4/#pseudo-elements
-    ':' kAfterToken {
-    $$ = new cssom::AfterPseudoElement();
-  }
-  | ':' kBeforeToken {
-    $$ = new cssom::BeforePseudoElement();
-  }
-  | ':' ':' kAfterToken {
-    $$ = new cssom::AfterPseudoElement();
-  }
-  | ':' ':' kBeforeToken {
-    $$ = new cssom::BeforePseudoElement();
-  }
-  | ':' ':' errors {
-    parser_impl->LogWarning(@1, "unsupported pseudo-element");
-    $$ = NULL;
-  }
-  ;
-
-// A simple selector represents an aspect of an element to be matched against.
-//   https://www.w3.org/TR/selectors4/#simple
-simple_selector_token:
-    attribute_selector_token
-  | class_selector_token
-  | id_selector_token
-  | pseudo_class_token
-  | pseudo_element_token
-  | type_selector_token
-  | universal_selector_token
-  ;
-
-// A compound selector is a chain of simple selectors that are not separated by
-// a combinator.
-//   https://www.w3.org/TR/selectors4/#compound
-compound_selector_token:
-    simple_selector_token {
-    scoped_ptr<cssom::SimpleSelector> simple_selector($1);
-
-    if (simple_selector) {
-      $$ = new cssom::CompoundSelector();
-      $$->AppendSelector(simple_selector.Pass());
-    } else {
-      $$ = NULL;
-    }
-  }
-  | compound_selector_token simple_selector_token {
-    scoped_ptr<cssom::CompoundSelector> compound_selector($1);
-    scoped_ptr<cssom::SimpleSelector> simple_selector($2);
-
-    if (compound_selector && simple_selector) {
-      $$ = compound_selector.release();
-      $$->AppendSelector(simple_selector.Pass());
-    } else {
-      $$ = NULL;
-    }
-  }
-  ;
-
-// A combinator is punctuation that represents a particular kind of relationship
-// between the selectors on either side.
-//   https://www.w3.org/TR/selectors4/#combinator
-combinator:
-    kWhitespaceToken {
-    $$ = new cssom::DescendantCombinator();
-  }
-  | '>' maybe_whitespace {
-    $$ = new cssom::ChildCombinator();
-  }
-  | '+' maybe_whitespace {
-    $$ = new cssom::NextSiblingCombinator();
-  }
-  | '~' maybe_whitespace {
-    $$ = new cssom::FollowingSiblingCombinator();
-  }
-  ;
-
-// A complex selector is a chain of one or more compound selectors separated by
-// combinators.
-//   https://www.w3.org/TR/selectors4/#complex
-complex_selector:
-    compound_selector_token {
-    scoped_ptr<cssom::CompoundSelector> compound_selector($1);
-
-    if (compound_selector) {
-      $$ = new cssom::ComplexSelector();
-      $$->AppendSelector(compound_selector.Pass());
-    } else {
-      $$ = NULL;
-    }
-  }
-  | complex_selector combinator compound_selector_token {
-    scoped_ptr<cssom::ComplexSelector> complex_selector($1);
-    scoped_ptr<cssom::Combinator> combinator($2);
-    scoped_ptr<cssom::CompoundSelector> compound_selector($3);
-
-    if (complex_selector && compound_selector) {
-      $$ = complex_selector.release();
-      $$->AppendCombinatorAndSelector(combinator.Pass(),
-          compound_selector.Pass());
-    } else {
-      $$ = NULL;
-    }
-  }
-  | complex_selector kWhitespaceToken
-  ;
-
-// A selector list is a comma-separated list of selectors.
-//   https://www.w3.org/TR/selectors4/#selector-list
-selector_list:
-    complex_selector {
-    scoped_ptr<cssom::ComplexSelector> complex_selector($1);
-
-    if (complex_selector) {
-      $$ = new cssom::Selectors();
-      $$->push_back(complex_selector.release());
-    } else {
-      $$ = NULL;
-    }
-  }
-  | selector_list comma complex_selector {
-    scoped_ptr<cssom::Selectors> selector_list($1);
-    scoped_ptr<cssom::ComplexSelector> complex_selector($3);
-
-    if (selector_list && complex_selector) {
-      $$ = selector_list.release();
-      $$->push_back(complex_selector.release());
-    } else {
-      $$ = NULL;
-    }
-  }
-  ;
-
-
-// ...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:.
-// Common rules used in property values.
-// ...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:.
-
-auto:
-    kAutoToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetAuto().get());
-  }
-
-// The scanner that we adopted from WebKit was built with assumption that sign
-// is handled in the grammar. Practically this means that tokens of <number>
-// and <real> types has to be prepended with this rule.
-//   https://www.w3.org/TR/css3-syntax/#consume-a-number
-maybe_sign_token:
-    /* empty */ { $$ = 1; }
-  | '+' { $$ = 1; }
-  | '-' { $$ = -1; }
-  ;
-
-// This is for integers that can only have the values 0 or 1, including '-0'.
-// As used in the 'grid' css media feature:
-//   https://www.w3.org/TR/css3-mediaqueries/#grid
-zero_or_one:
-    integer {
-    if (($1 < 0) || ($1 > 1)) {
-      parser_impl->LogError(@1, "integer value must be 0 or 1");
-      YYERROR;
-    }
-    $$ = $1;
-  }
-  ;
-
-// An integer is one or more decimal digits "0" through "9". The first digit
-// of an integer may be immediately preceded by "-" or "+" to indicate the sign.
-//   https://www.w3.org/TR/css3-values/#integers
-integer:
-    maybe_sign_token kIntegerToken maybe_whitespace {
-    $$ = $1 * $2;
-  }
-  ;
-
-// Wrap the |integer| in order to validate if the integer is not negative
-non_negative_integer:
-    integer {
-    if ($1 < 0) {
-      parser_impl->LogError(@1, "integer value must not be negative");
-      YYERROR;
-    }
-    $$ = $1;
-  }
-  ;
-
-// Wrap the |integer| in order to validate if the integer is positive
-positive_integer:
-    integer {
-    if ($1 < 1) {
-      parser_impl->LogError(@1, "integer value must be positive");
-      YYERROR;
-    }
-    $$ = $1;
-  }
-  ;
-
-// A number is either an |integer| or zero or more decimal digits followed
-// by a dot followed by one or more decimal digits.
-//   https://www.w3.org/TR/css3-values/#numbers
-number:
-    integer { $$ = $1; }
-  | maybe_sign_token kRealToken maybe_whitespace { $$ = $1 * $2; }
-  ;
-
-// Wrap |number| and validates that it is not negative.
-non_negative_number:
-    number {
-    if ($1 < 0) {
-      parser_impl->LogError(@1, "number value must not be negative");
-      YYERROR;
-    }
-    $$ = $1;
-  }
-  ;
-
-// Percentage values are always relative to another value, for example a length.
-// Each property that allows percentages also defines the value to which
-// the percentage refers.
-//   https://www.w3.org/TR/css3-values/#percentages
-percentage:
-    maybe_sign_token kPercentageToken maybe_whitespace {
-    $$ = AddRef(new cssom::PercentageValue($1 * $2 / 100));
-  }
-  ;
-
-// Wrap the |percentage| in order to validate if the percentage is positive.
-positive_percentage:
-    percentage {
-    scoped_refptr<cssom::PercentageValue> percentage =
-        MakeScopedRefPtrAndRelease($1);
-    if (percentage && percentage->value() < 0) {
-      parser_impl->LogError(@1, "negative values of percentage are illegal");
-      YYERROR;
-    }
-    $$ = AddRef(percentage.get());
-  }
-  ;
-
-// Opacity.
-//   https://www.w3.org/TR/css3-color/#alphavaluedt
-alpha:
-    number {
-    // Any values outside the range 0.0 (fully transparent)
-    // to 1.0 (fully opaque) will be clamped to this range.
-    $$ = ClampToRange(0.0f, 1.0f, $1);
-  }
-  ;
-
-// Distance units.
-//   https://www.w3.org/TR/css3-values/#lengths
-length:
-    number {
-    if ($1 != 0) {
-      parser_impl->LogError(
-          @1, "non-zero length is not allowed without unit identifier");
-      YYERROR;
-    }
-    $$ = AddRef(new cssom::LengthValue(0, cssom::kPixelsUnit));
-  }
-  | absolute_or_relative_length { $$ = $1; }
-  ;
-
-absolute_or_relative_length:
-  // Relative lengths.
-  //   https://www.w3.org/TR/css3-values/#relative-lengths
-    maybe_sign_token kFontSizesAkaEmToken maybe_whitespace {
-    $$ = AddRef(new cssom::LengthValue($1 * $2, cssom::kFontSizesAkaEmUnit));
-  }
-  | maybe_sign_token kRootElementFontSizesAkaRemToken maybe_whitespace {
-    $$ = AddRef(new cssom::LengthValue($1 * $2,
-        cssom::kRootElementFontSizesAkaRemUnit));
-  }
-  | maybe_sign_token kViewportWidthPercentsAkaVwToken maybe_whitespace {
-    $$ = AddRef(new cssom::LengthValue($1 * $2,
-        cssom::kViewportWidthPercentsAkaVwUnit));
-  }
-  | maybe_sign_token kViewportHeightPercentsAkaVhToken maybe_whitespace {
-    $$ = AddRef(new cssom::LengthValue($1 * $2,
-        cssom::kViewportHeightPercentsAkaVhUnit));
-  }
-  // Absolute lengths.
-  //   https://www.w3.org/TR/css3-values/#absolute-lengths
-  | maybe_sign_token kPixelsToken maybe_whitespace {
-    $$ = AddRef(new cssom::LengthValue($1 * $2, cssom::kPixelsUnit));
-  }
-  ;
-
-positive_length:
-  length {
-    scoped_refptr<cssom::LengthValue> length(MakeScopedRefPtrAndRelease($1));
-    if (length && length->value() < 0) {
-      parser_impl->LogError(@1, "negative values of length are illegal");
-      YYERROR;
-    }
-    $$ = AddRef(length.get());
-  }
-  ;
-
-// Ratio units.
-//   https://www.w3.org/TR/css3-mediaqueries/#values
-ratio:
-    positive_integer '/' maybe_whitespace positive_integer {
-    $$ = AddRef(new cssom::RatioValue(math::Rational($1, $4)));
-  }
-  ;
-
-// Resolution units.
-//   https://www.w3.org/TR/css3-mediaqueries/#resolution0
-resolution:
-    maybe_sign_token kDotsPerInchToken maybe_whitespace {
-    float value = $1 * $2;
-    if (value <= 0) {
-      parser_impl->LogError(@1, "resolution value must be positive");
-      YYERROR;
-    }
-    $$ = AddRef(new cssom::ResolutionValue(value, cssom::kDPIUnit));
-  }
-  | maybe_sign_token kDotsPerCentimeterToken maybe_whitespace {
-    float value = $1 * $2;
-    if (value <= 0) {
-      parser_impl->LogError(@1, "resolution value must be positive");
-      YYERROR;
-    }
-    $$ = AddRef(new cssom::ResolutionValue(value, cssom::kDPCMUnit));
-  }
-  ;
-
-// Angle units (returned synthetic value will always be in radians).
-//   https://www.w3.org/TR/css3-values/#angles
-angle:
-    maybe_sign_token kDegreesToken maybe_whitespace {
-    $$ = $1 * $2 * (2 * static_cast<float>(M_PI) / 360.0f);
-  }
-  | maybe_sign_token kGradiansToken maybe_whitespace {
-    $$ = $1 * $2 * (2 * static_cast<float>(M_PI) / 400.0f);
-  }
-  | maybe_sign_token kRadiansToken maybe_whitespace {
-    $$ = $1 * $2;
-  }
-  | maybe_sign_token kTurnsToken maybe_whitespace {
-    $$ = $1 * $2 * 2 * static_cast<float>(M_PI);
-  }
-  ;
-
-// Time units (used by animations and transitions).
-//   https://www.w3.org/TR/css3-values/#time
-time:
-    number {
-    $$ = base::TimeDelta::FromMilliseconds(
-             static_cast<int64>($1 * base::Time::kMillisecondsPerSecond)).
-             ToInternalValue();
-    if ($1 != 0) {
-      parser_impl->LogWarning(
-          @1, "non-zero time is not allowed without unit identifier");
-    }
-  }
-  | time_with_units_required
-  ;
-
-time_with_units_required:
-  maybe_sign_token kSecondsToken maybe_whitespace {
-    $$ = base::TimeDelta::FromMilliseconds(
-             static_cast<int64>($1 * $2 * base::Time::kMillisecondsPerSecond)).
-             ToInternalValue();
-  }
-  | maybe_sign_token kMillisecondsToken maybe_whitespace {
-    $$ = base::TimeDelta::FromMilliseconds(static_cast<int64>($1 * $2)).
-             ToInternalValue();
-  }
-  ;
-
-colon: ':' maybe_whitespace ;
-comma: ',' maybe_whitespace ;
-
-// All properties accept the CSS-wide keywords.
-//   https://www.w3.org/TR/css3-values/#common-keywords
-common_values:
-    common_values_without_errors
-  | errors {
-    // If a user agent does not support a particular value, it should ignore
-    // that value when parsing style sheets, as if that value was an illegal
-    // value.
-    //   https://www.w3.org/TR/CSS21/syndata.html#unsupported-values
-    //
-    // User agents must ignore a declaration with an illegal value.
-    //   https://www.w3.org/TR/CSS21/syndata.html#illegalvalues
-    parser_impl->LogWarning(@1, "unsupported value");
-    $$ = NULL;
-  }
-  ;
-
-common_values_without_errors:
-    kInheritToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetInherit().get());
-  }
-  | kInitialToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetInitial().get());
-  }
-  ;
-
-color:
-  // Hexadecimal notation.
-  //   https://www.w3.org/TR/css3-color/#numerical
-    kHexToken maybe_whitespace {
-    switch ($1.size()) {
-      // The three-digit RGB notation (#rgb) is converted into six-digit
-      // form (#rrggbb) by replicating digits.
-      case 3: {
-        uint32 rgb = ParseHexToken($1);
-        uint32 r = (rgb & 0xf00) >> 8;
-        uint32 g = (rgb & 0x0f0) >> 4;
-        uint32 b = (rgb & 0x00f);
-        $$ = AddRef(new cssom::RGBAColorValue((r << 28) | (r << 24) |
-                                              (g << 20) | (g << 16) |
-                                              (b << 12) | (b << 8) |
-                                              0xff));
-        break;
-      }
-      case 6: {
-        uint32 rgb = ParseHexToken($1);
-        $$ = AddRef(new cssom::RGBAColorValue((rgb << 8) | 0xff));
-        break;
-      }
-      default:
-        YYERROR;
-        break;
-    }
-  }
-  // RGB color model.
-  //   https://www.w3.org/TR/css3-color/#rgb-color
-  | kRGBFunctionToken maybe_whitespace integer comma
-      integer comma integer ')' maybe_whitespace {
-    uint8 r = static_cast<uint8>(ClampToRange(0, 255, $3));
-    uint8 g = static_cast<uint8>(ClampToRange(0, 255, $5));
-    uint8 b = static_cast<uint8>(ClampToRange(0, 255, $7));
-    $$ = AddRef(new cssom::RGBAColorValue(r, g, b, 0xff));
-  }
-  // RGB color model with opacity.
-  //   https://www.w3.org/TR/css3-color/#rgba-color
-  | kRGBAFunctionToken maybe_whitespace integer comma integer comma integer
-      comma alpha ')' maybe_whitespace {
-    uint8 r = static_cast<uint8>(ClampToRange(0, 255, $3));
-    uint8 g = static_cast<uint8>(ClampToRange(0, 255, $5));
-    uint8 b = static_cast<uint8>(ClampToRange(0, 255, $7));
-    float a = $9;  // Already clamped.
-    $$ = AddRef(
-        new cssom::RGBAColorValue(r, g, b, static_cast<uint8>(a * 0xff)));
-  }
-  | kAquaToken maybe_whitespace {
-    $$ = AddRef(cssom::RGBAColorValue::GetAqua().get());
-  }
-  | kBlackToken maybe_whitespace {
-    $$ = AddRef(cssom::RGBAColorValue::GetBlack().get());
-  }
-  | kBlueToken maybe_whitespace {
-    $$ = AddRef(cssom::RGBAColorValue::GetBlue().get());
-  }
-  | kFuchsiaToken maybe_whitespace {
-    $$ = AddRef(cssom::RGBAColorValue::GetFuchsia().get());
-  }
-  | kGrayToken maybe_whitespace {
-    $$ = AddRef(cssom::RGBAColorValue::GetGray().get());
-  }
-  | kGreenToken maybe_whitespace {
-    $$ = AddRef(cssom::RGBAColorValue::GetGreen().get());
-  }
-  | kLimeToken maybe_whitespace {
-    $$ = AddRef(cssom::RGBAColorValue::GetLime().get());
-  }
-  | kMaroonToken maybe_whitespace {
-    $$ = AddRef(cssom::RGBAColorValue::GetMaroon().get());
-  }
-  | kNavyToken maybe_whitespace {
-    $$ = AddRef(cssom::RGBAColorValue::GetNavy().get());
-  }
-  | kOliveToken maybe_whitespace {
-    $$ = AddRef(cssom::RGBAColorValue::GetOlive().get());
-  }
-  | kPurpleToken maybe_whitespace {
-    $$ = AddRef(cssom::RGBAColorValue::GetPurple().get());
-  }
-  | kRedToken maybe_whitespace {
-    $$ = AddRef(cssom::RGBAColorValue::GetRed().get());
-  }
-  | kSilverToken maybe_whitespace {
-    $$ = AddRef(cssom::RGBAColorValue::GetSilver().get());
-  }
-  | kTealToken maybe_whitespace {
-    $$ = AddRef(cssom::RGBAColorValue::GetTeal().get());
-  }
-  | kTransparentToken maybe_whitespace {
-    $$ = AddRef(cssom::RGBAColorValue::GetTransparent().get());
-  }
-  | kWhiteToken maybe_whitespace {
-    $$ = AddRef(cssom::RGBAColorValue::GetWhite().get());
-  }
-  | kYellowToken maybe_whitespace {
-    $$ = AddRef(cssom::RGBAColorValue::GetYellow().get());
-  }
-  ;
-
-url:
-    kUriToken ')' maybe_whitespace {
-    $$ = AddRef(new cssom::URLValue($1.ToString()));
-  }
-  ;
-
-
-// ...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:.
-// Property values.
-// ...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:.
-
-length_percent_property_value:
-    length {
-    $$ = $1;
-  }
-  | percentage {
-    $$ = $1;
-  }
-  ;
-
-positive_length_percent_property_value:
-    positive_length {
-    $$ = $1;
-  }
-  | positive_percentage {
-    $$ = $1;
-  }
-  ;
-
-background_property_element:
-    color {
-    scoped_refptr<cssom::PropertyValue> color(MakeScopedRefPtrAndRelease($1));
-    if (!$<background_shorthand_layer>0->background_color) {
-      $<background_shorthand_layer>0->background_color = color;
-    } else {
-      parser_impl->LogError(
-          @1, "background-color value declared twice in background.");
-      $<background_shorthand_layer>0->error = true;
-    }
-  }
-  | background_image_property_list_element {
-    scoped_refptr<cssom::PropertyValue> image(MakeScopedRefPtrAndRelease($1));
-    if (!$<background_shorthand_layer>0->background_image) {
-      scoped_ptr<cssom::PropertyListValue::Builder>
-          background_image_builder(new cssom::PropertyListValue::Builder());
-      background_image_builder->reserve(1);
-      background_image_builder->push_back(image);
-      $<background_shorthand_layer>0->background_image =
-          new cssom::PropertyListValue(background_image_builder.Pass());
-    } else {
-      parser_impl->LogError(
-          @1, "background-image value declared twice in background.");
-      $<background_shorthand_layer>0->error = true;
-    }
-  }
-  ;
-
-maybe_background_size_property_value:
-    /* empty */ {
-    $$ = NULL;
-  }
-  | '/' maybe_whitespace background_size_property_value_without_common_values {
-    $$ = $3;
-  }
-  ;
-
-background_position_and_size_shorthand_property_value:
-    validated_position_property
-    maybe_background_size_property_value {
-    scoped_ptr<BackgroundShorthandLayer> shorthand_layer(
-        new BackgroundShorthandLayer());
-
-    shorthand_layer->background_position = MakeScopedRefPtrAndRelease($1);
-    if ($2) {
-      shorthand_layer->background_size = MakeScopedRefPtrAndRelease($2);
-    }
-
-    $$ = shorthand_layer.release();
-  }
-  ;
-
-background_repeat_shorthand_property_value:
-    background_repeat_property_value_without_common_values {
-    scoped_ptr<BackgroundShorthandLayer> shorthand_layer(
-        new BackgroundShorthandLayer());
-    shorthand_layer->background_repeat = MakeScopedRefPtrAndRelease($1);
-    $$ = shorthand_layer.release();
-  }
-  ;
-
-
-// 'background-size' property should follow with 'background-position' property
-//  and a '/'.
-background_position_and_repeat_combination:
-    background_position_and_size_shorthand_property_value
-  | background_repeat_shorthand_property_value
-  | background_position_and_size_shorthand_property_value
-    background_repeat_shorthand_property_value {
-    scoped_ptr<BackgroundShorthandLayer> shorthand_layer($1);
-    scoped_ptr<BackgroundShorthandLayer> non_overlapped($2);
-    shorthand_layer->IntegrateNonOverlapped(*non_overlapped);
-    $$ = shorthand_layer.release();
-  }
-  | background_repeat_shorthand_property_value
-    background_position_and_size_shorthand_property_value {
-    scoped_ptr<BackgroundShorthandLayer> shorthand_layer($1);
-    scoped_ptr<BackgroundShorthandLayer> non_overlapped($2);
-    shorthand_layer->IntegrateNonOverlapped(*non_overlapped);
-    $$ = shorthand_layer.release();
-  }
-  ;
-
-final_background_layer_without_position_and_repeat:
-    /* empty */ {
-    // Initialize the background shorthand which is to be filled in by
-    // subsequent reductions.
-    $$ = new BackgroundShorthandLayer();
-  }
-  | final_background_layer background_property_element {
-    // Propagate the return value from the reduced list.
-    // Appending of the new background_property_element to the list is done
-    // within background_property_element's reduction.
-    $$ = $1;
-  }
-  ;
-
-// Only the final background layer is allowed to set the background color.
-//   https://www.w3.org/TR/css3-background/#ltfinal-bg-layergt
-final_background_layer:
-    /* empty */ {
-    // Initialize the background shorthand which is to be filled in by
-    // subsequent reductions.
-    $$ = new BackgroundShorthandLayer();
-  }
-  | final_background_layer_without_position_and_repeat
-    background_position_and_repeat_combination {
-    scoped_ptr<BackgroundShorthandLayer> shorthand($1);
-    scoped_ptr<BackgroundShorthandLayer> background_values($2);
-    if (!shorthand->IsBackgroundPropertyOverlapped(*background_values.get())) {
-      shorthand->IntegrateNonOverlapped(*background_values.get());
-      $$ = shorthand.release();
-    } else {
-      parser_impl->LogError(
-          @1, "background-position or background-repeat declared twice in "
-              "background.");
-      $$ = new BackgroundShorthandLayer();
-      $$->error = true;
-    }
-  }
-  | final_background_layer background_property_element {
-    // Propagate the return value from the reduced list.
-    // Appending of the new background_property_element to the list is done
-    // within background_property_element's reduction.
-    $$ = $1;
-  }
-  ;
-
-// Shorthand property for setting most background properties at the same place.
-//   https://www.w3.org/TR/css3-background/#the-background
-background_property_value:
-    final_background_layer
-  | common_values {
-    // Replicate the common value into each of the properties that background
-    // is a shorthand for.
-    scoped_ptr<BackgroundShorthandLayer> background(
-        new BackgroundShorthandLayer());
-    background->background_color = $1;
-    background->background_image = $1;
-    background->background_repeat = $1;
-    background->background_position = $1;
-    background->background_size = $1;
-    $$ = background.release();
-  }
-  ;
-
-// Background color of an element drawn behind any background images.
-//   https://www.w3.org/TR/css3-background/#the-background-color
-background_color_property_value:
-    color { $$ = $1; }
-  | common_values
-  ;
-
-color_stop:
-    color {
-    $$ = new cssom::ColorStop(MakeScopedRefPtrAndRelease($1));
-  }
-  | color length_percent_property_value {
-    $$ = new cssom::ColorStop(MakeScopedRefPtrAndRelease($1),
-                              MakeScopedRefPtrAndRelease($2));
-  }
-  ;
-
-// Only 2 or more color stops can make a valid color stop list.
-comma_separated_color_stop_list:
-    color_stop comma color_stop {
-    $$ = new cssom::ColorStopList();
-    $$->push_back($1);
-    $$->push_back($3);
-  }
-  | comma_separated_color_stop_list comma color_stop {
-    $$ = $1;
-    $$->push_back($3);
-  }
-  ;
-
-side:
-    kBottomToken maybe_whitespace {
-    $$ = cssom::LinearGradientValue::kBottom;
-  }
-  | kLeftToken maybe_whitespace {
-    $$ = cssom::LinearGradientValue::kLeft;
-  }
-  | kRightToken maybe_whitespace {
-    $$ = cssom::LinearGradientValue::kRight;
-  }
-  | kTopToken maybe_whitespace {
-    $$ = cssom::LinearGradientValue::kTop;
-  }
-  ;
-
-side_or_corner:
-    side
-  | side side {
-    if ($1 == cssom::LinearGradientValue::kBottom) {
-      if($2 == cssom::LinearGradientValue::kLeft) {
-        $$ = cssom::LinearGradientValue::kBottomLeft;
-      } else if ($2 == cssom::LinearGradientValue::kRight) {
-        $$ = cssom::LinearGradientValue::kBottomRight;
-      } else {
-        parser_impl->LogWarning(@1, "Illegal corner value.");
-      }
-    } else if ($1 == cssom::LinearGradientValue::kLeft) {
-      if($2 == cssom::LinearGradientValue::kBottom) {
-        $$ = cssom::LinearGradientValue::kBottomLeft;
-      } else if ($2 == cssom::LinearGradientValue::kTop) {
-        $$ = cssom::LinearGradientValue::kTopLeft;
-      } else {
-        parser_impl->LogWarning(@1, "Illegal corner value.");
-      }
-    } else if ($1 == cssom::LinearGradientValue::kRight) {
-      if($2 == cssom::LinearGradientValue::kBottom) {
-        $$ = cssom::LinearGradientValue::kBottomRight;
-      } else if ($2 == cssom::LinearGradientValue::kTop) {
-        $$ = cssom::LinearGradientValue::kTopRight;
-      } else {
-        parser_impl->LogWarning(@1, "Illegal corner value.");
-      }
-    } else if ($1 == cssom::LinearGradientValue::kTop) {
-      if($2 == cssom::LinearGradientValue::kLeft) {
-        $$ = cssom::LinearGradientValue::kTopLeft;
-      } else if ($2 == cssom::LinearGradientValue::kRight) {
-        $$ = cssom::LinearGradientValue::kTopRight;
-      } else {
-        parser_impl->LogWarning(@1, "Illegal corner value.");
-      }
-    }
-  }
-  ;
-
-linear_gradient_params:
-    comma_separated_color_stop_list {
-    scoped_ptr<cssom::ColorStopList> color_stop_list($1);
-    // If the first argument to the linear gradient function is omitted, it
-    // defaults to 'to bottom'.
-    $$ = AddRef(new cssom::LinearGradientValue(
-             cssom::LinearGradientValue::kBottom, color_stop_list->Pass()));
-  }
-  | angle comma comma_separated_color_stop_list {
-    scoped_ptr<cssom::ColorStopList> color_stop_list($3);
-    $$ = AddRef(new cssom::LinearGradientValue($1, color_stop_list->Pass()));
-  }
-  | kToToken kWhitespaceToken maybe_whitespace side_or_corner comma
-    comma_separated_color_stop_list {
-    scoped_ptr<cssom::ColorStopList> color_stop_list($6);
-    $$ = AddRef(new cssom::LinearGradientValue($4, color_stop_list->Pass()));
-  }
-  ;
-
-size_keyword:
-    kClosestSideToken maybe_whitespace {
-    $$ = cssom::RadialGradientValue::kClosestSide;
-  }
-  | kFarthestSideToken maybe_whitespace {
-    $$ = cssom::RadialGradientValue::kFarthestSide;
-  }
-  | kClosestCornerToken maybe_whitespace {
-    $$ = cssom::RadialGradientValue::kClosestCorner;
-  }
-  | kFarthestCornerToken maybe_whitespace {
-    $$ = cssom::RadialGradientValue::kFarthestCorner;
-  }
-  ;
-
-circle_with_size_keyword:
-    kCircleToken maybe_whitespace size_keyword {
-    $$ = $3;
-  }
-  | size_keyword kCircleToken maybe_whitespace {
-    $$ = $1;
-  }
-  ;
-
-// If <shape> is specified as 'circle' or is omitted, the <size> may be
-// given explicitly as a single <length> which gives the radius of the
-// circle explicitly. Negative values are invalid.
-circle_with_positive_length:
-    positive_length {
-    scoped_ptr<cssom::PropertyListValue::Builder> property_value(
-       new cssom::PropertyListValue::Builder());
-    property_value->reserve(1);
-    property_value->push_back(MakeScopedRefPtrAndRelease($1));
-    $$ = AddRef(new cssom::PropertyListValue(property_value.Pass()));
-  }
-  | positive_length kCircleToken maybe_whitespace {
-    scoped_ptr<cssom::PropertyListValue::Builder> property_value(
-       new cssom::PropertyListValue::Builder());
-    property_value->reserve(1);
-    property_value->push_back(MakeScopedRefPtrAndRelease($1));
-    $$ = AddRef(new cssom::PropertyListValue(property_value.Pass()));
-  }
-  | kCircleToken maybe_whitespace positive_length {
-    scoped_ptr<cssom::PropertyListValue::Builder> property_value(
-       new cssom::PropertyListValue::Builder());
-    property_value->reserve(1);
-    property_value->push_back(MakeScopedRefPtrAndRelease($3));
-    $$ = AddRef(new cssom::PropertyListValue(property_value.Pass()));
-  }
-  ;
-
-maybe_ellipse_with_size_keyword:
-    kEllipseToken maybe_whitespace size_keyword {
-    $$ = $3;
-  }
-  | size_keyword kEllipseToken maybe_whitespace {
-    $$ = $1;
-  }
-  | size_keyword {
-    // If only a size keyword is specified, the ending shape defaults to an
-    // ellipse.
-    $$ = $1;
-  }
-  ;
-
-// If <shape> is specified as 'ellipse' or is omitted, the <size> may be
-// given explicitly as [<length> | <percentage>]{2} which gives the size of
-// the ellipse explicitly. Negative values are invalid.
-ellipse_with_2_positive_length_percents:
-    positive_length_percent_property_value
-    positive_length_percent_property_value {
-    scoped_ptr<cssom::PropertyListValue::Builder> property_value(
-        new cssom::PropertyListValue::Builder());
-    property_value->reserve(2);
-    property_value->push_back(MakeScopedRefPtrAndRelease($1));
-    property_value->push_back(MakeScopedRefPtrAndRelease($2));
-    $$ = AddRef(new cssom::PropertyListValue(property_value.Pass()));
-  }
-  | positive_length_percent_property_value
-    positive_length_percent_property_value kEllipseToken maybe_whitespace {
-    scoped_ptr<cssom::PropertyListValue::Builder> property_value(
-        new cssom::PropertyListValue::Builder());
-    property_value->reserve(2);
-    property_value->push_back(MakeScopedRefPtrAndRelease($1));
-    property_value->push_back(MakeScopedRefPtrAndRelease($2));
-    $$ = AddRef(new cssom::PropertyListValue(property_value.Pass()));
-  }
-  | kEllipseToken maybe_whitespace positive_length_percent_property_value
-    positive_length_percent_property_value {
-    scoped_ptr<cssom::PropertyListValue::Builder> property_value(
-        new cssom::PropertyListValue::Builder());
-    property_value->reserve(2);
-    property_value->push_back(MakeScopedRefPtrAndRelease($3));
-    property_value->push_back(MakeScopedRefPtrAndRelease($4));
-    $$ = AddRef(new cssom::PropertyListValue(property_value.Pass()));
-  }
-  ;
-
-at_position:
-    kAtToken maybe_whitespace validated_position_property {
-    $$ = $3;
-  }
-  ;
-
-maybe_at_position:
-    /* empty */ {
-    $$ = NULL;
-  }
-  | at_position
-  ;
-
-//   https://www.w3.org/TR/css3-images/#radial-gradients
-radial_gradient_params:
-    circle_with_positive_length maybe_at_position comma
-    comma_separated_color_stop_list {
-    scoped_ptr<cssom::ColorStopList> color_stop_list($4);
-    $$ = AddRef(
-        new cssom::RadialGradientValue(cssom::RadialGradientValue::kCircle,
-                                       MakeScopedRefPtrAndRelease($1),
-                                       MakeScopedRefPtrAndRelease($2),
-                                       color_stop_list->Pass()));
-  }
-  | ellipse_with_2_positive_length_percents maybe_at_position comma
-    comma_separated_color_stop_list {
-    scoped_ptr<cssom::ColorStopList> color_stop_list($4);
-    $$ = AddRef(
-        new cssom::RadialGradientValue(cssom::RadialGradientValue::kEllipse,
-                                       MakeScopedRefPtrAndRelease($1),
-                                       MakeScopedRefPtrAndRelease($2),
-                                       color_stop_list->Pass()));
-  }
-  | circle_with_size_keyword maybe_at_position comma
-    comma_separated_color_stop_list {
-    scoped_ptr<cssom::ColorStopList> color_stop_list($4);
-    $$ = AddRef(
-        new cssom::RadialGradientValue(cssom::RadialGradientValue::kCircle,
-                                       $1,
-                                       MakeScopedRefPtrAndRelease($2),
-                                       color_stop_list->Pass()));
-  }
-  | maybe_ellipse_with_size_keyword maybe_at_position comma
-    comma_separated_color_stop_list {
-    scoped_ptr<cssom::ColorStopList> color_stop_list($4);
-    $$ = AddRef(
-        new cssom::RadialGradientValue(cssom::RadialGradientValue::kEllipse,
-                                       $1,
-                                       MakeScopedRefPtrAndRelease($2),
-                                       color_stop_list->Pass()));
-  }
-  | kCircleToken maybe_whitespace maybe_at_position comma
-    comma_separated_color_stop_list {
-    scoped_ptr<cssom::ColorStopList> color_stop_list($5);
-    $$ = AddRef(new cssom::RadialGradientValue(
-            cssom::RadialGradientValue::kCircle,
-            cssom::RadialGradientValue::kFarthestCorner,
-            MakeScopedRefPtrAndRelease($3),
-            color_stop_list->Pass()));
-  }
-  | kEllipseToken maybe_whitespace maybe_at_position comma
-    comma_separated_color_stop_list {
-    scoped_ptr<cssom::ColorStopList> color_stop_list($5);
-    $$ = AddRef(new cssom::RadialGradientValue(
-            cssom::RadialGradientValue::kEllipse,
-            cssom::RadialGradientValue::kFarthestCorner,
-            MakeScopedRefPtrAndRelease($3),
-            color_stop_list->Pass()));
-  }
-  | at_position comma comma_separated_color_stop_list {
-    // If no size or shape is specified, the ending shape defaults to an ellipse
-    // and the size defaults to 'farthest-corner'.
-    scoped_ptr<cssom::ColorStopList> color_stop_list($3);
-    $$ = AddRef(new cssom::RadialGradientValue(
-            cssom::RadialGradientValue::kEllipse,
-            cssom::RadialGradientValue::kFarthestCorner,
-            MakeScopedRefPtrAndRelease($1),
-            color_stop_list->Pass()));
-  }
-  | comma_separated_color_stop_list {
-    // If position is omitted as well, it defaults to 'center', indicated by
-    // passing in NULL.
-    scoped_ptr<cssom::ColorStopList> color_stop_list($1);
-    $$ = AddRef(new cssom::RadialGradientValue(
-            cssom::RadialGradientValue::kEllipse,
-            cssom::RadialGradientValue::kFarthestCorner,
-            NULL,
-            color_stop_list->Pass()));
-  }
-  ;
-
-background_image_property_list_element:
-    url { $$ = $1; }
-  | kLinearGradientFunctionToken maybe_whitespace linear_gradient_params ')' {
-    $$ = $3;
-  }
-  | kRadialGradientFunctionToken maybe_whitespace radial_gradient_params ')' {
-    $$ = $3;
-  }
-  | kNoneToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetNone().get());
-  }
-  ;
-
-comma_separated_background_image_list:
-    background_image_property_list_element {
-    $$ = new cssom::PropertyListValue::Builder();
-    $$->push_back(MakeScopedRefPtrAndRelease($1));
-  }
-  | comma_separated_background_image_list comma
-    background_image_property_list_element {
-    $$ = $1;
-    $$->push_back(MakeScopedRefPtrAndRelease($3));
-  }
-  ;
-
-// Images are drawn with the first specified one on top (closest to the user)
-// and each subsequent image behind the previous one.
-//   https://www.w3.org/TR/css3-background/#the-background-image
-background_image_property_value:
-  comma_separated_background_image_list {
-    scoped_ptr<cssom::PropertyListValue::Builder> property_value($1);
-    $$ = property_value
-         ? AddRef(new cssom::PropertyListValue(property_value.Pass()))
-         : NULL;
-  }
-  | common_values
-  ;
-
-position_list_element:
-    kBottomToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetBottom().get());
-  }
-  | kCenterToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetCenter().get());
-  }
-  | kLeftToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetLeft().get());
-  }
-  | kRightToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetRight().get());
-  }
-  | kTopToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetTop().get());
-  }
-  | length_percent_property_value
-  ;
-
-position_list:
-    position_list_element {
-    scoped_ptr<PositionParseStructure> position_info(
-        new PositionParseStructure());
-    position_info->PushBackElement(MakeScopedRefPtrAndRelease($1));
-    $$ = position_info.release();
-  }
-  | position_list
-    position_list_element {
-    scoped_ptr<PositionParseStructure> position_info($1);
-    scoped_refptr<cssom::PropertyValue> element(MakeScopedRefPtrAndRelease($2));
-    if (position_info &&
-        !position_info->PushBackElement(element)) {
-      parser_impl->LogWarning(@2, "invalid background position value");
-      $$ = NULL;
-    } else {
-      $$ = position_info.release();
-    }
-  }
-  ;
-
-validated_position_property:
-    position_list {
-    scoped_ptr<PositionParseStructure> position_info($1);
-    scoped_ptr<cssom::PropertyListValue::Builder> property_value;
-
-    if (!position_info) {
-      // No-ops.
-    } else if (position_info->position_builder().size() == 1) {
-      property_value.reset(new cssom::PropertyListValue::Builder(
-          position_info->position_builder()));
-    } else if (position_info->position_builder().size() == 2 &&
-               !position_info->IsPositionValidOnSizeTwo()) {
-      parser_impl->LogWarning(@1, "invalid background position value");
-      // No-ops.
-    } else {
-      DCHECK_GE(position_info->position_builder().size(), 2u);
-      DCHECK_LE(position_info->position_builder().size(), 4u);
-      property_value.reset(new cssom::PropertyListValue::Builder(
-          position_info->position_builder()));
-    }
-
-    $$ = property_value
-         ? AddRef(new cssom::PropertyListValue(property_value.Pass()))
-         : NULL;
-  }
-  ;
-
-// If background images have been specified, this property specifies their
-// initial position (after any resizing) within their corresponding background
-// positioning area.
-//   https://www.w3.org/TR/css3-background/#the-background-position
-background_position_property_value:
-    validated_position_property {
-    $$ = $1;
-  }
-  | common_values
-  ;
-
-// Specifies how background images are tiled after they have been sized and
-// positioned.
-//   https://www.w3.org/TR/css3-background/#the-background-repeat
-background_repeat_element:
-    kNoRepeatToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetNoRepeat().get());
-  }
-  | kRepeatToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetRepeat().get());
-  }
-  ;
-
-background_repeat_property_value_without_common_values:
-    background_repeat_element {
-    scoped_ptr<cssom::PropertyListValue::Builder> builder(
-        new cssom::PropertyListValue::Builder());
-    builder->reserve(2);
-    builder->push_back(MakeScopedRefPtrAndRelease($1));
-    builder->push_back($1);
-    $$ = AddRef(new cssom::PropertyListValue(builder.Pass()));
-  }
-  | background_repeat_element background_repeat_element {
-    scoped_ptr<cssom::PropertyListValue::Builder> builder(
-        new cssom::PropertyListValue::Builder());
-    builder->reserve(2);
-    builder->push_back(MakeScopedRefPtrAndRelease($1));
-    builder->push_back(MakeScopedRefPtrAndRelease($2));
-    $$ = AddRef(new cssom::PropertyListValue(builder.Pass()));
-  }
-  | kRepeatXToken maybe_whitespace {
-    scoped_ptr<cssom::PropertyListValue::Builder> builder(
-        new cssom::PropertyListValue::Builder());
-    builder->reserve(2);
-    builder->push_back(cssom::KeywordValue::GetRepeat().get());
-    builder->push_back(cssom::KeywordValue::GetNoRepeat().get());
-    $$ = AddRef(new cssom::PropertyListValue(builder.Pass()));
-  }
-  | kRepeatYToken maybe_whitespace {
-    scoped_ptr<cssom::PropertyListValue::Builder> builder(
-        new cssom::PropertyListValue::Builder());
-    builder->reserve(2);
-    builder->push_back(cssom::KeywordValue::GetNoRepeat().get());
-    builder->push_back(cssom::KeywordValue::GetRepeat().get());
-    $$ = AddRef(new cssom::PropertyListValue(builder.Pass()));
-  }
-  ;
-
-background_repeat_property_value:
-    background_repeat_property_value_without_common_values
-  | common_values
-  ;
-
-background_size_property_list_element:
-    length { $$ = $1; }
-  | positive_percentage { $$ = $1; }
-  | auto
-  ;
-
-background_size_property_list:
-    background_size_property_list_element {
-    $$ = new cssom::PropertyListValue::Builder();
-    $$->reserve(2);
-    $$->push_back(MakeScopedRefPtrAndRelease($1));
-    // Fill in the omitted 'auto'.
-    $$->push_back(cssom::KeywordValue::GetAuto().get());
-  }
-  | background_size_property_list_element
-    background_size_property_list_element {
-    $$ = new cssom::PropertyListValue::Builder();
-    $$->reserve(2);
-    $$->push_back(MakeScopedRefPtrAndRelease($1));
-    $$->push_back(MakeScopedRefPtrAndRelease($2));
-  }
-  ;
-
-// Specifies the size of the background images.
-//   https://www.w3.org/TR/css3-background/#the-background-size
-background_size_property_value_without_common_values:
-    background_size_property_list {
-    scoped_ptr<cssom::PropertyListValue::Builder> property_value($1);
-    $$ = property_value
-         ? AddRef(new cssom::PropertyListValue(property_value.Pass()))
-         : NULL;
-  }
-  | kContainToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetContain().get());
-  }
-  | kCoverToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetCover().get());
-  }
-  ;
-
-background_size_property_value:
-    background_size_property_value_without_common_values
-  | common_values
-  ;
-
-// 'border-color' sets the foreground color of the border specified by the
-// border-style properties.
-//   https://www.w3.org/TR/css3-background/#border-color
-border_color_property_list:
-    /* empty */ {
-    $$ = new cssom::PropertyListValue::Builder();
-  }
-  | border_color_property_list color {
-    scoped_ptr<cssom::PropertyListValue::Builder> property_value($1);
-    property_value->push_back(MakeScopedRefPtrAndRelease($2));
-    $$ = property_value.release();
-  }
-  ;
-
-border_color_property_value:
-    border_color_property_list {
-    scoped_ptr<cssom::PropertyListValue::Builder> property_value($1);
-    if (property_value->size() > 0u &&
-        property_value->size() <= 4u) {
-      $$ = AddRef(new cssom::PropertyListValue(property_value.Pass()));
-    } else {
-      parser_impl->LogWarning(@1, "invalid number of border color values");
-      $$ = NULL;
-    }
-  }
-  | common_values {
-    scoped_ptr<cssom::PropertyListValue::Builder> property_value(
-        new cssom::PropertyListValue::Builder());
-    property_value->push_back($1);
-    $$ = AddRef(new cssom::PropertyListValue(property_value.Pass()));
-  }
-  ;
-
-//   https://www.w3.org/TR/css3-background/#ltline-stylegt
-line_style:
-    kNoneToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetNone().get());
-  }
-  | kHiddenToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetHidden().get());
-  }
-  | kSolidToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetSolid().get());
-  }
-  ;
-
-line_style_with_common_values:
-    line_style
-  | common_values;
-  ;
-
-// 'border-style' sets the style of the border, unless there is a border-image.
-//   https://www.w3.org/TR/css3-background/#border-style
-border_style_property_list:
-    /* empty */ {
-    $$ = new cssom::PropertyListValue::Builder();
-  }
-  | border_style_property_list line_style {
-    scoped_ptr<cssom::PropertyListValue::Builder> property_value($1);
-    property_value->push_back(MakeScopedRefPtrAndRelease($2));
-    $$ = property_value.release();
-  }
-  ;
-
-border_style_property_value:
-    border_style_property_list {
-    scoped_ptr<cssom::PropertyListValue::Builder> property_value($1);
-    if (property_value->size() > 0u &&
-        property_value->size() <= 4u) {
-      $$ = AddRef(new cssom::PropertyListValue(property_value.Pass()));
-    } else {
-      parser_impl->LogWarning(@1, "invalid number of border style values");
-      $$ = NULL;
-    }
-  }
-  | common_values {
-    scoped_ptr<cssom::PropertyListValue::Builder> property_value(
-        new cssom::PropertyListValue::Builder());
-    property_value->push_back($1);
-    $$ = AddRef(new cssom::PropertyListValue(property_value.Pass()));
-  }
-  ;
-
-// 'border-width' sets the thickness of the border.
-//   https://www.w3.org/TR/css3-background/#border-width
-border_width_element:
-    positive_length  { $$ = $1; }
-  ;
-
-border_width_element_with_common_values:
-    border_width_element
-  | common_values
-  ;
-
-border_width_property_list:
-    /* empty */ {
-    $$ = new cssom::PropertyListValue::Builder();
-  }
-  | border_width_property_list border_width_element {
-    scoped_ptr<cssom::PropertyListValue::Builder> property_value($1);
-    property_value->push_back(MakeScopedRefPtrAndRelease($2));
-    $$ = property_value.release();
-  }
-  ;
-
-border_width_property_value:
-    border_width_property_list  {
-    scoped_ptr<cssom::PropertyListValue::Builder> property_value($1);
-    if (property_value->size() > 0u &&
-        property_value->size() <= 4u) {
-      $$ = AddRef(new cssom::PropertyListValue(property_value.Pass()));
-    } else {
-      parser_impl->LogWarning(@1, "invalid number of border width values");
-      $$ = NULL;
-    }
-  }
-  | common_values {
-    scoped_ptr<cssom::PropertyListValue::Builder> property_value(
-        new cssom::PropertyListValue::Builder());
-    property_value->push_back($1);
-    $$ = AddRef(new cssom::PropertyListValue(property_value.Pass()));
-  }
-  ;
-
-// border_or_outline_property_element represents a component of a single border
-// property. It uses $0 to access its parent's BorderOrOutlineShorthand object
-// and build it, so it should always be used to the right of a border shorthand
-// object.
-// The 'border' and 'outline' properties are shorthand properties for setting
-// the same width, color, and style for all four borders of a box. Unlike the
-// shorthand 'margin' and 'padding' properties, the 'border' property cannot set
-// different values on the four borders.
-border_or_outline_property_element:
-    color {
-    scoped_refptr<cssom::PropertyValue> color(MakeScopedRefPtrAndRelease($1));
-    if (!$<border_or_outline_shorthand>0->color) {
-      $<border_or_outline_shorthand>0->color = color;
-    } else {
-      parser_impl->LogError(
-          @1, "color value declared twice in border or outline.");
-      $<border_or_outline_shorthand>0->error = true;
-    }
-  }
-  | line_style {
-    scoped_refptr<cssom::PropertyValue> line_style =
-        MakeScopedRefPtrAndRelease($1);
-    if (!$<border_or_outline_shorthand>0->style) {
-      $<border_or_outline_shorthand>0->style = line_style;
-    } else {
-      parser_impl->LogError(
-          @1, "style value declared twice in border or outline.");
-      $<border_or_outline_shorthand>0->error = true;
-    }
-  }
-  | positive_length {
-    scoped_refptr<cssom::PropertyValue> positive_length =
-        MakeScopedRefPtrAndRelease($1);
-    if (!$<border_or_outline_shorthand>0->width) {
-      $<border_or_outline_shorthand>0->width = positive_length;
-    } else {
-      parser_impl->LogError(
-          @1, "width value declared twice in border or outline.");
-      $<border_or_outline_shorthand>0->error = true;
-    }
-  }
-  ;
-
-border_or_outline_property_list:
-    /* empty */ {
-    $$ = new BorderOrOutlineShorthand();
-  }
-  | border_or_outline_property_list border_or_outline_property_element {
-    $$ = $1;
-  }
-  ;
-
-// TODO: Support border-image.
-// The border can either be a predefined style (solid line, double line, dotted
-// line, pseudo-3D border, etc.) or it can be an image. In the former case,
-// various properties define the style ('border-style'), color ('border-color'),
-// and thickness ('border-width') of the border.
-//   https://www.w3.org/TR/css3-background/#borders
-border_or_outline_property_value:
-    border_or_outline_property_list
-  | common_values {
-    // Replicate the common value into each of the properties that border is a
-    // shorthand for.
-    scoped_ptr<BorderOrOutlineShorthand> border(new BorderOrOutlineShorthand());
-    border->color = $1;
-    border->style = $1;
-    border->width = $1;
-    $$ = border.release();
-  }
-  ;
-
-// The radii of a quarter ellipse that defines the shape of the corner
-// of the outer border edge.
-//   https://www.w3.org/TR/css3-background/#the-border-radius
-border_radius_element:
-    positive_length_percent_property_value { $$ = $1; }
-  ;
-border_radius_element_with_common_values:
-    border_radius_element
-  | common_values
-  ;
-
-border_radius_property_list:
-    /* empty */ {
-    $$ = new cssom::PropertyListValue::Builder();
-  }
-  | border_radius_property_list border_radius_element {
-    scoped_ptr<cssom::PropertyListValue::Builder> property_value($1);
-    property_value->push_back(MakeScopedRefPtrAndRelease($2));
-    $$ = property_value.release();
-  }
-  ;
-
-border_radius_property_value:
-    border_radius_property_list {
-    scoped_ptr<cssom::PropertyListValue::Builder> property_value($1);
-    if (property_value->size() > 0u &&
-        property_value->size() <= 4u) {
-      $$ = AddRef(new cssom::PropertyListValue(property_value.Pass()));
-    } else {
-      parser_impl->LogWarning(@1, "invalid number of border radius values");
-      $$ = NULL;
-    }
-  }
-  | common_values {
-    scoped_ptr<cssom::PropertyListValue::Builder> property_value(
-        new cssom::PropertyListValue::Builder());
-    property_value->push_back($1);
-    $$ = AddRef(new cssom::PropertyListValue(property_value.Pass()));
-  }
-  ;
-
-box_shadow_property_element:
-    length {
-    if ($<shadow_info>0->length_vector.size() == 2) {
-      scoped_refptr<cssom::LengthValue> length(MakeScopedRefPtrAndRelease($1));
-      // Negative values are not allowed for blur radius.
-      if (length && length->value() < 0) {
-        parser_impl->LogError(@1, "negative values of blur radius are illegal");
-        $<shadow_info>0->error = true;
-      }
-      $<shadow_info>0->length_vector.push_back(length);
-    } else {
-      $<shadow_info>0->length_vector.push_back(
-          MakeScopedRefPtrAndRelease($1));
-    }
-  }
-  | color {
-    scoped_refptr<cssom::RGBAColorValue> color(MakeScopedRefPtrAndRelease($1));
-    if (!$<shadow_info>0->color) {
-      $<shadow_info>0->color = color;
-    } else {
-      parser_impl->LogError(@1, "color value declared twice in box shadow.");
-      $<shadow_info>0->error = true;
-    }
-  }
-  | kInsetToken maybe_whitespace {
-    if (!$<shadow_info>0->has_inset) {
-      $<shadow_info>0->has_inset = true;
-    } else {
-      parser_impl->LogError(@1, "inset value declared twice in box shadow.");
-      $<shadow_info>0->error = true;
-    }
-  }
-  ;
-
-box_shadow_list:
-    /* empty */ {
-    $$ = new ShadowPropertyInfo();
-  }
-  | box_shadow_list box_shadow_property_element {
-    $$ = $1;
-  }
-  ;
-
-validated_box_shadow_list:
-    box_shadow_list {
-    scoped_ptr<ShadowPropertyInfo> shadow_property_info($1);
-    if (!shadow_property_info->IsShadowPropertyValid(kBoxShadow)) {
-      parser_impl->LogWarning(@1, "invalid box shadow property.");
-      $$ = NULL;
-    } else {
-      $$ = AddRef(new cssom::ShadowValue(
-              shadow_property_info->length_vector, shadow_property_info->color,
-              shadow_property_info->has_inset));
-    }
-  }
-  ;
-
-comma_separated_box_shadow_list:
-    validated_box_shadow_list {
-    scoped_refptr<cssom::PropertyValue> shadow = MakeScopedRefPtrAndRelease($1);
-    if (shadow) {
-      $$ = new cssom::PropertyListValue::Builder();
-      $$->push_back(shadow);
-    }
-  }
-  | comma_separated_box_shadow_list comma validated_box_shadow_list {
-    $$ = $1;
-    scoped_refptr<cssom::PropertyValue> shadow = MakeScopedRefPtrAndRelease($3);
-    if ($$ && shadow) {
-      $$->push_back(shadow);
-    }
-  }
-  ;
-
-// The 'box-shadow' property attaches one or more drop-shadows to the box.
-// The property takes a comma-separated list of shadows, ordered front to back.
-//   https://www.w3.org/TR/css3-background/#box-shadow
-box_shadow_property_value:
-    comma_separated_box_shadow_list {
-    if ($1) {
-      scoped_ptr<cssom::PropertyListValue::Builder> property_value($1);
-      $$ = AddRef(new cssom::PropertyListValue(property_value.Pass()));
-    }
-  }
-  | kNoneToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetNone().get());
-  }
-  | common_values
-  ;
-
-// Foreground color of an element's text content.
-//   https://www.w3.org/TR/css3-color/#foreground
-color_property_value:
-    color { $$ = $1; }
-  | common_values
-  ;
-
-// Used to add generated content with a :before or :after pseudo-element.
-//   https://www.w3.org/TR/CSS21/generate.html#content
-content_property_value:
-    kNoneToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetNone().get());
-  }
-  | kNormalToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetNormal().get());
-  }
-  | url { $$ = $1; }
-  | kStringToken maybe_whitespace {
-    $$ = AddRef(new cssom::StringValue($1.ToString()));
-  }
-  | common_values
-;
-
-// Controls the generation of boxes.
-//   https://www.w3.org/TR/CSS21/visuren.html#display-prop
-display_property_value:
-    kBlockToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetBlock().get());
-  }
-  | kInlineToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetInline().get());
-  }
-  | kInlineBlockToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetInlineBlock().get());
-  }
-  | kNoneToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetNone().get());
-  }
-  | common_values
-  ;
-
-// External font-face references consist of a URL, followed by an optional
-// hint describing the format of the font resource referenced by that URL.
-//   https://www.w3.org/TR/css3-fonts/#descdef-src
-font_face_url_src:
-    url kFormatFunctionToken maybe_whitespace kStringToken maybe_whitespace ')'
-        maybe_whitespace {
-    $$ = AddRef(new cssom::UrlSrcValue(MakeScopedRefPtrAndRelease($1),
-                                       $4.ToString()));
-  }
-  | url {
-    $$ = AddRef(new cssom::UrlSrcValue(MakeScopedRefPtrAndRelease($1), ""));
-  }
-  ;
-
-// The syntax for a local font-face reference is a unique font face name
-// enclosed by "local(" and ")".
-//   https://www.w3.org/TR/css3-fonts/#descdef-src
-font_face_local_src:
-    kLocalFunctionToken maybe_whitespace font_family_specific_name ')'
-        maybe_whitespace {
-    $$ = AddRef(new cssom::LocalSrcValue($3->value()));
-    $3->Release();
-  }
-  ;
-
-font_face_src_list_element:
-    font_face_url_src
-  | font_face_local_src
-  ;
-
-comma_separated_font_face_src_list:
-    font_face_src_list_element {
-    $$ = new cssom::PropertyListValue::Builder();
-    $$->push_back(MakeScopedRefPtrAndRelease($1));
-  }
-  | comma_separated_font_face_src_list comma font_face_src_list_element {
-    $$ = $1;
-    $$->push_back(MakeScopedRefPtrAndRelease($3));
-  }
-  ;
-
-// The src descriptor specifies the resource containing font data. Its value is
-// a prioritized, comma-separated list of external references or
-// locally-installed font face names.
-//   https://www.w3.org/TR/css3-fonts/#src-desc
-font_face_src_property_value:
-    comma_separated_font_face_src_list {
-    scoped_ptr<cssom::PropertyListValue::Builder> property_value($1);
-    $$ = property_value
-         ? AddRef(new cssom::PropertyListValue(property_value.Pass()))
-         : NULL;
-  }
-  | common_values
-  ;
-
-// The unquoted name must be a sequence of identifiers separated by whitespace
-// which is converted to a string by joining the identifiers together separated
-// by a single space.
-//   https://www.w3.org/TR/css3-fonts/#descdef-src
-font_family_name_identifier_list:
-    identifier_token maybe_whitespace {
-    $$ = AddRef(new cssom::StringValue($1.ToString()));
-  }
-  | font_family_name_identifier_list identifier_token maybe_whitespace {
-    $$ = AddRef(new cssom::StringValue($1->value() + " " + $2.ToString()));
-    $1->Release();
-  }
-  ;
-
-font_family_string_name:
-    kStringToken maybe_whitespace {
-    $$ = AddRef(new cssom::StringValue($1.ToString()));
-  }
-  ;
-
-// Font family names other than generic families must be quoted
-// as strings or unquoted as a sequence of one or more identifiers.
-//   https://www.w3.org/TR/css3-fonts/#family-name-value
-font_family_specific_name:
-    font_family_name_identifier_list
-  | font_family_string_name
-  ;
-
-// Specific font name that does not accept a single identifier. This is needed
-// in certain cases to avoid ambiguous states, since single identifier names
-// require special rules for keywords.
-font_family_specific_name_no_single_identifier:
-    font_family_name_identifier_list identifier_token maybe_whitespace {
-    $$ = AddRef(new cssom::StringValue($1->value() + " " + $2.ToString()));
-    $1->Release();
-  }
-  | font_family_string_name
-  ;
-
-// There are two types of font family names:
-//   -- The name of a specific font family
-//   -- A generic font family which can be used as a general fallback mechanism
-//   https://www.w3.org/TR/css3-fonts/#family-name-value
-font_family_name:
-    identifier_token maybe_whitespace {
-    // Generic families are defined in all CSS implementations.
-    //   https://www.w3.org/TR/css3-fonts/#generic-font-families
-    if ($1 == cssom::kCursiveKeywordName) {
-      $$ = AddRef(cssom::KeywordValue::GetCursive().get());
-    } else if ($1 == cssom::kFantasyKeywordName) {
-      $$ = AddRef(cssom::KeywordValue::GetFantasy().get());
-    } else if ($1 == cssom::kMonospaceKeywordName) {
-      $$ = AddRef(cssom::KeywordValue::GetMonospace().get());
-    } else if ($1 == cssom::kSansSerifKeywordName) {
-      $$ = AddRef(cssom::KeywordValue::GetSansSerif().get());
-    } else if ($1 == cssom::kSerifKeywordName) {
-      $$ = AddRef(cssom::KeywordValue::GetSerif().get());
-    } else {
-      $$ = AddRef(new cssom::StringValue($1.ToString()));
-    }
-  }
-  | font_family_specific_name_no_single_identifier { $$ = $1; }
-  ;
-
-comma_separated_font_family_name_list:
-    font_family_name {
-    $$ = new cssom::PropertyListValue::Builder();
-    $$->push_back(MakeScopedRefPtrAndRelease($1));
-  }
-  | comma_separated_font_family_name_list comma font_family_name {
-    $$ = $1;
-    $$->push_back(MakeScopedRefPtrAndRelease($3));
-  }
-  ;
-
-// Prioritized list of font family names.
-//   https://www.w3.org/TR/css3-fonts/#font-family-prop
-font_family_property_value:
-  // Special case for a single identifier, which can be a reserved keyword or
-  // a generic font name.
-    identifier_token maybe_whitespace {
-    // "inherit" and "initial" are reserved values and not allowed as font
-    // family names.
-    //   https://www.w3.org/TR/css3-fonts/#propdef-font-family
-    if ($1 == cssom::kInheritKeywordName) {
-      $$ = AddRef(cssom::KeywordValue::GetInherit().get());
-    } else if ($1 == cssom::kInitialKeywordName) {
-      $$ = AddRef(cssom::KeywordValue::GetInitial().get());
-    } else {
-      scoped_ptr<cssom::PropertyListValue::Builder>
-          builder(new cssom::PropertyListValue::Builder());
-
-      // Generic families are defined in all CSS implementations.
-      //   https://www.w3.org/TR/css3-fonts/#generic-font-families
-      if ($1 == cssom::kCursiveKeywordName) {
-        builder->push_back(cssom::KeywordValue::GetCursive().get());
-      } else if ($1 == cssom::kFantasyKeywordName) {
-        builder->push_back(cssom::KeywordValue::GetFantasy().get());
-      } else if ($1 == cssom::kMonospaceKeywordName) {
-        builder->push_back(cssom::KeywordValue::GetMonospace().get());
-      } else if ($1 == cssom::kSansSerifKeywordName) {
-        builder->push_back(cssom::KeywordValue::GetSansSerif().get());
-      } else if ($1 == cssom::kSerifKeywordName) {
-        builder->push_back(cssom::KeywordValue::GetSerif().get());
-      } else {
-        builder->push_back(new cssom::StringValue($1.ToString()));
-      }
-
-      $$ = AddRef(new cssom::PropertyListValue(builder.Pass()));
-    }
-  }
-  | font_family_specific_name_no_single_identifier {
-    scoped_ptr<cssom::PropertyListValue::Builder>
-        builder(new cssom::PropertyListValue::Builder());
-    builder->push_back(MakeScopedRefPtrAndRelease($1));
-    $$ = AddRef(new cssom::PropertyListValue(builder.Pass()));
-  }
-  | comma_separated_font_family_name_list comma font_family_name {
-    scoped_ptr<cssom::PropertyListValue::Builder> builder($1);
-    builder->push_back(MakeScopedRefPtrAndRelease($3));
-    $$ = AddRef(new cssom::PropertyListValue(builder.Pass()));
-  }
-  | errors {
-    parser_impl->LogError(@1, "unsupported property value for font-family");
-    $$ = NULL;
-  }
-  ;
-
-// Desired height of glyphs from the font.
-//   https://www.w3.org/TR/css3-fonts/#font-size-prop
-font_size_property_value:
-    positive_length_percent_property_value
-  | common_values
-  ;
-
-// All acceptable 'font-style' property values, excluding 'normal', 'inherit'
-// and 'initial'.
-font_style_exclusive_property_value:
-    kItalicToken maybe_whitespace {
-    $$ = AddRef(cssom::FontStyleValue::GetItalic().get());
-  }
-  | kObliqueToken maybe_whitespace {
-    $$ = AddRef(cssom::FontStyleValue::GetOblique().get());
-  }
-  ;
-
-// The 'font-style' property allows italic or oblique faces to be selected.
-//   https://www.w3.org/TR/css3-fonts/#font-style-prop
-font_style_property_value:
-    font_style_exclusive_property_value
-  | kNormalToken maybe_whitespace {
-    $$ = AddRef(cssom::FontStyleValue::GetNormal().get());
-  }
-  | common_values
-  ;
-
-// All acceptable 'font-weight' property values, excluding 'normal', 'inherit'
-// and 'initial'.
-font_weight_exclusive_property_value:
-    kBoldToken maybe_whitespace {
-    $$ = AddRef(cssom::FontWeightValue::GetBoldAka700().get());
-  }
-  | positive_integer {
-    switch ($1) {
-      case 100:
-        $$ = AddRef(cssom::FontWeightValue::GetThinAka100().get());
-        break;
-      case 200:
-        $$ = AddRef(cssom::FontWeightValue::GetExtraLightAka200().get());
-        break;
-      case 300:
-        $$ = AddRef(cssom::FontWeightValue::GetLightAka300().get());
-        break;
-      case 400:
-        $$ = AddRef(cssom::FontWeightValue::GetNormalAka400().get());
-        break;
-      case 500:
-        $$ = AddRef(cssom::FontWeightValue::GetMediumAka500().get());
-        break;
-      case 600:
-        $$ = AddRef(cssom::FontWeightValue::GetSemiBoldAka600().get());
-        break;
-      case 700:
-        $$ = AddRef(cssom::FontWeightValue::GetBoldAka700().get());
-        break;
-      case 800:
-        $$ = AddRef(cssom::FontWeightValue::GetExtraBoldAka800().get());
-        break;
-      case 900:
-        $$ = AddRef(cssom::FontWeightValue::GetBlackAka900().get());
-        break;
-      default:
-        parser_impl->LogError(@1, "unsupported property value for font-weight");
-        $$ = NULL;
-    }
-  }
-  ;
-
-// The weight of glyphs in the font, their degree of blackness
-// or stroke thickness.
-//   https://www.w3.org/TR/css3-fonts/#font-weight-prop
-font_weight_property_value:
-    font_weight_exclusive_property_value
-  | kNormalToken maybe_whitespace {
-    $$ = AddRef(cssom::FontWeightValue::GetNormalAka400().get());
-  }
-  | common_values
-  ;
-
-// Optional font element represents a single optional font shorthand value.
-// It uses $0 to access its parent's FontShorthand object and build it, so it
-// should always be used to the right of an optional_font_value_list. Note that
-// outside of being set via the second normal token, font weight, while
-// optional, is handled separately. This is due to Bison having parsing
-// conflicts with differentiating a number (which is an allowable font weight
-// value) followed by a token as either two optional font elements or the font
-// size followed by the font family. As a result, the recommended ordering is
-// required and font weight must come after font style.
-optional_font_element:
-    font_style_exclusive_property_value {
-    if (!$<font>0->font_style) {
-      $<font>0->font_style = MakeScopedRefPtrAndRelease($1);
-    } else {
-      parser_impl->LogWarning(
-          @1, "font-style value declared twice in font.");
-    }
-  }
-  | kNormalToken maybe_whitespace {
-    // The normal token is treated as representing font style if it is
-    // encountered before the style is set. Otherwise, it is treated as the
-    // font weight.
-    if (!$<font>0->font_style) {
-      $<font>0->font_style =
-        AddRef(cssom::FontStyleValue::GetNormal().get());
-    } else if (!$<font>0->font_weight) {
-      $<font>0->font_weight =
-        AddRef(cssom::FontWeightValue::GetNormalAka400().get());
-    } else {
-      parser_impl->LogWarning(
-        @1, "too many font values declared in font.");
-    }
-  }
-  | error maybe_whitespace {
-    parser_impl->LogError(@1, "unsupported property value for font");
-    $<font>0->error = true;
-  }
-  ;
-
-optional_font_value_list:
-    /* empty */ {
-    // Initialize the result, to be filled in by
-    // non_empty_optional_font_value_list
-    $$ = new FontShorthand();
-  }
-  | non_empty_optional_font_value_list
-  ;
-
-non_empty_optional_font_value_list:
-    optional_font_value_list optional_font_element {
-    // Propagate the list from our parent.
-    // optional_font_element will have already taken care of adding itself
-    // to the list via $0.
-    $$ = $1;
-  }
-  ;
-
-// Font shorthand property.
-//   https://www.w3.org/TR/css3-fonts/#font-prop
-font_property_value:
-    optional_font_value_list positive_length_percent_property_value
-        comma_separated_font_family_name_list {
-    // Font shorthand properties without a non-normal weight value.
-    scoped_ptr<FontShorthand> font($1);
-
-    font->font_size = MakeScopedRefPtrAndRelease($2);
-
-    scoped_ptr<cssom::PropertyListValue::Builder> builder($3);
-    font->font_family = new cssom::PropertyListValue(builder.Pass());
-
-    $$ = font.release();
-  }
-  | optional_font_value_list font_weight_exclusive_property_value
-        positive_length_percent_property_value
-        comma_separated_font_family_name_list {
-    // Font shorthand properties with a non-normal weight value. This and the
-    // preceding without expression are not simply combined into a single
-    // maybe_font_weight_exclusive_property_value as a result of Bison having
-    // parsing conflicts when the weight value appears in that form.
-    scoped_ptr<FontShorthand> font($1);
-
-    if (!font->font_weight) {
-      font->font_weight = MakeScopedRefPtrAndRelease($2);
-    } else {
-      parser_impl->LogWarning(
-          @1, "font-weight value declared twice in font.");
-    }
-
-    font->font_size = MakeScopedRefPtrAndRelease($3);
-
-    scoped_ptr<cssom::PropertyListValue::Builder> builder($4);
-    font->font_family = new cssom::PropertyListValue(builder.Pass());
-
-    $$ = font.release();
-  }
-  | common_values_without_errors {
-    // Replicate the common value into each of the properties that font
-    // is a shorthand for.
-    scoped_ptr<FontShorthand> font(new FontShorthand());
-    font->font_style = $1;
-    font->font_weight = $1;
-    font->font_size = $1;
-    font->font_family = $1;
-    $1->Release();
-
-    $$ = font.release();
-  }
-  ;
-
-// Specifies the content height of boxes.
-//   https://www.w3.org/TR/CSS21/visudet.html#the-height-property
-height_property_value:
-    positive_length_percent_property_value
-  | auto
-  | common_values
-  ;
-
-// Specifies the minimum content height of boxes.
-//   https://www.w3.org/TR/CSS21/visudet.html#propdef-min-height
-min_height_property_value:
-    positive_length_percent_property_value
-  | common_values
-  ;
-
-// Specifies the maximum content height of boxes.
-//   https://www.w3.org/TR/CSS2/visudet.html#propdef-max-height
-max_height_property_value:
-    kNoneToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetNone().get());
-  }
-  | positive_length_percent_property_value
-  | common_values
-  ;
-
-
-// Specifies the minimal height of line boxes within the element.
-//   https://www.w3.org/TR/CSS21/visudet.html#line-height
-line_height_property_value:
-    kNormalToken maybe_whitespace  {
-    $$ = AddRef(cssom::KeywordValue::GetNormal().get());
-  }
-  | non_negative_number {
-    $$ = AddRef(new cssom::NumberValue($1));
-  }
-  | absolute_or_relative_length {
-    $$ = $1;
-  }
-  | positive_percentage {
-    $$ = $1;
-  }
-  | common_values
-  ;
-
-// <margin-width> value type.
-//   https://www.w3.org/TR/CSS21/box.html#value-def-margin-width
-margin_width:
-    length_percent_property_value
-  | auto
-  ;
-
-// Specifies the width of a top, right, bottom, or left side of the margin area
-// of a box.
-//   https://www.w3.org/TR/CSS21/box.html#margin-properties
-margin_side_property_value:
-    margin_width
-  | common_values
-  ;
-
-// The "margin" property is a shorthand property for setting "margin-top",
-// "margin-right", "margin-bottom", and "margin-left" at the same place.
-//   https://www.w3.org/TR/CSS21/box.html#margin-properties
-margin_property_value:
-    // If there is only one component value, it applies to all sides.
-    margin_width {
-    scoped_refptr<cssom::PropertyValue> width(MakeScopedRefPtrAndRelease($1));
-    $$ = MarginOrPaddingShorthand::TryCreate(
-        width, width, width, width).release();
-  }
-    // If there are two values, the top and bottom margins are set to the first
-    // value and the right and left margins are set to the second.
-  | margin_width margin_width {
-    scoped_refptr<cssom::PropertyValue> vertical_width =
-        MakeScopedRefPtrAndRelease($1);
-    scoped_refptr<cssom::PropertyValue> horizontal_width =
-        MakeScopedRefPtrAndRelease($2);
-    $$ = MarginOrPaddingShorthand::TryCreate(
-             vertical_width, horizontal_width,
-             vertical_width, horizontal_width).release();
-  }
-    // If there are three values, the top is set to the first value, the left
-    // and right are set to the second, and the bottom is set to the third.
-  | margin_width margin_width margin_width {
-    scoped_refptr<cssom::PropertyValue> top_width =
-        MakeScopedRefPtrAndRelease($1);
-    scoped_refptr<cssom::PropertyValue> horizontal_width =
-        MakeScopedRefPtrAndRelease($2);
-    scoped_refptr<cssom::PropertyValue> bottom_width =
-        MakeScopedRefPtrAndRelease($3);
-    $$ = MarginOrPaddingShorthand::TryCreate(
-             top_width, horizontal_width,
-             bottom_width, horizontal_width).release();
-  }
-    // If there are four values, they apply to the top, right, bottom, and left,
-    // respectively.
-  | margin_width margin_width margin_width margin_width {
-    scoped_refptr<cssom::PropertyValue> top_width =
-        MakeScopedRefPtrAndRelease($1);
-    scoped_refptr<cssom::PropertyValue> left_width =
-        MakeScopedRefPtrAndRelease($2);
-    scoped_refptr<cssom::PropertyValue> bottom_width =
-        MakeScopedRefPtrAndRelease($3);
-    scoped_refptr<cssom::PropertyValue> right_width =
-        MakeScopedRefPtrAndRelease($4);
-    $$ = MarginOrPaddingShorthand::TryCreate(
-             top_width, left_width, bottom_width, right_width).release();
-  }
-  | common_values {
-    $$ = MarginOrPaddingShorthand::TryCreate($1, $1, $1, $1).release();
-  }
-  ;
-
-// Specifies top, right, bottom, or left offset of the box relatively
-// to the container block.
-//   https://www.w3.org/TR/CSS21/visuren.html#position-props
-offset_property_value:
-    length_percent_property_value
-  | auto
-  | common_values
-  ;
-
-// Specifies how to blend the element (including its descendants)
-// into the current composite rendering.
-//   https://www.w3.org/TR/css3-color/#transparency
-opacity_property_value:
-    alpha { $$ = AddRef(new cssom::NumberValue($1)); }
-  | common_values
-  ;
-
-// Specifies whether content of a block container element is clipped when it
-// overflows the element's box.
-//   https://www.w3.org/TR/CSS2/visufx.html#overflow
-overflow_property_value:
-    kHiddenToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetHidden().get());
-  }
-  | kVisibleToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetVisible().get());
-  }
-  | common_values
-  ;
-
-// Specifies whether the user agent may arbitrarily break within a word to
-// prevent overflow when an otherwise unbreakable string is too long to
-// fit within the line box.
-//   https://www.w3.org/TR/css-text-3/#overflow-wrap-property
-overflow_wrap_property_value:
-    kBreakWordToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetBreakWord().get());
-  }
-  | kNormalToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetNormal().get());
-  }
-  | common_values
-  ;
-
-// <padding-width> value type is the same as
-// positive_length_percent_property_value.
-//   https://www.w3.org/TR/CSS21/box.html#value-def-padding-width
-// Specifies the width of a top, right, bottom, or left side of the padding area
-// of a box.
-//   https://www.w3.org/TR/CSS21/box.html#padding-properties
-padding_side_property_value:
-    positive_length_percent_property_value
-  | common_values
-  ;
-
-// The "padding" property is a shorthand property for setting "padding-top",
-// "padding-right", "padding-bottom", and "padding-left" at the same place.
-//   https://www.w3.org/TR/CSS21/box.html#padding-properties
-padding_property_value:
-    // If there is only one component value, it applies to all sides.
-    positive_length_percent_property_value {
-    scoped_refptr<cssom::PropertyValue> width =
-        MakeScopedRefPtrAndRelease($1);
-    $$ = MarginOrPaddingShorthand::TryCreate(
-             width, width, width, width).release();
-  }
-    // If there are two values, the top and bottom paddings are set to the first
-    // value and the right and left paddings are set to the second.
-  | positive_length_percent_property_value
-    positive_length_percent_property_value {
-    scoped_refptr<cssom::PropertyValue> vertical_width =
-        MakeScopedRefPtrAndRelease($1);
-    scoped_refptr<cssom::PropertyValue> horizontal_width =
-        MakeScopedRefPtrAndRelease($2);
-    $$ = MarginOrPaddingShorthand::TryCreate(
-             vertical_width, horizontal_width,
-             vertical_width, horizontal_width).release();
-  }
-    // If there are three values, the top is set to the first value, the left
-    // and right are set to the second, and the bottom is set to the third.
-  | positive_length_percent_property_value
-    positive_length_percent_property_value
-    positive_length_percent_property_value {
-    scoped_refptr<cssom::PropertyValue> top_width =
-        MakeScopedRefPtrAndRelease($1);
-    scoped_refptr<cssom::PropertyValue> horizontal_width =
-        MakeScopedRefPtrAndRelease($2);
-    scoped_refptr<cssom::PropertyValue> bottom_width =
-        MakeScopedRefPtrAndRelease($3);
-    $$ = MarginOrPaddingShorthand::TryCreate(
-             top_width, horizontal_width,
-             bottom_width, horizontal_width).release();
-  }
-    // If there are four values, they apply to the top, right, bottom, and left,
-    // respectively.
-  | positive_length_percent_property_value
-    positive_length_percent_property_value
-    positive_length_percent_property_value
-    positive_length_percent_property_value {
-    scoped_refptr<cssom::PropertyValue> top_width =
-        MakeScopedRefPtrAndRelease($1);
-    scoped_refptr<cssom::PropertyValue> left_width =
-        MakeScopedRefPtrAndRelease($2);
-    scoped_refptr<cssom::PropertyValue> bottom_width =
-        MakeScopedRefPtrAndRelease($3);
-    scoped_refptr<cssom::PropertyValue> right_width =
-        MakeScopedRefPtrAndRelease($4);
-    $$ = MarginOrPaddingShorthand::TryCreate(
-             top_width, left_width, bottom_width, right_width).release();
-  }
-  | common_values {
-    $$ = MarginOrPaddingShorthand::TryCreate($1, $1, $1, $1).release();
-  }
-  ;
-
-// Used to control designation of elements by pointers.
-// While only defined in the SVG spec, the pointer-events property has been
-// proposed an commonly implemented to also apply to HTML elements for
-// values of 'none' (element can not be indicated by a pointer) and 'auto'
-// (element can be indicated by a pointer if the element has 'visibility' set
-// to 'visible').
-//   https://www.w3.org/TR/SVG11/interact.html#PointerEventsProperty
-pointer_events_property_value:
-    kAutoToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetAuto().get());
-  }
-  | kNoneToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetNone().get());
-  }
-  | common_values
-  ;
-
-// Determines which of the positioning algorithms is used to calculate
-// the position of a box.
-//   https://www.w3.org/TR/CSS21/visuren.html#choose-position
-position_property_value:
-    kAbsoluteToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetAbsolute().get());
-  }
-  | kFixedToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetFixed().get());
-  }
-  | kRelativeToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetRelative().get());
-  }
-  | kStaticToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetStatic().get());
-  }
-  | common_values
-  ;
-
-// If the second parameter is not provided, it takes a value equal to the first.
-//   https://www.w3.org/TR/css3-transforms/#funcdef-scale
-scale_function_parameters:
-    number {
-    $$ = new cssom::ScaleFunction($1, $1);
-  }
-  | number comma number {
-    $$ = new cssom::ScaleFunction($1, $3);
-  }
-  ;
-
-// This property describes how inline-level content of a block container is
-// aligned.
-//   https://www.w3.org/TR/css-text-3/#text-align
-text_align_property_value:
-    kEndToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetEnd().get());
-  }
-  | kLeftToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetLeft().get());
-  }
-  | kCenterToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetCenter().get());
-  }
-  | kRightToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetRight().get());
-  }
-  | kStartToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetStart().get());
-  }
-  | common_values
-  ;
-
-// This property specifies what line decorations.
-//   https://www.w3.org/TR/css-text-decor-3/#text-decoration-line
-text_decoration_line_property_value:
-    kNoneToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetNone().get());
-  }
-  | kLineThroughToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetLineThrough().get());
-  }
-  | common_values
-  ;
-
-// Text decoration is a shorthand for setting 'text-decoration-line',
-// 'text-decoration-color', and 'text-decoration-style' in one declaration.
-// TODO: Redirect text decoration to text decoration line for now and
-// change it when fully implement text decoration.
-//   https://www.w3.org/TR/css-text-decor-3/#text-decoration
-text_decoration_property_value: text_decoration_line_property_value;
-
-// This property specifies the indentation applied to lines of inline content in
-// a block.
-//   https://www.w3.org/TR/css-text-3/#text-indent
-text_indent_property_value:
-    length {
-    $$ = $1;
-  }
-  | common_values
-  ;
-
-// This property specifies rendering when inline content overflows its line box
-// edge in the inline progression direction of its block container element.
-//   https://www.w3.org/TR/css3-ui/#propdef-text-overflow
-text_overflow_property_value:
-    kClipToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetClip().get());
-  }
-  | kEllipsisToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetEllipsis().get());
-  }
-  | common_values
-  ;
-
-text_shadow_property_element:
-    length {
-    if ($<shadow_info>0->length_vector.size() == 2) {
-      scoped_refptr<cssom::LengthValue> length(MakeScopedRefPtrAndRelease($1));
-      // Negative values are not allowed for blur radius.
-      if (length && length->value() < 0) {
-        parser_impl->LogError(@1, "negative values of blur radius are illegal");
-        $<shadow_info>0->error = true;
-      }
-      $<shadow_info>0->length_vector.push_back(length);
-    } else {
-      $<shadow_info>0->length_vector.push_back(
-          MakeScopedRefPtrAndRelease($1));
-    }
-  }
-  | color {
-    scoped_refptr<cssom::RGBAColorValue> color(MakeScopedRefPtrAndRelease($1));
-    if (!$<shadow_info>0->color) {
-      $<shadow_info>0->color = color;
-    } else {
-      parser_impl->LogError(
-          @1, "color value declared twice in text shadow.");
-      $<shadow_info>0->error = true;
-    }
-  }
-  ;
-
-text_shadow_list:
-    /* empty */ {
-    $$ = new ShadowPropertyInfo();
-  }
-  | text_shadow_list text_shadow_property_element {
-    $$ = $1;
-  }
-  ;
-
-validated_text_shadow_list:
-    text_shadow_list {
-    scoped_ptr<ShadowPropertyInfo> shadow_property_info($1);
-    if (!shadow_property_info->IsShadowPropertyValid(kTextShadow)) {
-      parser_impl->LogWarning(@1, "invalid text shadow property.");
-      $$ = NULL;
-    } else {
-      $$ = AddRef(new cssom::ShadowValue(
-              shadow_property_info->length_vector, shadow_property_info->color,
-              false));
-    }
-  }
-  ;
-
-comma_separated_text_shadow_list:
-    validated_text_shadow_list {
-    if ($1) {
-      $$ = new cssom::PropertyListValue::Builder();
-      $$->push_back(MakeScopedRefPtrAndRelease($1));
-    }
-  }
-  | comma_separated_text_shadow_list comma validated_text_shadow_list {
-    $$ = $1;
-    if ($$ && $3) {
-      $$->push_back(MakeScopedRefPtrAndRelease($3));
-    }
-  }
-  ;
-
-// This property accepts a comma-separated list of shadow effects to be applied
-// to the text of the element.
-//   https://www.w3.org/TR/css-text-decor-3/#text-shadow-property
-text_shadow_property_value:
-    comma_separated_text_shadow_list {
-    if ($1) {
-      scoped_ptr<cssom::PropertyListValue::Builder> property_value($1);
-      $$ = AddRef(new cssom::PropertyListValue(property_value.Pass()));
-    }
-  }
-  | kNoneToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetNone().get());
-  }
-  | common_values
-  ;
-
-// This property controls capitalization effects of an element's text.
-//   https://www.w3.org/TR/css3-text/#text-transform-property
-text_transform_property_value:
-    kNoneToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetNone().get());
-  }
-  | kUppercaseToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetUppercase().get());
-  }
-  | common_values
-  ;
-
-// The set of allowed transform functions.
-//   https://www.w3.org/TR/css3-transforms/#transform-functions
-transform_function:
-  // Specifies an arbitrary affine 2D transformation.
-    kMatrixFunctionToken maybe_whitespace number comma number comma number
-      comma number comma number comma number ')' maybe_whitespace {
-    $<transform_functions>0->push_back(
-        new cssom::MatrixFunction($3, $5, $7, $9, $11, $13));
-  }
-  // Specifies a 2D rotation around the z-axis.
-  //   https://www.w3.org/TR/css3-transforms/#funcdef-rotate
-  | kRotateFunctionToken maybe_whitespace angle ')'
-      maybe_whitespace {
-    $<transform_functions>0->push_back(new cssom::RotateFunction($3));
-  }
-  // Specifies a 2D scale operation by the scaling vector.
-  //   https://www.w3.org/TR/css3-transforms/#funcdef-scale
-  | kScaleFunctionToken maybe_whitespace scale_function_parameters ')'
-      maybe_whitespace {
-    $<transform_functions>0->push_back($3);
-  }
-  // Specifies a 2D scale operation using the [sx, 1] scaling vector, where sx
-  // is given as the parameter.
-  //   https://www.w3.org/TR/css3-transforms/#funcdef-scalex
-  | kScaleXFunctionToken maybe_whitespace number ')'
-      maybe_whitespace {
-    $<transform_functions>0->push_back(new cssom::ScaleFunction($3, 1.0f));
-  }
-  // Specifies a 2D scale operation using the [1, sy] scaling vector, where sy
-  // is given as the parameter.
-  //   https://www.w3.org/TR/css3-transforms/#funcdef-scaley
-  | kScaleYFunctionToken maybe_whitespace number ')'
-      maybe_whitespace {
-    $<transform_functions>0->push_back(new cssom::ScaleFunction(1.0f, $3));
-  }
-  // Specifies a 2D translation by the vector [tx, ty], where tx is the first
-  // translation-value parameter and ty is the optional second translation-value
-  // parameter. If <ty> is not provided, ty has zero as a value.
-  //   https://www.w3.org/TR/css3-transforms/#funcdef-translate
-  | kTranslateFunctionToken maybe_whitespace length_percent_property_value ')'
-      maybe_whitespace {
-    if ($3) {
-      $<transform_functions>0->push_back(new cssom::TranslateFunction(
-          cssom::TranslateFunction::kXAxis, MakeScopedRefPtrAndRelease($3)));
-      $<transform_functions>0->push_back(new cssom::TranslateFunction(
-          cssom::TranslateFunction::kYAxis,
-          scoped_refptr<cssom::LengthValue>(
-              new cssom::LengthValue(0, cssom::kPixelsUnit))));
-    }
-  }
-  | kTranslateFunctionToken maybe_whitespace length_percent_property_value comma
-    length_percent_property_value ')' maybe_whitespace {
-    if ($3 && $5) {
-      $<transform_functions>0->push_back(new cssom::TranslateFunction(
-          cssom::TranslateFunction::kXAxis, MakeScopedRefPtrAndRelease($3)));
-      $<transform_functions>0->push_back(new cssom::TranslateFunction(
-          cssom::TranslateFunction::kYAxis, MakeScopedRefPtrAndRelease($5)));
-    }
-  }
-  // Specifies a translation by the given amount in the X direction.
-  //   https://www.w3.org/TR/css3-transforms/#funcdef-translatex
-  | kTranslateXFunctionToken maybe_whitespace length_percent_property_value ')'
-      maybe_whitespace {
-    if ($3) {
-      $<transform_functions>0->push_back(new cssom::TranslateFunction(
-          cssom::TranslateFunction::kXAxis, MakeScopedRefPtrAndRelease($3)));
-    }
-  }
-  // Specifies a translation by the given amount in the Y direction.
-  //   https://www.w3.org/TR/css3-transforms/#funcdef-translatey
-  | kTranslateYFunctionToken maybe_whitespace length_percent_property_value ')'
-      maybe_whitespace {
-    if ($3) {
-      $<transform_functions>0->push_back(new cssom::TranslateFunction(
-          cssom::TranslateFunction::kYAxis, MakeScopedRefPtrAndRelease($3)));
-    }
-  }
-  // Specifies a 3D translation by the vector [0,0,z] with the given amount
-  // in the Z direction.
-  //   https://www.w3.org/TR/css3-transforms/#funcdef-translatez
-  | kTranslateZFunctionToken maybe_whitespace length ')'
-      maybe_whitespace {
-    if ($3) {
-      $<transform_functions>0->push_back(new cssom::TranslateFunction(
-          cssom::TranslateFunction::kZAxis, MakeScopedRefPtrAndRelease($3)));
-    }
-  }
-  ;
-
-// One or more transform functions separated by whitespace.
-//   https://www.w3.org/TR/css3-transforms/#typedef-transform-list
-transform_list:
-    /* empty */ {
-    $$ = new cssom::TransformFunctionListValue::Builder();
-  }
-  | transform_list transform_function {
-    $$ = $1;
-  }
-  ;
-
-// A transformation that is applied to the coordinate system an element
-// renders in.
-//   https://www.w3.org/TR/css3-transforms/#transform-property
-transform_property_value:
-    kNoneToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetNone().get());
-  }
-  | transform_list {
-    scoped_ptr<cssom::TransformFunctionListValue::Builder>
-        transform_functions($1);
-    $$ = transform_functions->size() == 0u ? NULL :
-            AddRef(new cssom::TransformFunctionListValue(
-                transform_functions->Pass()));
-  }
-  | transform_list errors {
-    scoped_ptr<cssom::TransformFunctionListValue::Builder>
-        transform_functions($1);
-    parser_impl->LogWarning(@2, "invalid transform function");
-    $$ = NULL;
-  }
-  | common_values_without_errors
-  ;
-
-validated_two_position_list_elements:
-    position_list_element position_list_element {
-    scoped_ptr<PositionParseStructure> position_info(
-        new PositionParseStructure());
-    position_info->PushBackElement(MakeScopedRefPtrAndRelease($1));
-    if (position_info->PushBackElement(MakeScopedRefPtrAndRelease($2)) &&
-        position_info->IsPositionValidOnSizeTwo()) {
-      $$ = new cssom::PropertyListValue::Builder(
-              position_info->position_builder());
-    } else {
-      parser_impl->LogWarning(@2, "invalid transform-origin value");
-      $$ = NULL;
-    }
-  }
-  ;
-
-// The transform-origin property lets you modify the origin for transformations
-// of an element.
-//   https://www.w3.org/TR/css3-transforms/#propdef-transform-origin
-transform_origin_property_value:
-    position_list_element {
-    scoped_ptr<cssom::PropertyListValue::Builder> property_value(
-        new cssom::PropertyListValue::Builder());
-    property_value->push_back(MakeScopedRefPtrAndRelease($1));
-    $$ = AddRef(new cssom::PropertyListValue(property_value.Pass()));
-  }
-  | validated_two_position_list_elements {
-    scoped_ptr<cssom::PropertyListValue::Builder> property_value($1);
-    $$ = property_value
-         ? AddRef(new cssom::PropertyListValue(property_value.Pass()))
-         : NULL;
-  }
-  | validated_two_position_list_elements length {
-    scoped_ptr<cssom::PropertyListValue::Builder> property_value($1);
-    if (property_value) {
-      property_value->push_back(MakeScopedRefPtrAndRelease($2));
-      $$ = AddRef(new cssom::PropertyListValue(property_value.Pass()));
-    } else {
-      $$ = NULL;
-    }
-  }
-  | common_values
-  ;
-
-// Determines the vertical alignment of a box.
-//   https://www.w3.org/TR/CSS21/visudet.html#propdef-vertical-align
-vertical_align_property_value:
-    kBottomToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetBottom().get());
-  }
-  | kTopToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetTop().get());
-  }
-  | kMiddleToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetMiddle().get());
-  }
-  | kBaselineToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetBaseline().get());
-  }
-  | common_values
-  ;
-
-// The 'visibility' property specifies whether the boxes generated by an element
-// are rendered.
-//   https://www.w3.org/TR/CSS21/visufx.html#propdef-visibility
-visibility_property_value:
-    kHiddenToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetHidden().get());
-  }
-  | kVisibleToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetVisible().get());
-  }
-  | common_values
-  ;
-
-// One ore more time values separated by commas.
-comma_separated_time_list:
-    time {
-    $$ = new cssom::TimeListValue::Builder();
-    $$->push_back(base::TimeDelta::FromInternalValue($1));
-  }
-  | comma_separated_time_list comma time {
-    $$ = $1;
-    $$->push_back(base::TimeDelta::FromInternalValue($3));
-  }
-  ;
-
-time_list_property_value:
-    comma_separated_time_list {
-    scoped_ptr<cssom::ListValue<base::TimeDelta>::Builder> time_list($1);
-    $$ = time_list
-         ? AddRef(new cssom::TimeListValue(time_list.Pass()))
-         : NULL;
-  }
-  | common_values
-  ;
-
-
-maybe_steps_start_or_end_parameter:
-    /* empty */ {
-    // Default value is 'end'.
-    $$ = cssom::SteppingTimingFunction::kEnd;
-  }
-  | comma kStartToken maybe_whitespace {
-    $$ = cssom::SteppingTimingFunction::kStart;
-  }
-  | comma kEndToken maybe_whitespace {
-    $$ = cssom::SteppingTimingFunction::kEnd;
-  }
-  ;
-
-single_timing_function:
-    kCubicBezierFunctionToken maybe_whitespace
-    number comma number comma number comma number ')' {
-    float p1_x = $3;
-    float p1_y = $5;
-    float p2_x = $7;
-    float p2_y = $9;
-
-    if (p1_x < 0 || p1_x > 1 || p2_x < 0 || p2_x > 1) {
-      parser_impl->LogError(
-          @1,
-          "cubic-bezier control point x values must be in the range [0, 1].");
-      // In the case of an error, return the ease function as a default.
-      $$ = AddRef(cssom::TimingFunction::GetEase().get());
-    } else {
-      $$ = AddRef(new cssom::CubicBezierTimingFunction(p1_x, p1_y, p2_x, p2_y));
-    }
-  }
-  | kStepsFunctionToken maybe_whitespace kIntegerToken maybe_whitespace
-    maybe_steps_start_or_end_parameter ')' {
-    int number_of_steps = $3;
-    if (number_of_steps <= 0) {
-      parser_impl->LogError(
-          @1,
-          "The steps() number of steps parameter must be greater than 0.");
-      number_of_steps = 1;
-    }
-    $$ = AddRef(new cssom::SteppingTimingFunction(number_of_steps, $5));
-  }
-  | kEaseInOutToken {
-    $$ = AddRef(cssom::TimingFunction::GetEaseInOut().get());
-  }
-  | kEaseInToken {
-    $$ = AddRef(cssom::TimingFunction::GetEaseIn().get());
-  }
-  | kEaseOutToken {
-    $$ = AddRef(cssom::TimingFunction::GetEaseOut().get());
-  }
-  | kEaseToken {
-    $$ = AddRef(cssom::TimingFunction::GetEase().get());
-  }
-  | kLinearToken {
-    $$ = AddRef(cssom::TimingFunction::GetLinear().get());
-  }
-  | kStepEndToken {
-    $$ = AddRef(cssom::TimingFunction::GetStepEnd().get());
-  }
-  | kStepStartToken {
-    $$ = AddRef(cssom::TimingFunction::GetStepStart().get());
-  }
-  ;
-
-comma_separated_single_timing_function_list:
-    single_timing_function {
-    $$ = new cssom::TimingFunctionListValue::Builder();
-    $$->push_back(MakeScopedRefPtrAndRelease($1));
-  }
-  | comma_separated_single_timing_function_list comma
-    single_timing_function {
-    $$ = $1;
-    $$->push_back(MakeScopedRefPtrAndRelease($3));
-  }
-  ;
-
-timing_function_list_property_value:
-    comma_separated_single_timing_function_list {
-    scoped_ptr<cssom::TimingFunctionListValue::Builder>
-        timing_function_list($1);
-    $$ = timing_function_list
-         ? AddRef(new cssom::TimingFunctionListValue(
-               timing_function_list.Pass()))
-         : NULL;
-  }
-  | common_values
-  ;
-
-// The 'animation-delay' property defines when the animation will start.
-//  https://www.w3.org/TR/2013/WD-css3-animations-20130219/#animation-delay-property
-animation_delay_property_value: time_list_property_value;
-
-// The 'animation-direction' property defines which direction time should flow
-// given the current iteration number.
-//  https://www.w3.org/TR/2013/WD-css3-animations-20130219/#animation-direction-property
-animation_direction_list_element:
-    kNormalToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetNormal().get());
-  }
-  | kReverseToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetReverse().get());
-  }
-  | kAlternateToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetAlternate().get());
-  }
-  | kAlternateReverseToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetAlternateReverse().get());
-  }
-  ;
-
-comma_separated_animation_direction_list:
-    animation_direction_list_element {
-    $$ = new cssom::PropertyListValue::Builder();
-    $$->push_back(MakeScopedRefPtrAndRelease($1));
-  }
-  | comma_separated_animation_direction_list comma
-        animation_direction_list_element {
-    $$ = $1;
-    $$->push_back(MakeScopedRefPtrAndRelease($3));
-  }
-  ;
-
-animation_direction_property_value:
-    comma_separated_animation_direction_list {
-    scoped_ptr<cssom::PropertyListValue::Builder> direction_list($1);
-    $$ = direction_list
-         ? AddRef(new cssom::PropertyListValue(direction_list.Pass()))
-         : NULL;
-  }
-  | common_values_without_errors
-  | errors {
-    parser_impl->LogError(
-        @1, "unsupported property value for animation-direction");
-    $$ = NULL;
-  }
-  ;
-
-// The 'animation-duration' property defines the length of time that an
-// animation takes to complete one cycle.
-//  https://www.w3.org/TR/2013/WD-css3-animations-20130219/#animation-duration-property
-animation_duration_property_value: time_list_property_value;
-
-// The 'animation-fill-mode' property defines what values are applied by the
-// animation outside the time it is executing.
-//  https://www.w3.org/TR/2013/WD-css3-animations-20130219/#animation-fill-mode-property
-animation_fill_mode_list_element:
-    kNoneToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetNone().get());
-  }
-  | kForwardsToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetForwards().get());
-  }
-  | kBackwardsToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetBackwards().get());
-  }
-  | kBothToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetBoth().get());
-  }
-  ;
-
-comma_separated_animation_fill_mode_list:
-    animation_fill_mode_list_element {
-    $$ = new cssom::PropertyListValue::Builder();
-    $$->push_back(MakeScopedRefPtrAndRelease($1));
-  }
-  | comma_separated_animation_fill_mode_list comma
-        animation_fill_mode_list_element {
-    $$ = $1;
-    $$->push_back(MakeScopedRefPtrAndRelease($3));
-  }
-  ;
-
-animation_fill_mode_property_value:
-    comma_separated_animation_fill_mode_list {
-    scoped_ptr<cssom::PropertyListValue::Builder> fill_mode_list($1);
-    $$ = fill_mode_list
-         ? AddRef(new cssom::PropertyListValue(fill_mode_list.Pass()))
-         : NULL;
-  }
-  | common_values_without_errors
-  | errors {
-    parser_impl->LogError(
-        @1, "unsupported property value for animation-fill-mode");
-    $$ = NULL;
-  }
-  ;
-
-// The 'animation-iteration-count' property specifies the number of times an
-// animation cycle is played.
-//  https://www.w3.org/TR/2013/WD-css3-animations-20130219/#animation-iteration-count-property
-animation_iteration_count_list_element:
-    kInfiniteToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetInfinite().get());
-  }
-  | non_negative_number {
-    $$ = AddRef(new cssom::NumberValue($1));
-  }
-  ;
-
-comma_separated_animation_iteration_count_list:
-    animation_iteration_count_list_element {
-    $$ = new cssom::PropertyListValue::Builder();
-    $$->push_back(MakeScopedRefPtrAndRelease($1));
-  }
-  | comma_separated_animation_iteration_count_list comma
-        animation_iteration_count_list_element {
-    $$ = $1;
-    $$->push_back(MakeScopedRefPtrAndRelease($3));
-  }
-  ;
-
-animation_iteration_count_property_value:
-    comma_separated_animation_iteration_count_list {
-    scoped_ptr<cssom::PropertyListValue::Builder> iteration_count_list($1);
-    $$ = iteration_count_list
-         ? AddRef(new cssom::PropertyListValue(iteration_count_list.Pass()))
-         : NULL;
-  }
-  | common_values_without_errors
-  | errors {
-    parser_impl->LogError(
-        @1, "unsupported property value for animation-iteration-count");
-    $$ = NULL;
-  }
-  ;
-
-// The 'animation-name' property defines a list of animations that apply.
-//  https://www.w3.org/TR/2013/WD-css3-animations-20130219/#animation-name-property
-animation_name_list_element:
-    kNoneToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetNone().get());
-  }
-  | kIdentifierToken maybe_whitespace {
-    $$ = AddRef(new cssom::StringValue($1.ToString()));
-  }
-  ;
-
-comma_separated_animation_name_list:
-    animation_name_list_element {
-    $$ = new cssom::PropertyListValue::Builder();
-    $$->push_back(MakeScopedRefPtrAndRelease($1));
-  }
-  | comma_separated_animation_name_list comma
-        animation_name_list_element {
-    $$ = $1;
-    $$->push_back(MakeScopedRefPtrAndRelease($3));
-  }
-  ;
-
-animation_name_property_value:
-    comma_separated_animation_name_list {
-    scoped_ptr<cssom::PropertyListValue::Builder> name_list($1);
-    $$ = name_list
-         ? AddRef(new cssom::PropertyListValue(name_list.Pass()))
-         : NULL;
-  }
-  | common_values_without_errors
-  | errors {
-    parser_impl->LogError(
-        @1, "unsupported property value for animation-name");
-    $$ = NULL;
-  }
-  ;
-
-// The 'animation-timing-function' property describes how the animation will
-// progress over one cycle of its duration.
-//  https://www.w3.org/TR/2013/WD-css3-animations-20130219/#animation-timing-function-property
-animation_timing_function_property_value: timing_function_list_property_value;
-
-// single_animation_element represents a component of a single animation.
-// It uses $0 to access its parent's SingleAnimationShorthand object and build
-// it, so it should always be used to the right of a single_animation object.
-single_animation_element:
-    kIdentifierToken maybe_whitespace {
-    if (!$<single_animation>0->name) {
-      $<single_animation>0->name = new cssom::StringValue($1.ToString());
-    } else {
-      parser_impl->LogWarning(
-          @1, "animation-name value declared twice in animation.");
-    }
-  }
-  | animation_direction_list_element {
-    if (!$<single_animation>0->direction) {
-      $<single_animation>0->direction = MakeScopedRefPtrAndRelease($1);
-    } else {
-      parser_impl->LogWarning(
-          @1, "animation-direction value declared twice in animation.");
-    }
-  }
-  | animation_fill_mode_list_element {
-    if (!$<single_animation>0->fill_mode) {
-      $<single_animation>0->fill_mode = MakeScopedRefPtrAndRelease($1);
-    } else {
-      parser_impl->LogWarning(
-          @1, "animation-fill-mode value declared twice in animation.");
-    }
-  }
-  | animation_iteration_count_list_element {
-    if (!$<single_animation>0->iteration_count) {
-      $<single_animation>0->iteration_count = MakeScopedRefPtrAndRelease($1);
-    } else {
-      parser_impl->LogWarning(
-          @1, "animation-iteration-count value declared twice in animation.");
-    }
-  }
-  | time_with_units_required {
-    if (!$<single_animation>0->duration) {
-      // The first time encountered sets the duration.
-      $<single_animation>0->duration = base::TimeDelta::FromInternalValue($1);
-    } else if (!$<single_animation>0->delay) {
-      // The second time encountered sets the delay.
-      $<single_animation>0->delay = base::TimeDelta::FromInternalValue($1);
-    } else {
-      parser_impl->LogWarning(
-          @1, "time value declared too many times in animation.");
-    }
-  }
-  | single_timing_function maybe_whitespace {
-    if (!$<single_animation>0->timing_function) {
-      $<single_animation>0->timing_function = MakeScopedRefPtrAndRelease($1);
-    } else {
-      parser_impl->LogWarning(
-          @1, "animation-timing-function value declared twice in animation.");
-    }
-  }
-  | error maybe_whitespace {
-    parser_impl->LogError(@1, "unsupported property value for animation");
-    $<single_animation>0->error = true;
-  }
-  ;
-
-single_animation:
-    /* empty */ {
-    // Initialize the result, to be filled in by single_animation_element
-    $$ = new SingleAnimationShorthand();
-  }
-  | single_non_empty_animation
-  ;
-
-single_non_empty_animation:
-    single_animation single_animation_element {
-    // Propagate the list from our parent single_animation.
-    // single_animation_element will have already taken care of adding itself
-    // to the list via $0.
-    $$ = $1;
-  }
-  ;
-
-comma_separated_animation_list:
-    single_non_empty_animation {
-    scoped_ptr<SingleAnimationShorthand> single_animation($1);
-    scoped_ptr<AnimationShorthandBuilder> animation_builder(
-        new AnimationShorthandBuilder());
-
-    if (!single_animation->error) {
-      single_animation->ReplaceNullWithInitialValues();
-
-      animation_builder->delay_list_builder->push_back(
-          *single_animation->delay);
-      animation_builder->direction_list_builder->push_back(
-          single_animation->direction);
-      animation_builder->duration_list_builder->push_back(
-          *single_animation->duration);
-      animation_builder->fill_mode_list_builder->push_back(
-          single_animation->fill_mode);
-      animation_builder->iteration_count_list_builder->push_back(
-          single_animation->iteration_count);
-      animation_builder->name_list_builder->push_back(
-          single_animation->name);
-      animation_builder->timing_function_list_builder->push_back(
-          single_animation->timing_function);
-    }
-
-    $$ = animation_builder.release();
-  }
-  | comma_separated_animation_list comma single_non_empty_animation {
-    scoped_ptr<SingleAnimationShorthand> single_animation($3);
-    $$ = $1;
-
-    if (!single_animation->error) {
-      single_animation->ReplaceNullWithInitialValues();
-
-      $$->delay_list_builder->push_back(*single_animation->delay);
-      $$->direction_list_builder->push_back(single_animation->direction);
-      $$->duration_list_builder->push_back(*single_animation->duration);
-      $$->fill_mode_list_builder->push_back(single_animation->fill_mode);
-      $$->iteration_count_list_builder->push_back(
-          single_animation->iteration_count);
-      $$->name_list_builder->push_back(single_animation->name);
-      $$->timing_function_list_builder->push_back(
-          single_animation->timing_function);
-    }
-  }
-  ;
-
-// Animation shorthand property.
-//   https://www.w3.org/TR/2013/WD-css3-animations-20130219/#animation-shorthand-property
-animation_property_value:
-    comma_separated_animation_list {
-    scoped_ptr<AnimationShorthandBuilder> animation_builder($1);
-
-    if (animation_builder->empty()) {
-      YYERROR;
-    }
-
-    scoped_ptr<AnimationShorthand> animation(new AnimationShorthand());
-
-    animation->delay_list = new cssom::TimeListValue(
-        animation_builder->delay_list_builder.Pass());
-    animation->direction_list = new cssom::PropertyListValue(
-        animation_builder->direction_list_builder.Pass());
-    animation->duration_list = new cssom::TimeListValue(
-        animation_builder->duration_list_builder.Pass());
-    animation->fill_mode_list = new cssom::PropertyListValue(
-        animation_builder->fill_mode_list_builder.Pass());
-    animation->iteration_count_list = new cssom::PropertyListValue(
-        animation_builder->iteration_count_list_builder.Pass());
-    animation->name_list = new cssom::PropertyListValue(
-        animation_builder->name_list_builder.Pass());
-    animation->timing_function_list = new cssom::TimingFunctionListValue(
-        animation_builder->timing_function_list_builder.Pass());
-
-    $$ = animation.release();
-  }
-  | common_values_without_errors {
-    // Replicate the common value into each of the properties that animation
-    // is a shorthand for.
-    scoped_ptr<AnimationShorthand> animation(new AnimationShorthand());
-    animation->delay_list = $1;
-    animation->direction_list = $1;
-    animation->duration_list = $1;
-    animation->fill_mode_list = $1;
-    animation->iteration_count_list = $1;
-    animation->name_list = $1;
-    animation->timing_function_list = $1;
-    $$ = animation.release();
-  }
-  ;
-
-// Parse a list of time values for transition-delay.
-//   https://www.w3.org/TR/css3-transitions/#transition-delay
-transition_delay_property_value: time_list_property_value;
-
-// Parse a list of time values for transition-duration.
-//   https://www.w3.org/TR/css3-transitions/#transition-duration
-transition_duration_property_value: time_list_property_value;
-
-// Parse a list of timing function values for transition-timing-function.
-//   https://www.w3.org/TR/css3-transitions/#transition-timing-function-property
-transition_timing_function_property_value: timing_function_list_property_value;
-
-// One or more property names separated by commas.
-//   https://www.w3.org/TR/css3-transitions/#transition-property
-comma_separated_animatable_property_name_list:
-    animatable_property_token maybe_whitespace {
-    $$ = new cssom::PropertyKeyListValue::Builder();
-    $$->push_back($1);
-  }
-  | comma_separated_animatable_property_name_list comma
-    animatable_property_token maybe_whitespace {
-    scoped_ptr<cssom::PropertyKeyListValue::Builder> property_name_list($1);
-    if (property_name_list) {
-      property_name_list->push_back($3);
-    }
-    $$ = property_name_list.release();
-  }
-  | errors {
-    parser_impl->LogError(@1, "unsupported property value for animation");
-    $$ = NULL;
-  }
-  ;
-
-// Parse a list of references to property names.
-//   https://www.w3.org/TR/css3-transitions/#transition-property
-transition_property_property_value:
-    kNoneToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetNone().get());
-  }
-  | comma_separated_animatable_property_name_list {
-    scoped_ptr<cssom::PropertyKeyListValue::Builder> property_name_list($1);
-    $$ = property_name_list
-         ? AddRef(new cssom::PropertyKeyListValue(property_name_list.Pass()))
-         : NULL;
-  }
-  | common_values_without_errors
-  ;
-
-// single_transition_element represents a component of a single transition.
-// It uses $0 to access its parent's SingleTransitionShorthand object and build
-// it, so it should always be used to the right of a single_transition object.
-single_transition_element:
-    animatable_property_token maybe_whitespace {
-    if (!$<single_transition>0->property) {
-      $<single_transition>0->property = $1;
-    } else {
-      parser_impl->LogWarning(
-          @1, "transition-property value declared twice in transition.");
-    }
-  }
-  | kNoneToken maybe_whitespace {
-    if (!$<single_transition>0->property) {
-      // We use cssom::kNoneProperty as a symbol that 'none' was specified
-      // here and that the entire transition-property list value should be set
-      // to the None keyword.
-      $<single_transition>0->property = cssom::kNoneProperty;
-    } else {
-      parser_impl->LogWarning(
-          @1, "transition-property value declared twice in transition.");
-    }
-  }
-  | time {
-    if (!$<single_transition>0->duration) {
-      // The first time encountered sets the duration.
-      $<single_transition>0->duration = base::TimeDelta::FromInternalValue($1);
-    } else if (!$<single_transition>0->delay) {
-      // The second time encountered sets the delay.
-      $<single_transition>0->delay = base::TimeDelta::FromInternalValue($1);
-    } else {
-      parser_impl->LogWarning(
-          @1, "time value declared twice in transition.");
-    }
-  }
-  | single_timing_function maybe_whitespace {
-    if (!$<single_transition>0->timing_function) {
-      $<single_transition>0->timing_function = MakeScopedRefPtrAndRelease($1);
-    } else {
-      parser_impl->LogWarning(
-          @1, "transition-timing-function value declared twice in transition.");
-    }
-  }
-  | error maybe_whitespace {
-    parser_impl->LogError(@1, "unsupported property value for animation");
-    $<single_transition>0->error = true;
-  }
-  ;
-
-single_transition:
-    /* empty */ {
-    // Initialize the result, to be filled in by single_transition_element
-    $$ = new SingleTransitionShorthand();
-  }
-  | single_non_empty_transition
-  ;
-
-single_non_empty_transition:
-    single_transition single_transition_element {
-    // Propagate the list from our parent single_transition.
-    // single_transition_element will have already taken care of adding itself
-    // to the list via $0.
-    $$ = $1;
-  }
-  ;
-
-comma_separated_transition_list:
-    single_non_empty_transition {
-    scoped_ptr<SingleTransitionShorthand> single_transition($1);
-    scoped_ptr<TransitionShorthandBuilder> transition_builder(
-        new TransitionShorthandBuilder());
-
-    if (!single_transition->error) {
-      single_transition->ReplaceNullWithInitialValues();
-
-      transition_builder->property_list_builder->push_back(
-          *single_transition->property);
-      transition_builder->duration_list_builder->push_back(
-          *single_transition->duration);
-      transition_builder->timing_function_list_builder->push_back(
-          single_transition->timing_function);
-      transition_builder->delay_list_builder->push_back(
-          *single_transition->delay);
-    }
-
-    $$ = transition_builder.release();
-  }
-  | comma_separated_transition_list comma single_non_empty_transition {
-    scoped_ptr<SingleTransitionShorthand> single_transition($3);
-    $$ = $1;
-
-    if (!single_transition->error) {
-      single_transition->ReplaceNullWithInitialValues();
-
-      $$->property_list_builder->push_back(*single_transition->property);
-      $$->duration_list_builder->push_back(*single_transition->duration);
-      $$->timing_function_list_builder->push_back(
-          single_transition->timing_function);
-      $$->delay_list_builder->push_back(*single_transition->delay);
-    }
-  }
-  ;
-
-// Transition shorthand property.
-//   https://www.w3.org/TR/css3-transitions/#transition
-transition_property_value:
-    comma_separated_transition_list {
-    scoped_ptr<TransitionShorthandBuilder> transition_builder($1);
-
-    // Before proceeding, check that 'none' is not specified if the
-    // number of transition statements is larger than 1, as per the
-    // specification.
-    const cssom::PropertyKeyListValue::Builder& property_list_builder =
-        *(transition_builder->property_list_builder);
-    if (property_list_builder.size() > 1) {
-      for (int i = 0; i < static_cast<int>(property_list_builder.size()); ++i) {
-        if (property_list_builder[i] == cssom::kNoneProperty) {
-          parser_impl->LogWarning(
-              @1, "If 'none' is specified, transition can only have one item.");
-          break;
-        }
-      }
-    }
-
-    scoped_ptr<TransitionShorthand> transition(new TransitionShorthand());
-
-    if (property_list_builder.empty() ||
-        (property_list_builder.size() == 1 &&
-         property_list_builder[0] == cssom::kNoneProperty)) {
-      transition->property_list = cssom::KeywordValue::GetNone();
-    } else {
-      transition->property_list = new cssom::PropertyKeyListValue(
-          transition_builder->property_list_builder.Pass());
-    }
-    if (!transition_builder->duration_list_builder->empty()) {
-      transition->duration_list = new cssom::TimeListValue(
-          transition_builder->duration_list_builder.Pass());
-    }
-    if (!transition_builder->timing_function_list_builder->empty()) {
-      transition->timing_function_list = new cssom::TimingFunctionListValue(
-          transition_builder->timing_function_list_builder.Pass());
-    }
-    if (!transition_builder->delay_list_builder->empty()) {
-      transition->delay_list = new cssom::TimeListValue(
-          transition_builder->delay_list_builder.Pass());
-    }
-
-    $$ = transition.release();
-  }
-  | common_values_without_errors {
-    // Replicate the common value into each of the properties that transition
-    // is a shorthand for.
-    scoped_ptr<TransitionShorthand> transition(new TransitionShorthand());
-    transition->property_list = $1;
-    transition->duration_list = $1;
-    transition->timing_function_list = $1;
-    transition->delay_list = $1;
-    $$ = transition.release();
-  }
-  ;
-
-unicode_range_property_value:
-    comma_separated_unicode_range_list {
-    scoped_ptr<cssom::PropertyListValue::Builder> property_value($1);
-    $$ = property_value
-         ? AddRef(new cssom::PropertyListValue(property_value.Pass()))
-         : NULL;
-  }
-  | common_values
-  ;
-
-comma_separated_unicode_range_list:
-    kUnicodeRangeToken maybe_whitespace {
-    $$ = new cssom::PropertyListValue::Builder();
-    $$->push_back(new cssom::UnicodeRangeValue($1.first, $1.second));
-  }
-  | comma_separated_unicode_range_list comma kUnicodeRangeToken
-        maybe_whitespace {
-    $$ = $1;
-    $$->push_back(new cssom::UnicodeRangeValue($3.first, $3.second));
-  }
-  ;
-
-// This property declares how white space inside the element is handled.
-//   https://www.w3.org/TR/css3-text/#white-space-property
-white_space_property_value:
-    kNormalToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetNormal().get());
-  }
-  | kNoWrapToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetNoWrap().get());
-  }
-  | kPreToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetPre().get());
-  }
-  | kPreLineToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetPreLine().get());
-  }
-  | kPreWrapToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetPreWrap().get());
-  }
-  | common_values
-  ;
-
-// Specifies the content width of boxes.
-//   https://www.w3.org/TR/CSS21/visudet.html#the-width-property
-width_property_value:
-    positive_length_percent_property_value
-  | auto
-  | common_values
-  ;
-
-// Specifies the minimum content width of boxes.
-//   https://www.w3.org/TR/CSS2/visudet.html#propdef-min-width
-min_width_property_value:
-    positive_length_percent_property_value
-  | common_values
-  ;
-
-// Specifies the maximum content width of boxes.
-//   https://www.w3.org/TR/CSS2/visudet.html#propdef-max-width
-max_width_property_value:
-    kNoneToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetNone().get());
-  }
-  | positive_length_percent_property_value
-  | common_values
-  ;
-
-maybe_important:
-    /* empty */ { $$ = false; }
-  | kImportantToken maybe_whitespace { $$ = true; }
-  ;
-
-z_index_property_value:
-  integer {
-    $$ = AddRef(new cssom::IntegerValue($1));
-  }
-  | auto
-  | common_values
-  ;
-
-// ...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:.
-// Animatable properties.
-// ...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:.
-
-// Some property name identifiers can be specified as animations, either by
-// CSS animations or CSS transitions.  We explicitly list them here for use
-// in animatable property lists.
-// Note that for Cobalt we modify this list to contain only the properties that
-// are supported for animations in Cobalt.
-//   https://www.w3.org/TR/css3-transitions/#animatable-css
-animatable_property_token:
-    kAllToken {
-    $$ = cssom::kAllProperty;
-  }
-  | kBackgroundColorToken {
-    $$ = cssom::kBackgroundColorProperty;
-  }
-  | kBorderBottomColorToken {
-    $$ = cssom::kBorderBottomColorProperty;
-  }
-  | kBorderLeftColorToken {
-    $$ = cssom::kBorderLeftColorProperty;
-  }
-  | kBorderRightColorToken {
-    $$ = cssom::kBorderRightColorProperty;
-  }
-  | kBorderTopColorToken {
-    $$ = cssom::kBorderTopColorProperty;
-  }
-  | kColorToken {
-    $$ = cssom::kColorProperty;
-  }
-  | kOpacityToken {
-    $$ = cssom::kOpacityProperty;
-  }
-  | kOutlineColorToken {
-    $$ = cssom::kOutlineColorProperty;
-  }
-  | kOutlineWidthToken {
-    $$ = cssom::kOutlineWidthProperty;
-  }
-  | kTransformToken {
-    $$ = cssom::kTransformProperty;
-  }
-  ;
-
-
-// ...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:.
-// Declarations.
-// ...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:.
-
-// Consume a declaration.
-//   https://www.w3.org/TR/css3-syntax/#consume-a-declaration0
-maybe_declaration:
-    /* empty */ { $$ = NULL; }
-  | kAnimationDelayToken maybe_whitespace colon
-      animation_delay_property_value maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kAnimationDelayProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kAnimationDirectionToken maybe_whitespace colon
-      animation_direction_property_value maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kAnimationDirectionProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kAnimationDurationToken maybe_whitespace colon
-      animation_duration_property_value maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kAnimationDurationProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kAnimationFillModeToken maybe_whitespace colon
-      animation_fill_mode_property_value maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kAnimationFillModeProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kAnimationIterationCountToken maybe_whitespace colon
-      animation_iteration_count_property_value maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kAnimationIterationCountProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kAnimationNameToken maybe_whitespace colon
-      animation_name_property_value maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kAnimationNameProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kAnimationTimingFunctionToken maybe_whitespace colon
-      animation_timing_function_property_value maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kAnimationTimingFunctionProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kAnimationToken maybe_whitespace colon
-      animation_property_value maybe_important {
-    scoped_ptr<AnimationShorthand> animation($4);
-    DCHECK(animation);
-
-    scoped_ptr<PropertyDeclaration> property_declaration(
-        new PropertyDeclaration($5));
-
-    // Unpack the animation shorthand property values.
-    property_declaration->property_values.push_back(
-        PropertyDeclaration::PropertyKeyValuePair(
-            cssom::kAnimationDelayProperty,
-            animation->delay_list));
-    property_declaration->property_values.push_back(
-        PropertyDeclaration::PropertyKeyValuePair(
-            cssom::kAnimationDirectionProperty,
-            animation->direction_list));
-    property_declaration->property_values.push_back(
-        PropertyDeclaration::PropertyKeyValuePair(
-            cssom::kAnimationDurationProperty,
-            animation->duration_list));
-    property_declaration->property_values.push_back(
-        PropertyDeclaration::PropertyKeyValuePair(
-            cssom::kAnimationFillModeProperty,
-            animation->fill_mode_list));
-    property_declaration->property_values.push_back(
-        PropertyDeclaration::PropertyKeyValuePair(
-            cssom::kAnimationIterationCountProperty,
-            animation->iteration_count_list));
-    property_declaration->property_values.push_back(
-        PropertyDeclaration::PropertyKeyValuePair(
-            cssom::kAnimationNameProperty,
-            animation->name_list));
-    property_declaration->property_values.push_back(
-        PropertyDeclaration::PropertyKeyValuePair(
-            cssom::kAnimationTimingFunctionProperty,
-            animation->timing_function_list));
-
-    $$ = property_declaration.release();
-  }
-  | kBackgroundToken maybe_whitespace colon background_property_value
-      maybe_important {
-    scoped_ptr<BackgroundShorthandLayer> background($4);
-    if (background && !background->error) {
-      background->ReplaceNullWithInitialValues();
-      scoped_ptr<PropertyDeclaration> property_declaration(
-          new PropertyDeclaration($5));
-
-      // Unpack the background shorthand property values.
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBackgroundColorProperty,
-              background->background_color));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBackgroundImageProperty,
-              background->background_image));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBackgroundPositionProperty,
-              background->background_position));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBackgroundRepeatProperty,
-              background->background_repeat));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBackgroundSizeProperty,
-              background->background_size));
-
-      $$ = property_declaration.release();
-    } else {
-      $$ = NULL;
-    }
-  }
-  | kBackgroundColorToken maybe_whitespace colon background_color_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kBackgroundColorProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kBackgroundImageToken maybe_whitespace colon background_image_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kBackgroundImageProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kBackgroundPositionToken maybe_whitespace colon
-    background_position_property_value maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kBackgroundPositionProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kBackgroundRepeatToken maybe_whitespace colon
-    background_repeat_property_value maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kBackgroundRepeatProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kBackgroundSizeToken maybe_whitespace colon background_size_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kBackgroundSizeProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kBorderToken maybe_whitespace colon border_or_outline_property_value
-      maybe_important {
-    scoped_ptr<BorderOrOutlineShorthand> border($4);
-    DCHECK(border);
-    if (!border->error) {
-      scoped_ptr<PropertyDeclaration> property_declaration(
-          new PropertyDeclaration($5));
-
-      // Unpack border color.
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderTopColorProperty, border->color));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderRightColorProperty, border->color));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderBottomColorProperty, border->color));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderLeftColorProperty, border->color));
-
-      // Unpack border style.
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderTopStyleProperty, border->style));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderRightStyleProperty, border->style));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderBottomStyleProperty, border->style));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderLeftStyleProperty, border->style));
-
-      // Unpack border width.
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderTopWidthProperty, border->width));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderRightWidthProperty, border->width));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderBottomWidthProperty, border->width));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderLeftWidthProperty, border->width));
-
-      $$ = property_declaration.release();
-    } else {
-      parser_impl->LogWarning(@1, "invalid border");
-      $$ = NULL;
-    }
-  }
-  | kBorderBottomLeftRadiusToken maybe_whitespace colon border_radius_element_with_common_values
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kBorderBottomLeftRadiusProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kBorderBottomRightRadiusToken maybe_whitespace colon border_radius_element_with_common_values
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kBorderBottomRightRadiusProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kBorderBottomToken maybe_whitespace colon border_or_outline_property_value
-      maybe_important {
-    scoped_ptr<BorderOrOutlineShorthand> border($4);
-    DCHECK(border);
-    if (!border->error) {
-      scoped_ptr<PropertyDeclaration> property_declaration(
-          new PropertyDeclaration($5));
-
-      // Unpack border bottom.
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderBottomColorProperty, border->color));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderBottomStyleProperty, border->style));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderBottomWidthProperty, border->width));
-
-      $$ = property_declaration.release();
-    } else {
-      parser_impl->LogWarning(@1, "invalid border-bottom");
-      $$ = NULL;
-    }
-  }
-  | kBorderBottomColorToken maybe_whitespace colon color_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kBorderBottomColorProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kBorderBottomStyleToken maybe_whitespace colon line_style_with_common_values
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kBorderBottomStyleProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kBorderBottomWidthToken maybe_whitespace colon
-      border_width_element_with_common_values maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kBorderBottomWidthProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kBorderColorToken maybe_whitespace colon border_color_property_value
-      maybe_important {
-    scoped_refptr<cssom::PropertyValue> property_list_value(
-        MakeScopedRefPtrAndRelease($4));
-    if (property_list_value) {
-      BorderShorthandToLonghand shorthand_to_longhand;
-      shorthand_to_longhand.Assign4BordersBasedOnPropertyList(
-            property_list_value);
-
-      scoped_ptr<PropertyDeclaration> property_declaration(
-          new PropertyDeclaration($5));
-
-      // Unpack border color.
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderTopColorProperty,
-              shorthand_to_longhand.border_top));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderRightColorProperty,
-              shorthand_to_longhand.border_right));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderBottomColorProperty,
-              shorthand_to_longhand.border_bottom));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderLeftColorProperty,
-              shorthand_to_longhand.border_left));
-
-      $$ = property_declaration.release();
-    } else {
-      $$ = NULL;
-    }
-  }
-  | kBorderLeftToken maybe_whitespace colon border_or_outline_property_value
-      maybe_important {
-    scoped_ptr<BorderOrOutlineShorthand> border($4);
-    DCHECK(border);
-    if (!border->error) {
-      scoped_ptr<PropertyDeclaration> property_declaration(
-          new PropertyDeclaration($5));
-
-      // Unpack border left.
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderLeftColorProperty, border->color));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderLeftStyleProperty, border->style));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderLeftWidthProperty, border->width));
-
-      $$ = property_declaration.release();
-    } else {
-      parser_impl->LogWarning(@1, "invalid border-left");
-      $$ = NULL;
-    }
-  }
-  | kBorderLeftColorToken maybe_whitespace colon color_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kBorderLeftColorProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kBorderLeftStyleToken maybe_whitespace colon line_style_with_common_values
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kBorderLeftStyleProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kBorderLeftWidthToken maybe_whitespace colon
-      border_width_element_with_common_values maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kBorderLeftWidthProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kBorderRadiusToken maybe_whitespace colon border_radius_property_value
-      maybe_important {
-    scoped_refptr<cssom::PropertyValue> property_list_value(
-        MakeScopedRefPtrAndRelease($4));
-    if (property_list_value) {
-      BorderShorthandToLonghand shorthand_to_longhand;
-      shorthand_to_longhand.Assign4BordersBasedOnPropertyList(
-            property_list_value);
-
-      scoped_ptr<PropertyDeclaration> property_declaration(
-          new PropertyDeclaration($5));
-
-      // Unpack border radius.
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderTopLeftRadiusProperty,
-              shorthand_to_longhand.border_top));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderTopRightRadiusProperty,
-              shorthand_to_longhand.border_right));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderBottomRightRadiusProperty,
-              shorthand_to_longhand.border_bottom));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderBottomLeftRadiusProperty,
-              shorthand_to_longhand.border_left));
-
-      $$ = property_declaration.release();
-    } else {
-      $$ = NULL;
-    }
-  }
-  | kBorderRightToken maybe_whitespace colon border_or_outline_property_value
-      maybe_important {
-    scoped_ptr<BorderOrOutlineShorthand> border($4);
-    DCHECK(border);
-    if (!border->error) {
-      scoped_ptr<PropertyDeclaration> property_declaration(
-          new PropertyDeclaration($5));
-
-      // Unpack border right.
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderRightColorProperty, border->color));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderRightStyleProperty, border->style));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderRightWidthProperty, border->width));
-
-      $$ = property_declaration.release();
-    } else {
-      parser_impl->LogWarning(@1, "invalid border-right");
-      $$ = NULL;
-    }
-  }
-  | kBorderRightColorToken maybe_whitespace colon color_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kBorderRightColorProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kBorderRightStyleToken maybe_whitespace colon line_style_with_common_values
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kBorderRightStyleProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kBorderRightWidthToken maybe_whitespace colon
-      border_width_element_with_common_values maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kBorderRightWidthProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kBorderStyleToken maybe_whitespace colon border_style_property_value
-      maybe_important {
-    scoped_refptr<cssom::PropertyValue> property_list_value(
-        MakeScopedRefPtrAndRelease($4));
-    if (property_list_value) {
-      BorderShorthandToLonghand shorthand_to_longhand;
-      shorthand_to_longhand.Assign4BordersBasedOnPropertyList(
-            property_list_value);
-
-      scoped_ptr<PropertyDeclaration> property_declaration(
-          new PropertyDeclaration($5));
-
-      // Unpack border style.
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderTopStyleProperty,
-              shorthand_to_longhand.border_top));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderRightStyleProperty,
-              shorthand_to_longhand.border_right));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderBottomStyleProperty,
-              shorthand_to_longhand.border_bottom));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderLeftStyleProperty,
-              shorthand_to_longhand.border_left));
-
-      $$ = property_declaration.release();
-    } else {
-      $$ = NULL;
-    }
-  }
-  | kBorderTopToken maybe_whitespace colon border_or_outline_property_value
-      maybe_important {
-    scoped_ptr<BorderOrOutlineShorthand> border($4);
-    DCHECK(border);
-    if (!border->error) {
-      scoped_ptr<PropertyDeclaration> property_declaration(
-          new PropertyDeclaration($5));
-
-      // Unpack border top.
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderTopColorProperty, border->color));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderTopStyleProperty, border->style));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kBorderTopWidthProperty, border->width));
-
-      $$ = property_declaration.release();
-    } else {
-      parser_impl->LogWarning(@1, "invalid border-right");
-      $$ = NULL;
-    }
-  }
-  | kBorderTopColorToken maybe_whitespace colon color_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kBorderTopColorProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kBorderTopLeftRadiusToken maybe_whitespace colon border_radius_element_with_common_values
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kBorderTopLeftRadiusProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kBorderTopRightRadiusToken maybe_whitespace colon border_radius_element_with_common_values
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kBorderTopRightRadiusProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kBorderTopStyleToken maybe_whitespace colon line_style_with_common_values
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kBorderTopStyleProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kBorderTopWidthToken maybe_whitespace colon
-      border_width_element_with_common_values maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kBorderTopWidthProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kBorderWidthToken maybe_whitespace colon border_width_property_value
-      maybe_important {
-    scoped_refptr<cssom::PropertyValue> property_list_value(
-        MakeScopedRefPtrAndRelease($4));
-      if (property_list_value) {
-        BorderShorthandToLonghand shorthand_to_longhand;
-        shorthand_to_longhand.Assign4BordersBasedOnPropertyList(
-            property_list_value);
-
-        scoped_ptr<PropertyDeclaration> property_declaration(
-            new PropertyDeclaration($5));
-
-        // Unpack border width.
-        property_declaration->property_values.push_back(
-            PropertyDeclaration::PropertyKeyValuePair(
-                cssom::kBorderTopWidthProperty,
-                shorthand_to_longhand.border_top));
-        property_declaration->property_values.push_back(
-            PropertyDeclaration::PropertyKeyValuePair(
-                cssom::kBorderRightWidthProperty,
-                shorthand_to_longhand.border_right));
-        property_declaration->property_values.push_back(
-            PropertyDeclaration::PropertyKeyValuePair(
-                cssom::kBorderBottomWidthProperty,
-                shorthand_to_longhand.border_bottom));
-        property_declaration->property_values.push_back(
-            PropertyDeclaration::PropertyKeyValuePair(
-                cssom::kBorderLeftWidthProperty,
-                shorthand_to_longhand.border_left));
-
-        $$ = property_declaration.release();
-    } else {
-      $$ = NULL;
-    }
-  }
-  | kBottomToken maybe_whitespace colon offset_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kBottomProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kBoxShadowToken maybe_whitespace colon box_shadow_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kBoxShadowProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kColorToken maybe_whitespace colon color_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kColorProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kContentToken maybe_whitespace colon content_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kContentProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kDisplayToken maybe_whitespace colon display_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kDisplayProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kFilterToken maybe_whitespace colon filter_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kFilterProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kFontToken maybe_whitespace colon font_property_value maybe_important {
-    scoped_ptr<FontShorthand> font($4);
-    DCHECK(font);
-
-    scoped_ptr<PropertyDeclaration> property_declaration(
-        new PropertyDeclaration($5));
-
-    if (!font->error) {
-      font->ReplaceNullWithInitialValues();
-
-      // Unpack the font shorthand property values.
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kFontStyleProperty,
-              font->font_style));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kFontWeightProperty,
-              font->font_weight));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kFontSizeProperty,
-              font->font_size));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kFontFamilyProperty,
-              font->font_family));
-    }
-
-    $$ = property_declaration.release();
-  }
-  | kFontFamilyToken maybe_whitespace colon font_family_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kFontFamilyProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kFontSizeToken maybe_whitespace colon font_size_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kFontSizeProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kFontStyleToken maybe_whitespace colon font_style_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kFontStyleProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kFontWeightToken maybe_whitespace colon font_weight_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kFontWeightProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kHeightToken maybe_whitespace colon height_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kHeightProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kLeftToken maybe_whitespace colon offset_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kLeftProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kLineHeightToken maybe_whitespace colon line_height_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kLineHeightProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kMarginBottomToken maybe_whitespace colon margin_side_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kMarginBottomProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kMarginLeftToken maybe_whitespace colon margin_side_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kMarginLeftProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kMarginRightToken maybe_whitespace colon margin_side_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kMarginRightProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kMarginTopToken maybe_whitespace colon margin_side_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kMarginTopProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kMarginToken maybe_whitespace colon margin_property_value maybe_important {
-    scoped_ptr<MarginOrPaddingShorthand> margin($4);
-    if (margin) {
-      scoped_ptr<PropertyDeclaration> property_declaration(
-          new PropertyDeclaration($5));
-
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kMarginTopProperty, margin->top));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kMarginRightProperty, margin->right));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kMarginBottomProperty, margin->bottom));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kMarginLeftProperty, margin->left));
-
-      $$ = property_declaration.release();
-    } else {
-      $$ = NULL;
-    }
-  }
-  | kMaxHeightToken maybe_whitespace colon max_height_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kMaxHeightProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kMaxWidthToken maybe_whitespace colon max_width_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kMaxWidthProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kMinHeightToken maybe_whitespace colon min_height_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kMinHeightProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kMinWidthToken maybe_whitespace colon min_width_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kMinWidthProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kOpacityToken maybe_whitespace colon opacity_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kOpacityProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kOutlineToken maybe_whitespace colon border_or_outline_property_value
-      maybe_important {
-    scoped_ptr<BorderOrOutlineShorthand> outline($4);
-    DCHECK(outline);
-    if (!outline->error) {
-      scoped_ptr<PropertyDeclaration> property_declaration(
-          new PropertyDeclaration($5));
-
-      // Unpack outline color.
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kOutlineColorProperty, outline->color));
-
-      // Unpack outline style.
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kOutlineStyleProperty, outline->style));
-
-      // Unpack outline width.
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kOutlineWidthProperty, outline->width));
-
-      $$ = property_declaration.release();
-    } else {
-      parser_impl->LogWarning(@1, "invalid outline");
-      $$ = NULL;
-    }
-  }
-  | kOutlineColorToken maybe_whitespace colon color_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kOutlineColorProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kOutlineStyleToken maybe_whitespace colon line_style_with_common_values
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kOutlineStyleProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kOutlineWidthToken maybe_whitespace colon
-      border_width_element_with_common_values maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kOutlineWidthProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kOverflowToken maybe_whitespace colon overflow_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kOverflowProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kOverflowWrapToken maybe_whitespace colon overflow_wrap_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kOverflowWrapProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kPaddingBottomToken maybe_whitespace colon padding_side_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kPaddingBottomProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kPaddingLeftToken maybe_whitespace colon padding_side_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kPaddingLeftProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kPaddingRightToken maybe_whitespace colon padding_side_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kPaddingRightProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kPaddingTopToken maybe_whitespace colon padding_side_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kPaddingTopProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kPaddingToken maybe_whitespace colon padding_property_value
-      maybe_important {
-    scoped_ptr<MarginOrPaddingShorthand> padding($4);
-    if (padding) {
-      scoped_ptr<PropertyDeclaration> property_declaration(
-          new PropertyDeclaration($5));
-
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kPaddingTopProperty, padding->top));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kPaddingRightProperty, padding->right));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kPaddingBottomProperty, padding->bottom));
-      property_declaration->property_values.push_back(
-          PropertyDeclaration::PropertyKeyValuePair(
-              cssom::kPaddingLeftProperty, padding->left));
-
-      $$ = property_declaration.release();
-    } else {
-      $$ = NULL;
-    }
-  }
-  | kPointerEventsToken maybe_whitespace colon pointer_events_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kPointerEventsProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kPositionToken maybe_whitespace colon position_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kPositionProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kRightToken maybe_whitespace colon offset_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kRightProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kSrcToken maybe_whitespace colon font_face_src_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kSrcProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kTextAlignToken maybe_whitespace colon text_align_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kTextAlignProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kTextIndentToken maybe_whitespace colon text_indent_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kTextIndentProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kTextDecorationToken maybe_whitespace colon text_decoration_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kTextDecorationLineProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kTextDecorationColorToken maybe_whitespace colon
-      color_property_value maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kTextDecorationColorProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kTextDecorationLineToken maybe_whitespace colon
-      text_decoration_line_property_value maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kTextDecorationLineProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kTextOverflowToken maybe_whitespace colon text_overflow_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kTextOverflowProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kTextShadowToken maybe_whitespace colon text_shadow_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kTextShadowProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kTextTransformToken maybe_whitespace colon text_transform_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kTextTransformProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kTopToken maybe_whitespace colon offset_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kTopProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kTransformToken maybe_whitespace colon transform_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kTransformProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kTransformOriginToken maybe_whitespace colon transform_origin_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kTransformOriginProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kTransitionToken maybe_whitespace colon
-      transition_property_value maybe_important {
-    scoped_ptr<TransitionShorthand> transition($4);
-    DCHECK(transition);
-
-    scoped_ptr<PropertyDeclaration> property_declaration(
-        new PropertyDeclaration($5));
-
-    // Unpack the transition shorthand property values.
-    property_declaration->property_values.push_back(
-        PropertyDeclaration::PropertyKeyValuePair(
-            cssom::kTransitionPropertyProperty,
-            transition->property_list));
-    property_declaration->property_values.push_back(
-        PropertyDeclaration::PropertyKeyValuePair(
-            cssom::kTransitionDurationProperty,
-            transition->duration_list));
-    property_declaration->property_values.push_back(
-        PropertyDeclaration::PropertyKeyValuePair(
-            cssom::kTransitionTimingFunctionProperty,
-            transition->timing_function_list));
-    property_declaration->property_values.push_back(
-        PropertyDeclaration::PropertyKeyValuePair(
-            cssom::kTransitionDelayProperty,
-            transition->delay_list));
-
-    $$ = property_declaration.release();
-  }
-  | kTransitionDelayToken maybe_whitespace colon
-      transition_delay_property_value maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kTransitionDelayProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kTransitionDurationToken maybe_whitespace colon
-      transition_duration_property_value maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kTransitionDurationProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kTransitionPropertyToken maybe_whitespace colon
-      transition_property_property_value maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kTransitionPropertyProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kTransitionTimingFunctionToken maybe_whitespace colon
-      transition_timing_function_property_value maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kTransitionTimingFunctionProperty,
-                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kUnicodeRangePropertyToken maybe_whitespace colon
-      unicode_range_property_value maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kUnicodeRangeProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kVerticalAlignToken maybe_whitespace colon vertical_align_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kVerticalAlignProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kVisibilityToken maybe_whitespace colon visibility_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kVisibilityProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kWhiteSpacePropertyToken maybe_whitespace colon white_space_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kWhiteSpaceProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kWidthToken maybe_whitespace colon width_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kWidthProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kZIndexToken maybe_whitespace colon z_index_property_value
-      maybe_important {
-    $$ = $4 ? new PropertyDeclaration(cssom::kZIndexProperty,
-                                      MakeScopedRefPtrAndRelease($4), $5)
-            : NULL;
-  }
-  | kIdentifierToken maybe_whitespace colon errors {
-    std::string property_name = $1.ToString();
-    DCHECK_GT(property_name.size(), 0U);
-
-    // Do not warn about non-standard or non-WebKit properties.
-    if (property_name[0] != '-') {
-      base::AutoLock lock(non_trivial_static_fields.Get().lock);
-      base::hash_set<std::string>& properties_warned_about =
-          non_trivial_static_fields.Get().properties_warned_about;
-
-      if (properties_warned_about.find(property_name) ==
-          properties_warned_about.end()) {
-        properties_warned_about.insert(property_name);
-        parser_impl->LogWarning(@1, "unsupported property " + property_name);
-      }
-    }
-
-    $$ = NULL;
-  }
-  | errors {
-    parser_impl->LogWarning(@1, "invalid declaration");
-    $$ = NULL;
-  }
-  ;
-
-semicolon: ';' maybe_whitespace ;
-
-// Consume a list of declarations.
-//   https://www.w3.org/TR/css3-syntax/#consume-a-list-of-declarations0
-style_declaration_list:
-    maybe_declaration {
-    $$ = AddRef(new cssom::CSSDeclaredStyleData());
-
-    scoped_ptr<PropertyDeclaration> property_declaration($1);
-    if (property_declaration) {
-      property_declaration->Apply($$);
-      for (size_t i = 0;
-           i < property_declaration->unsupported_property_keys.size(); ++i) {
-        std::string unsupported_property_name =
-            cssom::GetPropertyName(
-                property_declaration->unsupported_property_keys[i]);
-        parser_impl->LogWarning(
-            @1, "unsupported style property: "  + unsupported_property_name);
-      }
-    }
-  }
-  | style_declaration_list semicolon maybe_declaration {
-    $$ = $1;
-
-    scoped_ptr<PropertyDeclaration> property_declaration($3);
-    if (property_declaration) {
-      property_declaration->Apply($$);
-      for (size_t i = 0;
-           i < property_declaration->unsupported_property_keys.size(); ++i) {
-        std::string unsupported_property_name =
-            cssom::GetPropertyName(
-                property_declaration->unsupported_property_keys[i]);
-        parser_impl->LogWarning(
-            @1, "unsupported style property: "  + unsupported_property_name);
-      }
-    }
-  }
-  ;
-
-font_face_declaration_list:
-    maybe_declaration {
-    $$ = AddRef(new cssom::CSSFontFaceDeclarationData());
-
-    scoped_ptr<PropertyDeclaration> property_declaration($1);
-    if (property_declaration) {
-      property_declaration->Apply($$);
-    }
-  }
-  | font_face_declaration_list semicolon maybe_declaration {
-    $$ = $1;
-
-    scoped_ptr<PropertyDeclaration> property_declaration($3);
-    if (property_declaration) {
-      property_declaration->Apply($$);
-    }
-  }
-  ;
-
-style_declaration_block:
-    '{' maybe_whitespace style_declaration_list '}' maybe_whitespace {
-    $$ = AddRef(new cssom::CSSRuleStyleDeclaration(
-             MakeScopedRefPtrAndRelease($3), parser_impl->css_parser()));
-  }
-  ;
-
-rule_list_block:
-    '{' maybe_whitespace rule_list '}' maybe_whitespace {
-    $$ = $3;
-  }
-  | semicolon {
-    $$ = AddRef(new cssom::CSSRuleList());
-  }
-  ;
-
-// ...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:.
-// Rules.
-// ...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:.
-
-// A style rule is a qualified rule that associates a selector list with a list
-// of property declarations.
-//   https://www.w3.org/TR/css3-syntax/#style-rule
-style_rule:
-    selector_list style_declaration_block {
-    scoped_ptr<cssom::Selectors> selectors($1);
-    scoped_refptr<cssom::CSSRuleStyleDeclaration> style =
-        MakeScopedRefPtrAndRelease($2);
-
-    if (selectors) {
-      $$ = AddRef(new cssom::CSSStyleRule(selectors->Pass(), style));
-    } else {
-      $$ = NULL;
-    }
-  }
-  ;
-
-// To parse a CSS stylesheet, interpret all of the resulting top-level qualified
-// rules as style rules.
-//   https://www.w3.org/TR/css3-syntax/#css-stylesheets
-qualified_rule:
-    style_rule
-  | error style_declaration_block {
-    scoped_refptr<cssom::CSSRuleStyleDeclaration> unused_style =
-        MakeScopedRefPtrAndRelease($2);
-    parser_impl->LogWarning(@1, "invalid qualified rule");
-    $$ = NULL;
-  }
-  ;
-
-invalid_rule:
-    kInvalidAtBlockToken maybe_whitespace {
-    parser_impl->LogWarning(@1, "invalid rule " + $1.ToString());
-  }
-  | kOtherBrowserAtBlockToken maybe_whitespace {
-    // Do not warn about other browser at rules.
-  }
-  ;
-
-// Consume a list of rules.
-//   https://www.w3.org/TR/css3-syntax/#consume-a-list-of-rules
-rule:
-    kSgmlCommentDelimiterToken maybe_whitespace { $$ = NULL; }
-  | qualified_rule { $$ = $1; }
-  | at_font_face_rule { $$ = $1; }
-  | at_media_rule { $$ = $1; }
-  | at_keyframes_rule { $$ = $1; }
-  | invalid_rule { $$ = NULL; }
-  ;
-
-rule_list:
-    /* empty */ {
-    $$ = AddRef(new cssom::CSSRuleList());
-  }
-  | rule_list rule {
-    $$ = $1;
-    scoped_refptr<cssom::CSSRule> css_rule =
-        MakeScopedRefPtrAndRelease($2);
-    if (css_rule) {
-      $$->AppendCSSRule(css_rule);
-    }
-  }
-  ;
-
-
-// ...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:.
-// Entry points.
-// ...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:...:.
-
-// To parse a stylesheet, consume a list of rules.
-//   https://www.w3.org/TR/css3-syntax/#parse-a-stylesheet
-style_sheet:
-    rule_list {
-    $$ = AddRef(new cssom::CSSStyleSheet(parser_impl->css_parser()));
-    $$->set_css_rules(MakeScopedRefPtrAndRelease($1));
-  }
-  ;
-
-// Parser entry points.
-//   http://dev.w3.org/csswg/css-syntax/#parser-entry-points
-entry_point:
-  // Parses the entire stylesheet.
-    kStyleSheetEntryPointToken maybe_whitespace style_sheet {
-    scoped_refptr<cssom::CSSStyleSheet> style_sheet =
-        MakeScopedRefPtrAndRelease($3);
-    parser_impl->set_style_sheet(style_sheet);
-  }
-  // Parses the media list.
-  | kMediaListEntryPointToken maybe_whitespace media_list {
-    scoped_refptr<cssom::MediaList> media_list =
-        MakeScopedRefPtrAndRelease($3);
-    parser_impl->set_media_list(media_list);
-  }
-  // Parses the media query.
-  | kMediaQueryEntryPointToken maybe_whitespace media_query {
-    scoped_refptr<cssom::MediaQuery> media_query =
-        MakeScopedRefPtrAndRelease($3);
-    parser_impl->set_media_query(media_query);
-  }
-  // Parses the rule.
-  | kRuleEntryPointToken maybe_whitespace rule {
-    scoped_refptr<cssom::CSSRule> rule(MakeScopedRefPtrAndRelease($3));
-    parser_impl->set_rule(rule);
-  }
-  // Parses the contents of a HTMLElement.style attribute.
-  | kStyleDeclarationListEntryPointToken maybe_whitespace
-        style_declaration_list {
-    scoped_refptr<cssom::CSSDeclaredStyleData> declaration_data =
-        MakeScopedRefPtrAndRelease($3);
-    parser_impl->set_style_declaration_data(declaration_data);
-  }
-  // Parses the contents of an @font-face rule.
-  | kFontFaceDeclarationListEntryPointToken maybe_whitespace
-        font_face_declaration_list {
-    scoped_refptr<cssom::CSSFontFaceDeclarationData> declaration_data =
-        MakeScopedRefPtrAndRelease($3);
-    parser_impl->set_font_face_declaration_data(declaration_data);
-  }
-  // Parses a single non-shorthand property value.
-  | kPropertyValueEntryPointToken maybe_whitespace maybe_declaration {
-    scoped_ptr<PropertyDeclaration> property_declaration($3);
-    if (property_declaration != NULL) {
-      if (property_declaration->property_values.size() != 1) {
-        parser_impl->LogError(
-            @1, "Cannot parse shorthand properties as single property values.");
-      } else {
-        if (property_declaration->is_important) {
-          parser_impl->LogWarning(
-            @1,
-            "!important is not allowed when setting single property values.");
-        } else {
-          if (!property_declaration->property_values[0].value) {
-            parser_impl->LogWarning(
-              @1, "declaration must have a property value.");
-          } else {
-            parser_impl->set_property_value(
-                property_declaration->property_values[0].value);
-          }
-        }
-      }
-    }
-  }
-  // Parses the property value and correspondingly sets the values of a passed
-  // in CSSDeclarationData.
-  // This is Cobalt's equivalent of a "list of component values".
-  | kPropertyIntoDeclarationDataEntryPointToken maybe_whitespace
-        maybe_declaration {
-    scoped_ptr<PropertyDeclaration> property_declaration($3);
-    if (property_declaration != NULL) {
-      if (property_declaration->is_important) {
-        parser_impl->LogError(
-            @1, "!important is not allowed when setting single property value");
-      } else {
-        DCHECK(parser_impl->into_declaration_data());
-        property_declaration->Apply(
-            parser_impl->into_declaration_data());
-      }
-    }
-  }
-  ;
-
-// Filters that can be applied to the object's rendering.
-//   https://www.w3.org/TR/filter-effects-1/#FilterProperty
-filter_property_value:
-    kNoneToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetNone().get());
-  }
-  | filter_function_list {
-    scoped_ptr<cssom::FilterFunctionListValue::Builder> property_value($1);
-    $$ = AddRef(new cssom::FilterFunctionListValue(property_value->Pass()));
-  }
-  | common_values
-  ;
-
-filter_function_list:
-  // TODO: Parse list of filter_function's. This only parses one-element lists.
-    filter_function {
-    $$ = new cssom::FilterFunctionListValue::Builder();
-    $$->push_back($1);
-  }
-  ;
-
-// The set of allowed filter functions.
-//   https://www.w3.org/TR/filter-effects-1/
-filter_function:
-    cobalt_mtm_filter_function {
-    $$ = $1;
-  }
-  ;
-
-cobalt_mtm_filter_function:
-  // Encodes an mtm filter. Currently the only type of filter function supported.
-    cobalt_mtm_function_name maybe_whitespace cobalt_map_to_mesh_spec comma angle
-        angle comma cobalt_mtm_transform_function maybe_cobalt_mtm_stereo_mode
-        ')' maybe_whitespace {
-    scoped_ptr<cssom::MapToMeshFunction::MeshSpec>
-        mesh_spec($3);
-    scoped_ptr<glm::mat4> transform($8);
-    scoped_refptr<cssom::KeywordValue> stereo_mode =
-        MakeScopedRefPtrAndRelease($9);
-
-    if (!parser_impl->supports_map_to_mesh()) {
-      YYERROR;
-    } else {
-      $$ = new cssom::MapToMeshFunction(
-          mesh_spec.Pass(),
-          $5,
-          $6,
-          *transform,
-          stereo_mode);
-    }
-  }
-  // map-to-mesh filter with the rectangular built-in mesh. Does not take FOV
-  // or transforms.
-  |  cobalt_mtm_function_name maybe_whitespace kRectangularToken comma
-        kNoneToken comma kNoneToken maybe_cobalt_mtm_stereo_mode
-        ')' maybe_whitespace {
-    scoped_refptr<cssom::KeywordValue> stereo_mode =
-        MakeScopedRefPtrAndRelease($8);
-
-    if (!parser_impl->supports_map_to_mesh_rectangular()) {
-      YYERROR;
-    } else {
-      $$ = new cssom::MapToMeshFunction(cssom::MapToMeshFunction::kRectangular,
-                                        stereo_mode);
-    }
-  }
-  ;
-
-cobalt_map_to_mesh_spec:
-    kEquirectangularToken {
-    $$ = new cssom::MapToMeshFunction::MeshSpec(
-        cssom::MapToMeshFunction::kEquirectangular);
-  }
-  | url cobalt_mtm_resolution_matched_mesh_list {
-    scoped_refptr<cssom::PropertyValue> url = MakeScopedRefPtrAndRelease($1);
-    scoped_ptr<cssom::MapToMeshFunction::ResolutionMatchedMeshListBuilder>
-        resolution_matched_mesh_urls($2);
-
-    $$ = new cssom::MapToMeshFunction::MeshSpec(
-        cssom::MapToMeshFunction::kUrls,
-        url,
-        resolution_matched_mesh_urls->Pass());
-  }
-  ;
-
-cobalt_mtm_function_name:
-    kCobaltMtmFunctionToken
-  | kMapToMeshFunctionToken
-  ;
-
-cobalt_mtm_resolution_matched_mesh_list:
-    /* empty */ {
-    $$ = new cssom::MapToMeshFunction::ResolutionMatchedMeshListBuilder();
-  }
-  // Specifies a different mesh for a particular image resolution.
-  | cobalt_mtm_resolution_matched_mesh_list cobalt_mtm_resolution_matched_mesh {
-    $$ = $1;
-    $$->push_back($2);
-  }
-  ;
-
-cobalt_mtm_resolution_matched_mesh:
-    non_negative_integer non_negative_integer url {
-    $$ = new cssom::MapToMeshFunction::ResolutionMatchedMesh($1, $2,
-      MakeScopedRefPtrAndRelease($3));
-  }
-  ;
-
-// The set of transform functions allowed in MTM filters, currently a separate
-// production hierarchy from the main <transform_function> and represented as a
-// glm::mat4.
-//   https://www.w3.org/TR/css-transforms-1/#three-d-transform-functions
-cobalt_mtm_transform_function:
-  // Specifies an arbitrary affine 3D transformation, currently the only
-  // supported transform in MTM.
-    kMatrix3dFunctionToken maybe_whitespace number_matrix ')' maybe_whitespace {
-    scoped_ptr<std::vector<float> > matrix($3);
-    if (matrix == NULL || matrix->size() !=  16) {
-      parser_impl->LogError(
-          @3,
-          "matrix3d function expects 16 floating-point numbers as arguments");
-      YYERROR;
-    } else {
-      // GLM and the W3 spec both use column-major order.
-      $$ = new glm::mat4(glm::make_mat4(&(*matrix)[0]));
-    }
-  }
-  ;
-
-number_matrix:
-    number {
-    $$ = new std::vector<float>(1, $1);
-  }
-  | number_matrix comma number {
-    $$ = $1;
-    $$->push_back($3);
-  }
-  ;
-
-maybe_cobalt_mtm_stereo_mode:
-    /* empty */ {
-    $$ = AddRef(cssom::KeywordValue::GetMonoscopic().get());
-  }
-  | comma cobalt_mtm_stereo_mode {
-    $$ = $2;
-  }
-  ;
-
-cobalt_mtm_stereo_mode:
-    kMonoscopicToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetMonoscopic().get());
-  }
-  | kStereoscopicLeftRightToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetStereoscopicLeftRight().get());
-  }
-  | kStereoscopicTopBottomToken maybe_whitespace {
-    $$ = AddRef(cssom::KeywordValue::GetStereoscopicTopBottom().get());
-  }
-  ;
diff --git a/src/cobalt/css_parser/grammar.h b/src/cobalt/css_parser/grammar.h
index 37ea62b..977ba1af 100644
--- a/src/cobalt/css_parser/grammar.h
+++ b/src/cobalt/css_parser/grammar.h
@@ -89,9 +89,7 @@
 struct MarginOrPaddingShorthand;
 class ParserImpl;
 struct PropertyDeclaration;
-#if BISON_VERSION_MAJOR >= 3
 class Scanner;
-#endif  // BISON_VERSION_MAJOR >= 3
 
 // Override the default source location type from Bison with our own.
 struct cobalt_yyltype {
@@ -113,12 +111,8 @@
 
 // A header generated by Bison must be included inside our namespace
 // to avoid global namespace pollution.
-#if BISON_VERSION_MAJOR >= 3
 #include "cobalt/css_parser/grammar_generated.h"
 typedef YYSTYPE TokenValue;
-#else
-#include "cobalt/css_parser/grammar-bison-2_generated.h"
-#endif
 
 }  // namespace css_parser
 }  // namespace cobalt
diff --git a/src/cobalt/css_parser/grammar.y b/src/cobalt/css_parser/grammar.y
index 63e26c9..4ce4b67 100644
--- a/src/cobalt/css_parser/grammar.y
+++ b/src/cobalt/css_parser/grammar.y
@@ -14,6 +14,8 @@
 
 // This file contains a definition of CSS grammar.
 
+%require "3.0"
+
 // A reentrant parser.
 %define api.pure full
 
diff --git a/src/cobalt/css_parser/parser.cc b/src/cobalt/css_parser/parser.cc
index 2b2c2fe..a2e28c9 100644
--- a/src/cobalt/css_parser/parser.cc
+++ b/src/cobalt/css_parser/parser.cc
@@ -86,10 +86,6 @@
 #include "cobalt/cssom/url_value.h"
 #include "nb/memory_scope.h"
 
-#if BISON_VERSION_MAJOR == 2
-#pragma message ("Building with bison 2 is deprecated. Please upgrade to bison 3")
-#endif  // BISON_VERSION_MAJOR == 2
-
 namespace cobalt {
 namespace css_parser {
 
@@ -139,10 +135,6 @@
   scoped_refptr<cssom::MediaList> ParseMediaList();
   scoped_refptr<cssom::MediaQuery> ParseMediaQuery();
 
-#if BISON_VERSION_MAJOR == 2
-  Scanner& scanner() { return scanner_; }
-#endif  // BISON_VERSION_MAJOR == 2
-
   void set_last_syntax_error_location(
       const YYLTYPE& last_syntax_error_location) {
     last_syntax_error_location_ = last_syntax_error_location;
@@ -237,11 +229,7 @@
     callback.Run(message + "\n" + input);
   }
 
-#if BISON_VERSION_MAJOR >= 3
   friend int yyparse(ParserImpl* parser_impl, Scanner* scanner);
-#else  // BISON_VERSION_MAJOR >= 3
-  friend int yyparse(ParserImpl* parser_impl);
-#endif  // BISON_VERSION_MAJOR >= 3
 };
 
 // TODO: Stop deduplicating warnings.
@@ -402,11 +390,7 @@
   // see http://www.gnu.org/software/bison/manual/html_node/Parser-Function.html
   TRACE_EVENT0("cobalt::css_parser", "ParseImpl::Parse");
   last_syntax_error_location_ = base::nullopt;
-#if BISON_VERSION_MAJOR >= 3
   int error_code(yyparse(this, &scanner_));
-#else  // BISON_VERSION_MAJOR >= 3
-  int error_code(yyparse(this));
-#endif  // BISON_VERSION_MAJOR >= 3
   switch (error_code) {
     case 0:
       // Parsed successfully or was able to recover from errors.
@@ -517,11 +501,7 @@
 // syntax error. Most of error reporting is implemented in semantic actions
 // in the grammar.
 inline void yyerror(YYLTYPE* source_location, ParserImpl* parser_impl,
-#if BISON_VERSION_MAJOR >= 3
                     Scanner* /*scanner*/, const char* /*message*/) {
-#else  // BISON_VERSION_MAJOR >= 3
-                    const char* /*message*/) {
-#endif  // BISON_VERSION_MAJOR >= 3
   parser_impl->set_last_syntax_error_location(*source_location);
 }
 
@@ -545,11 +525,7 @@
 
 // A header generated by Bison must be included inside our namespace
 // to avoid global namespace pollution.
-#if BISON_VERSION_MAJOR < 3
-#include "cobalt/css_parser/grammar-bison-2_impl_generated.h"
-#else
 #include "cobalt/css_parser/grammar_impl_generated.h"
-#endif  // BISON_VERSION_MAJOR < 3
 
 #if defined(__clang__)
 #pragma clang diagnostic pop
diff --git a/src/cobalt/cssom/css_condition_rule.cc b/src/cobalt/cssom/css_condition_rule.cc
index e16990d..2ed2e1c 100644
--- a/src/cobalt/cssom/css_condition_rule.cc
+++ b/src/cobalt/cssom/css_condition_rule.cc
@@ -25,8 +25,6 @@
   return cached_condition_value_changed;
 }
 
-CSSConditionRule::CSSConditionRule() : cached_condition_value_(false) {}
-
 CSSConditionRule::CSSConditionRule(
     const scoped_refptr<CSSRuleList>& css_rule_list)
     : CSSGroupingRule(css_rule_list), cached_condition_value_(false) {}
diff --git a/src/cobalt/cssom/css_condition_rule.h b/src/cobalt/cssom/css_condition_rule.h
index 525947d..6148618 100644
--- a/src/cobalt/cssom/css_condition_rule.h
+++ b/src/cobalt/cssom/css_condition_rule.h
@@ -56,7 +56,6 @@
   DEFINE_WRAPPABLE_TYPE(CSSConditionRule);
 
  protected:
-  CSSConditionRule();
   explicit CSSConditionRule(const scoped_refptr<CSSRuleList>& css_rule_list);
 
   ~CSSConditionRule() override {}
diff --git a/src/cobalt/cssom/css_grouping_rule.cc b/src/cobalt/cssom/css_grouping_rule.cc
index e56e28d..549d0c9 100644
--- a/src/cobalt/cssom/css_grouping_rule.cc
+++ b/src/cobalt/cssom/css_grouping_rule.cc
@@ -20,16 +20,13 @@
 namespace cobalt {
 namespace cssom {
 
-CSSGroupingRule::CSSGroupingRule() {}
-
 CSSGroupingRule::CSSGroupingRule(
     const scoped_refptr<CSSRuleList>& css_rule_list)
-    : css_rule_list_(css_rule_list) {}
+    : css_rule_list_(css_rule_list) {
+  DCHECK(css_rule_list_);
+}
 
 const scoped_refptr<CSSRuleList>& CSSGroupingRule::css_rules() {
-  if (!css_rule_list_) {
-    set_css_rules(new CSSRuleList());
-  }
   return css_rule_list_;
 }
 
@@ -38,6 +35,20 @@
   return css_rules()->InsertRule(rule, index);
 }
 
+void CSSGroupingRule::SetIndex(int index) {
+  int index_difference = index - this->index();
+  CSSRule::SetIndex(index);
+
+  // Update all of our child rules' indices so that they are consistently
+  // indexed within the parent's rule indices.
+  for (unsigned int i = 0; i < css_rule_list_->length(); ++i) {
+    css_rule_list_->Item(i)->SetIndex(css_rule_list_->Item(i)->index() +
+                                      index_difference);
+  }
+}
+
+int CSSGroupingRule::IndexWidth() const { return css_rule_list_->length(); }
+
 void CSSGroupingRule::set_css_rules(
     const scoped_refptr<CSSRuleList>& css_rule_list) {
   DCHECK(css_rule_list);
diff --git a/src/cobalt/cssom/css_grouping_rule.h b/src/cobalt/cssom/css_grouping_rule.h
index 17132ee..ec71af8 100644
--- a/src/cobalt/cssom/css_grouping_rule.h
+++ b/src/cobalt/cssom/css_grouping_rule.h
@@ -35,7 +35,6 @@
 //   https://www.w3.org/TR/css3-conditional/#cssgroupingrule
 class CSSGroupingRule : public CSSRule {
  public:
-  CSSGroupingRule();
   explicit CSSGroupingRule(const scoped_refptr<CSSRuleList>& css_rule_list);
 
   // Web API: CSSGroupingRule
@@ -55,6 +54,9 @@
     NOTREACHED();
   }
 
+  void SetIndex(int index) override;
+  int IndexWidth() const override;
+
   // Sets the CSS rule list for the grouping rule.
   void set_css_rules(const scoped_refptr<CSSRuleList>& css_rule_list);
 
diff --git a/src/cobalt/cssom/css_grouping_rule_test.cc b/src/cobalt/cssom/css_grouping_rule_test.cc
index a837247..c43f0e5 100644
--- a/src/cobalt/cssom/css_grouping_rule_test.cc
+++ b/src/cobalt/cssom/css_grouping_rule_test.cc
@@ -31,6 +31,8 @@
 
 class FakeCSSGroupingRule : public CSSGroupingRule {
  public:
+  FakeCSSGroupingRule() : CSSGroupingRule(new CSSRuleList()) {}
+
   // From CSSRule.
   Type type() const override { return kMediaRule; }
   std::string css_text(
diff --git a/src/cobalt/cssom/css_media_rule.cc b/src/cobalt/cssom/css_media_rule.cc
index d802d78..fbe073e 100644
--- a/src/cobalt/cssom/css_media_rule.cc
+++ b/src/cobalt/cssom/css_media_rule.cc
@@ -22,11 +22,11 @@
 namespace cobalt {
 namespace cssom {
 
-CSSMediaRule::CSSMediaRule() {}
-
 CSSMediaRule::CSSMediaRule(const scoped_refptr<MediaList>& media_list,
                            const scoped_refptr<CSSRuleList>& css_rule_list)
-    : CSSConditionRule(css_rule_list), media_list_(media_list) {}
+    : CSSConditionRule(css_rule_list), media_list_(media_list) {
+  DCHECK(media_list_);
+}
 
 const scoped_refptr<MediaList>& CSSMediaRule::media() const {
   return media_list_;
@@ -49,15 +49,9 @@
   NOTIMPLEMENTED() << "CSSMediaRule css_text setting not implemented yet.";
 }
 
-std::string CSSMediaRule::condition_text() {
-  return media_list_ ? media_list_->media_text() : "";
-}
+std::string CSSMediaRule::condition_text() { return media_list_->media_text(); }
 
 void CSSMediaRule::set_condition_text(const std::string& condition) {
-  if (!media_list_) {
-    DCHECK(parent_style_sheet());
-    media_list_ = new MediaList(parent_style_sheet()->css_parser());
-  }
   media_list_->set_media_text(condition);
 }
 
@@ -67,11 +61,8 @@
 
 bool CSSMediaRule::EvaluateConditionValueAndReturnIfChanged(
     const math::Size& viewport_size) {
-  bool condition_value = true;
-  if (media_list_) {
-    condition_value = media_list_->EvaluateConditionValue(viewport_size);
-  }
-  return SetConditionValueAndTestIfChanged(condition_value);
+  return SetConditionValueAndTestIfChanged(
+      media_list_->EvaluateConditionValue(viewport_size));
 }
 
 void CSSMediaRule::AttachToCSSStyleSheet(CSSStyleSheet* style_sheet) {
diff --git a/src/cobalt/cssom/css_media_rule.h b/src/cobalt/cssom/css_media_rule.h
index ab923ab..4515046 100644
--- a/src/cobalt/cssom/css_media_rule.h
+++ b/src/cobalt/cssom/css_media_rule.h
@@ -37,7 +37,6 @@
 //   https://www.w3.org/TR/cssom/#the-cssmediarule-interface
 class CSSMediaRule : public CSSConditionRule {
  public:
-  CSSMediaRule();
   CSSMediaRule(const scoped_refptr<MediaList>& media_list,
                const scoped_refptr<CSSRuleList>& css_rule_list);
 
diff --git a/src/cobalt/cssom/css_rule.h b/src/cobalt/cssom/css_rule.h
index 6ca98a9..bdad21b 100644
--- a/src/cobalt/cssom/css_rule.h
+++ b/src/cobalt/cssom/css_rule.h
@@ -72,7 +72,16 @@
   void set_parent_style_sheet(CSSStyleSheet *parent_style_sheet);
 
   int index() const { return index_; }
-  void set_index(int index) { index_ = index; }
+
+  // This may be overridden for derived classes representing groups of rules
+  // such that when the parent rule's index is updated, the children's rules
+  // are also updated.
+  virtual void SetIndex(int index) { index_ = index; }
+
+  // Returns how many indices this rule consumes within its parent rule list.
+  // It is useful to override this value for rule groups such that each inner
+  // rule is represented as an index within all its parents.
+  virtual int IndexWidth() const { return 1; }
 
   virtual void Accept(CSSRuleVisitor *visitor) = 0;
   virtual void AttachToCSSStyleSheet(CSSStyleSheet *style_sheet) = 0;
@@ -86,7 +95,7 @@
   virtual ~CSSRule() {}
 
  private:
-  int index_;
+  int index_ = 0;
   base::WeakPtr<CSSRule> parent_rule_;
   base::WeakPtr<CSSStyleSheet> parent_style_sheet_;
 
diff --git a/src/cobalt/cssom/css_rule_list.cc b/src/cobalt/cssom/css_rule_list.cc
index 46fb56e..0f1de29 100644
--- a/src/cobalt/cssom/css_rule_list.cc
+++ b/src/cobalt/cssom/css_rule_list.cc
@@ -82,7 +82,8 @@
     css_rule->AttachToCSSStyleSheet(parent_css_style_sheet_);
     parent_css_style_sheet_->OnCSSMutation();
   }
-  css_rule->set_index(static_cast<int>(css_rules_.size()));
+  css_rule->SetIndex(next_index_);
+  next_index_ += css_rule->IndexWidth();
   css_rules_.push_back(css_rule);
 }
 
diff --git a/src/cobalt/cssom/css_rule_list.h b/src/cobalt/cssom/css_rule_list.h
index 8e883cc..796be3f 100644
--- a/src/cobalt/cssom/css_rule_list.h
+++ b/src/cobalt/cssom/css_rule_list.h
@@ -73,6 +73,8 @@
   CSSRules css_rules_;
   CSSStyleSheet* parent_css_style_sheet_;
 
+  int next_index_ = 0;
+
   DISALLOW_COPY_AND_ASSIGN(CSSRuleList);
 };
 
diff --git a/src/cobalt/cssom/css_rule_list_test.cc b/src/cobalt/cssom/css_rule_list_test.cc
index cbeca06..0feebf2 100644
--- a/src/cobalt/cssom/css_rule_list_test.cc
+++ b/src/cobalt/cssom/css_rule_list_test.cc
@@ -18,6 +18,7 @@
 #include "cobalt/cssom/css_media_rule.h"
 #include "cobalt/cssom/css_rule_style_declaration.h"
 #include "cobalt/cssom/css_style_rule.h"
+#include "cobalt/cssom/media_list.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace cobalt {
@@ -60,7 +61,8 @@
 
 TEST(CSSRuleListTest, AppendCSSRuleShouldTakeCSSMediaRule) {
   scoped_refptr<CSSRuleList> rule_list = new CSSRuleList();
-  scoped_refptr<CSSMediaRule> rule = new CSSMediaRule();
+  scoped_refptr<CSSMediaRule> rule =
+      new CSSMediaRule(new MediaList(), new CSSRuleList());
   rule_list->AppendCSSRule(rule);
 
   ASSERT_EQ(1, rule_list->length());
diff --git a/src/cobalt/cssom/css_rule_visitor_test.cc b/src/cobalt/cssom/css_rule_visitor_test.cc
index 21933f9..48b4b3a 100644
--- a/src/cobalt/cssom/css_rule_visitor_test.cc
+++ b/src/cobalt/cssom/css_rule_visitor_test.cc
@@ -21,6 +21,7 @@
 #include "cobalt/cssom/css_keyframes_rule.h"
 #include "cobalt/cssom/css_media_rule.h"
 #include "cobalt/cssom/css_style_rule.h"
+#include "cobalt/cssom/media_list.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -45,7 +46,8 @@
 }
 
 TEST(CSSRuleVisitorTest, VisitsCSSMediaRule) {
-  scoped_refptr<CSSMediaRule> rule = new CSSMediaRule();
+  scoped_refptr<CSSMediaRule> rule =
+      new CSSMediaRule(new MediaList(), new CSSRuleList());
   MockCSSRuleVisitor mock_visitor;
   EXPECT_CALL(mock_visitor, VisitCSSMediaRule(rule.get()));
   rule->Accept(&mock_visitor);
diff --git a/src/cobalt/cssom/css_style_sheet_test.cc b/src/cobalt/cssom/css_style_sheet_test.cc
index eedaa30..00abb91 100644
--- a/src/cobalt/cssom/css_style_sheet_test.cc
+++ b/src/cobalt/cssom/css_style_sheet_test.cc
@@ -111,7 +111,8 @@
   scoped_refptr<CSSRuleList> rule_list =
       css_style_sheet_->css_rules_same_origin();
   // A CSSMediaRule with no expression always evaluates to true.
-  scoped_refptr<CSSMediaRule> rule = new CSSMediaRule();
+  scoped_refptr<CSSMediaRule> rule =
+      new CSSMediaRule(new MediaList(), new CSSRuleList());
 
   EXPECT_CALL(mutation_observer_, OnCSSMutation()).Times(0);
   css_style_sheet_->EvaluateMediaRules(math::Size(1920, 1080));
@@ -131,7 +132,8 @@
   scoped_refptr<MediaQuery> media_query(new MediaQuery(false));
   scoped_refptr<MediaList> media_list(new MediaList());
   media_list->Append(media_query);
-  scoped_refptr<CSSMediaRule> rule = new CSSMediaRule(media_list, NULL);
+  scoped_refptr<CSSMediaRule> rule =
+      new CSSMediaRule(media_list, new CSSRuleList());
   scoped_refptr<CSSRuleList> rule_list =
       css_style_sheet_->css_rules_same_origin();
 
@@ -159,7 +161,8 @@
       new MediaQuery(true, media_features.Pass()));
   scoped_refptr<MediaList> media_list(new MediaList());
   media_list->Append(media_query);
-  scoped_refptr<CSSMediaRule> rule = new CSSMediaRule(media_list, NULL);
+  scoped_refptr<CSSMediaRule> rule =
+      new CSSMediaRule(media_list, new CSSRuleList());
 
   // This should result in a call to OnCSSMutation(), because a media rule is
   // added to the style sheet.
diff --git a/src/cobalt/cssom/media_list.cc b/src/cobalt/cssom/media_list.cc
index e0931b9..991791e 100644
--- a/src/cobalt/cssom/media_list.cc
+++ b/src/cobalt/cssom/media_list.cc
@@ -78,6 +78,11 @@
 }
 
 bool MediaList::EvaluateConditionValue(const math::Size& viewport_size) {
+  if (media_queries_.empty()) {
+    // A CSSMediaRule with no expressions always evaluates to true.
+    return true;
+  }
+
   for (MediaQueries::iterator it = media_queries_.begin();
        it != media_queries_.end(); ++it) {
     if ((*it)->EvaluateConditionValue(viewport_size)) {
diff --git a/src/cobalt/cssom/property_definitions.h b/src/cobalt/cssom/property_definitions.h
index d4ffe46..da0709e 100644
--- a/src/cobalt/cssom/property_definitions.h
+++ b/src/cobalt/cssom/property_definitions.h
@@ -244,8 +244,8 @@
 #if defined(BASE_HASH_USE_HASH_STRUCT)
 
 // Forward declaration in case <hash_fun.h> is not #include'd.
-template <typename Key>
-struct hash;
+template <>
+struct hash<cobalt::cssom::PropertyKey>;
 
 template <>
 struct hash<cobalt::cssom::PropertyKey> {
diff --git a/src/cobalt/dom/custom_event_test.cc b/src/cobalt/dom/custom_event_test.cc
index 73b4007..48082a5 100644
--- a/src/cobalt/dom/custom_event_test.cc
+++ b/src/cobalt/dom/custom_event_test.cc
@@ -53,8 +53,8 @@
 class CustomEventTest : public ::testing::Test {
  public:
   CustomEventTest()
-      : environment_settings_(new script::EnvironmentSettings),
-        message_loop_(MessageLoop::TYPE_DEFAULT),
+      : message_loop_(MessageLoop::TYPE_DEFAULT),
+        environment_settings_(new script::EnvironmentSettings),
         css_parser_(css_parser::Parser::Create()),
         dom_parser_(new dom_parser::Parser(mock_error_callback_)),
         fetcher_factory_(new loader::FetcherFactory(NULL)),
@@ -87,11 +87,10 @@
   bool EvaluateScript(const std::string& js_code, std::string* result);
 
  private:
-  scoped_ptr<script::JavaScriptEngine> engine_;
-  scoped_refptr<script::GlobalEnvironment> global_environment_;
-
-  const scoped_ptr<script::EnvironmentSettings> environment_settings_;
   MessageLoop message_loop_;
+  scoped_ptr<script::JavaScriptEngine> engine_;
+  const scoped_ptr<script::EnvironmentSettings> environment_settings_;
+  scoped_refptr<script::GlobalEnvironment> global_environment_;
   MockErrorCallback mock_error_callback_;
   scoped_ptr<css_parser::Parser> css_parser_;
   scoped_ptr<dom_parser::Parser> dom_parser_;
diff --git a/src/cobalt/dom/document.cc b/src/cobalt/dom/document.cc
index 0fb768c..93ad5b6 100644
--- a/src/cobalt/dom/document.cc
+++ b/src/cobalt/dom/document.cc
@@ -214,6 +214,7 @@
 scoped_refptr<Element> Document::CreateElementNS(
     const std::string& namespace_uri, const std::string& local_name) {
   // TODO: Implement namespaces, if we actually need this.
+  NOTIMPLEMENTED();
   UNREFERENCED_PARAMETER(namespace_uri);
   return CreateElement(local_name);
 }
diff --git a/src/cobalt/dom/element.cc b/src/cobalt/dom/element.cc
index d774257..933bd32 100644
--- a/src/cobalt/dom/element.cc
+++ b/src/cobalt/dom/element.cc
@@ -114,6 +114,22 @@
 
 bool Element::HasAttributes() const { return !attribute_map_.empty(); }
 
+base::optional<std::string> Element::GetAttributeNS(
+    const std::string& namespace_uri, const std::string& name) const {
+  // TODO: Implement namespaces, if we actually need this.
+  NOTIMPLEMENTED();
+  UNREFERENCED_PARAMETER(namespace_uri);
+  return GetAttribute(name);
+}
+
+bool Element::HasAttributeNS(const std::string& namespace_uri,
+                             const std::string& name) const {
+  // TODO: Implement namespaces, if we actually need this.
+  NOTIMPLEMENTED();
+  UNREFERENCED_PARAMETER(namespace_uri);
+  return HasAttribute(name);
+}
+
 scoped_refptr<NamedNodeMap> Element::attributes() {
   TRACK_MEMORY_SCOPE("DOM");
   scoped_refptr<NamedNodeMap> named_node_map = named_node_map_.get();
diff --git a/src/cobalt/dom/element.h b/src/cobalt/dom/element.h
index 60ada5b..eb80f06 100644
--- a/src/cobalt/dom/element.h
+++ b/src/cobalt/dom/element.h
@@ -93,6 +93,11 @@
   void RemoveAttribute(const std::string& name);
   bool HasAttribute(const std::string& name) const;
 
+  base::optional<std::string> GetAttributeNS(const std::string& namespace_uri,
+                                             const std::string& name) const;
+  bool HasAttributeNS(const std::string& namespace_uri,
+                      const std::string& name) const;
+
   scoped_refptr<HTMLCollection> GetElementsByTagName(
       const std::string& local_name) const;
   scoped_refptr<HTMLCollection> GetElementsByClassName(
diff --git a/src/cobalt/dom/element.idl b/src/cobalt/dom/element.idl
index a97273f..f6a0ca4 100644
--- a/src/cobalt/dom/element.idl
+++ b/src/cobalt/dom/element.idl
@@ -27,6 +27,8 @@
   void setAttribute(DOMString name, DOMString value);
   void removeAttribute(DOMString name);
   boolean hasAttribute(DOMString name);
+  boolean hasAttributeNS(DOMString namespace_uri, DOMString localName);
+  DOMString? getAttributeNS(DOMString namespace_uri, DOMString name);
   HTMLCollection getElementsByTagName(DOMString localName);
   HTMLCollection getElementsByClassName(DOMString classNames);
 };
diff --git a/src/cobalt/dom/element_test.cc b/src/cobalt/dom/element_test.cc
index 03328eb..e8a0017 100644
--- a/src/cobalt/dom/element_test.cc
+++ b/src/cobalt/dom/element_test.cc
@@ -25,6 +25,7 @@
 #include "cobalt/dom/dom_stat_tracker.h"
 #include "cobalt/dom/dom_token_list.h"
 #include "cobalt/dom/global_stats.h"
+#include "cobalt/dom/html_div_element.h"
 #include "cobalt/dom/html_element.h"
 #include "cobalt/dom/html_element_context.h"
 #include "cobalt/dom/named_node_map.h"
@@ -554,12 +555,39 @@
           ->AsElement();
   element_b2->AppendChild(new Text(document_, "Text"));
 
+  element_a->AppendChild(new Text(document_, "\n  "));
+
+  // Start specifically testing that the "style" attribute is serialized
+  // correctly.
+  scoped_refptr<HTMLElement> div_element_1 =
+      element_a->AppendChild(new HTMLDivElement(document_))->AsElement()
+          ->AsHTMLElement();
+  div_element_1->SetAttribute("style", "height: 20px;");
+
+  element_a->AppendChild(new Text(document_, "\n  "));
+
+  scoped_refptr<HTMLElement> div_element_2 =
+      element_a->AppendChild(new HTMLDivElement(document_))->AsElement()
+          ->AsHTMLElement();
+  div_element_2->AsHTMLElement()->style()->set_width("10px", nullptr);
+
+  element_a->AppendChild(new Text(document_, "\n  "));
+
+  scoped_refptr<HTMLElement> div_element_3 =
+      element_a->AppendChild(new HTMLDivElement(document_))->AsElement()
+          ->AsHTMLElement();
+  div_element_3->SetAttribute("style", "height: 20px;");
+  div_element_3->AsHTMLElement()->style()->set_width("10px", nullptr);
+
   element_a->AppendChild(new Text(document_, "\n"));
 
   const char kExpectedHTML[] =
       "<root><element_a key=\"value\">\n"
       "  <element_b1 just_key></element_b1>\n"
       "  <element_b2>Text</element_b2>\n"
+      "  <div style=\"height: 20px;\"></div>\n"
+      "  <div style=\"width: 10px;\"></div>\n"
+      "  <div style=\"height: 20px; width: 10px;\"></div>\n"
       "</element_a></root>";
   EXPECT_EQ(kExpectedHTML, root->outer_html(NULL));
 
diff --git a/src/cobalt/dom/eme/media_key_session.cc b/src/cobalt/dom/eme/media_key_session.cc
index 35b4abf..b3543ec 100644
--- a/src/cobalt/dom/eme/media_key_session.cc
+++ b/src/cobalt/dom/eme/media_key_session.cc
@@ -27,72 +27,17 @@
 #include "cobalt/script/array_buffer_view.h"
 #include "cobalt/script/script_value_factory.h"
 
-// TODO: Remove this workaround.
-#include "cobalt/network/network_module.h"
-
 namespace cobalt {
 namespace dom {
 namespace eme {
 
-// TODO: Remove this workaround.
-namespace {
-
-const char kIndividualizationUrlPrefix[] =
-    "https://www.googleapis.com/certificateprovisioning/v1/devicecertificates/"
-    "create?key=AIzaSyB-5OLKTx2iU5mko18DfdwK5611JIjbUhE&signedRequest=";
-
-}  // namespace
-
-MediaKeySession::IndividualizationFetcherDelegate::
-    IndividualizationFetcherDelegate(MediaKeySession* media_key_session)
-    : media_key_session_(media_key_session) {
-  DCHECK(media_key_session_);
-}
-
-void MediaKeySession::IndividualizationFetcherDelegate::OnURLFetchDownloadData(
-    const net::URLFetcher* source, scoped_ptr<std::string> download_data) {
-  UNREFERENCED_PARAMETER(source);
-  if (download_data) {
-    response_.insert(response_.end(), download_data->begin(),
-                     download_data->end());
-  }
-}
-
-void MediaKeySession::IndividualizationFetcherDelegate::OnURLFetchComplete(
-    const net::URLFetcher* source) {
-  UNREFERENCED_PARAMETER(source);
-  media_key_session_->OnIndividualizationResponse(response_);
-}
-
-void MediaKeySession::OnIndividualizationResponse(const std::string& response) {
-  DCHECK(invidualization_fetcher_);
-  invidualization_fetcher_.reset();
-
-  if (response.empty()) {
-    // TODO: Add error handling if we are going to keep this workaround.
-    return;
-  }
-
-  script::Handle<script::Promise<void>> promise =
-      script_value_factory_->CreateBasicPromise<void>();
-  drm_system_session_->Update(
-      reinterpret_cast<const uint8*>(response.data()),
-      static_cast<int>(response.size()),
-      base::Bind(&MediaKeySession::OnSessionUpdated, base::AsWeakPtr(this),
-                 base::Owned(new VoidPromiseValue::Reference(this, promise))),
-      base::Bind(&MediaKeySession::OnSessionDidNotUpdate, base::AsWeakPtr(this),
-                 base::Owned(new VoidPromiseValue::Reference(this, promise))));
-}
-
 // See step 3.1 of
 // https://www.w3.org/TR/encrypted-media/#dom-mediakeys-createsession.
 MediaKeySession::MediaKeySession(
     const scoped_refptr<media::DrmSystem>& drm_system,
     script::ScriptValueFactory* script_value_factory,
     const ClosedCallback& closed_callback)
-    : // TODO: Remove this workaround.
-      ALLOW_THIS_IN_INITIALIZER_LIST(invidualization_fetcher_delegate_(this)),
-      ALLOW_THIS_IN_INITIALIZER_LIST(event_queue_(this)),
+    : ALLOW_THIS_IN_INITIALIZER_LIST(event_queue_(this)),
       drm_system_(drm_system),
       drm_system_session_(drm_system->CreateSession(
 #if SB_HAS(DRM_KEY_STATUSES)
@@ -332,32 +277,6 @@
           kMediaKeyMessageTypeLicenseRelease);
       break;
     case kSbDrmSessionRequestTypeIndividualizationRequest:
-      // TODO: Remove this workaround.
-      // Note that |message_size| will never be 0, the if statement serves the
-      // purpose to keep the statements after it uncommented without triggering
-      // any build error.
-      if (message_size != 0) {
-        DCHECK(!invidualization_fetcher_);
-
-        std::string request(
-            reinterpret_cast<const char*>(message.get()),
-            reinterpret_cast<const char*>(message.get()) + message_size);
-        GURL request_url(kIndividualizationUrlPrefix + request);
-        invidualization_fetcher_.reset(
-            net::URLFetcher::Create(request_url, net::URLFetcher::POST,
-                                    &invidualization_fetcher_delegate_));
-        invidualization_fetcher_->SetRequestContext(
-            dom_settings->network_module()->url_request_context_getter());
-        // Don't cache the response, send it to us in OnURLFetchDownloadData().
-        invidualization_fetcher_->DiscardResponse();
-        // Handle redirect automatically.
-        invidualization_fetcher_->SetAutomaticallyRetryOn5xx(true);
-        invidualization_fetcher_->SetStopOnRedirect(false);
-        // TODO: Handle CORS properly if we are going to keep this workaround.
-        invidualization_fetcher_->Start();
-
-        return;
-      }
       media_key_message_event_init.set_message_type(
           kMediaKeyMessageTypeIndividualizationRequest);
       break;
diff --git a/src/cobalt/dom/eme/media_key_session.h b/src/cobalt/dom/eme/media_key_session.h
index 62863e2..73cccbc 100644
--- a/src/cobalt/dom/eme/media_key_session.h
+++ b/src/cobalt/dom/eme/media_key_session.h
@@ -31,10 +31,6 @@
 #include "cobalt/script/script_value_factory.h"
 #include "starboard/drm.h"
 
-// TODO: Remove this workaround.
-#include "net/url_request/url_fetcher.h"
-#include "net/url_request/url_fetcher_delegate.h"
-
 namespace cobalt {
 namespace dom {
 namespace eme {
@@ -72,24 +68,6 @@
   void TraceMembers(script::Tracer* tracer) override;
 
  private:
-  // TODO: Remove this workaround.
-  class IndividualizationFetcherDelegate : public net::URLFetcherDelegate {
-   public:
-    explicit IndividualizationFetcherDelegate(
-        MediaKeySession* media_key_session);
-    void OnURLFetchDownloadData(const net::URLFetcher* source,
-                                scoped_ptr<std::string> download_data) override;
-    void OnURLFetchComplete(const net::URLFetcher* source) override;
-    bool ShouldSendDownloadData() override { return true; }
-
-   private:
-    MediaKeySession* media_key_session_;
-    std::string response_;
-  };
-  IndividualizationFetcherDelegate invidualization_fetcher_delegate_;
-  scoped_ptr<net::URLFetcher> invidualization_fetcher_;
-  void OnIndividualizationResponse(const std::string& response);
-
   ~MediaKeySession() override;
 
   void OnSessionUpdateRequestGenerated(
diff --git a/src/cobalt/dom/error_event_test.cc b/src/cobalt/dom/error_event_test.cc
index 3ca9ae3..483ba90 100644
--- a/src/cobalt/dom/error_event_test.cc
+++ b/src/cobalt/dom/error_event_test.cc
@@ -53,8 +53,8 @@
 class ErrorEventTest : public ::testing::Test {
  public:
   ErrorEventTest()
-      : environment_settings_(new script::EnvironmentSettings),
-        message_loop_(MessageLoop::TYPE_DEFAULT),
+      : message_loop_(MessageLoop::TYPE_DEFAULT),
+        environment_settings_(new script::EnvironmentSettings),
         css_parser_(css_parser::Parser::Create()),
         dom_parser_(new dom_parser::Parser(mock_error_callback_)),
         fetcher_factory_(new loader::FetcherFactory(NULL)),
@@ -89,11 +89,10 @@
   bool EvaluateScript(const std::string& js_code, std::string* result);
 
  private:
-  scoped_ptr<script::JavaScriptEngine> engine_;
-  scoped_refptr<script::GlobalEnvironment> global_environment_;
-
-  const scoped_ptr<script::EnvironmentSettings> environment_settings_;
   MessageLoop message_loop_;
+  scoped_ptr<script::JavaScriptEngine> engine_;
+  const scoped_ptr<script::EnvironmentSettings> environment_settings_;
+  scoped_refptr<script::GlobalEnvironment> global_environment_;
   MockErrorCallback mock_error_callback_;
   scoped_ptr<css_parser::Parser> css_parser_;
   scoped_ptr<dom_parser::Parser> dom_parser_;
diff --git a/src/cobalt/dom/global_event_handlers.idl b/src/cobalt/dom/global_event_handlers.idl
index 9f5ecc8..5e1ab6a 100644
--- a/src/cobalt/dom/global_event_handlers.idl
+++ b/src/cobalt/dom/global_event_handlers.idl
@@ -18,7 +18,7 @@
 interface GlobalEventHandlers {
   attribute EventHandler onblur;
   attribute EventHandler onclick;
-  attribute OnErrorEventListener onerror;
+  attribute OnErrorEventHandler onerror;
   attribute EventHandler onfocus;
 
   attribute EventHandler onkeydown;
diff --git a/src/cobalt/dom/html_media_element.cc b/src/cobalt/dom/html_media_element.cc
index 05f3636..ba28f7b 100644
--- a/src/cobalt/dom/html_media_element.cc
+++ b/src/cobalt/dom/html_media_element.cc
@@ -1124,6 +1124,11 @@
     MediaEngineError(new MediaError(
         MediaError::kMediaErrDecode,
         message.empty() ? "Media loading failed with decode error." : message));
+  } else if (error == WebMediaPlayer::kNetworkStateCapabilityChangedError) {
+    MediaEngineError(new MediaError(
+        MediaError::kMediaErrCapabilityChanged,
+        message.empty() ? "Media loading failed with capability changed error."
+                        : message));
   } else if ((error == WebMediaPlayer::kNetworkStateFormatError ||
               error == WebMediaPlayer::kNetworkStateNetworkError) &&
              load_state_ == kLoadingFromSrcAttr) {
@@ -1354,6 +1359,7 @@
     case WebMediaPlayer::kNetworkStateFormatError:
     case WebMediaPlayer::kNetworkStateNetworkError:
     case WebMediaPlayer::kNetworkStateDecodeError:
+    case WebMediaPlayer::kNetworkStateCapabilityChangedError:
       NOTREACHED() << "Passed SetNetworkState an error state";
       break;
   }
@@ -1365,6 +1371,7 @@
     case WebMediaPlayer::kNetworkStateFormatError:
     case WebMediaPlayer::kNetworkStateNetworkError:
     case WebMediaPlayer::kNetworkStateDecodeError:
+    case WebMediaPlayer::kNetworkStateCapabilityChangedError:
       MediaLoadingFailed(state, message);
       break;
     case WebMediaPlayer::kNetworkStateEmpty:
diff --git a/src/cobalt/dom/media_error.h b/src/cobalt/dom/media_error.h
index d448be8..45b2538 100644
--- a/src/cobalt/dom/media_error.h
+++ b/src/cobalt/dom/media_error.h
@@ -36,6 +36,7 @@
     kMediaErrDecode = 3,
     kMediaErrSrcNotSupported = 4,
     kMediaErrEncrypted = 5,
+    kMediaErrCapabilityChanged = 1000,
   };
 
   // Custom, not in any spec.
diff --git a/src/cobalt/dom/media_error.idl b/src/cobalt/dom/media_error.idl
index 5913592..d188e25 100644
--- a/src/cobalt/dom/media_error.idl
+++ b/src/cobalt/dom/media_error.idl
@@ -20,6 +20,9 @@
   const unsigned short MEDIA_ERR_DECODE = 3;
   const unsigned short MEDIA_ERR_SRC_NOT_SUPPORTED = 4;
   const unsigned short MEDIA_ERR_ENCRYPTED = 5;
+  // The underlying playback capability has changed, the app should treat this
+  // as a transient error and retry playback.
+  const unsigned short MEDIA_ERR_CAPABILITY_CHANGED = 1000;
 
   readonly attribute unsigned short code;
   readonly attribute DOMString message;
diff --git a/src/cobalt/dom/serializer.cc b/src/cobalt/dom/serializer.cc
index b7952a3..16c06f3 100644
--- a/src/cobalt/dom/serializer.cc
+++ b/src/cobalt/dom/serializer.cc
@@ -31,24 +31,35 @@
 namespace dom {
 namespace {
 
+const char kStyleAttributeName[] = "style";
+
 void WriteAtttributes(const scoped_refptr<const Element>& element,
                       std::ostream* out_stream) {
-  if (element->HasAttributes()) {
-    const Element::AttributeMap& attributes = element->attribute_map();
-    typedef std::map<std::string, std::string> SortedAttributeMap;
-    SortedAttributeMap sorted_attribute_map;
-    sorted_attribute_map.insert(attributes.begin(), attributes.end());
+  const Element::AttributeMap& attributes = element->attribute_map();
+  typedef std::map<std::string, std::string> SortedAttributeMap;
+  SortedAttributeMap sorted_attribute_map;
+  sorted_attribute_map.insert(attributes.begin(), attributes.end());
 
-    for (SortedAttributeMap::const_iterator iter = sorted_attribute_map.begin();
-         iter != sorted_attribute_map.end(); ++iter) {
-      const std::string& name = iter->first;
-      const std::string& value = iter->second;
+  {
+    // The "style" attribute is handled specially because HTMLElements store
+    // it explicitly as a cssom::CSSDeclaredStyleDeclaration structure instead
+    // of as an attribute string, so we add it (or replace it) explicitly in the
+    // attribute map.
+    base::optional<std::string> style_attribute = element->GetStyleAttribute();
+    if (style_attribute && !style_attribute->empty()) {
+      sorted_attribute_map[kStyleAttributeName] = std::move(*style_attribute);
+    }
+  }
 
-      *out_stream << " " << name;
-      if (!value.empty()) {
-        *out_stream << "="
-                    << "\"" << value << "\"";
-      }
+  for (SortedAttributeMap::const_iterator iter = sorted_attribute_map.begin();
+       iter != sorted_attribute_map.end(); ++iter) {
+    const std::string& name = iter->first;
+    const std::string& value = iter->second;
+
+    *out_stream << " " << name;
+    if (!value.empty()) {
+      *out_stream << "="
+                  << "\"" << value << "\"";
     }
   }
 }
diff --git a/src/cobalt/dom/window.cc b/src/cobalt/dom/window.cc
index dd833d6..1ae118e 100644
--- a/src/cobalt/dom/window.cc
+++ b/src/cobalt/dom/window.cc
@@ -420,7 +420,7 @@
   }
 }
 
-void Window::DestroyTimers() { window_timers_.reset(); }
+void Window::DestroyTimers() { window_timers_->DisableCallbacks(); }
 
 scoped_refptr<Storage> Window::local_storage() const { return local_storage_; }
 
diff --git a/src/cobalt/dom/window_timers.cc b/src/cobalt/dom/window_timers.cc
index a762d47..265b465 100644
--- a/src/cobalt/dom/window_timers.cc
+++ b/src/cobalt/dom/window_timers.cc
@@ -35,11 +35,16 @@
     return 0;
   }
 
-  scoped_ptr<base::Timer> timer(new base::OneShotTimer<TimerInfo>());
-  timer->Start(FROM_HERE, base::TimeDelta::FromMilliseconds(timeout),
-               base::Bind(&WindowTimers::RunTimerCallback,
-                          base::Unretained(this), handle));
-  timers_[handle] = new TimerInfo(owner_, timer.Pass(), handler);
+  if (callbacks_active_) {
+    scoped_ptr<base::Timer> timer(new base::OneShotTimer<TimerInfo>());
+    timer->Start(FROM_HERE, base::TimeDelta::FromMilliseconds(timeout),
+                 base::Bind(&WindowTimers::RunTimerCallback,
+                            base::Unretained(this), handle));
+    timers_[handle] = new TimerInfo(owner_, timer.Pass(), handler);
+  } else {
+    timers_[handle] = nullptr;
+  }
+
   return handle;
 }
 
@@ -54,11 +59,16 @@
     return 0;
   }
 
-  scoped_ptr<base::Timer> timer(new base::RepeatingTimer<TimerInfo>());
-  timer->Start(FROM_HERE, base::TimeDelta::FromMilliseconds(timeout),
-               base::Bind(&WindowTimers::RunTimerCallback,
-                          base::Unretained(this), handle));
-  timers_[handle] = new TimerInfo(owner_, timer.Pass(), handler);
+  if (callbacks_active_) {
+    scoped_ptr<base::Timer> timer(new base::RepeatingTimer<TimerInfo>());
+    timer->Start(FROM_HERE, base::TimeDelta::FromMilliseconds(timeout),
+                 base::Bind(&WindowTimers::RunTimerCallback,
+                            base::Unretained(this), handle));
+    timers_[handle] = new TimerInfo(owner_, timer.Pass(), handler);
+  } else {
+    timers_[handle] = nullptr;
+  }
+
   return handle;
 }
 
@@ -66,6 +76,14 @@
 
 void WindowTimers::ClearAllIntervalsAndTimeouts() { timers_.clear(); }
 
+void WindowTimers::DisableCallbacks() {
+  callbacks_active_ = false;
+  // Immediately cancel any pending timers.
+  for (auto& timer_entry : timers_) {
+    timer_entry.second = nullptr;
+  }
+}
+
 int WindowTimers::GetFreeTimerHandle() {
   int next_timer_index = current_timer_index_;
   while (true) {
@@ -88,6 +106,8 @@
 
 void WindowTimers::RunTimerCallback(int handle) {
   TRACE_EVENT0("cobalt::dom", "WindowTimers::RunTimerCallback");
+  DCHECK(callbacks_active_)
+      << "All timer callbacks should have already been cancelled.";
   Timers::iterator timer = timers_.find(handle);
   DCHECK(timer != timers_.end());
 
diff --git a/src/cobalt/dom/window_timers.h b/src/cobalt/dom/window_timers.h
index fff7e3c..9021a9b 100644
--- a/src/cobalt/dom/window_timers.h
+++ b/src/cobalt/dom/window_timers.h
@@ -44,6 +44,12 @@
 
   void ClearAllIntervalsAndTimeouts();
 
+  // When called, it will irreversibly put the WindowTimers object in an
+  // inactive state where timer callbacks are ignored.  This is useful when
+  // we're in the process of shutting down and wish to drain the JavaScript
+  // event queue without adding more on to the end of it.
+  void DisableCallbacks();
+
  private:
   class TimerInfo : public base::RefCounted<TimerInfo> {
    public:
@@ -75,6 +81,10 @@
   int current_timer_index_;
   script::Wrappable* const owner_;
 
+  // Set to false when we're about to shutdown, to ensure that no new JavaScript
+  // is fired as we are waiting for it to drain.
+  bool callbacks_active_ = true;
+
   DISALLOW_COPY_AND_ASSIGN(WindowTimers);
 };
 
diff --git a/src/cobalt/layout_tests/layout_tests.cc b/src/cobalt/layout_tests/layout_tests.cc
index bfb3710..a4f0a03 100644
--- a/src/cobalt/layout_tests/layout_tests.cc
+++ b/src/cobalt/layout_tests/layout_tests.cc
@@ -157,6 +157,11 @@
 INSTANTIATE_TEST_CASE_P(
     CSSImages3LayoutTests, LayoutTest,
     ::testing::ValuesIn(EnumerateLayoutTests("css3-images")));
+// Custom CSS Media Queries (https://www.w3.org/TR/css3-mediaqueries/) test
+// cases.
+INSTANTIATE_TEST_CASE_P(
+    CSSMediaQueriesLayoutTests, LayoutTest,
+    ::testing::ValuesIn(EnumerateLayoutTests("css3-mediaqueries")));
 // Custom CSS Text (https://www.w3.org/TR/css-text-3/) test cases.
 INSTANTIATE_TEST_CASE_P(
     CSSText3LayoutTests, LayoutTest,
diff --git a/src/cobalt/layout_tests/testdata/cobalt/window-onerror.html b/src/cobalt/layout_tests/testdata/cobalt/window-onerror.html
index 20bf0b7..399068a 100644
--- a/src/cobalt/layout_tests/testdata/cobalt/window-onerror.html
+++ b/src/cobalt/layout_tests/testdata/cobalt/window-onerror.html
@@ -27,6 +27,12 @@
 }
 
 let windowOnErrorWasCalled = false;
+
+// No need to set this to null, but there was a regression at one point where
+// doing so would result in an erroneous JS error, so add this line in to get
+// some extra test coverage.
+window.onerror = null;
+
 window.onerror = (message, filename, lineno, colno, error) => {
   // We allow anything that ends with "myCoolMessage" to pass, Chrome/Firefox behavior differs here
   // (Chrome: "Uncaught Error: myCoolMessage", Firefox: "Error: myCoolMessage").
@@ -34,7 +40,7 @@
   // Allow any filename that ends with "window-onerror.html", in order to not couple too heavily to
   // the implementation of layout_tests.
   expect(/.*window-onerror.html/.test(filename), filename);
-  expect(lineno === 83, lineno);
+  expect(lineno === 89, lineno);
   // The value of the column number is not standard across major browsers.
   //   Chrome: 1 without devtools open, 7 with devtools open.
   //   Edge: Always 1.
@@ -60,7 +66,7 @@
   expect(/.*myCoolMessage/.test(errorEvent.message), errorEvent.message);
   expect(/.*window-onerror.html/.test(errorEvent.filename),
          errorEvent.filename);
-  expect(errorEvent.lineno === 83, errorEvent.lineno);
+  expect(errorEvent.lineno === 89, errorEvent.lineno);
   expect(errorEvent.colno === 1 || errorEvent.colno === 7 ||
          errorEvent.colno === 18, errorEvent.colno);
   expect(typeof errorEvent.error === 'object', typeof errorEvent.error);
diff --git a/src/cobalt/layout_tests/testdata/css3-mediaqueries/bug_style.css b/src/cobalt/layout_tests/testdata/css3-mediaqueries/bug_style.css
new file mode 100644
index 0000000..51a79a6
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-mediaqueries/bug_style.css
@@ -0,0 +1,55 @@
+body, html {
+  height: 100%;
+  background-color: white;
+  color: black;
+  min-height: 300px;
+  width: 100%;
+  min-width: 300px;
+  margin: 0;
+  overflow: hidden;
+  padding: 0;
+  font-size: 2.0em;
+  line-height: 1.4em;
+  font-family: Roboto;
+}
+
+#span300 {
+  display: block;
+  width:50px;
+  height:100px;
+  background-color: black;
+}
+
+#span400 {
+  display: block;
+  width:100px;
+  height:50px;
+  background-color: yellow;
+}
+
+
+/* Responsive design. Put this at the bottom of this file. */
+@media screen and (min-height: 300px) {
+  body, html {
+    background-color: red;
+    font-size: 3.0em;
+  }
+  #span300 {
+    display: block;
+  }
+  #span400 {
+    display: none;
+  }
+}
+
+@media screen and (min-height: 400px) {
+  body, html {
+    background-color: blue;
+  }
+  #span400 {
+    display: block;
+  }
+  #span300 {
+    display: none;
+  }
+}
diff --git a/src/cobalt/layout_tests/testdata/css3-mediaqueries/layout_tests.txt b/src/cobalt/layout_tests/testdata/css3-mediaqueries/layout_tests.txt
new file mode 100644
index 0000000..3e523a2
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-mediaqueries/layout_tests.txt
@@ -0,0 +1,3 @@
+media_query_rule_precedence_200:200x200
+media_query_rule_precedence_300:300x300
+media_query_rule_precedence_400:400x400
diff --git a/src/cobalt/layout_tests/testdata/css3-mediaqueries/media_query_rule_precedence_200-expected.png b/src/cobalt/layout_tests/testdata/css3-mediaqueries/media_query_rule_precedence_200-expected.png
new file mode 100644
index 0000000..9b4d030
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-mediaqueries/media_query_rule_precedence_200-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-mediaqueries/media_query_rule_precedence_200.html b/src/cobalt/layout_tests/testdata/css3-mediaqueries/media_query_rule_precedence_200.html
new file mode 100644
index 0000000..08fb06a
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-mediaqueries/media_query_rule_precedence_200.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Cascading Media Queries Rule Precedence</title>
+  <link rel='stylesheet' href='bug_style.css' type='text/css'>
+</head>
+
+<body>
+  <span id="span400"></span>
+  <span id="span300"></span>
+</body>
+</html>
diff --git a/src/cobalt/layout_tests/testdata/css3-mediaqueries/media_query_rule_precedence_300-expected.png b/src/cobalt/layout_tests/testdata/css3-mediaqueries/media_query_rule_precedence_300-expected.png
new file mode 100644
index 0000000..5f234e0
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-mediaqueries/media_query_rule_precedence_300-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-mediaqueries/media_query_rule_precedence_300.html b/src/cobalt/layout_tests/testdata/css3-mediaqueries/media_query_rule_precedence_300.html
new file mode 100644
index 0000000..08fb06a
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-mediaqueries/media_query_rule_precedence_300.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Cascading Media Queries Rule Precedence</title>
+  <link rel='stylesheet' href='bug_style.css' type='text/css'>
+</head>
+
+<body>
+  <span id="span400"></span>
+  <span id="span300"></span>
+</body>
+</html>
diff --git a/src/cobalt/layout_tests/testdata/css3-mediaqueries/media_query_rule_precedence_400-expected.png b/src/cobalt/layout_tests/testdata/css3-mediaqueries/media_query_rule_precedence_400-expected.png
new file mode 100644
index 0000000..60e6471
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-mediaqueries/media_query_rule_precedence_400-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-mediaqueries/media_query_rule_precedence_400.html b/src/cobalt/layout_tests/testdata/css3-mediaqueries/media_query_rule_precedence_400.html
new file mode 100644
index 0000000..08fb06a
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-mediaqueries/media_query_rule_precedence_400.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Cascading Media Queries Rule Precedence</title>
+  <link rel='stylesheet' href='bug_style.css' type='text/css'>
+</head>
+
+<body>
+  <span id="span400"></span>
+  <span id="span300"></span>
+</body>
+</html>
diff --git a/src/cobalt/media/base/drm_system.cc b/src/cobalt/media/base/drm_system.cc
index bc63275..5cf1eb6 100644
--- a/src/cobalt/media/base/drm_system.cc
+++ b/src/cobalt/media/base/drm_system.cc
@@ -16,6 +16,7 @@
 
 #include "base/bind.h"
 #include "base/logging.h"
+#include "base/message_loop.h"
 
 namespace cobalt {
 namespace media {
@@ -103,11 +104,9 @@
                                             OnSessionClosedFunc
 #endif  // SB_HAS(DRM_SESSION_CLOSED)
                                             )),  // NOLINT(whitespace/parens)
-      message_loop_(MessageLoop::current()),
+      message_loop_(MessageLoop::current()->message_loop_proxy()),
       ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)),
-      weak_this_(weak_ptr_factory_.GetWeakPtr()),
-      next_session_update_request_ticket_(0),
-      next_session_update_ticket_(0) {
+      weak_this_(weak_ptr_factory_.GetWeakPtr()) {
   DCHECK_NE(kSbDrmSystemInvalid, wrapped_drm_system_);
 }
 
@@ -122,6 +121,7 @@
 #endif  // SB_HAS(DRM_SESSION_CLOSED)
 #endif  // SB_HAS(DRM_KEY_STATUSES)
     ) {  // NOLINT(whitespace/parens)
+  DCHECK(message_loop_->BelongsToCurrentThread());
   return make_scoped_ptr(new Session(this
 #if SB_HAS(DRM_KEY_STATUSES)
                                      ,
@@ -136,25 +136,31 @@
 
 #if SB_API_VERSION >= 10
 bool DrmSystem::IsServerCertificateUpdatable() {
+  DCHECK(message_loop_->BelongsToCurrentThread());
   return SbDrmIsServerCertificateUpdatable(wrapped_drm_system_);
 }
 
 void DrmSystem::UpdateServerCertificate(
     const uint8_t* certificate, int certificate_size,
     ServerCertificateUpdatedCallback server_certificate_updated_callback) {
+  DCHECK(message_loop_->BelongsToCurrentThread());
   DCHECK(IsServerCertificateUpdatable());
-  int ticket = next_session_update_request_ticket_++;
+  int ticket = next_ticket_++;
   ticket_to_server_certificate_updated_map_.insert(
       std::make_pair(ticket, server_certificate_updated_callback));
   SbDrmUpdateServerCertificate(wrapped_drm_system_, ticket, certificate,
                                certificate_size);
 }
 #else   // SB_API_VERSION >= 10
-bool DrmSystem::IsServerCertificateUpdatable() { return false; }
+bool DrmSystem::IsServerCertificateUpdatable() {
+  DCHECK(message_loop_->BelongsToCurrentThread());
+  return false;
+}
 
 void DrmSystem::UpdateServerCertificate(
     const uint8_t* certificate, int certificate_size,
     ServerCertificateUpdatedCallback server_certificate_updated_callback) {
+  DCHECK(message_loop_->BelongsToCurrentThread());
   NOTREACHED();
 }
 #endif  // SB_API_VERSION >= 10
@@ -165,6 +171,8 @@
                               session_update_request_generated_callback,
     const SessionUpdateRequestDidNotGenerateCallback&
         session_update_request_did_not_generate_callback) {
+  DCHECK(message_loop_->BelongsToCurrentThread());
+
   // Store the context of the call.
   SessionUpdateRequest session_update_request;
   session_update_request.session = session;
@@ -172,7 +180,7 @@
       session_update_request_generated_callback;
   session_update_request.did_not_generate_callback =
       session_update_request_did_not_generate_callback;
-  int ticket = next_session_update_request_ticket_++;
+  int ticket = next_ticket_++;
   ticket_to_session_update_request_map_.insert(
       std::make_pair(ticket, session_update_request));
 
@@ -184,11 +192,13 @@
     const std::string& session_id, const uint8_t* key, int key_length,
     const SessionUpdatedCallback& session_updated_callback,
     const SessionDidNotUpdateCallback& session_did_not_update_callback) {
+  DCHECK(message_loop_->BelongsToCurrentThread());
+
   // Store the context of the call.
   SessionUpdate session_update;
   session_update.updated_callback = session_updated_callback;
   session_update.did_not_update_callback = session_did_not_update_callback;
-  int ticket = next_session_update_ticket_++;
+  int ticket = next_ticket_++;
   ticket_to_session_update_map_.insert(std::make_pair(ticket, session_update));
 
   SbDrmUpdateSession(wrapped_drm_system_, ticket, key, key_length,
@@ -196,6 +206,8 @@
 }
 
 void DrmSystem::CloseSession(const std::string& session_id) {
+  DCHECK(message_loop_->BelongsToCurrentThread());
+
   id_to_session_map_.erase(session_id);
   SbDrmCloseSession(wrapped_drm_system_, session_id.c_str(), session_id.size());
 }
diff --git a/src/cobalt/media/base/drm_system.h b/src/cobalt/media/base/drm_system.h
index 6896710..e0fc79b 100644
--- a/src/cobalt/media/base/drm_system.h
+++ b/src/cobalt/media/base/drm_system.h
@@ -22,7 +22,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop.h"
+#include "base/message_loop_proxy.h"
 #include "base/optional.h"
 #include "starboard/drm.h"
 
@@ -272,7 +272,7 @@
 #endif  // SB_API_VERSION >= 10
 
   const SbDrmSystem wrapped_drm_system_;
-  MessageLoop* const message_loop_;
+  scoped_refptr<base::MessageLoopProxy> const message_loop_;
 
   // Factory should only be used to create the initial weak pointer. All
   // subsequent weak pointers are created by copying the initial one. This is
@@ -280,8 +280,8 @@
   base::WeakPtrFactory<DrmSystem> weak_ptr_factory_;
   base::WeakPtr<DrmSystem> weak_this_;
 
+  int next_ticket_ = 0;
   // Supports concurrent calls to |GenerateSessionUpdateRequest|.
-  int next_session_update_request_ticket_;
   TicketToSessionUpdateRequestMap ticket_to_session_update_request_map_;
 
   // Supports spontaneous invocations of |SbDrmSessionUpdateRequestFunc|.
@@ -290,7 +290,6 @@
   TicketToServerCertificateUpdatedMap ticket_to_server_certificate_updated_map_;
 
   // Supports concurrent calls to |Session::Update|.
-  int next_session_update_ticket_;
   TicketToSessionUpdateMap ticket_to_session_update_map_;
 
   DISALLOW_COPY_AND_ASSIGN(DrmSystem);
diff --git a/src/cobalt/media/base/media_log.cc b/src/cobalt/media/base/media_log.cc
index 38a045f..403fe1b 100644
--- a/src/cobalt/media/base/media_log.cc
+++ b/src/cobalt/media/base/media_log.cc
@@ -143,6 +143,8 @@
       return "audio renderer: output device reported an error";
     case AUDIO_RENDERER_ERROR_SPLICE_FAILED:
       return "audio renderer: post-decode audio splicing failed";
+    case PLAYBACK_CAPABILITY_CHANGED:
+      return "pipeline: playback capability changed";
   }
   NOTREACHED();
   return NULL;
diff --git a/src/cobalt/media/base/pipeline_status.h b/src/cobalt/media/base/pipeline_status.h
index 4aa3f0b..79a5d50 100644
--- a/src/cobalt/media/base/pipeline_status.h
+++ b/src/cobalt/media/base/pipeline_status.h
@@ -46,8 +46,11 @@
   AUDIO_RENDERER_ERROR = 19,
   AUDIO_RENDERER_ERROR_SPLICE_FAILED = 20,
 
+  // Transient errors.
+  PLAYBACK_CAPABILITY_CHANGED = 22,
+
   // Must be equal to the largest value ever logged.
-  PIPELINE_STATUS_MAX = PIPELINE_ERROR_EXTERNAL_RENDERER_FAILED,
+  PIPELINE_STATUS_MAX = PLAYBACK_CAPABILITY_CHANGED,
 };
 
 typedef base::Callback<void(PipelineStatus)> PipelineStatusCB;
diff --git a/src/cobalt/media/base/sbplayer_pipeline.cc b/src/cobalt/media/base/sbplayer_pipeline.cc
index 9ef716f..0832b46 100644
--- a/src/cobalt/media/base/sbplayer_pipeline.cc
+++ b/src/cobalt/media/base/sbplayer_pipeline.cc
@@ -1142,18 +1142,28 @@
       ResetAndRunIfNotNull(&error_cb_, PIPELINE_ERROR_NETWORK, message);
       break;
     case kSbPlayerErrorDecode:
+      ResetAndRunIfNotNull(&error_cb_, PIPELINE_ERROR_DECODE, message);
+      break;
 #if SB_API_VERSION >= 10
     case kSbPlayerErrorCapabilityChanged:
 #endif  // SB_API_VERSION >= 10
-      ResetAndRunIfNotNull(&error_cb_, PIPELINE_ERROR_DECODE, message);
+      ResetAndRunIfNotNull(&error_cb_, PLAYBACK_CAPABILITY_CHANGED, message);
       break;
     case kSbPlayerErrorSrcNotSupported:
       ResetAndRunIfNotNull(&error_cb_, DEMUXER_ERROR_COULD_NOT_OPEN, message);
       break;
   }
 #else
-  DCHECK_EQ(error, kSbPlayerErrorDecode);
-  ResetAndRunIfNotNull(&error_cb_, PIPELINE_ERROR_DECODE, message);
+  switch (error) {
+    case kSbPlayerErrorDecode:
+      ResetAndRunIfNotNull(&error_cb_, PIPELINE_ERROR_DECODE, message);
+      break;
+#if SB_API_VERSION >= 10
+    case kSbPlayerErrorCapabilityChanged:
+      ResetAndRunIfNotNull(&error_cb_, PLAYBACK_CAPABILITY_CHANGED, message);
+      break;
+#endif  // SB_API_VERSION >= 10
+  }
 #endif  // SB_HAS(PLAYER_WITH_URL)
 }
 #endif  // SB_HAS(PLAYER_ERROR_MESSAGE)
diff --git a/src/cobalt/media/filters/shell_demuxer.cc b/src/cobalt/media/filters/shell_demuxer.cc
index b9d6b94..5232d1b 100644
--- a/src/cobalt/media/filters/shell_demuxer.cc
+++ b/src/cobalt/media/filters/shell_demuxer.cc
@@ -461,14 +461,9 @@
   // Notify host of each disjoint range.
   host_->OnBufferedTimeRangesChanged(buffered);
 
-  // Post the task with a delay to make the request loop a bit friendly to
-  // other tasks as otherwise IssueNextRequest(), Request(), AllocateBuffer(),
-  // and Download() can form a tight loop on the |blocking_thread_|.
-  const base::TimeDelta kDelay = base::TimeDelta::FromMilliseconds(5);
-  blocking_thread_.message_loop_proxy()->PostDelayedTask(
+  blocking_thread_.message_loop_proxy()->PostTask(
       FROM_HERE,
-      base::Bind(&ShellDemuxer::IssueNextRequest, base::Unretained(this)),
-      kDelay);
+      base::Bind(&ShellDemuxer::IssueNextRequest, base::Unretained(this)));
 }
 
 void ShellDemuxer::IssueNextRequest() {
diff --git a/src/cobalt/media/player/web_media_player.h b/src/cobalt/media/player/web_media_player.h
index 61a379d..3ca8eb7 100644
--- a/src/cobalt/media/player/web_media_player.h
+++ b/src/cobalt/media/player/web_media_player.h
@@ -45,6 +45,7 @@
     kNetworkStateFormatError,
     kNetworkStateNetworkError,
     kNetworkStateDecodeError,
+    kNetworkStateCapabilityChangedError,
   };
 
   enum ReadyState {
diff --git a/src/cobalt/media/player/web_media_player_impl.cc b/src/cobalt/media/player/web_media_player_impl.cc
index a5ac65f..1920b76 100644
--- a/src/cobalt/media/player/web_media_player_impl.cc
+++ b/src/cobalt/media/player/web_media_player_impl.cc
@@ -739,6 +739,10 @@
           WebMediaPlayer::kNetworkStateDecodeError,
           message.empty() ? "Audio renderer splice failed." : message);
       break;
+    case PLAYBACK_CAPABILITY_CHANGED:
+      SetNetworkError(WebMediaPlayer::kNetworkStateCapabilityChangedError,
+                      message.empty() ? "Capability changed." : message);
+      break;
   }
 }
 
diff --git a/src/cobalt/renderer/rasterizer/egl/draw_object.cc b/src/cobalt/renderer/rasterizer/egl/draw_object.cc
index f45e726..98a095e 100644
--- a/src/cobalt/renderer/rasterizer/egl/draw_object.cc
+++ b/src/cobalt/renderer/rasterizer/egl/draw_object.cc
@@ -205,7 +205,7 @@
   }
   if (corners->bottom_left.IsSquare()) {
     corners->bottom_left.horizontal = 0.0f;
-    corners->bottom_right.horizontal = 0.0f;
+    corners->bottom_left.vertical = 0.0f;
   }
 
   // Ensure corner sizes are non-zero to allow generic handling of square and
diff --git a/src/cobalt/renderer/rasterizer/egl/render_tree_node_visitor.cc b/src/cobalt/renderer/rasterizer/egl/render_tree_node_visitor.cc
index 0b00c68..51a4a08 100644
--- a/src/cobalt/renderer/rasterizer/egl/render_tree_node_visitor.cc
+++ b/src/cobalt/renderer/rasterizer/egl/render_tree_node_visitor.cc
@@ -938,11 +938,20 @@
     const backend::TextureEGL** out_texture,
     math::Matrix3F* out_texcoord_transform,
     math::RectF* out_content_rect) {
+
   // Check whether the node is visible.
   math::RectF mapped_bounds = draw_state_.transform.MapRect(node->GetBounds());
+
+  if (!mapped_bounds.IsExpressibleAsRect()) {
+    DLOG(WARNING) << "Invalid rectangle of " << mapped_bounds.ToString()
+                  << " will not be rendered";
+    return;
+  }
+
   math::RectF rounded_out_bounds = RoundOut(mapped_bounds, 0.0f);
   math::RectF clipped_bounds =
       math::IntersectRects(rounded_out_bounds, draw_state_.scissor);
+
   if (clipped_bounds.IsEmpty()) {
     out_content_rect->SetRect(0.0f, 0.0f, 0.0f, 0.0f);
     return;
diff --git a/src/cobalt/renderer/test/jpeg_utils/jpeg_encode.cc b/src/cobalt/renderer/test/jpeg_utils/jpeg_encode.cc
index dde12f6..3284bb1 100644
--- a/src/cobalt/renderer/test/jpeg_utils/jpeg_encode.cc
+++ b/src/cobalt/renderer/test/jpeg_utils/jpeg_encode.cc
@@ -49,8 +49,13 @@
 
   *out_size = jpegSize;
 
-  // Copy the memory from the buffer to a scoped_array to return to the caller.
-  return scoped_array<uint8>(jpeg_buffer);
+  // Copy the memory to return to the caller.
+  // tjCompress2 allocates the data with malloc, and scoped_array deallocates
+  // with delete, so the data has to be copied in.
+  scoped_array<uint8> out_buffer(new uint8[jpegSize]);
+  memcpy(out_buffer.get(), &(jpeg_buffer[0]), jpegSize);
+  SbMemoryDeallocate(jpeg_buffer);
+  return out_buffer.Pass();
 }
 
 }  // namespace jpeg_utils
diff --git a/src/cobalt/script/v8c/cobalt_platform.cc b/src/cobalt/script/v8c/cobalt_platform.cc
new file mode 100644
index 0000000..fd433af
--- /dev/null
+++ b/src/cobalt/script/v8c/cobalt_platform.cc
@@ -0,0 +1,111 @@
+// 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/script/v8c/cobalt_platform.h"
+
+#include "base/logging.h"
+
+namespace cobalt {
+namespace script {
+namespace v8c {
+
+CobaltPlatform::MessageLoopMapEntry* CobaltPlatform::FindOrAddMapEntry(
+    v8::Isolate* isolate) {
+  auto iter = message_loop_map_.find(isolate);
+  // Because of the member unique_ptr, we need explicit creation.
+  if (iter == message_loop_map_.end()) {
+    auto new_entry = std::unique_ptr<CobaltPlatform::MessageLoopMapEntry>(
+        new CobaltPlatform::MessageLoopMapEntry());
+    message_loop_map_.emplace(std::make_pair(isolate, std::move(new_entry)));
+  }
+  DCHECK(message_loop_map_[isolate]);
+  return message_loop_map_[isolate].get();
+}
+
+void CobaltPlatform::RegisterIsolateOnThread(v8::Isolate* isolate,
+                                             MessageLoop* message_loop) {
+  base::AutoLock auto_lock(lock_);
+  auto* message_loop_entry = FindOrAddMapEntry(isolate);
+  message_loop_entry->message_loop = message_loop;
+  if (!message_loop) {
+    DLOG(WARNING) << "Isolate is registered without a valid message loop!";
+    return;
+  }
+  std::vector<std::unique_ptr<TaskBeforeRegistration>> task_vec;
+  task_vec.swap(message_loop_entry->tasks_before_registration);
+  DCHECK(message_loop_entry->tasks_before_registration.empty());
+  for (unsigned int i = 0; i < task_vec.size(); ++i) {
+    scoped_ptr<v8::Task> scoped_task(task_vec[i]->task.release());
+    base::TimeDelta delay =
+        std::max(task_vec[i]->target_time - base::TimeTicks::Now(),
+                 base::TimeDelta::FromSeconds(0));
+    message_loop->PostDelayedTask(
+        FROM_HERE,
+        base::Bind(&CobaltPlatform::RunV8Task, this, isolate,
+                   base::Passed(&scoped_task)),
+        delay);
+  }
+}
+
+void CobaltPlatform::UnregisterIsolateOnThread(v8::Isolate* isolate) {
+  base::AutoLock auto_lock(lock_);
+  MessageLoopMap::iterator iter = message_loop_map_.find(isolate);
+  if (iter != message_loop_map_.end()) {
+    message_loop_map_.erase(iter);
+  } else {
+    DLOG(WARNING) << "Isolate is not in the map and can not be unregistered.";
+  }
+}
+
+void CobaltPlatform::RunV8Task(v8::Isolate* isolate,
+                               scoped_ptr<v8::Task> task) {
+  {
+    base::AutoLock auto_lock(lock_);
+    MessageLoopMap::iterator iter = message_loop_map_.find(isolate);
+    if (iter == message_loop_map_.end() || !iter->second->message_loop) {
+      DLOG(WARNING) << "V8 foreground task executes after isolate "
+                       "unregistered, aborting.";
+      return;
+    }
+  }
+  task->Run();
+}
+
+void CobaltPlatform::CallOnForegroundThread(v8::Isolate* isolate,
+                                            v8::Task* task) {
+  CallDelayedOnForegroundThread(isolate, task, 0);
+}
+
+void CobaltPlatform::CallDelayedOnForegroundThread(v8::Isolate* isolate,
+                                                   v8::Task* task,
+                                                   double delay_in_seconds) {
+  base::AutoLock auto_lock(lock_);
+  auto* message_loop_entry = FindOrAddMapEntry(isolate);
+  if (message_loop_entry->message_loop != NULL) {
+    scoped_ptr<v8::Task> scoped_task(task);
+    message_loop_entry->message_loop->PostDelayedTask(
+        FROM_HERE,
+        base::Bind(&CobaltPlatform::RunV8Task, this, isolate,
+                   base::Passed(&scoped_task)),
+        base::TimeDelta::FromSecondsD(delay_in_seconds));
+  } else {
+    message_loop_map_[isolate]->tasks_before_registration.push_back(
+        std::unique_ptr<TaskBeforeRegistration>(
+            new TaskBeforeRegistration(delay_in_seconds, task)));
+  }
+}
+
+}  // namespace v8c
+}  // namespace script
+}  // namespace cobalt
diff --git a/src/cobalt/script/v8c/cobalt_platform.h b/src/cobalt/script/v8c/cobalt_platform.h
new file mode 100644
index 0000000..e730277
--- /dev/null
+++ b/src/cobalt/script/v8c/cobalt_platform.h
@@ -0,0 +1,142 @@
+// 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_SCRIPT_V8C_COBALT_PLATFORM_H_
+#define COBALT_SCRIPT_V8C_COBALT_PLATFORM_H_
+
+#include <map>
+#include <memory>
+
+#include "base/memory/ref_counted.h"
+#include "base/message_loop.h"
+#include "base/synchronization/lock.h"
+#include "v8/include/libplatform/libplatform.h"
+#include "v8/include/v8-platform.h"
+#include "v8/include/v8.h"
+
+namespace cobalt {
+namespace script {
+namespace v8c {
+
+// Implements v8's platform class to handle some requests from v8 to cobalt.
+// It contains a v8::DefaultPlatform and uses most of its implementations.
+class CobaltPlatform : public base::RefCounted<CobaltPlatform>,
+                       public v8::Platform {
+ public:
+  explicit CobaltPlatform(std::unique_ptr<v8::Platform> platform)
+      : default_platform_(std::move(platform)) {
+    DCHECK(default_platform_.get());
+  }
+
+  // Because foreground tasks have to be run on the isolate's main thread,
+  // each JavaScriptEngine needs to register its isolate in IsolateFellowship
+  // so that when v8 post tasks to an isolate, we know which thread to call
+  // PumpMessageLoop and run the posted task on.
+  void RegisterIsolateOnThread(v8::Isolate* isolate, MessageLoop* message_loop);
+  void UnregisterIsolateOnThread(v8::Isolate* isolate);
+  void RunV8Task(v8::Isolate* isolate, scoped_ptr<v8::Task> task);
+
+  // v8::Platform APIs.
+  v8::PageAllocator* GetPageAllocator() override {
+    return default_platform_->GetPageAllocator();
+  }
+
+  void OnCriticalMemoryPressure() override {
+    default_platform_->OnCriticalMemoryPressure();
+  }
+
+  bool OnCriticalMemoryPressure(size_t length) override {
+    return default_platform_->OnCriticalMemoryPressure(length);
+  }
+
+  std::shared_ptr<v8::TaskRunner> GetForegroundTaskRunner(
+      v8::Isolate* isolate) override {
+    return default_platform_->GetForegroundTaskRunner(isolate);
+  }
+
+  std::shared_ptr<v8::TaskRunner> GetBackgroundTaskRunner(
+      v8::Isolate* isolate) override {
+    return default_platform_->GetBackgroundTaskRunner(isolate);
+  }
+
+  void CallOnBackgroundThread(v8::Task* task,
+                              ExpectedRuntime expected_runtime) override {
+    // DefaultPlatform initializes threads running in the background to do
+    // requested background work.
+    default_platform_->CallOnBackgroundThread(task, expected_runtime);
+  }
+
+  // Post task on the message loop of the isolate's corresponding
+  // JavaScriptEngine's main thread.
+  void CallOnForegroundThread(v8::Isolate* isolate, v8::Task* task) override;
+
+  void CallDelayedOnForegroundThread(v8::Isolate* isolate, v8::Task* task,
+                                     double delay_in_seconds) override;
+
+  void CallIdleOnForegroundThread(v8::Isolate* isolate,
+                                  v8::IdleTask* task) override {
+    SB_NOTIMPLEMENTED();
+  }
+
+  bool IdleTasksEnabled(v8::Isolate* isolate) override { return false; }
+
+  double MonotonicallyIncreasingTime() override {
+    return default_platform_->MonotonicallyIncreasingTime();
+  }
+
+  double CurrentClockTimeMillis() override {
+    return default_platform_->CurrentClockTimeMillis();
+  }
+
+  v8::TracingController* GetTracingController() override {
+    return default_platform_->GetTracingController();
+  }
+
+  v8::Platform* platform() const { return default_platform_.get(); }
+
+ private:
+  std::unique_ptr<v8::Platform> default_platform_;
+
+  struct TaskBeforeRegistration {
+    TaskBeforeRegistration(double delay_in_seconds, v8::Task* task)
+        : target_time(base::TimeTicks::Now() +
+                      base::TimeDelta::FromSecondsD(delay_in_seconds)),
+          task(task) {}
+    base::TimeTicks target_time;
+    std::unique_ptr<v8::Task> task;
+  };
+  struct MessageLoopMapEntry {
+    // If tasks are posted before isolate is registered, we record their delay
+    // and post them when isolate is registered.
+    std::vector<std::unique_ptr<TaskBeforeRegistration>>
+        tasks_before_registration;
+    MessageLoop* message_loop = NULL;
+  };
+  typedef std::map<v8::Isolate*, std::unique_ptr<MessageLoopMapEntry>>
+      MessageLoopMap;
+
+  MessageLoopMapEntry* FindOrAddMapEntry(v8::Isolate* isolate);
+
+  // A lookup table of isolate to its main thread's task runner.
+  MessageLoopMap message_loop_map_;
+  base::Lock lock_;
+
+  DISALLOW_COPY_AND_ASSIGN(CobaltPlatform);
+};
+
+}  // namespace v8c
+}  // namespace script
+}  // namespace cobalt
+
+#endif  // COBALT_SCRIPT_V8C_COBALT_PLATFORM_H_
diff --git a/src/cobalt/script/v8c/isolate_fellowship.cc b/src/cobalt/script/v8c/isolate_fellowship.cc
index 41c59ca..78a99e4 100644
--- a/src/cobalt/script/v8c/isolate_fellowship.cc
+++ b/src/cobalt/script/v8c/isolate_fellowship.cc
@@ -21,24 +21,53 @@
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "starboard/file.h"
-#include "v8/include/libplatform/libplatform.h"
 
 namespace cobalt {
 namespace script {
 namespace v8c {
 
+namespace {
 // This file will also be touched and rebuilt every time V8 is re-built
 // according to the update_snapshot_time gyp target.
 const char kIsolateFellowshipBuildTime[] = __DATE__ " " __TIME__;
 
+const char* kV8CommandLineFlags[] = {"--optimize_for_size",
+                                     // Starboard disallow rwx memory access.
+                                     "--write_protect_code_memory",
+                                     // Cobalt's TraceMembers and
+                                     // ScriptValue::*Reference do not currently
+                                     // support incremental tracing.
+                                     "--noincremental_marking_wrappers",
+#if defined(COBALT_GC_ZEAL)
+                                     "--gc_interval=1200"
+#endif
+};
+
+
+// Configure v8's global command line flag options for Cobalt.
+// It can be called more than once, but make sure it is called before any
+// v8 instance is created.
+void V8FlagsInit() {
+  for (auto flag_str : kV8CommandLineFlags) {
+    v8::V8::SetFlagsFromString(flag_str, SbStringGetLength(flag_str));
+  }
+}
+
+} // namespace
+
 IsolateFellowship::IsolateFellowship() {
   TRACE_EVENT0("cobalt::script", "IsolateFellowship::IsolateFellowship");
   // TODO: Initialize V8 ICU stuff here as well.
-  platform = v8::platform::CreateDefaultPlatform();
+  platform = new CobaltPlatform(
+      std::unique_ptr<v8::Platform>(v8::platform::CreateDefaultPlatform()));
   v8::V8::InitializePlatform(platform);
   v8::V8::Initialize();
   array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
 
+  // If a new snapshot data is needed, a temporary v8 isoalte will be created
+  // to write the snapshot data. We need to make sure all global command line
+  // flags are set before that.
+  V8FlagsInit();
   InitializeStartupData();
 }
 
@@ -47,10 +76,6 @@
   v8::V8::Dispose();
   v8::V8::ShutdownPlatform();
 
-  DCHECK(platform);
-  delete platform;
-  platform = nullptr;
-
   DCHECK(array_buffer_allocator);
   delete array_buffer_allocator;
   array_buffer_allocator = nullptr;
diff --git a/src/cobalt/script/v8c/isolate_fellowship.h b/src/cobalt/script/v8c/isolate_fellowship.h
index 677b060..6b6a631 100644
--- a/src/cobalt/script/v8c/isolate_fellowship.h
+++ b/src/cobalt/script/v8c/isolate_fellowship.h
@@ -16,6 +16,8 @@
 #define COBALT_SCRIPT_V8C_ISOLATE_FELLOWSHIP_H_
 
 #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"
 
@@ -34,7 +36,7 @@
                      StaticMemorySingletonTraits<IsolateFellowship>>::get();
   }
 
-  v8::Platform* platform = nullptr;
+  scoped_refptr<CobaltPlatform> platform = nullptr;
   v8::ArrayBuffer::Allocator* array_buffer_allocator = nullptr;
   v8::StartupData startup_data = {nullptr, 0};
 
diff --git a/src/cobalt/script/v8c/v8c.gyp b/src/cobalt/script/v8c/v8c.gyp
index fe0b091..7fd4c7a 100644
--- a/src/cobalt/script/v8c/v8c.gyp
+++ b/src/cobalt/script/v8c/v8c.gyp
@@ -21,6 +21,8 @@
         'algorithm_helpers.cc',
         'algorithm_helpers.h',
         'callback_function_conversion.h',
+        'cobalt_platform.cc',
+        'cobalt_platform.h',
         'conversion_helpers.cc',
         'conversion_helpers.h',
         'entry_scope.h',
@@ -161,29 +163,30 @@
       # its update indicates V8 code change.
       'target_name': 'update_snapshot_time',
       'type': 'none',
+      'hard_dependency': 1,
       'dependencies': [
         '<(DEPTH)/v8/src/v8.gyp:v8_base',
         '<(DEPTH)/v8/src/v8.gyp:v8_initializers',
         '<(DEPTH)/v8/src/v8.gyp:v8_libplatform',
       ],
       'variables': {
-        'script_path': '<(DEPTH)/starboard/build/touch.py',
-        'output_path': '<(DEPTH)/cobalt/script/v8c/isolate_fellowship.cc',
+        'touch_script_path': '<(DEPTH)/starboard/build/touch.py',
+        'touch_file_path': '<(DEPTH)/cobalt/script/v8c/isolate_fellowship.cc',
+        'dummy_output_path': '<(SHARED_INTERMEDIATE_DIR)/cobalt/script/v8c/isolate_fellowship_is_touched.stamp',
       },
       'actions': [
         {
           'action_name': 'update_snapshot_time',
           'inputs': [
-            '<(script_path)',
+            '<(touch_script_path)',
             '<(PRODUCT_DIR)/obj/v8/src/<(STATIC_LIB_PREFIX)v8_base<(STATIC_LIB_SUFFIX)',
             '<(PRODUCT_DIR)/obj/v8/src/<(STATIC_LIB_PREFIX)v8_initializers<(STATIC_LIB_SUFFIX)',
             '<(PRODUCT_DIR)/obj/v8/src/<(STATIC_LIB_PREFIX)v8_libplatform<(STATIC_LIB_SUFFIX)',
           ],
           'outputs': [
-            '<(output_path)',
+            '<(dummy_output_path)',
           ],
-          'action': ['python', '<(script_path)',
-                     '<(output_path)',
+          'action': ['python', '<(touch_script_path)', '<(touch_file_path)', '<(dummy_output_path)',
           ],
           'message': 'Updating V8 snapshot creation time.',
         },
diff --git a/src/cobalt/script/v8c/v8c_engine.cc b/src/cobalt/script/v8c/v8c_engine.cc
index 2a4234b..25daf87 100644
--- a/src/cobalt/script/v8c/v8c_engine.cc
+++ b/src/cobalt/script/v8c/v8c_engine.cc
@@ -19,7 +19,6 @@
 
 #include "base/debug/trace_event.h"
 #include "base/logging.h"
-#include "base/message_loop.h"
 #include "cobalt/base/c_val.h"
 #include "cobalt/browser/stack_size_constants.h"
 #include "cobalt/script/v8c/isolate_fellowship.h"
@@ -99,15 +98,6 @@
   }
 }
 
-SbOnceControl v8_flag_init_once_control = SB_ONCE_INITIALIZER;
-
-// Configure v8's global command line flag options for Cobalt.
-void V8FlagInitOnce() {
-  char optimize_for_size_flag_str[] = "--optimize_for_size=true";
-  v8::V8::SetFlagsFromString(optimize_for_size_flag_str,
-                             sizeof(optimize_for_size_flag_str));
-}
-
 }  // namespace
 
 V8cEngine::V8cEngine(const Options& options) : options_(options) {
@@ -128,9 +118,10 @@
                     "significantly slow down startup time.";
   }
 
-  SbOnce(&v8_flag_init_once_control, V8FlagInitOnce);
   isolate_ = v8::Isolate::New(create_params);
   CHECK(isolate_);
+  isolate_fellowship->platform->RegisterIsolateOnThread(isolate_,
+                                                        MessageLoop::current());
 
   // There are 2 total isolate data slots, one for the sole |V8cEngine| (us),
   // and one for the |V8cGlobalEnvironment|.
@@ -158,6 +149,8 @@
   TRACE_EVENT0("cobalt::script", "V8cEngine::~V8cEngine");
   DCHECK(thread_checker_.CalledOnValidThread());
 
+  IsolateFellowship::GetInstance()->platform->UnregisterIsolateOnThread(
+      isolate_);
   // Send a low memory notification to V8 in order to force a garbage
   // collection before shut down.  This is required to run weak callbacks that
   // are responsible for freeing native objects that live in the internal
diff --git a/src/cobalt/site/docs/development/setup-linux.md b/src/cobalt/site/docs/development/setup-linux.md
index 0a73913..7320c00 100644
--- a/src/cobalt/site/docs/development/setup-linux.md
+++ b/src/cobalt/site/docs/development/setup-linux.md
@@ -30,7 +30,7 @@
     Cobalt on Linux:
 
     ```
-    $ sudo apt-get install build-essential coreutils git gperf \
+    $ sudo apt-get install bison build-essential coreutils git gperf \
            libasound2-dev libavformat-dev libavresample-dev \
            libdirectfb-dev libdirectfb-extra libpulse-dev \
            libgl1-mesa-dev libgles2-mesa-dev libx11-dev \
@@ -45,23 +45,6 @@
     sudo apt-get install libstdc++-4.8-dev
     ```
 
-1.  Install `bison-2.7`. Note that this series of commands uninstalls any
-    version of `bison` that you already have installed to ensure that the
-    desired version is installed.
-
-    ```
-    $ sudo apt-get remove bison
-    $ cd /tmp
-    $ wget http://ftp.gnu.org/gnu/bison/bison-2.7.1.tar.gz
-    $ tar zxf bison-2.7.1.tar.gz
-    $ cd bison-2.7.1
-    $ sh configure && make && sudo make install
-    $ which bison
-    /usr/local/bin/bison
-    $ bison --version
-    bison (GNU Bison) 2.7.12-4996
-    ```
-
 1.  Clone the Cobalt code repository. The following `git` command creates a
     `cobalt` directory that contains the repository:
 
diff --git a/src/cobalt/tools/cobalt_in_a_tab/README.md b/src/cobalt/tools/cobalt_in_a_tab/README.md
index 912cbbb..e147115 100644
--- a/src/cobalt/tools/cobalt_in_a_tab/README.md
+++ b/src/cobalt/tools/cobalt_in_a_tab/README.md
@@ -16,6 +16,12 @@
 
 1. Launch Cobalt
 2. Press the Cobalt extension icon
+3. Select the device you want to connect to
+
+## Save custom IP endpoints
+
+1. Right-click on the Cobalt extension icon and choose "options"
+2. From here you can save and name device endpoints for future use
 
 ## Future Goals:
 
diff --git a/src/cobalt/tools/cobalt_in_a_tab/background.js b/src/cobalt/tools/cobalt_in_a_tab/background.js
index 63bfe0c..6080171 100644
--- a/src/cobalt/tools/cobalt_in_a_tab/background.js
+++ b/src/cobalt/tools/cobalt_in_a_tab/background.js
@@ -1,8 +1,9 @@
-chrome.browserAction.onClicked.addListener(function(){
-    //open a new tab
-    createProperties = {
-        url: chrome.extension.getURL('cobaltView.html')
-    };
-    chrome.tabs.create(createProperties, function(tab){
+// Local machine is the first "Default" IP.
+chrome.runtime.onInstalled.addListener(function() {
+    chrome.storage.sync.set({
+        ip_endpoints: [{
+            device: 'Local',
+            endpoint: 'http://localhost'
+        }],
     });
-});
\ No newline at end of file
+});
diff --git a/src/cobalt/tools/cobalt_in_a_tab/cobaltService.js b/src/cobalt/tools/cobalt_in_a_tab/cobaltService.js
index fcff762..4c71801 100644
--- a/src/cobalt/tools/cobalt_in_a_tab/cobaltService.js
+++ b/src/cobalt/tools/cobalt_in_a_tab/cobaltService.js
@@ -1,11 +1,24 @@
 let CobaltService = class CobaltService{
-    constructor(){
-        this.webdriverAddress = "http://localhost:4444";
+    constructor(){}
+
+    async initialize(){
+        this.cobaltIP = await this.getCobaltIP();
+        this.webdriverAddress = this.cobaltIP + ":4444";
+
         this.screencastAddress = "";
-    };
+        this.imageId = 0;
+    }
+
+    async getCobaltIP(){
+        return new Promise((resolve) => {
+            chrome.storage.sync.get('selected_ip', function(data) {
+                resolve(data.selected_ip);
+            });
+        });
+    }
 
     setScreencastPort(port){
-        this.screencastAddress = "http://localhost:" + port;
+        this.screencastAddress = this.cobaltIP + ":" + port;
     }
 
     // Boilerplate code. It makes a request to |address| with |data|
@@ -50,6 +63,14 @@
         return this.fetchRequest(address, dataObject, resolveFunction);
     }
 
+    deleteSession(sessionId){
+        let address = `${this.webdriverAddress}/session/${sessionId}`;
+        let dataObject = {
+            method: "DELETE"
+        };
+        return this.fetchRequest(address, dataObject);
+    }
+
     getElement(sessionId){
         let address = `${this.webdriverAddress}/session/${sessionId}/element`;
         let data = {
@@ -89,10 +110,12 @@
     }
 
     sendMouseMove(sessionId, data){
-        fetch(`${this.webdriverAddress}/session/${sessionId}/moveto`, {
+        let address = `${this.webdriverAddress}/session/${sessionId}/moveto`;
+        let headers = {
             method: "POST",
             body: JSON.stringify(data)
-        })
+        };
+        return this.fetchRequest(address, headers);
     }
 
     startScreencast(sessionId){
@@ -107,11 +130,13 @@
         return this.fetchRequest(address, data);
     }
 
-    getScreenshot(sessionId){
-        let address = `${this.screencastAddress}/screenshot`;
-        let data = {method: "GET"};
+    //combine this call to a call with getNextScreenshotId()
+    getScreenshotURL(){
+        return `${this.screencastAddress}/screenshot/`;
+    }
 
-        return this.fetchRequest(address, data);
+    createNextScreenshotId(){
+        return this.imageId++;
     }
 }
 
diff --git a/src/cobalt/tools/cobalt_in_a_tab/cobaltView.html b/src/cobalt/tools/cobalt_in_a_tab/cobaltView.html
index d07c76d..49169c7 100644
--- a/src/cobalt/tools/cobalt_in_a_tab/cobaltView.html
+++ b/src/cobalt/tools/cobalt_in_a_tab/cobaltView.html
@@ -5,7 +5,8 @@
     <script type="module" src="./screenshot.js"></script>
     <link rel="stylesheet" href="styles.css">
 </head>
-<body>
-    <img id="screen"/>
+<body class="black">
+    <div id="screenContainer">
+    </div>
 </body>
 </html>
\ No newline at end of file
diff --git a/src/cobalt/tools/cobalt_in_a_tab/manifest.json b/src/cobalt/tools/cobalt_in_a_tab/manifest.json
index 74ed18d..c1f60cd 100644
--- a/src/cobalt/tools/cobalt_in_a_tab/manifest.json
+++ b/src/cobalt/tools/cobalt_in_a_tab/manifest.json
@@ -4,13 +4,15 @@
   "description": "Run cobalt through chrome.",
   "manifest_version": 2,
   "permissions":
-    ["tabs", "webRequest", "webRequestBlocking", "*://*/"],
+    ["tabs", "webRequest", "webRequestBlocking", "*://*/", "storage"],
   "background": {
     "scripts": ["background.js"],
     "persistent": true
   },
+  "options_page": "options.html",
   "browser_action": {
-    "default_title": "Cobalt"
+    "default_title": "Cobalt",
+    "default_popup": "popup.html" 
   },
   "web_accessible_resources": [
     "cobaltService.js"
diff --git a/src/cobalt/tools/cobalt_in_a_tab/options.html b/src/cobalt/tools/cobalt_in_a_tab/options.html
new file mode 100644
index 0000000..53bcd01
--- /dev/null
+++ b/src/cobalt/tools/cobalt_in_a_tab/options.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+  <html>
+    <head>
+      <link rel="stylesheet" href="styles.css">
+    </head>
+    <body>
+      <h1>IP Endpoints</h1>
+      <div id="ip_list" class="table">
+        <div class="row">
+          <h3 class="listItem">Name</h3>
+          <h3 class="listItem">Endpoint</h3>
+        </div>
+        <div class="row">
+          <input id="inputDevice" type="text" class="listItem" />
+          <div class="listItem">
+            <p class="inline">http://</p>
+            <input id="inputIP" type="text" />
+          </div>
+          <input type="button" value="+" id="addIP"/>
+        </div>
+      </div>
+    </body>
+    <script src="options.js"></script>
+  </html>
\ No newline at end of file
diff --git a/src/cobalt/tools/cobalt_in_a_tab/options.js b/src/cobalt/tools/cobalt_in_a_tab/options.js
new file mode 100644
index 0000000..9b0629e
--- /dev/null
+++ b/src/cobalt/tools/cobalt_in_a_tab/options.js
@@ -0,0 +1,49 @@
+let ip_list = document.getElementById('ip_list');
+let ip_data = null;
+
+// Make list of ip endpoints dynamically.
+let current_ips = chrome.storage.sync.get('ip_endpoints', function(data) {
+  ip_data = data.ip_endpoints;
+  for (let i = 0; i < data.ip_endpoints.length; i++){
+    let item = data.ip_endpoints[i];
+    let ip_item = document.createElement('div');
+    ip_item.classList.add("row");
+    ip_item.id = item.endpoint;
+
+    let ip_title = document.createElement('p');
+    ip_title.innerText += item.device;
+    ip_title.classList.add("listItem");
+
+    let ip_endpoint = document.createElement('p');
+    ip_endpoint.innerText += item.endpoint;
+    ip_endpoint.classList.add("listItem");
+
+    let delete_button = document.createElement('input');
+    delete_button.type = "button";
+    delete_button.value = "-";
+    delete_button.classList.add("listItem");
+    delete_button.onclick = function(){
+      ip_data.splice(i, 1);
+      chrome.storage.sync.set({ip_endpoints: ip_data});
+      window.location.reload();
+    };
+
+    ip_list.appendChild(ip_item);
+
+    ip_item.appendChild(ip_title);
+    ip_item.appendChild(ip_endpoint);
+    ip_item.appendChild(delete_button);
+  }
+});
+
+document.getElementById("addIP").onclick = function () {
+  let add_device = document.getElementById("inputDevice").value;
+  let add_endpoint = "http://" + document.getElementById("inputIP").value;
+  let item = {
+    device: add_device,
+    endpoint: add_endpoint
+  };
+  ip_data.push(item);
+  chrome.storage.sync.set({ip_endpoints: ip_data});
+  window.location.reload();
+};
\ No newline at end of file
diff --git a/src/cobalt/tools/cobalt_in_a_tab/popup.html b/src/cobalt/tools/cobalt_in_a_tab/popup.html
new file mode 100644
index 0000000..afe1427
--- /dev/null
+++ b/src/cobalt/tools/cobalt_in_a_tab/popup.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <link rel="stylesheet" href="styles.css">
+  </head>
+  <body id="popup_body">
+  </body>
+  <script type="text/javascript" src="popup.js"></script>
+</html>
\ No newline at end of file
diff --git a/src/cobalt/tools/cobalt_in_a_tab/popup.js b/src/cobalt/tools/cobalt_in_a_tab/popup.js
new file mode 100644
index 0000000..f8ba95b
--- /dev/null
+++ b/src/cobalt/tools/cobalt_in_a_tab/popup.js
@@ -0,0 +1,23 @@
+let body = document.getElementById('popup_body');
+
+// Dynamically create list of device endpoints.
+let current_ips = chrome.storage.sync.get('ip_endpoints', function(data) {
+  for (let i = 0; i < data.ip_endpoints.length; i++){
+    let item = data.ip_endpoints[i];
+    let ip_item = document.createElement('input');
+    item.device !== "" ? ip_item.value = item.device : ip_item.value = item.endpoint;
+    ip_item.type = "button";
+    ip_item.classList.add("buttonListItem");
+    ip_item.onclick = function(){
+      chrome.storage.sync.set({selected_ip: item.endpoint});
+      //open a new tab
+      createProperties = {
+        url: chrome.extension.getURL('cobaltView.html')
+      };
+      chrome.tabs.create(createProperties, function(tab){
+      });
+    };
+
+    body.appendChild(ip_item);
+  }
+});
\ No newline at end of file
diff --git a/src/cobalt/tools/cobalt_in_a_tab/screenshot.js b/src/cobalt/tools/cobalt_in_a_tab/screenshot.js
index 4543f56..17833eb 100644
--- a/src/cobalt/tools/cobalt_in_a_tab/screenshot.js
+++ b/src/cobalt/tools/cobalt_in_a_tab/screenshot.js
@@ -1,64 +1,106 @@
 import cobaltService from "./cobaltService.js";
 
+// The unique ID needed for almost every webdriver command.
 let sessionId = null;
-let screenshotFrame = null;
+// A container holding all the screens sending requests for frames.
+let screenList = [];
+// The number of screens requesting frames from Cobalt.
+// This must be greater than 1, but can be optimized for performance.
+// On flakey networks, more may be necessary.
+// 3-4 are recommended for stable behavior on a reliable, fast network.
+let numScreens = 4;
+// The screen that is currently displayed to the user.
+let visibleScreen = null;
+// The current position of the mouse relative to the screens.
 let mousePosition = {xPos: 0, yPos:0};
+// The ID of cobalt's body element.
+// Used to send mouse positioning instructions.
 let bodyElementId = null;
+// A cancelable event that sends mouse position to Cobalt.
 let mouseInterval = null;
+// The div that contains all the image frames.
+let parentContainer = null;
 
 window.onload = async function(){
-    screenshotFrame = document.getElementById('screen');
+    await cobaltService.initialize();
+    // Create image tags with the appropriate css.
+    parentContainer = document.getElementById("screenContainer");
+    if (numScreens < 1) return;
+    for (let i = 0; i < numScreens; i++){
+        // Create an image and append it to DOM.
+        let newScreen = document.createElement("img");
+        newScreen.id = "screen" + i;
+        newScreen.classList.add("screen");
+        parentContainer.appendChild(newScreen);
+        screenList.push(newScreen);
+    }
 
+    // Grab a current session.
     let sessions = await cobaltService.getSessions();
-    //grab a current session
     if(sessions.length > 0){
         sessionId = sessions[0];
     }
     else{
-        //create a new session if none are already created
+        // Create a new session if none are already created.
         sessionId = await cobaltService.makeSession();
     }
+    // Get Webdriver body element for mouse positioning.
     bodyElementId = await cobaltService.getElement(sessionId);
-    console.log("session ID is " + sessionId);
 
     cobaltService.startScreencast(sessionId).then((response) => {
-        cobaltService.setScreencastPort(response)
+        cobaltService.setScreencastPort(response);
         subscribeToMouseEvents();
-        //16fps
-        setInterval(takeScreenshot, 500);
+        window.addEventListener("keydown", sendKeyPress);
+        window.addEventListener("beforeunload", function(e){
+            cobaltService.stopScreencast(sessionId);
+            cobaltService.deleteSession(sessionId);
+        }, false);
+
+        // Start requesting screenshots.
+        for (let i = 0; i < screenList.length; i++) {
+            assignScreenshotURLAndId(screenList[i]);
+            // No screenshots are currently displayed.
+            screenList[i].currentImageId = -1;
+            visibleScreen = screenList[0];
+        }
     });
+
+    // Assign image behavior.
+    for (let i = 0; i < screenList.length; i++) {
+        screenList[i].onload = () => { imageLoaded(screenList[i]) };
+        // Reload on error.
+        // TODO - differentiate between types of errors.
+        screenList[i].onerror = () => { assignScreenshotURLAndId(screenList[i]) };
+    }
 }
 
-window.addEventListener("beforeunload", function(e){
-    cobaltService.stopScreencast(sessionId);
- }, false);
+function assignScreenshotURLAndId(screen){
+    let nextImageId = cobaltService.createNextScreenshotId();
+    screen.nextImageId = nextImageId;
+    screen.src = cobaltService.getScreenshotURL() + nextImageId;
+}
 
-function takeScreenshot(){
-    cobaltService.getScreenshot(sessionId)
-    .then((imageSrc) => {
-        screenshotFrame.src = `data:image/jpeg;base64,${imageSrc}`;
-    })
-    .catch((error) => {
-        console.log(error);
-    });
+function imageLoaded(screen){
+    // The image will only become visible if it's more recent than the last image.
+    if(screen.nextImageId > visibleScreen.currentImageId){
+        visibleScreen.classList.remove("visibleScreen");
+        screen.classList.add("visibleScreen");
+        visibleScreen = screen;
+    }
+    screen.currentImageId = screen.nextImageId;
+    assignScreenshotURLAndId(screen);
 }
 
 function sendClick(event){
-    console.log("send click")
     let data = {
         button: event.button
-    }
+    };
     cobaltService.sendClick(sessionId, data);
 }
 
 function sendScroll(event){
-    //prevent default browser action like scrolling on mouseKey
+    // Prevent default browser action like scrolling on mouseKey.
     event.preventDefault();
-
-    let data = {
-
-    }
-    cobaltService.sendScroll(sessionId, scroll)
 }
 
 function saveMousePos(event){
@@ -68,50 +110,33 @@
     };
 }
 
-function sendMousePos(event){
-    let viewportOffset = screenshotFrame.getBoundingClientRect();
+// Requests that get stalled send outdated mouse positions,
+// so only send one at a time. This will help ensure no mouse
+// movements are delayed.
+var mouseLock = false;
+function sendMousePos(){
+    if (mouseLock) return;
+    let viewportOffset = parentContainer.getBoundingClientRect();
 
     let data = {
         element: bodyElementId,
         xoffset: mousePosition.xPos - viewportOffset.left,
         yoffset: mousePosition.yPos - viewportOffset.top
-    }
-    console.log(data)
-    cobaltService.sendMouseMove(sessionId, data);
+    };
+    mouseLock = true;
+    cobaltService.sendMouseMove(sessionId, data)
+    .then((response) => {
+        mouseLock = false;
+    });
 }
 
 function subscribeToMouseEvents(){
-    //send mouse events
-    screenshotFrame.addEventListener('mouseenter', (event) => {
-
-        //subscribe to events
-        window.addEventListener('mousemove', saveMousePos);
-        window.addEventListener('click', sendClick);
-        window.addEventListener('scroll', sendScroll);
-        mouseInterval = setInterval(sendMousePos, 500);
-    });
-
-    //unsubscribe from mouse events
-    screenshotFrame.addEventListener('mouseleave', () => {
-        window.removeEventListener('mousemove', saveMousePos);
-        window.removeEventListener('click', sendClick);
-        window.removeEventListener('scroll', sendScroll);
-        clearInterval(sendMousePos);
-    })
+    window.addEventListener('mousemove', saveMousePos);
+    window.addEventListener('click', sendClick);
+    window.addEventListener('scroll', sendScroll);
+    mouseInterval = setInterval(sendMousePos, 200);
 }
 
-function sendKeyPress(event){
-    console.log("send key press")
-    //prevent default browser action like scrolling on mouseKey
-    event.preventDefault();
-
-    let uKeyCode = mapKeyCode(event.keyCode);
-    if(uKeyCode === null) uKeyCode = event.key;
-    cobaltService.sendKeystrokes(sessionId, [uKeyCode]);
-}
-
-window.addEventListener('keydown', sendKeyPress)
-
 if (typeof KeyEvent === 'undefined') {
     var KeyEvent = {
         DOM_VK_CANCEL: 3,
@@ -233,7 +258,7 @@
 }
 
 function mapKeyCode(code){
-    //want to optimize this for all printable characters ideally
+    // We want to optimize this for all printable characters ideally.
     switch(code){
         case KeyEvent.DOM_VK_UP:
             return '\ue013';
@@ -258,4 +283,13 @@
         default:
             return null;
     }
-}
\ No newline at end of file
+}
+
+function sendKeyPress(event){
+    // Prevent default browser action like scrolling on mouseKey.
+    event.preventDefault();
+
+    let uKeyCode = mapKeyCode(event.keyCode);
+    if(uKeyCode === null) uKeyCode = event.key;
+    cobaltService.sendKeystrokes(sessionId, [uKeyCode]);
+}
diff --git a/src/cobalt/tools/cobalt_in_a_tab/styles.css b/src/cobalt/tools/cobalt_in_a_tab/styles.css
index e6a5578..d0ee406 100644
--- a/src/cobalt/tools/cobalt_in_a_tab/styles.css
+++ b/src/cobalt/tools/cobalt_in_a_tab/styles.css
@@ -1,3 +1,41 @@
-body {
+.black {
     background-color: black;
+}
+
+#screenContainer {
+    position: relative;
+}
+
+.screen {
+    position: absolute;
+    top: 0;
+    left: 0;
+    visibility: hidden;
+}
+
+.visibleScreen {
+    visibility: visible;
+}
+
+.table {
+    display: table;
+}
+
+.row {
+    display: table-row;
+    align-items: center;
+}
+
+.listItem {
+    display: table-cell;
+    padding-right: 5px;
+    padding-left: 5px;
+}
+
+.inline {
+    display: inline;
+}
+
+.buttonListItem {
+    display: block;
 }
\ No newline at end of file
diff --git a/src/cobalt/webdriver/dispatcher.cc b/src/cobalt/webdriver/dispatcher.cc
index 6ef80d7..c4fe36d 100644
--- a/src/cobalt/webdriver/dispatcher.cc
+++ b/src/cobalt/webdriver/dispatcher.cc
@@ -50,6 +50,18 @@
     }
   }
 
+  void SendResultWithContentType(protocol::Response::StatusCode status_code,
+                                 const std::string& content_type,
+                                 const char* data, int len) override {
+    if (status_code == protocol::Response::kSuccess) {
+      response_handler_->SuccessData(content_type, data, len);
+    } else {
+      scoped_ptr<base::Value> response = protocol::Response::CreateResponse(
+          base::nullopt, status_code, scoped_ptr<base::Value>().Pass());
+      response_handler_->FailedCommand(response.Pass());
+    }
+  }
+
   void SendInvalidRequestResponse(RequestError error,
                                   const std::string& error_string) override {
     switch (error) {
diff --git a/src/cobalt/webdriver/dispatcher.h b/src/cobalt/webdriver/dispatcher.h
index 90d9637..c8fbf84 100644
--- a/src/cobalt/webdriver/dispatcher.h
+++ b/src/cobalt/webdriver/dispatcher.h
@@ -83,6 +83,15 @@
         protocol::Response::StatusCode status_code,
         scoped_ptr<base::Value> result) = 0;
 
+    // Send data as a result of a command to the dispatcher. This is similar to
+    // SendResult with the primary difference being the type of data can be of
+    // any valid HTTP content type, specified with |content_type|. For example,
+    // this could be used to send an image. Not used in any
+    // commands in the WebDriver specification.
+    virtual void SendResultWithContentType(
+        protocol::Response::StatusCode status_code,
+        const std::string& content_type, const char* data, int len) = 0;
+
     // Some forms of Invalid Requests are detected in the CommandCallback by
     // checking the path variables and command parameters. Invalid requests are
     // described here:
diff --git a/src/cobalt/webdriver/execute_test.cc b/src/cobalt/webdriver/execute_test.cc
index f188c73..50da6a7 100644
--- a/src/cobalt/webdriver/execute_test.cc
+++ b/src/cobalt/webdriver/execute_test.cc
@@ -127,7 +127,7 @@
       script_executor_->Execute(gc_prevented_params.params, &result_handler));
 }
 
-TEST_F(ScriptExecutorTest, ExecuteAsync) {
+TEST_F(ScriptExecutorTest, FLAKY_ExecuteAsync) {
   // Create a script that will call the async callback after 50 ms, with
   // an async timeout of 100 ms.
   auto gc_prevented_params = ScriptExecutorParams::Create(
diff --git a/src/cobalt/webdriver/screencast/screencast_module.cc b/src/cobalt/webdriver/screencast/screencast_module.cc
index 3b2e53c..dbddbe7 100644
--- a/src/cobalt/webdriver/screencast/screencast_module.cc
+++ b/src/cobalt/webdriver/screencast/screencast_module.cc
@@ -15,7 +15,10 @@
 #include <string>
 
 #include "base/base64.h"
+#include "base/bind.h"
 #include "base/debug/trace_event.h"
+#include "base/logging.h"
+#include "base/string_number_conversions.h"
 #include "base/string_piece.h"
 #include "base/synchronization/waitable_event.h"
 
@@ -26,90 +29,24 @@
 namespace screencast {
 
 namespace {
-
-// Helper struct for getting a JPEG screenshot synchronously.
-struct ScreenshotResultContext {
-  ScreenshotResultContext() : complete_event(true, false) {}
-  scoped_refptr<loader::image::EncodedStaticImage> compressed_file;
-  base::WaitableEvent complete_event;
-};
-
-// Callback function to be called when JPEG encoding is complete.
-void OnJPEGEncodeComplete(
-    ScreenshotResultContext* context,
-    const scoped_refptr<loader::image::EncodedStaticImage>&
-        compressed_image_data) {
-  DCHECK(context);
-  DCHECK(compressed_image_data->GetImageFormat() ==
-         loader::image::EncodedStaticImage::ImageFormat::kJPEG);
-  context->compressed_file = compressed_image_data;
-  context->complete_event.Signal();
-}
-
-}  // namespace
-
-RepeatingScreenshotTaker::RepeatingScreenshotTaker(
-    base::TimeDelta screenshot_interval,
-    const GetScreenshotFunction& screenshot_function)
-    : screenshot_function_(screenshot_function) {
-  const bool retain_user_task = true;
-  const bool is_repeating = true;
-  timed_screenshots_.reset(new base::Timer(retain_user_task, is_repeating));
-
-  const base::Closure screenshot_event = base::Bind(
-      &RepeatingScreenshotTaker::TakeScreenshot, base::Unretained(this));
-  timed_screenshots_->Start(FROM_HERE, screenshot_interval, screenshot_event);
-}
-
-std::string RepeatingScreenshotTaker::GetCurrentScreenshot() {
-  return current_screenshot_;
-}
-
-void RepeatingScreenshotTaker::TakeScreenshot() {
-  TRACE_EVENT0("cobalt::Screencast", "ScreenshotTaker::TakeScreenshot()");
-  ScreenshotResultContext context;
-  screenshot_function_.Run(
-      loader::image::EncodedStaticImage::ImageFormat::kJPEG,
-      base::Bind(&OnJPEGEncodeComplete, base::Unretained(&context)));
-
-  context.complete_event.Wait();
-  DCHECK(context.compressed_file);
-
-  uint32 file_size_in_bytes =
-      context.compressed_file->GetEstimatedSizeInBytes();
-  if (file_size_in_bytes == 0 || !context.compressed_file->GetMemory()) {
-    return;
-  }
-
-  // Encode the JPEG data as a base64 encoded string.
-  std::string encoded;
-  {
-    // base64 encode the contents of the file to be returned to the client.
-    if (!base::Base64Encode(
-            base::StringPiece(
-                reinterpret_cast<char*>(context.compressed_file->GetMemory()),
-                file_size_in_bytes),
-            &encoded)) {
-      return;
-    }
-  }
-
-  current_screenshot_ = encoded;
+const char kJpegContentType[] = "image/jpeg";
 }
 
 ScreencastModule::ScreencastModule(
     int server_port, const std::string& listen_ip,
     const GetScreenshotFunction& screenshot_function)
-    : screenshot_dispatcher_(new webdriver::WebDriverDispatcher()),
+    : screenshot_dispatcher_(new WebDriverDispatcher()),
       screenshot_thread_("Screencast Driver thread"),
-      screenshot_taker_(base::TimeDelta::FromMillisecondsD(
-                            COBALT_MINIMUM_FRAME_TIME_IN_MILLISECONDS),
-                        screenshot_function) {
-  screenshot_dispatcher_->RegisterCommand(
-      webdriver::WebDriverServer::kGet, "/screenshot",
-      base::Bind(&ScreencastModule::GetRecentScreenshot,
-                 base::Unretained(this)));
+      incoming_requests_(),
+      last_served_request_(-1),
+      screenshot_function_(screenshot_function),
+      no_screenshots_pending_(true, false),
+      num_screenshots_processing_(0) {
+  thread_checker_.DetachFromThread();
 
+  screenshot_dispatcher_->RegisterCommand(
+      WebDriverServer::kGet, "/screenshot/:id",
+      base::Bind(&ScreencastModule::PutRequestInQueue, base::Unretained(this)));
   // Start the thread and create the HTTP server on that thread.
   screenshot_thread_.StartWithOptions(
       base::Thread::Options(MessageLoop::TYPE_IO, 0));
@@ -119,6 +56,13 @@
 }
 
 ScreencastModule::~ScreencastModule() {
+  TRACE_EVENT0("cobalt::Screencast", "ScreencastModule::~ScreencastModule()");
+  screenshot_thread_.message_loop()->PostTask(
+      FROM_HERE,
+      base::Bind(&ScreencastModule::StopTimer, base::Unretained(this)));
+
+  no_screenshots_pending_.Wait();
+
   screenshot_thread_.message_loop()->PostTask(
       FROM_HERE,
       base::Bind(&ScreencastModule::StopServer, base::Unretained(this)));
@@ -129,26 +73,118 @@
                                    const std::string& listen_ip) {
   DCHECK(thread_checker_.CalledOnValidThread());
   // Create a new WebDriverServer and pass in the Dispatcher.
+
   screenshot_server_.reset(new WebDriverServer(
       server_port, listen_ip,
       base::Bind(&WebDriverDispatcher::HandleWebDriverServerRequest,
                  base::Unretained(screenshot_dispatcher_.get())),
       "Cobalt.Server.Screencast"));
+
+  bool retain_user_task = true;
+  bool is_repeating = true;
+  screenshot_timer_.reset(new base::Timer(retain_user_task, is_repeating));
+
+  const base::Closure screenshot_event =
+      base::Bind(&ScreencastModule::TakeScreenshot, base::Unretained(this));
+  screenshot_timer_->Start(FROM_HERE,
+                           base::TimeDelta::FromMilliseconds(
+                               COBALT_MINIMUM_FRAME_TIME_IN_MILLISECONDS),
+                           screenshot_event);
 }
 
-void ScreencastModule::StopServer() { screenshot_server_.reset(); }
+void ScreencastModule::StopTimer() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  screenshot_timer_.reset();
 
-void ScreencastModule::GetRecentScreenshot(
+  if (num_screenshots_processing_ < 1) {
+    no_screenshots_pending_.Signal();
+  }
+}
+
+void ScreencastModule::StopServer() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  // Clear out queue of requests.
+  while (!incoming_requests_.empty()) {
+    scoped_refptr<WaitingRequest> next_request = incoming_requests_.front();
+    incoming_requests_.pop();
+    scoped_ptr<base::Value> message = scoped_ptr<base::Value>();
+    // Send rejection to request with invalid ID.
+    next_request->result_handler->SendResult(
+        base::nullopt, protocol::Response::kUnknownError, message.Pass());
+  }
+  screenshot_server_.reset();
+}
+
+void ScreencastModule::PutRequestInQueue(
     const base::Value* parameters,
     const WebDriverDispatcher::PathVariableMap* path_variables,
     scoped_ptr<WebDriverDispatcher::CommandResultHandler> result_handler) {
-  TRACE_EVENT0("cobalt::Screencast", "ScreencastModule::GetRecentScreenshot()");
+  TRACE_EVENT0("cobalt::Screencast", "ScreencastModule::PutRequestInQueue()");
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  scoped_ptr<base::Value> message = scoped_ptr<base::Value>(
-      new base::StringValue(screenshot_taker_.GetCurrentScreenshot()));
-  result_handler->SendResult(base::nullopt, protocol::Response::kSuccess,
-                             message.Pass());
+  scoped_refptr<WaitingRequest> current_request = new WaitingRequest;
+  current_request->result_handler = result_handler.Pass();
+  // The id of request, e.g. screencast/2 would be 2.
+  if (base::StringToInt(path_variables->GetVariable(":id"),
+                        &(current_request->request_id))) {
+    incoming_requests_.push(current_request);
+  } else {
+    // Send rejection to request with invalid ID.
+    scoped_ptr<base::Value> message = scoped_ptr<base::Value>();
+    result_handler->SendResult(base::nullopt, protocol::Response::kUnknownError,
+                               message.Pass());
+  }
+}
+
+void ScreencastModule::SendScreenshotToNextInQueue(
+    const scoped_refptr<loader::image::EncodedStaticImage>& screenshot) {
+  TRACE_EVENT0("cobalt::Screencast",
+               "ScreencastModule::SendScreenshotToNextInQueue()");
+
+  if (MessageLoop::current() != screenshot_thread_.message_loop()) {
+    screenshot_thread_.message_loop()->PostTask(
+        FROM_HERE, base::Bind(&ScreencastModule::SendScreenshotToNextInQueue,
+                              base::Unretained(this), screenshot));
+    return;
+  }
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  num_screenshots_processing_--;
+  // If the timer is off we can check if it's ready to be shutdown.
+  if (screenshot_timer_.get() == nullptr && num_screenshots_processing_ < 1) {
+    no_screenshots_pending_.Signal();
+  }
+
+  while (!incoming_requests_.empty()) {
+    scoped_refptr<WaitingRequest> next_request = incoming_requests_.front();
+    incoming_requests_.pop();
+    scoped_ptr<base::Value> message = scoped_ptr<base::Value>();
+    // Check if request is valid.
+    if (next_request->request_id > last_served_request_) {
+      // Send screenshot.
+      last_served_request_ = next_request->request_id;
+      next_request->result_handler->SendResultWithContentType(
+          protocol::Response::kSuccess, kJpegContentType,
+          reinterpret_cast<char*>(screenshot->GetMemory()),
+          screenshot->GetEstimatedSizeInBytes());
+      return;
+    } else {
+      // Send rejection to request with invalid ID.
+      next_request->result_handler->SendResult(
+          base::nullopt, protocol::Response::kUnknownError, message.Pass());
+    }
+  }
+}
+
+void ScreencastModule::TakeScreenshot() {
+  TRACE_EVENT0("cobalt::Screencast", "ScreencastModule::TakeScreenshot()");
+  if (num_screenshots_processing_ < max_num_screenshots_processing_) {
+    num_screenshots_processing_++;
+    screenshot_function_.Run(
+        loader::image::EncodedStaticImage::ImageFormat::kJPEG,
+        base::Bind(&ScreencastModule::SendScreenshotToNextInQueue,
+                   base::Unretained(this)));
+  }
 }
 
 }  // namespace screencast
diff --git a/src/cobalt/webdriver/screencast/screencast_module.h b/src/cobalt/webdriver/screencast/screencast_module.h
index 3944837..c24e1a9 100644
--- a/src/cobalt/webdriver/screencast/screencast_module.h
+++ b/src/cobalt/webdriver/screencast/screencast_module.h
@@ -15,6 +15,7 @@
 #ifndef COBALT_WEBDRIVER_SCREENCAST_SCREENCAST_MODULE_H_
 #define COBALT_WEBDRIVER_SCREENCAST_SCREENCAST_MODULE_H_
 
+#include <queue>
 #include <string>
 
 #include "base/memory/scoped_ptr.h"
@@ -28,43 +29,20 @@
 namespace webdriver {
 namespace screencast {
 
-// This class is responsible for taking screenshots at regular intervals for the
-// Screencast Module. It's main components are a timer and a callback that takes
-// screenshots The class keeps the last encoded screenshot as a base64 encoded
-// string.
-class RepeatingScreenshotTaker {
- public:
-  typedef base::Callback<void(
-      const scoped_refptr<loader::image::EncodedStaticImage>& image_data)>
-      ScreenshotCompleteCallback;
-  typedef base::Callback<void(loader::image::EncodedStaticImage::ImageFormat,
-                              const ScreenshotCompleteCallback&)>
-      GetScreenshotFunction;
-
-  RepeatingScreenshotTaker(base::TimeDelta screenshot_interval,
-                           const GetScreenshotFunction& screenshot_function);
-
-  std::string GetCurrentScreenshot();
-
- private:
-  // Takes a screenshot, encodes it as a JPEG, converts it to a base64 string,
-  // and saves it as current_screenshot.
-  void TakeScreenshot();
-
-  // The latest available screenshot
-  std::string current_screenshot_;
-
-  scoped_ptr<base::Timer> timed_screenshots_;
-
-  GetScreenshotFunction screenshot_function_;
+struct WaitingRequest : public base::RefCounted<WaitingRequest> {
+  scoped_ptr<webdriver::WebDriverDispatcher::CommandResultHandler>
+      result_handler;
+  int request_id;
 };
 
 // The Screencast Module waits for requests from the server. When the
-// WebDriverDispatcher gets a request for a screenshot it responds with the
-// latest taken screenshot from the RepeatingScreenshotTaker. The server
-// recognises one command - /screenshot. That will return a base64 encoded JPEG
-// image. The client should repeatedly ask for screenshots from this server to
-// get the desired "screencast" affect.
+// WebDriverDispatcher gets a request for a screenshot it puts the request in a
+// queue.  A timer takes screenshots at the current frame rate. When a
+// screenshot is finished, it will be sent to the first valid request on the
+// queue. The server recognises one command - /screenshot:id. That will return a
+// JPEG image. The client should repeatedly ask for screenshots from this server
+// to get the desired "screencast" affect, and it can layer these requests for
+// the optimal framerate.
 class ScreencastModule {
  public:
   typedef base::Callback<void(
@@ -80,15 +58,25 @@
   ~ScreencastModule();
 
  private:
+  void TakeScreenshot();
   void StartServer(int server_port, const std::string& listen_ip);
 
+  void StopTimer();
   void StopServer();
 
-  void GetRecentScreenshot(
+  void PutRequestInQueue(
       const base::Value* parameters,
       const WebDriverDispatcher::PathVariableMap* path_variables,
       scoped_ptr<WebDriverDispatcher::CommandResultHandler> result_handler);
 
+  // This method will search the queue for the first valid request. A valid
+  // request must have an id higher than the last valid request. When an invalid
+  // request is popped off the queue, the screencast server will respond to the
+  // request with an error. At the first valid request, the server will respond
+  // with an image and return.
+  void SendScreenshotToNextInQueue(
+      const scoped_refptr<loader::image::EncodedStaticImage>& screenshot);
+
   // All operations including HTTP server will occur on this thread.
   base::Thread screenshot_thread_;
 
@@ -102,8 +90,32 @@
   // The |screenshot_dispatcher_| sends responses through this HTTP server.
   scoped_ptr<WebDriverServer> screenshot_server_;
 
-  // This constantly compresses screenshots
-  RepeatingScreenshotTaker screenshot_taker_;
+  // The id of the last valid request the screencast server responded to.
+  int last_served_request_;
+
+  // A queue of all the requests, valid or invalid, that are waiting on a
+  // response from the screencast server.
+  std::queue<scoped_refptr<WaitingRequest>> incoming_requests_;
+
+  // Takes a screenshot of the most current frame.
+  GetScreenshotFunction screenshot_function_;
+
+  // This timer is responsible for taking screenshots at regular intervals.
+  scoped_ptr<base::Timer> screenshot_timer_;
+
+  // This event is responsible for a safe shutdown. The event will be signalled
+  // only after the timer has been shutdown and will not request any more
+  // screenshots, and the |num_screenshots_processing_| is zero. Without this
+  // check, the processing screenshots would try to call
+  // SendScreenshotToNextInQueue after the object is destroyed, causing an
+  // error.
+  base::WaitableEvent no_screenshots_pending_;
+
+  // The number of screenshots that |screenshot_timer_| has triggered that are
+  // not complete.
+  int num_screenshots_processing_;
+  // The maximum number of requests that will process simultaneously.
+  int max_num_screenshots_processing_ = 2;
 };
 
 }  // namespace screencast
diff --git a/src/cobalt/webdriver/server.cc b/src/cobalt/webdriver/server.cc
index 9d3ad37..09a6efd 100644
--- a/src/cobalt/webdriver/server.cc
+++ b/src/cobalt/webdriver/server.cc
@@ -82,6 +82,13 @@
     SendInternal(net::HTTP_OK, data, kJsonContentType);
   }
 
+  void SuccessData(const std::string& content_type, const char* data,
+                   int len) override {
+    std::vector<std::string> headers;
+    std::string data_copied(data, len);
+    server_->Send(connection_id_, net::HTTP_OK, data_copied, content_type, headers);
+  }
+
   // Failed commands map to a valid WebDriver command and contain the expected
   // parameters, but otherwise failed to execute for some reason. This should
   // send a 500 Internal Server Error.
diff --git a/src/cobalt/webdriver/server.h b/src/cobalt/webdriver/server.h
index 66841b3..63ff835 100644
--- a/src/cobalt/webdriver/server.h
+++ b/src/cobalt/webdriver/server.h
@@ -57,6 +57,9 @@
     // Called after a successful WebDriver command.
     // https://code.google.com/p/selenium/wiki/JsonWireProtocol#Responses
     virtual void Success(scoped_ptr<base::Value>) = 0;
+    // |content_type| specifies the type of the data using HTTP mime types.
+    virtual void SuccessData(const std::string& content_type, const char* data,
+                             int len) = 0;
 
     // Called after a failed WebDriver command
     // https://code.google.com/p/selenium/wiki/JsonWireProtocol#Failed_Commands
diff --git a/src/net/http/infinite_cache.cc b/src/net/http/infinite_cache.cc
index c261f2d..e0bf878 100644
--- a/src/net/http/infinite_cache.cc
+++ b/src/net/http/infinite_cache.cc
@@ -410,10 +410,10 @@
  private:
   friend class base::RefCountedThreadSafe<Worker>;
 #if defined(BASE_HASH_USE_HASH_STRUCT)
-  typedef BASE_HASH_NAMESPACE::hash_map<
+  typedef base::hash_map<
       Key, Details, BASE_HASH_NAMESPACE::hash<Key>, Key_eq> KeyMap;
 #else
-  typedef BASE_HASH_NAMESPACE::hash_map<
+  typedef base::hash_map<
       Key, Details, BASE_HASH_NAMESPACE::hash_compare<Key, Key_less> > KeyMap;
 #endif
 
diff --git a/src/starboard/build/collect_deploy_content.py b/src/starboard/build/collect_deploy_content.py
index d13ee66..0511b1f 100644
--- a/src/starboard/build/collect_deploy_content.py
+++ b/src/starboard/build/collect_deploy_content.py
@@ -22,11 +22,20 @@
 import shutil
 import sys
 
+import _env # pylint: disable=unused-import
+
 # The name of an environment variable that when set to |'1'|, signals to us that
 # we should log all output directories that we have populated.
 _SHOULD_LOG_ENV_KEY = 'STARBOARD_GYP_SHOULD_LOG_COPIES'
 
 
+_USE_WINDOWS_SYMLINK = sys.platform in ['win32', 'cygwin'] and \
+                       not hasattr(os, 'symlink')
+
+if _USE_WINDOWS_SYMLINK:
+  import starboard.build.win_symlink as win_symlink
+
+
 def EscapePath(path):
   """Returns a path with spaces escaped."""
   return path.replace(' ', '\\ ')
@@ -57,8 +66,19 @@
   for subdir in options.subdirs:
     logging.info('+ %s', subdir)
 
-  if os.path.exists(options.output_dir):
-    shutil.rmtree(options.output_dir)
+  # shutil.rmtree() does not document it's behavior about
+  # how symbolic links UNDER the root directry are traversed.
+  # Following the symlinks and deleting content under windows
+  # causes problems. But under unix systems it may just delete
+  # the symbolink instead of the original content.
+  if _USE_WINDOWS_SYMLINK:
+    # Don't delete objects in original folder.
+    pass
+  else:
+    # TODO: Investigate removing shutil.rmtree() and replacing
+    # it with a recursive delete function which removes symlinks.
+    if os.path.isdir(options.output_dir):
+      shutil.rmtree(options.output_dir)
 
   for subdir in options.subdirs:
     src_path = os.path.abspath(
@@ -71,14 +91,18 @@
 
     logging.info('%s => %s', dst_path, rel_path)
 
-    # TODO: Add an alternate implementation for win32.
     if not os.path.exists(dst_dir):
       os.makedirs(dst_dir)
-    os.symlink(rel_path, dst_path)
+
+    if _USE_WINDOWS_SYMLINK:
+      win_symlink.CreateReparsePoint(src_path, dst_path)
+    else:
+      os.symlink(rel_path, dst_path)
 
   if options.stamp_file:
     with open(options.stamp_file, 'w') as stamp_file:
       stamp_file.write('\n'.join(options.subdirs))
 
+
 if __name__ == '__main__':
   sys.exit(main(sys.argv))
diff --git a/src/starboard/build/win_symlink.py b/src/starboard/build/win_symlink.py
new file mode 100644
index 0000000..514e968
--- /dev/null
+++ b/src/starboard/build/win_symlink.py
@@ -0,0 +1,216 @@
+#!/usr/bin/python
+# 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.
+
+"""
+This file provides functions that provide symlinking of folders. This is
+necessary because os.symlink in python 2.7 is missing for Windows.
+
+Reparse points: Are os-level symlinks for folders which can be created without
+admin access. Symlinks for folders are supported using this mechanism. Note
+that reparse points require special care for traversal, because reparse points
+are often skipped or treated as files by the various python path manipulation
+functions in os and shutil modules. rmtree() as a replacement for
+shutil.rmtree() is provided.
+
+Junction points: Are low level file system symlinks. We do not support these
+yet because creating them requires admin level acccess, or Windows 10 Insiders
+build 14972, which is not widely available yet.
+"""
+
+import os
+import shutil
+import subprocess
+import traceback
+
+
+def CreateReparsePoint(from_folder, link_folder):
+  """ Mimics os.symlink for usage. """
+  return _CreateReparsePoint(from_folder, link_folder)
+
+
+def ReadReparsePoint(path):
+  """ Mimics os.readlink for usage. """
+  return _ReadReparsePoint(path)
+
+
+def IsReparsePoint(path):
+  """ Mimics os.islink for usage. """
+  return _IsReparsePoint(path)
+
+
+def UnlinkReparsePoint(link_dir):
+  """ Mimics os.unlink for usage. """
+  return _UnlinkReparsePoint(link_dir)
+
+
+def Rmtree(dirpath):
+  """ Mimics shutil.rmtree for usage. """
+  return _Rmtree(dirpath)
+
+
+#####################
+# Implementation
+#####################
+
+
+def _Rmtree(dirpath):
+  """ Mimics shutil.rmtree, since that function won't handle
+  reparse points. """
+  delete_path = dirpath
+  reparse_path = _ReadReparsePoint(dirpath)
+  delete_path = reparse_path if reparse_path else dirpath
+  if not delete_path:
+    return
+  if not os.path.exists(delete_path):
+    raise IOError("path " + delete_path + " does not exist.")
+  paths = os.listdir(delete_path)
+  for path in os.listdir(delete_path):
+    fullpath = os.path.join(dirpath, path)
+    if os.path.isdir(fullpath):
+      _Rmtree(fullpath)
+    elif os.path.isfile(fullpath):
+      os.remove(fullpath)
+    else:
+      child_reparse_path = _ReadReparsePoint(fullpath)
+      if child_reparse_path:
+        _Rmtree(child_reparse_path)
+      else:
+        raise IOError("Unknown path type: " + fullpath)
+  if reparse_path:
+    UnlinkReparsePoint(dirpath)
+  if os.path.isdir(delete_path):
+    try:
+      os.removedirs(delete_path)
+    except Exception as err:
+      print("Error while removing " + delete_path \
+            + " because " + str(err))
+
+
+def _ReadReparsePoint(path):
+  path = os.path.abspath(path)
+  cmd_parts = ['fsutil', 'reparsepoint', 'query', path]
+  try:
+    out = subprocess.check_output(cmd_parts)
+  except subprocess.CalledProcessError:
+    # Expected if the link doesn't exist.
+    return None
+  try:
+    lines = out.splitlines()
+    lines = [ l for l in lines if "Print Name:" in l ]
+    if not lines:
+      return None
+    out = lines[0].split()
+    return out[2]
+  except Exception as err:
+    traceback.print_exc()
+    print err
+    return None
+
+
+def _IsReparsePoint(path):
+  return None != _ReadReparsePoint(path)
+
+
+def _CreateReparsePoint(from_folder, link_folder):
+  from_folder = os.path.abspath(from_folder)
+  link_folder = os.path.abspath(link_folder)
+  if os.path.isdir(link_folder):
+    os.removedirs(link_folder)
+  else:
+    _UnlinkReparsePoint(link_folder)  # Deletes if it exists.
+  cmd_parts = ['mklink', '/j', link_folder, from_folder]
+  # Shell is required for reparse point creation.
+  subprocess.check_output(' '.join(cmd_parts), shell=True)
+
+
+def _UnlinkReparsePoint(link_dir):
+  if not _IsReparsePoint(link_dir):
+    return
+  cmd_parts = ['fsutil', 'reparsepoint', 'delete', link_dir]
+  subprocess.check_output(cmd_parts)
+  # The folder will now be unlinked, but will still exist.
+  if os.path.isdir(link_dir):
+    try:
+      os.removedirs(link_dir)
+    except Exception as err:
+      print(__file__ + " could not remove " + link_dir)
+      print(str(err))
+  if _IsReparsePoint(link_dir):
+    raise IOError("Link still exists: " + _ReadReparsePoint(link_dir))
+  if os.path.isdir(link_dir):
+    raise IOError("Link as folder still exists: " + link_dir)
+
+
+def _IsSamePath(p1, p2):
+  if not p1:
+    p1 = None
+  if not p2:
+    p2 = None
+  if p1 == p2:
+    return True
+  if (not p1) or (not p2):
+    return False
+  p1 = os.path.abspath(os.path.normpath(p1))
+  p2 = os.path.abspath(os.path.normpath(p2))
+  if p1 == p2:
+    return True
+  try:
+    return os.stat(p1) == os.stat(p2)
+  except:
+    return False
+
+def UnitTest():
+  """Tests that a small directory hierarchy can be created and then symlinked,
+  and then removed."""
+  tmp_dir = os.path.join(os.environ['temp'], 'win_symlink')
+  from_dir = os.path.join(tmp_dir, 'from_dir')
+  inner_dir = os.path.join(from_dir, 'inner_dir')
+  link_dir = os.path.join(tmp_dir, 'link')
+  if IsReparsePoint(link_dir):
+    print "Deleting previous link_dir:", link_dir
+    UnlinkReparsePoint(link_dir)
+  else:
+    print "Previous link dir does not exist."
+  print "from_dir:", os.path.abspath(from_dir)
+  print "link_dir:", os.path.abspath(link_dir)
+  print "link_dir exists? ", _ReadReparsePoint(link_dir)
+
+  if not os.path.isdir(from_dir):
+    os.makedirs(from_dir)
+  if not os.path.isdir(inner_dir):
+    os.makedirs(inner_dir)
+
+  CreateReparsePoint(from_dir, link_dir)
+  link_created_ok = IsReparsePoint(link_dir)
+  if link_created_ok:
+    print("Link created: " + str(link_created_ok))
+  else:
+    raise IOError("Failed to create link " + link_dir)
+
+  from_dir_2 = ReadReparsePoint(link_dir)
+  if _IsSamePath(from_dir_2, from_dir):
+    print "Link exists."
+  else:
+    raise IOError("Link mismatch: " + from_dir_2 + ' != ' + from_dir)
+
+  Rmtree(link_dir)
+  if os.path.exists(link_dir):
+    raise IOError("Link dir " + link_dir + " still exists.")
+  if os.path.exists(from_dir):
+    raise IOError("From Dir " + from_dir + " still exits.")
+  print "Test completed."
+
+if __name__ == "__main__":
+  UnitTest()
diff --git a/src/starboard/common/scoped_ptr.h b/src/starboard/common/scoped_ptr.h
index b62f1c6..181e271 100644
--- a/src/starboard/common/scoped_ptr.h
+++ b/src/starboard/common/scoped_ptr.h
@@ -358,13 +358,20 @@
   return p1 != p2.get();
 }
 
-// This class wraps the c library function free() in a class that can be
+// This class wraps the SbMemoryDeallocate() function in a class that can be
 // passed as a template argument to scoped_ptr_malloc below.
 class ScopedPtrMallocFree {
  public:
   inline void operator()(void* x) const { SbMemoryDeallocate(x); }
 };
 
+// This class wraps the SbMemoryDeallocateAligned() function in a class that
+// can be passed as a template argument to scoped_ptr_malloc below.
+class ScopedPtrMallocFreeAligned {
+ public:
+  inline void operator()(void* x) const { SbMemoryDeallocateAligned(x); }
+};
+
 // scoped_ptr_malloc<> is similar to scoped_ptr<>, but it accepts a
 // second template argument, the functor used to free the object.
 
diff --git a/src/starboard/configuration.h b/src/starboard/configuration.h
index 65a8a31..edb30c7 100644
--- a/src/starboard/configuration.h
+++ b/src/starboard/configuration.h
@@ -68,6 +68,19 @@
 //   //   exposes functionality for my new feature.
 //   #define SB_MY_EXPERIMENTAL_FEATURE_VERSION SB_EXPERIMENTAL_API_VERSION
 
+// Add support for using C++11 standard unordered maps and sets.
+//   By setting SB_HAS_STD_UNORDERED_HASH to 1, a platform can be configured
+//   to use C++11 standard hash table implementations, specifically, using:
+//   . std::unordered_map<> for base::hash_map<>, and
+//   . std::unordered_multimap<> for base::hash_multimap<>, and
+//   . std::unordered_set<> for base::hash_set<>, and
+//   . std::unordered_multiset<> for base::hash_multiset<>.
+//   When SB_HAS_STD_UNORDERED_HASH is used, it is no longer necessary to
+//   specify SB_HAS_LONG_LONG_HASH, SB_HAS_STRING_HASH, SB_HAS_HASH_USING,
+//   SB_HAS_HASH_VALUE, SB_HAS_HASH_WARNING, SB_HASH_MAP_INCLUDE,
+//   SB_HASH_NAMESPACE, or SB_HASH_SET_INCLUDE.
+#define SB_HAS_STD_UNORDERED_HASH_API_VERSION SB_EXPERIMENTAL_API_VERSION
+
 // --- Release Candidate Feature Defines -------------------------------------
 
 // --- Common Detected Features ----------------------------------------------
@@ -397,6 +410,30 @@
 #error "Your platform must define SB_IMPORT_PLATFORM."
 #endif
 
+#if SB_API_VERSION >= SB_HAS_STD_UNORDERED_HASH_API_VERSION
+#if !SB_HAS(STD_UNORDERED_HASH)
+
+#if !defined(SB_HASH_MAP_INCLUDE)
+#error \
+    "Your platform must define SB_HASH_MAP_INCLUDE or "\
+    "define SB_HAS_STD_UNORDERED_HASH 1."
+#endif
+
+#if !defined(SB_HASH_NAMESPACE)
+#error \
+    "Your platform must define SB_HASH_NAMESPACE or "\
+    "define SB_HAS_STD_UNORDERED_HASH 1."
+#endif
+
+#if !defined(SB_HASH_SET_INCLUDE)
+#error \
+    "Your platform must define SB_HASH_SET_INCLUDE or "\
+    "define SB_HAS_STD_UNORDERED_HASH 1."
+#endif
+
+#endif  // !SB_HAS(STD_UNORDERED_HASH)
+#else   // SB_API_VERSION >= SB_HAS_STD_UNORDERED_HASH_API_VERSION
+
 #if !defined(SB_HASH_MAP_INCLUDE)
 #error "Your platform must define SB_HASH_MAP_INCLUDE."
 #endif
@@ -409,6 +446,7 @@
 #error "Your platform must define SB_HASH_SET_INCLUDE."
 #endif
 
+#endif  // SB_API_VERSION >= SB_HAS_STD_UNORDERED_HASH_API_VERSION
 #if !defined(SB_FILE_MAX_NAME) || SB_FILE_MAX_NAME < 2
 #error "Your platform must define SB_FILE_MAX_NAME > 1."
 #endif
@@ -601,8 +639,9 @@
 
 #if SB_API_VERSION >= 10
 #if !defined(SB_HAS_ASYNC_AUDIO_FRAMES_REPORTING)
-#error Your platform must define SB_HAS_ASYNC_AUDIO_FRAMES_REPORTING in API \
-    version 10 or later.
+#error \
+    "Your platform must define SB_HAS_ASYNC_AUDIO_FRAMES_REPORTING in API "\
+    "version 10 or later."
 #endif  // !defined(SB_HAS_ASYNC_AUDIO_FRAMES_REPORTING)
 #endif  // SB_API_VERSION >= 10
 
diff --git a/src/starboard/contrib/creator/ci20x11/gyp_configuration.py b/src/starboard/contrib/creator/ci20x11/gyp_configuration.py
index b5feb4e..75d9285 100644
--- a/src/starboard/contrib/creator/ci20x11/gyp_configuration.py
+++ b/src/starboard/contrib/creator/ci20x11/gyp_configuration.py
@@ -43,6 +43,7 @@
         ar.StaticThinLinker(),
         ar.StaticLinker(),
         clangxx.ExecutableLinker(path=cxx_path),
+        clangxx.SharedLibraryLinker(path=cxx_path),
         cp.Copy(),
         touch.Stamp(),
         bash.Shell(),
diff --git a/src/starboard/contrib/creator/ci20x11/starboard_platform.gypi b/src/starboard/contrib/creator/ci20x11/starboard_platform.gypi
index d5eabcb..b7446e0 100644
--- a/src/starboard/contrib/creator/ci20x11/starboard_platform.gypi
+++ b/src/starboard/contrib/creator/ci20x11/starboard_platform.gypi
@@ -24,11 +24,18 @@
       '<(DEPTH)/starboard/shared/starboard/link_receiver.cc',
       '<(DEPTH)/starboard/shared/x11/application_x11.cc',
       '<(DEPTH)/starboard/shared/x11/egl_swap_buffers.cc',
+      '<(DEPTH)/starboard/shared/x11/player_set_bounds.cc',
       '<(DEPTH)/starboard/shared/x11/window_create.cc',
       '<(DEPTH)/starboard/shared/x11/window_destroy.cc',
       '<(DEPTH)/starboard/shared/x11/window_get_platform_handle.cc',
       '<(DEPTH)/starboard/shared/x11/window_get_size.cc',
       '<(DEPTH)/starboard/shared/x11/window_internal.cc',
     ],
+
+    # Exclude shared implementations specified by the included .gypi if this
+    # file already specifies a platform-specific version.
+    'starboard_platform_sources!': [
+      '<(DEPTH)/starboard/shared/starboard/player/player_set_bounds.cc',
+    ],
   },
 }
diff --git a/src/starboard/contrib/creator/ci20x11/system_get_property.cc b/src/starboard/contrib/creator/ci20x11/system_get_property.cc
index 23c9e9a..b8461de 100644
--- a/src/starboard/contrib/creator/ci20x11/system_get_property.cc
+++ b/src/starboard/contrib/creator/ci20x11/system_get_property.cc
@@ -36,6 +36,8 @@
   return true;
 }
 
+#if SB_API_VERSION < 10
+
 bool GetPlatformUuid(char* out_value, int value_length) {
   struct ifreq interface;
   struct ifconf config;
@@ -78,6 +80,8 @@
   return false;
 }
 
+#endif  // SB_API_VERSION < 10
+
 }  // namespace
 
 bool SbSystemGetProperty(SbSystemPropertyId property_id,
@@ -103,8 +107,10 @@
     case kSbSystemPropertyPlatformName:
       return CopyStringAndTestIfSuccess(out_value, value_length, kPlatformName);
 
+#if SB_API_VERSION < 10
     case kSbSystemPropertyPlatformUuid:
       return GetPlatformUuid(out_value, value_length);
+#endif  // SB_API_VERSION < 10
 
     default:
       SB_DLOG(WARNING) << __FUNCTION__
diff --git a/src/starboard/contrib/creator/shared/configuration_public.h b/src/starboard/contrib/creator/shared/configuration_public.h
index 4dcec1d..bb5d572 100644
--- a/src/starboard/contrib/creator/shared/configuration_public.h
+++ b/src/starboard/contrib/creator/shared/configuration_public.h
@@ -88,7 +88,7 @@
 #define SB_HAS_CROSS_CORE_SCHEDULER 1
 
 // The API version implemented by this platform.
-#define SB_API_VERSION 6
+#define SB_API_VERSION SB_EXPERIMENTAL_API_VERSION
 
 // --- System Header Configuration -------------------------------------------
 
@@ -162,6 +162,9 @@
 
 // --- Extensions Configuration ----------------------------------------------
 
+// Do not use <unordered_map> and <unordered_set> for the hash table types.
+#define SB_HAS_STD_UNORDERED_HASH 0
+
 // GCC/Clang doesn't define a long long hash function, except for Android and
 // Game consoles.
 #define SB_HAS_LONG_LONG_HASH 0
@@ -276,6 +279,14 @@
 // Whether the current platform has speech synthesis.
 #define SB_HAS_SPEECH_SYNTHESIS 0
 
+#if SB_API_VERSION >= 8
+// Whether the current platform implements the on screen keyboard interface.
+#define SB_HAS_ON_SCREEN_KEYBOARD 0
+
+// Whether the current platform uses a media player that relies on a URL.
+#define SB_HAS_PLAYER_WITH_URL 0
+#endif  // SB_API_VERSION >= 8
+
 // --- Media Configuration ---------------------------------------------------
 
 // Specifies whether this platform has support for a possibly-decrypting
@@ -326,6 +337,13 @@
 // stack size for media stack threads.
 #define SB_MEDIA_THREAD_STACK_SIZE 0U
 
+// Specifies whether this platform updates audio frames asynchronously.  In such
+// case an extra parameter will be added to |SbAudioSinkConsumeFramesFunc| to
+// indicate the absolute time that the consumed audio frames are reported.
+// Check document for |SbAudioSinkConsumeFramesFunc| in audio_sink.h for more
+// details.
+#define SB_HAS_ASYNC_AUDIO_FRAMES_REPORTING 0
+
 // --- Decoder-only Params ---
 
 // Specifies how media buffers must be aligned on this platform as some
diff --git a/src/starboard/contrib/creator/shared/gyp_configuration.py b/src/starboard/contrib/creator/shared/gyp_configuration.py
index 0916e68..244d13d 100644
--- a/src/starboard/contrib/creator/shared/gyp_configuration.py
+++ b/src/starboard/contrib/creator/shared/gyp_configuration.py
@@ -72,8 +72,9 @@
 
   def GetEnvironmentVariables(self):
     self.ci20_home = self._GetCi20Home()
-    self.host_compiler_environment = build.GetHostCompilerEnvironment(
-        clang.GetClangSpecification(), False)
+    if not hasattr(self, 'host_compiler_environment'):
+      self.host_compiler_environment = build.GetHostCompilerEnvironment(
+          clang.GetClangSpecification(), False)
     env_variables = self.host_compiler_environment
     env_variables = {
         'CC': self.host_compiler_environment['CC_host'],
diff --git a/src/starboard/shared/starboard/media/media_is_video_supported_h264_1080p_sfr_only.cc b/src/starboard/contrib/creator/shared/media_is_video_supported.cc
similarity index 100%
rename from src/starboard/shared/starboard/media/media_is_video_supported_h264_1080p_sfr_only.cc
rename to src/starboard/contrib/creator/shared/media_is_video_supported.cc
diff --git a/src/starboard/contrib/creator/shared/starboard_platform.gypi b/src/starboard/contrib/creator/shared/starboard_platform.gypi
index dc68740..0353a9e 100644
--- a/src/starboard/contrib/creator/shared/starboard_platform.gypi
+++ b/src/starboard/contrib/creator/shared/starboard_platform.gypi
@@ -14,6 +14,7 @@
 {
   'variables': {
     'starboard_platform_sources': [
+      '<(DEPTH)/starboard/contrib/creator/shared/media_is_video_supported.cc',
       '<(DEPTH)/starboard/contrib/creator/shared/player_components_impl.cc',
       '<(DEPTH)/starboard/linux/shared/atomic_public.h',
       '<(DEPTH)/starboard/linux/shared/decode_target_internal.h',
@@ -35,6 +36,7 @@
       '<(DEPTH)/starboard/shared/dlmalloc/memory_free.cc',
       '<(DEPTH)/starboard/shared/dlmalloc/memory_free_aligned.cc',
       '<(DEPTH)/starboard/shared/dlmalloc/memory_map.cc',
+      '<(DEPTH)/starboard/shared/dlmalloc/memory_protect.cc',
       '<(DEPTH)/starboard/shared/dlmalloc/memory_reallocate_unchecked.cc',
       '<(DEPTH)/starboard/shared/dlmalloc/memory_unmap.cc',
       '<(DEPTH)/starboard/shared/gcc/atomic_gcc_public.h',
@@ -214,11 +216,22 @@
       '<(DEPTH)/starboard/shared/starboard/media/codec_util.cc',
       '<(DEPTH)/starboard/shared/starboard/media/codec_util.h',
       '<(DEPTH)/starboard/shared/starboard/media/media_can_play_mime_and_key_system.cc',
+      '<(DEPTH)/starboard/shared/starboard/media/media_get_audio_buffer_budget.cc',
       '<(DEPTH)/starboard/shared/starboard/media/media_get_audio_configuration_stereo_only.cc',
-      '<(DEPTH)/starboard/shared/starboard/media/media_get_audio_output_count_stereo_only.cc',
+      '<(DEPTH)/starboard/shared/starboard/media/media_get_audio_output_count_single_audio_output.cc',
+      '<(DEPTH)/starboard/shared/starboard/media/media_get_buffer_alignment.cc',
+      '<(DEPTH)/starboard/shared/starboard/media/media_get_buffer_allocation_unit.cc',
+      '<(DEPTH)/starboard/shared/starboard/media/media_get_buffer_garbage_collection_duration_threshold.cc',
+      '<(DEPTH)/starboard/shared/starboard/media/media_get_buffer_padding.cc',
+      '<(DEPTH)/starboard/shared/starboard/media/media_get_buffer_storage_type.cc',
+      '<(DEPTH)/starboard/shared/starboard/media/media_get_initial_buffer_capacity.cc',
+      '<(DEPTH)/starboard/shared/starboard/media/media_get_max_buffer_capacity.cc',
+      '<(DEPTH)/starboard/shared/starboard/media/media_get_progressive_buffer_budget.cc',
+      '<(DEPTH)/starboard/shared/starboard/media/media_get_video_buffer_budget.cc',
       '<(DEPTH)/starboard/shared/starboard/media/media_is_audio_supported_aac_only.cc',
       '<(DEPTH)/starboard/shared/starboard/media/media_is_output_protected.cc',
-      '<(DEPTH)/starboard/shared/starboard/media/media_is_video_supported_h264_1080p_sfr_only.cc',
+      '<(DEPTH)/starboard/shared/starboard/media/media_is_buffer_pool_allocate_on_demand.cc',
+      '<(DEPTH)/starboard/shared/starboard/media/media_is_buffer_using_memory_pool.cc',
       '<(DEPTH)/starboard/shared/starboard/media/media_set_output_protection.cc',
       '<(DEPTH)/starboard/shared/starboard/media/media_util.cc',
       '<(DEPTH)/starboard/shared/starboard/media/media_util.h',
@@ -274,10 +287,13 @@
       '<(DEPTH)/starboard/shared/starboard/player/player_destroy.cc',
       '<(DEPTH)/starboard/shared/starboard/player/player_get_current_frame.cc',
       '<(DEPTH)/starboard/shared/starboard/player/player_get_info.cc',
+      '<(DEPTH)/starboard/shared/starboard/player/player_get_info2.cc',
+      '<(DEPTH)/starboard/shared/starboard/player/player_get_maximum_number_of_samples_per_write.cc',
       '<(DEPTH)/starboard/shared/starboard/player/player_output_mode_supported.cc',
       '<(DEPTH)/starboard/shared/starboard/player/player_internal.cc',
       '<(DEPTH)/starboard/shared/starboard/player/player_internal.h',
       '<(DEPTH)/starboard/shared/starboard/player/player_seek.cc',
+      '<(DEPTH)/starboard/shared/starboard/player/player_seek2.cc',
       '<(DEPTH)/starboard/shared/starboard/player/player_set_bounds.cc',
       '<(DEPTH)/starboard/shared/starboard/player/player_set_playback_rate.cc',
       '<(DEPTH)/starboard/shared/starboard/player/player_set_volume.cc',
@@ -285,6 +301,7 @@
       '<(DEPTH)/starboard/shared/starboard/player/player_worker.h',
       '<(DEPTH)/starboard/shared/starboard/player/player_write_end_of_stream.cc',
       '<(DEPTH)/starboard/shared/starboard/player/player_write_sample.cc',
+      '<(DEPTH)/starboard/shared/starboard/player/player_write_sample2.cc',
       '<(DEPTH)/starboard/shared/starboard/queue_application.cc',
       '<(DEPTH)/starboard/shared/starboard/string_concat.cc',
       '<(DEPTH)/starboard/shared/starboard/string_concat_wide.cc',
@@ -296,6 +313,7 @@
       '<(DEPTH)/starboard/shared/starboard/system_request_stop.cc',
       '<(DEPTH)/starboard/shared/starboard/system_request_suspend.cc',
       '<(DEPTH)/starboard/shared/starboard/system_request_unpause.cc',
+      '<(DEPTH)/starboard/shared/starboard/system_supports_resume.cc',
       '<(DEPTH)/starboard/shared/starboard/window_set_default_options.cc',
       '<(DEPTH)/starboard/shared/stub/accessibility_get_display_settings.cc',
       '<(DEPTH)/starboard/shared/stub/accessibility_get_text_to_speech_settings.cc',
@@ -313,6 +331,8 @@
       '<(DEPTH)/starboard/shared/stub/drm_generate_session_update_request.cc',
       '<(DEPTH)/starboard/shared/stub/drm_system_internal.h',
       '<(DEPTH)/starboard/shared/stub/drm_update_session.cc',
+      '<(DEPTH)/starboard/shared/stub/drm_is_server_certificate_updatable.cc',
+      '<(DEPTH)/starboard/shared/stub/drm_update_server_certificate.cc',
       '<(DEPTH)/starboard/shared/stub/image_decode.cc',
       '<(DEPTH)/starboard/shared/stub/image_is_decode_supported.cc',
       '<(DEPTH)/starboard/shared/stub/media_is_supported.cc',
diff --git a/src/starboard/contrib/tizen/shared/configuration_public.h b/src/starboard/contrib/tizen/shared/configuration_public.h
index f6c7875..d004436 100644
--- a/src/starboard/contrib/tizen/shared/configuration_public.h
+++ b/src/starboard/contrib/tizen/shared/configuration_public.h
@@ -94,6 +94,9 @@
 
 // --- Extensions Configuration ----------------------------------------------
 
+// Do not use <unordered_map> and <unordered_set> for the hash table types.
+#define SB_HAS_STD_UNORDERED_HASH 0
+
 // GCC/Clang doesn't define a long long hash function, except for Android and
 // Game consoles.
 #define SB_HAS_LONG_LONG_HASH 0
diff --git a/src/starboard/linux/shared/configuration_public.h b/src/starboard/linux/shared/configuration_public.h
index daa5342..eacb7da 100644
--- a/src/starboard/linux/shared/configuration_public.h
+++ b/src/starboard/linux/shared/configuration_public.h
@@ -102,6 +102,9 @@
 
 // --- Extensions Configuration ----------------------------------------------
 
+// Do not use <unordered_map> and <unordered_set> for the hash table types.
+#define SB_HAS_STD_UNORDERED_HASH 0
+
 // GCC/Clang doesn't define a long long hash function, except for Android and
 // Game consoles.
 #define SB_HAS_LONG_LONG_HASH 0
diff --git a/src/starboard/linux/shared/drm_create_system.cc b/src/starboard/linux/shared/drm_create_system.cc
new file mode 100644
index 0000000..b213cb0
--- /dev/null
+++ b/src/starboard/linux/shared/drm_create_system.cc
@@ -0,0 +1,70 @@
+// 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/drm.h"
+
+#include "starboard/log.h"
+#include "starboard/shared/widevine/drm_system_widevine.h"
+#include "starboard/string.h"
+
+SbDrmSystem SbDrmCreateSystem(
+    const char* key_system,
+    void* context,
+    SbDrmSessionUpdateRequestFunc update_request_callback,
+    SbDrmSessionUpdatedFunc session_updated_callback
+#if SB_HAS(DRM_KEY_STATUSES)
+    ,
+    SbDrmSessionKeyStatusesChangedFunc key_statuses_changed_callback
+#endif  // SB_HAS(DRM_KEY_STATUSES)
+#if SB_API_VERSION >= 10
+    ,
+    SbDrmServerCertificateUpdatedFunc server_certificate_updated_callback,
+    SbDrmSessionClosedFunc session_closed_callback
+#endif  // SB_API_VERSION >= 10
+    ) {
+  using starboard::shared::widevine::DrmSystemWidevine;
+  if (!update_request_callback || !session_updated_callback) {
+    return kSbDrmSystemInvalid;
+  }
+#if SB_HAS(DRM_KEY_STATUSES)
+  if (!key_statuses_changed_callback) {
+    return kSbDrmSystemInvalid;
+  }
+#endif  // SB_HAS(DRM_KEY_STATUSES)
+#if SB_API_VERSION >= 10
+  if (!server_certificate_updated_callback || !session_closed_callback) {
+    return kSbDrmSystemInvalid;
+  }
+#endif  // SB_API_VERSION >= 10
+  if (!DrmSystemWidevine::IsKeySystemSupported(key_system)) {
+    SB_DLOG(WARNING) << "Invalid key system " << key_system;
+    return kSbDrmSystemInvalid;
+  }
+  return new DrmSystemWidevine(context, update_request_callback,
+                               session_updated_callback
+#if SB_HAS(DRM_KEY_STATUSES)
+                               ,
+                               key_statuses_changed_callback
+#endif  // SB_HAS(DRM_KEY_STATUSES)
+#if SB_API_VERSION >= 10
+                               ,
+                               server_certificate_updated_callback
+#endif  // SB_API_VERSION >= 10
+#if SB_HAS(DRM_SESSION_CLOSED)
+                               ,
+                               session_closed_callback
+#endif  // SB_HAS(DRM_SESSION_CLOSED)
+                               ,
+                               "Linux", "Linux");
+}
diff --git a/src/starboard/linux/shared/gyp_configuration.gypi b/src/starboard/linux/shared/gyp_configuration.gypi
index 4ee21a1..5706563 100644
--- a/src/starboard/linux/shared/gyp_configuration.gypi
+++ b/src/starboard/linux/shared/gyp_configuration.gypi
@@ -20,6 +20,7 @@
     'target_arch%': 'x64',
     'target_os': 'linux',
     'yasm_exists': 1,
+    'sb_widevine_platform' : 'linux',
 
     'platform_libraries': [
       '-lasound',
diff --git a/src/starboard/linux/shared/media_is_video_supported.cc b/src/starboard/linux/shared/media_is_video_supported.cc
index 906ef5b..cf31d04 100644
--- a/src/starboard/linux/shared/media_is_video_supported.cc
+++ b/src/starboard/linux/shared/media_is_video_supported.cc
@@ -21,7 +21,24 @@
                                        int frame_width,
                                        int frame_height,
                                        int64_t bitrate,
-                                       int fps) {
+                                       int fps
+#if SB_API_VERSION >= 10
+                                       ,
+                                       bool decode_to_texture_required
+#endif  // SB_API_VERSION >= 10
+                                       ) {
+#if SB_API_VERSION >= 10
+#if SB_HAS(BLITTER)
+  if (decode_to_texture_required) {
+    return false;
+  }
+#else
+  // Assume that all non-Blitter Linux platforms can play decode-to-texture
+  // video just as well as normal video.
+  SB_UNREFERENCED_PARAMETER(decode_to_texture_required);
+#endif  // SB_HAS(BLITTER)
+#endif  // SB_API_VERSION >= 10
+
   return (video_codec == kSbMediaVideoCodecH264 ||
           video_codec == kSbMediaVideoCodecVp9) &&
          frame_width <= 1920 && frame_height <= 1080 &&
diff --git a/src/starboard/linux/shared/oemcrypto_engine_device_properties_linux.cc b/src/starboard/linux/shared/oemcrypto_engine_device_properties_linux.cc
index e9d735b..a4b623f 100644
--- a/src/starboard/linux/shared/oemcrypto_engine_device_properties_linux.cc
+++ b/src/starboard/linux/shared/oemcrypto_engine_device_properties_linux.cc
@@ -22,9 +22,9 @@
 
 namespace wvoec_mock {
 
-class CryptoEngineXb1 : public CryptoEngine {
+class CryptoEngineLinux : public CryptoEngine {
  public:
-  explicit CryptoEngineXb1(std::auto_ptr<wvcdm::FileSystem> file_system)
+  explicit CryptoEngineLinux(std::auto_ptr<wvcdm::FileSystem> file_system)
       : CryptoEngine(file_system) {}
 
   OEMCrypto_HDCP_Capability config_current_hdcp_capability() override {
@@ -34,11 +34,14 @@
   OEMCrypto_HDCP_Capability config_maximum_hdcp_capability() override {
     return kWidevineMaximumHdcpVersion;
   }
+
+  // Max buffer size for encoded buffer.
+  size_t max_buffer_size() override { return 3840 * 2160 * 2; }
 };
 
 CryptoEngine* CryptoEngine::MakeCryptoEngine(
     std::auto_ptr<wvcdm::FileSystem> file_system) {
-  return new CryptoEngineXb1(file_system);
+  return new CryptoEngineLinux(file_system);
 }
 
 }  // namespace wvoec_mock
diff --git a/src/starboard/linux/shared/starboard_platform.gypi b/src/starboard/linux/shared/starboard_platform.gypi
index 71df991..c7588ca 100644
--- a/src/starboard/linux/shared/starboard_platform.gypi
+++ b/src/starboard/linux/shared/starboard_platform.gypi
@@ -341,10 +341,11 @@
       }],
       ['has_cdm==1', {
         'starboard_platform_dependencies': [
-          '<(DEPTH)/starboard/linux/shared/widevine3.gyp:oemcrypto',
-          '<(DEPTH)/starboard/linux/shared/widevine3.gyp:widevine_ce_cdm_static',
+          '<(DEPTH)/starboard/shared/widevine/widevine3.gyp:oemcrypto',
+          '<(DEPTH)/starboard/shared/widevine/widevine3.gyp:widevine_ce_cdm_static',
         ],
         'starboard_platform_sources': [
+          '<(DEPTH)/starboard/linux/shared/drm_create_system.cc',
           '<(DEPTH)/starboard/linux/shared/media_is_output_protected.cc',
           '<(DEPTH)/starboard/linux/shared/oemcrypto_engine_device_properties_linux.cc',
 
@@ -354,10 +355,9 @@
           '<(DEPTH)/starboard/shared/starboard/drm/drm_system_internal.h',
           '<(DEPTH)/starboard/shared/starboard/drm/drm_update_session.cc',
 
-          '<(DEPTH)/starboard/shared/widevine/drm_create_system.cc',
           '<(DEPTH)/starboard/shared/widevine/drm_is_server_certificate_updatable.cc',
-          '<(DEPTH)/starboard/shared/widevine/drm_system_widevine3.cc',
-          '<(DEPTH)/starboard/shared/widevine/drm_system_widevine3.h',
+          '<(DEPTH)/starboard/shared/widevine/drm_system_widevine.cc',
+          '<(DEPTH)/starboard/shared/widevine/drm_system_widevine.h',
           '<(DEPTH)/starboard/shared/widevine/drm_update_server_certificate.cc',
           '<(DEPTH)/starboard/shared/widevine/media_is_supported.cc',
           '<(DEPTH)/starboard/shared/widevine/widevine_storage.cc',
diff --git a/src/starboard/linux/shared/widevine3.gyp b/src/starboard/linux/shared/widevine3.gyp
deleted file mode 100644
index c081b11..0000000
--- a/src/starboard/linux/shared/widevine3.gyp
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright 2018 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-{
-  'includes': [
-    '<(DEPTH)/starboard/shared/widevine/widevine3.gypi',
-  ],
-  'variables': {
-    'platform_oem_sources': [
-      '<(DEPTH)/starboard/keyboxes/linux/linux.h',
-      '<(DEPTH)/starboard/keyboxes/linux/linux_client.c',
-      '<(DEPTH)/starboard/linux/shared/wv_keybox_linux.cc',
-    ],
-  },
-  'target_defaults': {
-    'defines': [
-      'COBALT_WIDEVINE_KEYBOX_INCLUDE="<(DEPTH)/starboard/keyboxes/widevine_settings_linux.h"',
-    ],
-  },
-}
diff --git a/src/starboard/linux/shared/wv_keybox_linux.cc b/src/starboard/linux/shared/wv_keybox_linux.cc
deleted file mode 100644
index 026b392..0000000
--- a/src/starboard/linux/shared/wv_keybox_linux.cc
+++ /dev/null
@@ -1,60 +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 "third_party/ce_cdm/oemcrypto/mock/src/oemcrypto_keybox_mock.h"
-
-#include <openssl/bn.h>
-#include <vector>
-
-extern "C" {
-#include "starboard/keyboxes/linux/linux.h"
-};
-
-#include "third_party/ce_cdm/oemcrypto/mock/src/wv_keybox.h"
-
-namespace wvoec_mock {
-
-namespace {
-#if defined(COBALT_WIDEVINE_KEYBOX_INCLUDE)
-#include COBALT_WIDEVINE_KEYBOX_INCLUDE
-#else  // COBALT_WIDEVINE_KEYBOX_INCLUDE
-#error "COBALT_WIDEVINE_KEYBOX_INCLUDE is not defined."
-#endif  // COBALT_WIDEVINE_KEYBOX_INCLUDE
-}  // namespace
-
-// |kKeybox| provided in obfiscated form: the key field need to be
-// de-obfiscated before installing to CryptoEngine, rest fields
-// left as-is and should not be de-obfuscated.
-bool WvKeybox::Prepare() {
-  // Create a temporary kKeybox's copy with ofuscated key.
-  WidevineKeybox keybox(kKeybox);
-
-  // Replace obfuscated with de-obfiscated and install.
-  uint8_t clear_key[sizeof(kObfuscatedKey)];
-  linux_client(clear_key, const_cast<unsigned char*>(kObfuscatedKey));
-  SbMemoryCopy(&keybox.device_key_, clear_key, sizeof(keybox.device_key_));
-
-  // Erase |de_obfuscated| because it contains clear key
-  SbMemorySet(&clear_key, 0, sizeof(clear_key));
-  if (!InstallKeybox(reinterpret_cast<const uint8_t*>(&keybox),
-                     sizeof(WidevineKeybox))) {
-    return false;
-  }
-
-  // Erase temporary kKeybox's copy because it is de-obfuscated
-  SbMemorySet(&keybox, 0, sizeof(WidevineKeybox));
-  return true;
-}
-
-}  // namespace wvoec_mock
diff --git a/src/starboard/linux/x64directfb/sbversion/10/atomic_public.h b/src/starboard/linux/x64directfb/sbversion/10/atomic_public.h
new file mode 100644
index 0000000..2f5b518
--- /dev/null
+++ b/src/starboard/linux/x64directfb/sbversion/10/atomic_public.h
@@ -0,0 +1,23 @@
+// 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.
+
+// This file was initially generated by starboard/tools/create_derived_build.py,
+// though it may have been modified since its creation.
+
+#ifndef STARBOARD_LINUX_X64DIRECTFB_SBVERSION_10_ATOMIC_PUBLIC_H_
+#define STARBOARD_LINUX_X64DIRECTFB_SBVERSION_10_ATOMIC_PUBLIC_H_
+
+#include "starboard/linux/x64directfb/atomic_public.h"
+
+#endif  // STARBOARD_LINUX_X64DIRECTFB_SBVERSION_10_ATOMIC_PUBLIC_H_
diff --git a/src/starboard/linux/x64directfb/sbversion/10/configuration_public.h b/src/starboard/linux/x64directfb/sbversion/10/configuration_public.h
new file mode 100644
index 0000000..887eb66
--- /dev/null
+++ b/src/starboard/linux/x64directfb/sbversion/10/configuration_public.h
@@ -0,0 +1,26 @@
+// 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.
+
+// This file was initially generated by starboard/tools/create_derived_build.py,
+// though it may have been modified since its creation.
+
+#ifndef STARBOARD_LINUX_X64DIRECTFB_SBVERSION_10_CONFIGURATION_PUBLIC_H_
+#define STARBOARD_LINUX_X64DIRECTFB_SBVERSION_10_CONFIGURATION_PUBLIC_H_
+
+#undef SB_API_VERSION
+#define SB_API_VERSION 10
+
+#include "starboard/linux/x64directfb/configuration_public.h"
+
+#endif  // STARBOARD_LINUX_X64DIRECTFB_SBVERSION_10_CONFIGURATION_PUBLIC_H_
diff --git a/src/starboard/linux/x64directfb/sbversion/10/gyp_configuration.gypi b/src/starboard/linux/x64directfb/sbversion/10/gyp_configuration.gypi
new file mode 100644
index 0000000..33e612d
--- /dev/null
+++ b/src/starboard/linux/x64directfb/sbversion/10/gyp_configuration.gypi
@@ -0,0 +1,40 @@
+# 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.
+
+# This file was initially generated by starboard/tools/create_derived_build.py,
+# though it may have been modified since its creation.
+
+{
+  'target_defaults': {
+    'default_configuration': 'linux-x64directfb-sbversion-10_debug',
+    'configurations': {
+      'linux-x64directfb-sbversion-10_debug': {
+        'inherit_from': ['debug_base'],
+      },
+      'linux-x64directfb-sbversion-10_devel': {
+        'inherit_from': ['devel_base'],
+      },
+      'linux-x64directfb-sbversion-10_qa': {
+        'inherit_from': ['qa_base'],
+      },
+      'linux-x64directfb-sbversion-10_gold': {
+        'inherit_from': ['gold_base'],
+      },
+    }, # end of configurations
+  },
+
+  'includes': [
+    '<(DEPTH)/starboard/linux/x64directfb/gyp_configuration.gypi',
+  ],
+}
diff --git a/src/starboard/linux/x64directfb/sbversion/10/gyp_configuration.py b/src/starboard/linux/x64directfb/sbversion/10/gyp_configuration.py
new file mode 100644
index 0000000..45ee34e
--- /dev/null
+++ b/src/starboard/linux/x64directfb/sbversion/10/gyp_configuration.py
@@ -0,0 +1,23 @@
+# 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.
+
+# This file was initially generated by starboard/tools/create_derived_build.py,
+# though it may have been modified since its creation.
+
+
+from starboard.linux.x64directfb import gyp_configuration as parent_configuration
+
+
+def CreatePlatformConfig():
+  return parent_configuration.CobaltLinuxX64DirectFbConfiguration('linux-x64directfb-sbversion-10')
diff --git a/src/starboard/linux/x64directfb/sbversion/10/starboard_platform.gyp b/src/starboard/linux/x64directfb/sbversion/10/starboard_platform.gyp
new file mode 100644
index 0000000..ec523b0
--- /dev/null
+++ b/src/starboard/linux/x64directfb/sbversion/10/starboard_platform.gyp
@@ -0,0 +1,24 @@
+# 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.
+
+# This file was initially generated by starboard/tools/create_derived_build.py,
+# though it may have been modified since its creation.
+
+{
+  'includes': [
+    # Note that we are 'includes'ing a 'gyp' file, not a 'gypi' file.  The idea
+    # is that we just want this file to *be* the parent gyp file.
+    '<(DEPTH)/starboard/linux/x64directfb/starboard_platform.gyp',
+  ],
+}
diff --git a/src/starboard/linux/x64directfb/sbversion/10/starboard_platform_tests.gyp b/src/starboard/linux/x64directfb/sbversion/10/starboard_platform_tests.gyp
new file mode 100644
index 0000000..b5175c6
--- /dev/null
+++ b/src/starboard/linux/x64directfb/sbversion/10/starboard_platform_tests.gyp
@@ -0,0 +1,24 @@
+# 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.
+
+# This file was initially generated by starboard/tools/create_derived_build.py,
+# though it may have been modified since its creation.
+
+{
+  'includes': [
+    # Note that we are 'includes'ing a 'gyp' file, not a 'gypi' file.  The idea
+    # is that we just want this file to *be* the parent gyp file.
+    '<(DEPTH)/starboard/linux/x64directfb/starboard_platform_tests.gyp',
+  ],
+}
diff --git a/src/starboard/linux/x64directfb/sbversion/10/thread_types_public.h b/src/starboard/linux/x64directfb/sbversion/10/thread_types_public.h
new file mode 100644
index 0000000..ffd1c28
--- /dev/null
+++ b/src/starboard/linux/x64directfb/sbversion/10/thread_types_public.h
@@ -0,0 +1,23 @@
+// 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.
+
+// This file was initially generated by starboard/tools/create_derived_build.py,
+// though it may have been modified since its creation.
+
+#ifndef STARBOARD_LINUX_X64DIRECTFB_SBVERSION_10_THREAD_TYPES_PUBLIC_H_
+#define STARBOARD_LINUX_X64DIRECTFB_SBVERSION_10_THREAD_TYPES_PUBLIC_H_
+
+#include "starboard/linux/x64directfb/thread_types_public.h"
+
+#endif  // STARBOARD_LINUX_X64DIRECTFB_SBVERSION_10_THREAD_TYPES_PUBLIC_H_
diff --git a/src/starboard/linux/x64x11/gyp_configuration.gypi b/src/starboard/linux/x64x11/gyp_configuration.gypi
index 721b16b..0620089 100644
--- a/src/starboard/linux/x64x11/gyp_configuration.gypi
+++ b/src/starboard/linux/x64x11/gyp_configuration.gypi
@@ -14,8 +14,9 @@
 
 {
   'variables': {
-    'enable_map_to_mesh%': 1,
+    'enable_map_to_mesh': 1,
   },
+
   'target_defaults': {
     'default_configuration': 'linux-x64x11_debug',
     'configurations': {
diff --git a/src/starboard/linux/x64x11/mock/configuration_public.h b/src/starboard/linux/x64x11/mock/configuration_public.h
index 84968e5..a2db369 100644
--- a/src/starboard/linux/x64x11/mock/configuration_public.h
+++ b/src/starboard/linux/x64x11/mock/configuration_public.h
@@ -176,6 +176,9 @@
 
 // --- Extensions Configuration ----------------------------------------------
 
+// Do not use <unordered_map> and <unordered_set> for the hash table types.
+#define SB_HAS_STD_UNORDERED_HASH 0
+
 // GCC/Clang doesn't define a long long hash function, except for Android and
 // Game consoles.
 #define SB_HAS_LONG_LONG_HASH 0
diff --git a/src/starboard/linux/x64x11/sbversion/10/atomic_public.h b/src/starboard/linux/x64x11/sbversion/10/atomic_public.h
new file mode 100644
index 0000000..5732d99
--- /dev/null
+++ b/src/starboard/linux/x64x11/sbversion/10/atomic_public.h
@@ -0,0 +1,23 @@
+// 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.
+
+// This file was initially generated by starboard/tools/create_derived_build.py,
+// though it may have been modified since its creation.
+
+#ifndef STARBOARD_LINUX_X64X11_SBVERSION_10_ATOMIC_PUBLIC_H_
+#define STARBOARD_LINUX_X64X11_SBVERSION_10_ATOMIC_PUBLIC_H_
+
+#include "starboard/linux/x64x11/atomic_public.h"
+
+#endif  // STARBOARD_LINUX_X64X11_SBVERSION_10_ATOMIC_PUBLIC_H_
diff --git a/src/starboard/linux/x64x11/sbversion/10/configuration_public.h b/src/starboard/linux/x64x11/sbversion/10/configuration_public.h
new file mode 100644
index 0000000..229dd3d
--- /dev/null
+++ b/src/starboard/linux/x64x11/sbversion/10/configuration_public.h
@@ -0,0 +1,26 @@
+// 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.
+
+// This file was initially generated by starboard/tools/create_derived_build.py,
+// though it may have been modified since its creation.
+
+#ifndef STARBOARD_LINUX_X64X11_SBVERSION_10_CONFIGURATION_PUBLIC_H_
+#define STARBOARD_LINUX_X64X11_SBVERSION_10_CONFIGURATION_PUBLIC_H_
+
+#undef SB_API_VERSION
+#define SB_API_VERSION 10
+
+#include "starboard/linux/x64x11/configuration_public.h"
+
+#endif  // STARBOARD_LINUX_X64X11_SBVERSION_10_CONFIGURATION_PUBLIC_H_
diff --git a/src/starboard/linux/x64x11/sbversion/10/gyp_configuration.gypi b/src/starboard/linux/x64x11/sbversion/10/gyp_configuration.gypi
new file mode 100644
index 0000000..cedca3a
--- /dev/null
+++ b/src/starboard/linux/x64x11/sbversion/10/gyp_configuration.gypi
@@ -0,0 +1,40 @@
+# 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.
+
+# This file was initially generated by starboard/tools/create_derived_build.py,
+# though it may have been modified since its creation.
+
+{
+  'target_defaults': {
+    'default_configuration': 'linux-x64x11-sbversion-10_debug',
+    'configurations': {
+      'linux-x64x11-sbversion-10_debug': {
+        'inherit_from': ['debug_base'],
+      },
+      'linux-x64x11-sbversion-10_devel': {
+        'inherit_from': ['devel_base'],
+      },
+      'linux-x64x11-sbversion-10_qa': {
+        'inherit_from': ['qa_base'],
+      },
+      'linux-x64x11-sbversion-10_gold': {
+        'inherit_from': ['gold_base'],
+      },
+    }, # end of configurations
+  },
+
+  'includes': [
+    '<(DEPTH)/starboard/linux/x64x11/gyp_configuration.gypi',
+  ],
+}
diff --git a/src/starboard/linux/x64x11/sbversion/10/gyp_configuration.py b/src/starboard/linux/x64x11/sbversion/10/gyp_configuration.py
new file mode 100644
index 0000000..cf77bb8
--- /dev/null
+++ b/src/starboard/linux/x64x11/sbversion/10/gyp_configuration.py
@@ -0,0 +1,23 @@
+# 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.
+
+# This file was initially generated by starboard/tools/create_derived_build.py,
+# though it may have been modified since its creation.
+
+
+from starboard.linux.x64x11 import gyp_configuration as parent_configuration
+
+
+def CreatePlatformConfig():
+  return parent_configuration.LinuxX64X11Configuration('linux-x64x11-sbversion-10')
diff --git a/src/starboard/linux/x64x11/sbversion/10/starboard_platform.gyp b/src/starboard/linux/x64x11/sbversion/10/starboard_platform.gyp
new file mode 100644
index 0000000..1478102
--- /dev/null
+++ b/src/starboard/linux/x64x11/sbversion/10/starboard_platform.gyp
@@ -0,0 +1,24 @@
+# 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.
+
+# This file was initially generated by starboard/tools/create_derived_build.py,
+# though it may have been modified since its creation.
+
+{
+  'includes': [
+    # Note that we are 'includes'ing a 'gyp' file, not a 'gypi' file.  The idea
+    # is that we just want this file to *be* the parent gyp file.
+    '<(DEPTH)/starboard/linux/x64x11/starboard_platform.gyp',
+  ],
+}
diff --git a/src/starboard/linux/x64x11/sbversion/10/starboard_platform_tests.gyp b/src/starboard/linux/x64x11/sbversion/10/starboard_platform_tests.gyp
new file mode 100644
index 0000000..7f6257c
--- /dev/null
+++ b/src/starboard/linux/x64x11/sbversion/10/starboard_platform_tests.gyp
@@ -0,0 +1,24 @@
+# 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.
+
+# This file was initially generated by starboard/tools/create_derived_build.py,
+# though it may have been modified since its creation.
+
+{
+  'includes': [
+    # Note that we are 'includes'ing a 'gyp' file, not a 'gypi' file.  The idea
+    # is that we just want this file to *be* the parent gyp file.
+    '<(DEPTH)/starboard/linux/x64x11/starboard_platform_tests.gyp',
+  ],
+}
diff --git a/src/starboard/linux/x64x11/sbversion/10/thread_types_public.h b/src/starboard/linux/x64x11/sbversion/10/thread_types_public.h
new file mode 100644
index 0000000..6e27c25
--- /dev/null
+++ b/src/starboard/linux/x64x11/sbversion/10/thread_types_public.h
@@ -0,0 +1,23 @@
+// 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.
+
+// This file was initially generated by starboard/tools/create_derived_build.py,
+// though it may have been modified since its creation.
+
+#ifndef STARBOARD_LINUX_X64X11_SBVERSION_10_THREAD_TYPES_PUBLIC_H_
+#define STARBOARD_LINUX_X64X11_SBVERSION_10_THREAD_TYPES_PUBLIC_H_
+
+#include "starboard/linux/x64x11/thread_types_public.h"
+
+#endif  // STARBOARD_LINUX_X64X11_SBVERSION_10_THREAD_TYPES_PUBLIC_H_
diff --git a/src/starboard/linux/x64x11/widevine.gyp b/src/starboard/linux/x64x11/widevine.gyp
deleted file mode 100644
index 1dedb90..0000000
--- a/src/starboard/linux/x64x11/widevine.gyp
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright 2017 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.
-{
-  'variables': {
-     'platform_oem_sources': [
-       '<(DEPTH)/starboard/keyboxes/linux/linux.h',
-       '<(DEPTH)/starboard/keyboxes/linux/linux_client.c',
-       'wv_keybox.cc',
-     ],
-  },
-  'includes': [
-    '<(DEPTH)/starboard/shared/widevine/widevine.gypi',
-  ],
-  'target_defaults': {
-    'defines': [
-      'COBALT_WIDEVINE_KEYBOX_INCLUDE="starboard/keyboxes/widevine_settings_linux.h"',
-    ],
-  },
-}
diff --git a/src/starboard/linux/x64x11/wv_keybox.cc b/src/starboard/linux/x64x11/wv_keybox.cc
deleted file mode 100644
index dacf66c..0000000
--- a/src/starboard/linux/x64x11/wv_keybox.cc
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2018 The Cobalt Authors. All Rights Reserved.
-
-#include <cstring>
-
-#include "starboard/keyboxes/linux/linux.h"
-#include "third_party/cdm/oemcrypto/mock/src/oemcrypto_keybox_mock.h"
-#include "third_party/cdm/oemcrypto/mock/src/wv_keybox.h"
-
-namespace wvoec_mock {
-
-namespace {
-
-#if defined(COBALT_WIDEVINE_KEYBOX_INCLUDE)
-#include COBALT_WIDEVINE_KEYBOX_INCLUDE
-#else  // COBALT_WIDEVINE_KEYBOX_INCLUDE
-#error "COBALT_WIDEVINE_KEYBOX_INCLUDE is not defined."
-#endif  // COBALT_WIDEVINE_KEYBOX_INCLUDE
-
-}  // namespace
-
-bool WvKeybox::Prepare() {
-  // Make a local copy of the keybox.
-  WidevineKeybox keybox;
-  memcpy(&keybox, &kKeybox, sizeof(WidevineKeybox));
-
-  // Unobfuscate the key.
-  uint8_t clear[sizeof(kObfuscatedKey)];
-  // Despite the non-const type, linux_client does not modify the second
-  // argument.
-  linux_client(clear, const_cast<uint8_t*>(kObfuscatedKey));
-
-  // Move the clear key into the local copy of the keybox.
-  // NOTE: Clear device keys are half the size of obfuscated ones.
-  memcpy(&keybox.device_key_, clear, sizeof(keybox.device_key_));
-  memset(clear, 0, sizeof(clear));
-
-  // Install the local copy of the keybox.
-  uint8_t* bytes = reinterpret_cast<uint8_t*>(&keybox);
-  InstallKeybox(bytes, sizeof(keybox));
-
-  // Wipe the local copy of the keybox.
-  memset(&keybox, 0, sizeof(keybox));
-
-  return true;
-}
-
-}  // namespace wvoec_mock
diff --git a/src/starboard/nplb/audio_sink_helpers.cc b/src/starboard/nplb/audio_sink_helpers.cc
index 5b5209e..e811e06 100644
--- a/src/starboard/nplb/audio_sink_helpers.cc
+++ b/src/starboard/nplb/audio_sink_helpers.cc
@@ -86,12 +86,7 @@
 
 AudioSinkTestEnvironment::AudioSinkTestEnvironment(
     const AudioSinkTestFrameBuffers& frame_buffers)
-    : frame_buffers_(frame_buffers),
-      condition_variable_(mutex_),
-      update_source_status_call_count_(0),
-      frames_appended_(0),
-      frames_consumed_(0),
-      is_playing_(true) {
+    : frame_buffers_(frame_buffers), condition_variable_(mutex_) {
   sink_ = SbAudioSinkCreate(
       frame_buffers_.channels(), sample_rate(), frame_buffers_.sample_type(),
       frame_buffers_.storage_type(), frame_buffers_.frame_buffers(),
@@ -151,6 +146,7 @@
 
 bool AudioSinkTestEnvironment::WaitUntilAllFramesAreConsumed() {
   ScopedLock lock(mutex_);
+  is_eos_reached_ = true;
   SbTimeMonotonic start = SbTimeGetMonotonicNow();
   while (frames_appended_ != frames_consumed_) {
     SbTime time_elapsed = SbTimeGetMonotonicNow() - start;
@@ -169,9 +165,9 @@
                                                     bool* is_eos_reached) {
   ScopedLock lock(mutex_);
   *frames_in_buffer = frames_appended_ - frames_consumed_;
-  *offset_in_frames = frames_appended_ % frame_buffers_.frames_per_channel();
+  *offset_in_frames = frames_consumed_ % frame_buffers_.frames_per_channel();
   *is_playing = is_playing_;
-  *is_eos_reached = false;
+  *is_eos_reached = is_eos_reached_;
   ++update_source_status_call_count_;
   condition_variable_.Signal();
 }
diff --git a/src/starboard/nplb/audio_sink_helpers.h b/src/starboard/nplb/audio_sink_helpers.h
index 5382d05..861d381 100644
--- a/src/starboard/nplb/audio_sink_helpers.h
+++ b/src/starboard/nplb/audio_sink_helpers.h
@@ -73,6 +73,8 @@
       const AudioSinkTestFrameBuffers& frame_buffers);
   ~AudioSinkTestEnvironment();
 
+  bool is_valid() const { return SbAudioSinkIsValid(sink_); }
+
   static int sample_rate() {
     return SbAudioSinkGetNearestSupportedSampleFrequency(kSampleRateCD);
   }
@@ -114,10 +116,11 @@
   Mutex mutex_;
   ConditionVariable condition_variable_;
 
-  int update_source_status_call_count_;
-  int frames_appended_;
-  int frames_consumed_;
-  bool is_playing_;
+  int update_source_status_call_count_ = 0;
+  int frames_appended_ = 0;
+  int frames_consumed_ = 0;
+  bool is_playing_ = true;
+  bool is_eos_reached_ = false;
 };
 
 }  // namespace nplb
diff --git a/src/starboard/nplb/audio_sink_test.cc b/src/starboard/nplb/audio_sink_test.cc
index 58a7437..5f167ef 100644
--- a/src/starboard/nplb/audio_sink_test.cc
+++ b/src/starboard/nplb/audio_sink_test.cc
@@ -17,6 +17,8 @@
 #include <algorithm>
 
 #include "starboard/nplb/audio_sink_helpers.h"
+#include "starboard/thread.h"
+#include "starboard/time.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace starboard {
@@ -25,6 +27,7 @@
 TEST(SbAudioSinkTest, UpdateStatusCalled) {
   AudioSinkTestFrameBuffers frame_buffers(SbAudioSinkGetMaxChannels());
   AudioSinkTestEnvironment environment(frame_buffers);
+  ASSERT_TRUE(environment.is_valid());
 
   EXPECT_TRUE(environment.WaitUntilUpdateStatusCalled());
   EXPECT_TRUE(environment.WaitUntilUpdateStatusCalled());
@@ -33,14 +36,16 @@
 TEST(SbAudioSinkTest, SomeFramesConsumed) {
   AudioSinkTestFrameBuffers frame_buffers(SbAudioSinkGetMaxChannels());
   AudioSinkTestEnvironment environment(frame_buffers);
+  ASSERT_TRUE(environment.is_valid());
 
-  environment.AppendFrame(1);
+  environment.AppendFrame(512);
   EXPECT_TRUE(environment.WaitUntilSomeFramesAreConsumed());
 }
 
 TEST(SbAudioSinkTest, AllFramesConsumed) {
   AudioSinkTestFrameBuffers frame_buffers(SbAudioSinkGetMaxChannels());
   AudioSinkTestEnvironment environment(frame_buffers);
+  ASSERT_TRUE(environment.is_valid());
 
   environment.AppendFrame(1024);
   EXPECT_TRUE(environment.WaitUntilAllFramesAreConsumed());
@@ -49,6 +54,7 @@
 TEST(SbAudioSinkTest, MultipleAppendAndConsume) {
   AudioSinkTestFrameBuffers frame_buffers(SbAudioSinkGetMaxChannels());
   AudioSinkTestEnvironment environment(frame_buffers);
+  ASSERT_TRUE(environment.is_valid());
 
   int frames_to_append = frame_buffers.frames_per_channel();
 
@@ -61,6 +67,8 @@
 TEST(SbAudioSinkTest, Pause) {
   AudioSinkTestFrameBuffers frame_buffers(SbAudioSinkGetMaxChannels());
   AudioSinkTestEnvironment environment(frame_buffers);
+  ASSERT_TRUE(environment.is_valid());
+
   environment.SetIsPlaying(false);
 
   int frames_to_append = frame_buffers.frames_per_channel();
@@ -74,10 +82,24 @@
   EXPECT_TRUE(environment.WaitUntilSomeFramesAreConsumed());
 }
 
+TEST(SbAudioSinkTest, Underflow) {
+  AudioSinkTestFrameBuffers frame_buffers(SbAudioSinkGetMaxChannels());
+  AudioSinkTestEnvironment environment(frame_buffers);
+  ASSERT_TRUE(environment.is_valid());
+
+  environment.AppendFrame(1024);
+  EXPECT_TRUE(environment.WaitUntilSomeFramesAreConsumed());
+  SbThreadSleep(250 * kSbTimeMillisecond);
+  environment.AppendFrame(1024);
+  EXPECT_TRUE(environment.WaitUntilAllFramesAreConsumed());
+}
+
 TEST(SbAudioSinkTest, ContinuousAppend) {
   AudioSinkTestFrameBuffers frame_buffers(SbAudioSinkGetMaxChannels());
 
   AudioSinkTestEnvironment environment(frame_buffers);
+  ASSERT_TRUE(environment.is_valid());
+
   int sample_rate = environment.sample_rate();
   // We are trying to send 1/4s worth of audio samples.
   int frames_to_append = sample_rate / 4;
diff --git a/src/starboard/nplb/condition_variable_wait_test.cc b/src/starboard/nplb/condition_variable_wait_test.cc
index 2490963..3e42109 100644
--- a/src/starboard/nplb/condition_variable_wait_test.cc
+++ b/src/starboard/nplb/condition_variable_wait_test.cc
@@ -49,7 +49,7 @@
 }
 
 TEST(SbConditionVariableWaitTest, SunnyDay) {
-  const int kMany = 64;
+  const int kMany = SB_MAX_THREADS > 64 ? 64 : SB_MAX_THREADS;
   WaiterContext context;
 
   SbThread threads[kMany];
diff --git a/src/starboard/nplb/directory_get_next_test.cc b/src/starboard/nplb/directory_get_next_test.cc
index 1e15a65..d382284 100644
--- a/src/starboard/nplb/directory_get_next_test.cc
+++ b/src/starboard/nplb/directory_get_next_test.cc
@@ -33,7 +33,8 @@
 
   std::string directory_name = files[0].filename();
   directory_name.resize(directory_name.find_last_of(SB_FILE_SEP_CHAR));
-  EXPECT_TRUE(SbFileExists(directory_name.c_str()));
+  EXPECT_TRUE(SbFileExists(directory_name.c_str()))
+      << "Directory_name is " << directory_name;
 
   SbFileError error = kSbFileErrorMax;
   SbDirectory directory = SbDirectoryOpen(directory_name.c_str(), &error);
@@ -88,15 +89,13 @@
 
   std::string path = GetTempDir();
   EXPECT_FALSE(path.empty());
-  EXPECT_TRUE(SbFileExists(path.c_str()));
+  EXPECT_TRUE(SbFileExists(path.c_str())) << "Directory is " << path;
 
   SbFileError error = kSbFileErrorMax;
   SbDirectory directory = SbDirectoryOpen(path.c_str(), &error);
   EXPECT_TRUE(SbDirectoryIsValid(directory));
   EXPECT_EQ(kSbFileOk, error);
-
   EXPECT_FALSE(SbDirectoryGetNext(directory, NULL));
-
   EXPECT_TRUE(SbDirectoryClose(directory));
 }
 
diff --git a/src/starboard/nplb/directory_open_test.cc b/src/starboard/nplb/directory_open_test.cc
index a9655a8..5b43367 100644
--- a/src/starboard/nplb/directory_open_test.cc
+++ b/src/starboard/nplb/directory_open_test.cc
@@ -24,10 +24,13 @@
 namespace nplb {
 namespace {
 
+#define EXPECT_FILE_EXISTS(path) \
+  EXPECT_TRUE(SbFileExists(path.c_str())) << "Filename is " << path.c_str()
+
 TEST(SbDirectoryOpenTest, SunnyDay) {
   std::string path = GetTempDir();
   EXPECT_FALSE(path.empty());
-  EXPECT_TRUE(SbFileExists(path.c_str()));
+  EXPECT_FILE_EXISTS(path);
 
   SbFileError error = kSbFileErrorMax;
   SbDirectory directory = SbDirectoryOpen(path.c_str(), &error);
@@ -39,7 +42,7 @@
 TEST(SbDirectoryOpenTest, SunnyDayWithNullError) {
   std::string path = GetTempDir();
   EXPECT_FALSE(path.empty());
-  EXPECT_TRUE(SbFileExists(path.c_str()));
+  EXPECT_FILE_EXISTS(path);
 
   SbDirectory directory = SbDirectoryOpen(path.c_str(), NULL);
   EXPECT_TRUE(SbDirectoryIsValid(directory));
@@ -49,7 +52,7 @@
 TEST(SbDirectoryOpenTest, ManySunnyDay) {
   std::string path = GetTempDir();
   EXPECT_FALSE(path.empty());
-  EXPECT_TRUE(SbFileExists(path.c_str()));
+  EXPECT_FILE_EXISTS(path);
 
   const int kMany = SB_FILE_MAX_OPEN;
   SbDirectory directories[kMany] = {0};
@@ -69,7 +72,7 @@
 TEST(SbDirectoryOpenTest, FailsInvalidPath) {
   std::string path = GetTempDir();
   EXPECT_FALSE(path.empty());
-  EXPECT_TRUE(SbFileExists(path.c_str()));
+  EXPECT_FILE_EXISTS(path);
 
   // Funny way to make sure the directory seems valid but doesn't exist.
   int len = static_cast<int>(path.length());
diff --git a/src/starboard/nplb/rwlock_test.cc b/src/starboard/nplb/rwlock_test.cc
index 869d3f2..72ba553 100644
--- a/src/starboard/nplb/rwlock_test.cc
+++ b/src/starboard/nplb/rwlock_test.cc
@@ -117,7 +117,7 @@
  private:
   SharedData* shared_data_;
 };
-TEST(RWLock, HoldsLockForTime) {
+TEST(RWLock, FLAKY_HoldsLockForTime) {
   const SbTime kTimeToHold = kSbTimeMillisecond * 5;
   const SbTime kAllowedError = kSbTimeMillisecond * 10;
 
diff --git a/src/starboard/nplb/semaphore_test.cc b/src/starboard/nplb/semaphore_test.cc
index caf7992..3a65cb4 100644
--- a/src/starboard/nplb/semaphore_test.cc
+++ b/src/starboard/nplb/semaphore_test.cc
@@ -79,19 +79,19 @@
   SbTime result_wait_time_;
 };
 
-TEST(Semaphore, ThreadTakesWait_PutBeforeTimeExpires) {
-  SbTime wait_time = kSbTimeMillisecond * 80;
-  ThreadTakesWaitSemaphore thread(wait_time);
+TEST(Semaphore, FLAKY_ThreadTakesWait_PutBeforeTimeExpires) {
+  SbTime timeout_time = kSbTimeMillisecond * 250;
+  SbTime wait_time = kSbTimeMillisecond;
+  ThreadTakesWaitSemaphore thread(timeout_time);
   thread.Start();
 
-  SbThreadSleep(wait_time / 2);
+  SbThreadSleep(wait_time);
   thread.semaphore_.Put();
 
   thread.Join();
 
   EXPECT_TRUE(thread.result_signaled_);
-  EXPECT_NEAR(thread.result_wait_time_ * 1.0, wait_time * 0.5,
-              kSbTimeMillisecond * 10.0);  // Error threshold
+  EXPECT_LT(thread.result_wait_time_, timeout_time);
 }
 
 double IsDoubleNear(double first, double second, double diff_threshold) {
@@ -102,7 +102,7 @@
   return diff < diff_threshold;
 }
 
-TEST(Semaphore, ThreadTakesWait_TimeExpires) {
+TEST(Semaphore, FLAKY_ThreadTakesWait_TimeExpires) {
   const int attempts = 20;  // Retest up to 20 times.
   bool passed = false;
 
diff --git a/src/starboard/nplb/system_get_path_test.cc b/src/starboard/nplb/system_get_path_test.cc
index 5a3babc..2e89803 100644
--- a/src/starboard/nplb/system_get_path_test.cc
+++ b/src/starboard/nplb/system_get_path_test.cc
@@ -14,6 +14,8 @@
 
 #include <string.h>
 
+#include <algorithm>
+
 #include "starboard/file.h"
 #include "starboard/memory.h"
 #include "starboard/nplb/file_helpers.h"
@@ -50,6 +52,19 @@
 #undef LOCAL_CONTEXT
 }
 
+void UnmodifiedOnFailureTest(SbSystemPathId id, int line) {
+  char path[kPathSize];
+  SbMemorySet(path, 0xCD, kPathSize);
+  for (size_t i = 0; i <= kPathSize; ++i) {
+    if (SbSystemGetPath(id, path, i)) {
+      return;
+    }
+    for (auto ch : path) {
+      ASSERT_EQ('\xCD', ch) << "Context : id=" << id << ", line=" << line;
+    }
+  }
+}
+
 TEST(SbSystemGetPathTest, ReturnsRequiredPaths) {
   BasicTest(kSbSystemPathContentDirectory, true, true, __LINE__);
   BasicTest(kSbSystemPathCacheDirectory, true, true, __LINE__);
@@ -85,6 +100,15 @@
   BasicTest(kSbSystemPathFontConfigurationDirectory, false, false, __LINE__);
 }
 
+TEST(SbSystemGetPathTest, DoesNotTouchOutputBufferOnFailureForDefinedIds) {
+  UnmodifiedOnFailureTest(kSbSystemPathDebugOutputDirectory, __LINE__);
+  UnmodifiedOnFailureTest(kSbSystemPathTempDirectory, __LINE__);
+  UnmodifiedOnFailureTest(kSbSystemPathTestOutputDirectory, __LINE__);
+  UnmodifiedOnFailureTest(kSbSystemPathCacheDirectory, __LINE__);
+  UnmodifiedOnFailureTest(kSbSystemPathFontDirectory, __LINE__);
+  UnmodifiedOnFailureTest(kSbSystemPathFontConfigurationDirectory, __LINE__);
+}
+
 TEST(SbSystemGetPathTest, CanCreateAndRemoveDirectoryInCache) {
   char path[kPathSize];
   SbMemorySet(path, 0xCD, kPathSize);
diff --git a/src/starboard/nplb/system_get_property_test.cc b/src/starboard/nplb/system_get_property_test.cc
index 5df797a..bb4379b 100644
--- a/src/starboard/nplb/system_get_property_test.cc
+++ b/src/starboard/nplb/system_get_property_test.cc
@@ -62,6 +62,19 @@
 #undef LOCAL_CONTEXT
 }
 
+void UnmodifiedOnFailureTest(SbSystemPropertyId id, int line) {
+  char value[kValueSize] = {0};
+  SbMemorySet(value, 0xCD, kValueSize);
+  for (size_t i = 0; i <= kValueSize; ++i) {
+    if (SbSystemGetProperty(id, value, i)) {
+      return;
+    }
+    for (auto ch : value) {
+      ASSERT_EQ('\xCD', ch) << "Context : id=" << id << ", line=" << line;
+    }
+  }
+}
+
 TEST(SbSystemGetPropertyTest, ReturnsRequired) {
   BasicTest(kSbSystemPropertyFriendlyName, true, true, __LINE__);
   BasicTest(kSbSystemPropertyPlatformName, true, true, __LINE__);
@@ -100,6 +113,25 @@
   BasicTest(static_cast<SbSystemPropertyId>(99999), true, false, __LINE__);
 }
 
+TEST(SbSystemGetPathTest, DoesNotTouchOutputBufferOnFailureForDefinedIds) {
+  UnmodifiedOnFailureTest(kSbSystemPropertyChipsetModelNumber, __LINE__);
+  UnmodifiedOnFailureTest(kSbSystemPropertyFirmwareVersion, __LINE__);
+  UnmodifiedOnFailureTest(kSbSystemPropertyFriendlyName, __LINE__);
+  UnmodifiedOnFailureTest(kSbSystemPropertyManufacturerName, __LINE__);
+  UnmodifiedOnFailureTest(kSbSystemPropertyBrandName, __LINE__);
+  UnmodifiedOnFailureTest(kSbSystemPropertyModelName, __LINE__);
+  UnmodifiedOnFailureTest(kSbSystemPropertyModelYear, __LINE__);
+  UnmodifiedOnFailureTest(kSbSystemPropertyNetworkOperatorName, __LINE__);
+  UnmodifiedOnFailureTest(kSbSystemPropertyPlatformName, __LINE__);
+#if SB_API_VERSION < 10
+  UnmodifiedOnFailureTest(kSbSystemPropertyPlatformUuid, __LINE__);
+#endif  // SB_API_VERSION < 10
+  UnmodifiedOnFailureTest(kSbSystemPropertySpeechApiKey, __LINE__);
+#if SB_API_VERSION >= 5
+  UnmodifiedOnFailureTest(kSbSystemPropertyUserAgentAuxField, __LINE__);
+#endif  // SB_API_VERSION >= 5
+}
+
 TEST(SbSystemGetPropertyTest, SpeechApiKeyNotLeaked) {
   static const size_t kSize = 512;
   char speech_api_key[kSize] = {0};
diff --git a/src/starboard/raspi/2/architecture.gypi b/src/starboard/raspi/2/architecture.gypi
index 276ad42..ce547ff 100644
--- a/src/starboard/raspi/2/architecture.gypi
+++ b/src/starboard/raspi/2/architecture.gypi
@@ -17,8 +17,7 @@
     # RasPi 2 is ARMv7
     'arm_version': 7,
     'armv7': 1,
-    'arm_neon': 0, # Disable neon until it shows measurable
-                   # benefit under cobalt benchmarks.
+    'arm_neon': 1,
     'arm_float_abi': 'hard',
 
     'compiler_flags': [
@@ -26,8 +25,7 @@
       '-march=armv7-a',
       '-mtune=cortex-a8',
       '-mfloat-abi=hard',
-      #'-mfpu=neon-vfpv4',  # Disable neon until it shows measurable
-                            # benefit under cobalt benchmarks.
+      '-mfpu=neon-vfpv4',
     ],
   },
 }
diff --git a/src/starboard/raspi/shared/configuration_public.h b/src/starboard/raspi/shared/configuration_public.h
index b9ec7b2..3edebb7 100644
--- a/src/starboard/raspi/shared/configuration_public.h
+++ b/src/starboard/raspi/shared/configuration_public.h
@@ -89,6 +89,9 @@
 
 // --- Extensions Configuration ----------------------------------------------
 
+// Do not use <unordered_map> and <unordered_set> for the hash table types.
+#define SB_HAS_STD_UNORDERED_HASH 0
+
 // GCC/Clang doesn't define a long long hash function, except for Android and
 // Game consoles.
 #define SB_HAS_LONG_LONG_HASH 0
diff --git a/src/starboard/raspi/shared/gyp_configuration.py b/src/starboard/raspi/shared/gyp_configuration.py
index 1acafbd..26f2a45 100644
--- a/src/starboard/raspi/shared/gyp_configuration.py
+++ b/src/starboard/raspi/shared/gyp_configuration.py
@@ -107,7 +107,10 @@
           '.SunnyDaySourceNotLoopback/1',
       ],
       'nplb_blitter_pixel_tests': [test_filter.FILTER_ALL],
-      # TODO: enable player_filter_tests.
-      'player_filter_tests': [test_filter.FILTER_ALL],
+      'player_filter_tests': [
+          # TODO: debug these failures.
+          'VideoDecoderTests/VideoDecoderTest.EndOfStreamWithoutAnyInput/0',
+          'VideoDecoderTests/VideoDecoderTest.SingleInvalidInput/0',
+      ],
       'starboard_platform_tests': [test_filter.FILTER_ALL],
   }
diff --git a/src/starboard/shared/starboard/media/media_is_video_supported_h264_1080p_hfr_only.cc b/src/starboard/raspi/shared/media_is_video_supported.cc
similarity index 80%
rename from src/starboard/shared/starboard/media/media_is_video_supported_h264_1080p_hfr_only.cc
rename to src/starboard/raspi/shared/media_is_video_supported.cc
index e7e1f0c..8ac8105 100644
--- a/src/starboard/shared/starboard/media/media_is_video_supported_h264_1080p_hfr_only.cc
+++ b/src/starboard/raspi/shared/media_is_video_supported.cc
@@ -21,8 +21,13 @@
                                        int frame_width,
                                        int frame_height,
                                        int64_t bitrate,
-                                       int fps) {
+                                       int fps,
+                                       bool decode_to_texture_required) {
+  if (decode_to_texture_required) {
+    // There currently is no Raspberry Pi 360 video implementation.
+    return false;
+  }
   return video_codec == kSbMediaVideoCodecH264 && frame_width <= 1920 &&
          frame_height <= 1080 &&
-         bitrate <= SB_MEDIA_MAX_VIDEO_BITRATE_IN_BITS_PER_SECOND && fps <= 60;
+         bitrate <= SB_MEDIA_MAX_VIDEO_BITRATE_IN_BITS_PER_SECOND && fps <= 30;
 }
diff --git a/src/starboard/raspi/shared/open_max/video_decoder.h b/src/starboard/raspi/shared/open_max/video_decoder.h
index 4816c62..09cc42c 100644
--- a/src/starboard/raspi/shared/open_max/video_decoder.h
+++ b/src/starboard/raspi/shared/open_max/video_decoder.h
@@ -49,6 +49,7 @@
                   const ErrorCB& error_cb) override;
   size_t GetPrerollFrameCount() const override { return 1; }
   SbTime GetPrerollTimeout() const override { return kSbTimeMax; }
+  size_t GetMaxNumberOfCachedFrames() const override { return 12; }
   void WriteInputBuffer(const scoped_refptr<InputBuffer>& input_buffer)
       override;
   void WriteEndOfStream() override;
diff --git a/src/starboard/raspi/shared/starboard_platform.gypi b/src/starboard/raspi/shared/starboard_platform.gypi
index fcfc889..be746db 100644
--- a/src/starboard/raspi/shared/starboard_platform.gypi
+++ b/src/starboard/raspi/shared/starboard_platform.gypi
@@ -50,6 +50,7 @@
         '<(DEPTH)/starboard/raspi/shared/dispmanx_util.cc',
         '<(DEPTH)/starboard/raspi/shared/dispmanx_util.h',
         '<(DEPTH)/starboard/raspi/shared/main.cc',
+        '<(DEPTH)/starboard/raspi/shared/media_is_video_supported.cc',
         '<(DEPTH)/starboard/raspi/shared/open_max/decode_target_create.cc',
         '<(DEPTH)/starboard/raspi/shared/open_max/decode_target_create.h',
         '<(DEPTH)/starboard/raspi/shared/open_max/decode_target_get_info.cc',
@@ -248,8 +249,6 @@
         '<(DEPTH)/starboard/shared/signal/suspend_signals.cc',
         '<(DEPTH)/starboard/shared/signal/suspend_signals.h',
         '<(DEPTH)/starboard/shared/starboard/application.cc',
-        '<(DEPTH)/starboard/shared/starboard/command_line.cc',
-        '<(DEPTH)/starboard/shared/starboard/command_line.h',
         '<(DEPTH)/starboard/shared/starboard/audio_sink/audio_sink_create.cc',
         '<(DEPTH)/starboard/shared/starboard/audio_sink/audio_sink_destroy.cc',
         '<(DEPTH)/starboard/shared/starboard/audio_sink/audio_sink_internal.cc',
@@ -257,6 +256,8 @@
         '<(DEPTH)/starboard/shared/starboard/audio_sink/audio_sink_is_valid.cc',
         '<(DEPTH)/starboard/shared/starboard/audio_sink/stub_audio_sink_type.cc',
         '<(DEPTH)/starboard/shared/starboard/audio_sink/stub_audio_sink_type.h',
+        '<(DEPTH)/starboard/shared/starboard/command_line.cc',
+        '<(DEPTH)/starboard/shared/starboard/command_line.h',
         '<(DEPTH)/starboard/shared/starboard/directory_can_open.cc',
         '<(DEPTH)/starboard/shared/starboard/event_cancel.cc',
         '<(DEPTH)/starboard/shared/starboard/event_schedule.cc',
@@ -289,7 +290,6 @@
         '<(DEPTH)/starboard/shared/starboard/media/media_is_buffer_pool_allocate_on_demand.cc',
         '<(DEPTH)/starboard/shared/starboard/media/media_is_buffer_using_memory_pool.cc',
         '<(DEPTH)/starboard/shared/starboard/media/media_is_output_protected.cc',
-        '<(DEPTH)/starboard/shared/starboard/media/media_is_video_supported_h264_1080p_sfr_only.cc',
         '<(DEPTH)/starboard/shared/starboard/media/media_set_output_protection.cc',
         '<(DEPTH)/starboard/shared/starboard/media/media_util.cc',
         '<(DEPTH)/starboard/shared/starboard/media/media_util.h',
@@ -308,9 +308,9 @@
         '<(DEPTH)/starboard/shared/starboard/player/player_get_info.cc',
         '<(DEPTH)/starboard/shared/starboard/player/player_get_info2.cc',
         '<(DEPTH)/starboard/shared/starboard/player/player_get_maximum_number_of_samples_per_write.cc',
-        '<(DEPTH)/starboard/shared/starboard/player/player_output_mode_supported.cc',
         '<(DEPTH)/starboard/shared/starboard/player/player_internal.cc',
         '<(DEPTH)/starboard/shared/starboard/player/player_internal.h',
+        '<(DEPTH)/starboard/shared/starboard/player/player_output_mode_supported.cc',
         '<(DEPTH)/starboard/shared/starboard/player/player_seek.cc',
         '<(DEPTH)/starboard/shared/starboard/player/player_seek2.cc',
         '<(DEPTH)/starboard/shared/starboard/player/player_set_bounds.cc',
diff --git a/src/starboard/shared/_env.py b/src/starboard/shared/_env.py
new file mode 100644
index 0000000..021908e
--- /dev/null
+++ b/src/starboard/shared/_env.py
@@ -0,0 +1,26 @@
+#
+# Copyright 2017 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.
+#
+"""Ask the parent directory to load the project environment."""
+
+from imp import load_source
+from os import path
+import sys
+
+_ENV = path.abspath(path.join(path.dirname(__file__), path.pardir, '_env.py'))
+if not path.exists(_ENV):
+  print '%s: Can\'t find repo root.\nMissing parent: %s' % (__file__, _ENV)
+  sys.exit(1)
+load_source('', _ENV)
diff --git a/src/starboard/shared/ffmpeg/ffmpeg_video_decoder_impl.h b/src/starboard/shared/ffmpeg/ffmpeg_video_decoder_impl.h
index 29e4ea5..b1b05b3 100644
--- a/src/starboard/shared/ffmpeg/ffmpeg_video_decoder_impl.h
+++ b/src/starboard/shared/ffmpeg/ffmpeg_video_decoder_impl.h
@@ -69,6 +69,7 @@
                   const ErrorCB& error_cb) override;
   size_t GetPrerollFrameCount() const override { return 8; }
   SbTime GetPrerollTimeout() const override { return kSbTimeMax; }
+  size_t GetMaxNumberOfCachedFrames() const override { return 12; }
 
   void WriteInputBuffer(
       const scoped_refptr<InputBuffer>& input_buffer) override;
diff --git a/src/starboard/shared/ffmpeg/ffmpeg_video_decoder_internal.cc b/src/starboard/shared/ffmpeg/ffmpeg_video_decoder_internal.cc
index 3179924..56e4a29 100644
--- a/src/starboard/shared/ffmpeg/ffmpeg_video_decoder_internal.cc
+++ b/src/starboard/shared/ffmpeg/ffmpeg_video_decoder_internal.cc
@@ -31,6 +31,9 @@
                                        SbDrmSystem drm_system) {
   SB_UNREFERENCED_PARAMETER(codec);
   SB_UNREFERENCED_PARAMETER(drm_system);
+#if SB_HAS(BLITTER)
+  return output_mode == kSbPlayerOutputModePunchOut;
+#endif
 
 #if defined(SB_FORCE_DECODE_TO_TEXTURE_ONLY)
   // Starboard lib targets may not draw directly to the window, so punch through
diff --git a/src/starboard/shared/libvpx/vpx_video_decoder.h b/src/starboard/shared/libvpx/vpx_video_decoder.h
index 7bea0c5..12eb6f3 100644
--- a/src/starboard/shared/libvpx/vpx_video_decoder.h
+++ b/src/starboard/shared/libvpx/vpx_video_decoder.h
@@ -47,6 +47,7 @@
                   const ErrorCB& error_cb) override;
   size_t GetPrerollFrameCount() const override { return 8; }
   SbTime GetPrerollTimeout() const override { return kSbTimeMax; }
+  size_t GetMaxNumberOfCachedFrames() const override { return 12; }
 
   void WriteInputBuffer(const scoped_refptr<InputBuffer>& input_buffer)
       override;
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..8ca4625
--- /dev/null
+++ b/src/starboard/shared/opus/opus_audio_decoder.cc
@@ -0,0 +1,177 @@
+// 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();
+  }
+}
+
+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/posix/socket_listen.cc b/src/starboard/shared/posix/socket_listen.cc
index f5f623f..6153c85 100644
--- a/src/starboard/shared/posix/socket_listen.cc
+++ b/src/starboard/shared/posix/socket_listen.cc
@@ -16,6 +16,7 @@
 
 #include <errno.h>
 #include <sys/socket.h>
+#include <sys/types.h>
 
 #include "starboard/log.h"
 #include "starboard/shared/posix/socket_internal.h"
@@ -29,10 +30,23 @@
   }
 
   SB_DCHECK(socket->socket_fd >= 0);
-  // TODO: Determine if we need to specify a > 0 backlog. It can go up to
-  // SOMAXCONN according to the documentation. Several places in chromium
-  // specify the literal "10" with the comment "maybe dont allow any backlog?"
-  int result = listen(socket->socket_fd, 0);
+  // We set the backlog to SOMAXCONN to ensure that it is above 1, and high
+  // enough that all tests are able to pass.  Some tests will fail on this
+  // because they expect to be able to successfully initiate multiple connects
+  // at once, and then after all connects have been initiated to subsequently
+  // initiate corresponding accepts.
+#if defined(SOMAXCONN)
+  const int kMaxConn = SOMAXCONN;
+#else
+  // Some posix platforms such as FreeBSD do not define SOMAXCONN.
+  // In this case, set the value to an arbitrary number large enough to
+  // satisfy most use-cases and tests, empirically we have found that 128
+  // is sufficient.  All implementations of listen() specify that a backlog
+  // parameter larger than the system max will be silently truncated to the
+  // system's max.
+  const int kMaxConn = 128;
+#endif
+  int result = listen(socket->socket_fd, kMaxConn);
   if (result != 0) {
     return (socket->error = sbposix::TranslateSocketErrno(result));
   }
diff --git a/src/starboard/shared/pthread/thread_create.cc b/src/starboard/shared/pthread/thread_create.cc
index d0a9e1f..581e713 100644
--- a/src/starboard/shared/pthread/thread_create.cc
+++ b/src/starboard/shared/pthread/thread_create.cc
@@ -100,9 +100,11 @@
     return kSbThreadInvalid;
   }
 
+#if !SB_HAS_QUIRK(NO_PTHREAD_ATTR_SETDETACHSTATE)
   pthread_attr_setdetachstate(
       &attributes,
       (joinable ? PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED));
+#endif  // NO_PTHREAD_ATTR_SETDETACHSTATE
   if (stack_size > 0) {
     pthread_attr_setstacksize(&attributes, stack_size);
   }
diff --git a/src/starboard/shared/starboard/drm/drm_system_internal.h b/src/starboard/shared/starboard/drm/drm_system_internal.h
index 6db745c..696855b 100644
--- a/src/starboard/shared/starboard/drm/drm_system_internal.h
+++ b/src/starboard/shared/starboard/drm/drm_system_internal.h
@@ -41,11 +41,11 @@
 
   virtual DecryptStatus Decrypt(InputBuffer* buffer) = 0;
 
-#if SB_API_VERSION >= SB_DRM_REFINEMENT_API_VERSION
+#if SB_API_VERSION >= 10
   virtual void UpdateServerCertificate(int ticket,
                                        const void* certificate,
                                        int certificate_size) = 0;
-#endif  // SB_API_VERSION >= SB_DRM_REFINEMENT_API_VERSION
+#endif  // SB_API_VERSION >= 10
 };
 
 #endif  // STARBOARD_SHARED_STARBOARD_DRM_DRM_SYSTEM_INTERNAL_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 5555f3f..a20ec3e 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
@@ -41,7 +41,12 @@
 //
 // Note that canPlayType() doesn't support extra parameters like width, height
 // and channels.
-SbMediaSupportType CanPlayProgressiveVideo(const MimeType& mime_type) {
+SbMediaSupportType CanPlayProgressiveVideo(const MimeType& mime_type,
+                                           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();
 
   SB_DCHECK(codecs.size() == 2) << codecs.size();
@@ -74,7 +79,12 @@
       }
     }
     if (!SbMediaIsVideoSupported(video_codec, width, height, kDefaultBitRate,
-                                 fps)) {
+                                 fps
+#if SB_API_VERSION >= 10
+                                 ,
+                                 decode_to_texture_required
+#endif  // SB_API_VERSION >= 10
+                                 )) {
       return kSbMediaSupportTypeNotSupported;
     }
   }
@@ -104,6 +114,9 @@
 //   isTypeSupported(audio/webm; codecs="opus")
 //   isTypeSupported(audio/mp4; codecs="mp4a.40.2"; channels=2)
 //   isTypeSupported(audio/mp4; codecs="mp4a.40.2"; channels=99)
+//   isTypeSupported(video/mp4; codecs="avc1.4d401e"; decode-to-texture=true)
+//   isTypeSupported(video/mp4; codecs="avc1.4d401e"; decode-to-texture=false)
+//   isTypeSupported(video/mp4; codecs="avc1.4d401e"; decode-to-texture=invalid)
 SbMediaSupportType CanPlayMimeAndKeySystem(const MimeType& mime_type,
                                            const char* key_system) {
   SB_DCHECK(mime_type.is_valid());
@@ -118,6 +131,19 @@
     }
   }
 
+  bool decode_to_texture_required = false;
+#if SB_API_VERSION >= 10
+  std::string decode_to_texture_value =
+      mime_type.GetParamStringValue("decode-to-texture", "false");
+  if (decode_to_texture_value == "true") {
+    decode_to_texture_required = true;
+  } else if (decode_to_texture_value != "false") {
+    // If an invalid value (e.g. not "true" or "false") is passed in for
+    // decode-to-texture, trivially reject.
+    return kSbMediaSupportTypeNotSupported;
+  }
+#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".
@@ -130,7 +156,7 @@
 
   if (codecs.size() == 2) {
     SB_DCHECK(SbStringGetLength(key_system) == 0);
-    return CanPlayProgressiveVideo(mime_type);
+    return CanPlayProgressiveVideo(mime_type, decode_to_texture_required);
   }
 
   SB_DCHECK(codecs.size() == 1);
@@ -208,7 +234,12 @@
 
     int bitrate = mime_type.GetParamIntValue("bitrate", kDefaultBitRate);
 
-    if (SbMediaIsVideoSupported(video_codec, width, height, bitrate, fps)) {
+    if (SbMediaIsVideoSupported(video_codec, width, height, bitrate, fps
+#if SB_API_VERSION >= 10
+                                ,
+                                decode_to_texture_required
+#endif  // SB_API_VERSION >= 10
+                                )) {
       return kSbMediaSupportTypeProbably;
     }
 
diff --git a/src/starboard/shared/starboard/media/media_support_internal.h b/src/starboard/shared/starboard/media/media_support_internal.h
index 3da76bb..0ecefdf 100644
--- a/src/starboard/shared/starboard/media/media_support_internal.h
+++ b/src/starboard/shared/starboard/media/media_support_internal.h
@@ -35,11 +35,18 @@
 // |frame_height|: The frame height of the media content.
 // |bitrate|: The bitrate of the media content.
 // |fps|: The number of frames per second in the media content.
+// |decode_to_texture_required|: Whether or not the resulting video frames can
+//                               be decoded and used as textures by the GPU.
 SB_EXPORT bool SbMediaIsVideoSupported(SbMediaVideoCodec video_codec,
                                        int frame_width,
                                        int frame_height,
                                        int64_t bitrate,
-                                       int fps);
+                                       int fps
+#if SB_API_VERSION >= 10
+                                       ,
+                                       bool decode_to_texture_required
+#endif  // SB_API_VERSION >= 10
+                                       );
 
 // Indicates whether this platform supports |audio_codec| at |bitrate|.
 // If |audio_codec| is not supported under any condition, this function
diff --git a/src/starboard/shared/starboard/player/filter/audio_renderer_internal.cc b/src/starboard/shared/starboard/player/filter/audio_renderer_internal.cc
index 386ddda..6cb6afe 100644
--- a/src/starboard/shared/starboard/player/filter/audio_renderer_internal.cc
+++ b/src/starboard/shared/starboard/player/filter/audio_renderer_internal.cc
@@ -288,9 +288,11 @@
 }
 
 SbTime AudioRenderer::GetCurrentMediaTime(bool* is_playing,
-                                          bool* is_eos_played) {
+                                          bool* is_eos_played,
+                                          bool* is_underflow) {
   SB_DCHECK(is_playing);
   SB_DCHECK(is_eos_played);
+  SB_DCHECK(is_underflow);
 
   SbTime media_time = 0;
   SbTimeMonotonic now = -1;
@@ -303,6 +305,7 @@
 
     *is_playing = !paused_ && !seeking_;
     *is_eos_played = IsEndOfStreamPlayed_Locked();
+    *is_underflow = underflow_;
     if (*is_eos_played && !ended_cb_called_) {
       ended_cb_called_ = true;
       Schedule(ended_cb_);
@@ -463,10 +466,12 @@
   }
 
   is_eos_reached_on_sink_thread_ = eos_state_ >= kEOSSentToSink;
-  is_playing_on_sink_thread_ = !paused_ && !seeking_;
   frames_in_buffer_on_sink_thread_ = static_cast<int>(
       frames_sent_to_sink_ + silence_frames_written_after_eos_on_sink_thread_ -
       frames_consumed_by_sink_ - frames_consumed_on_sink_thread_);
+  underflow_ |=
+      frames_in_buffer_on_sink_thread_ < kFramesInBufferBeginUnderflow;
+  is_playing_on_sink_thread_ = !paused_ && !seeking_ && !underflow_;
   offset_in_frames_on_sink_thread_ =
       (frames_consumed_by_sink_ + frames_consumed_on_sink_thread_) %
       max_cached_frames_;
@@ -596,6 +601,7 @@
           seeking_ = false;
           Schedule(prerolled_cb_);
         }
+        underflow_ = false;
       }
 
       resampled_audio = resampler_->WriteEndOfStream();
@@ -643,10 +649,13 @@
 
   *is_frame_buffer_full = false;
 
-  if (seeking_ && time_stretcher_.IsQueueFull()) {
+  if (time_stretcher_.IsQueueFull()) {
     ScopedLock lock(mutex_);
-    seeking_ = false;
-    Schedule(prerolled_cb_);
+    if (seeking_) {
+      seeking_ = false;
+      Schedule(prerolled_cb_);
+    }
+    underflow_ = false;
   }
 
   if (seeking_ || playback_rate_ == 0.0) {
diff --git a/src/starboard/shared/starboard/player/filter/audio_renderer_internal.h b/src/starboard/shared/starboard/player/filter/audio_renderer_internal.h
index 09f9da4..b25e959 100644
--- a/src/starboard/shared/starboard/player/filter/audio_renderer_internal.h
+++ b/src/starboard/shared/starboard/player/filter/audio_renderer_internal.h
@@ -45,6 +45,8 @@
 namespace player {
 namespace filter {
 
+const int kFramesInBufferBeginUnderflow = 1024;
+
 // A class that sits in between the audio decoder, the audio sink and the
 // pipeline to coordinate data transfer between these parties.  It also serves
 // as the authority of playback time.
@@ -86,7 +88,9 @@
   void Pause() override;
   void SetPlaybackRate(double playback_rate) override;
   void Seek(SbTime seek_to_time) override;
-  SbTime GetCurrentMediaTime(bool* is_playing, bool* is_eos_played) override;
+  SbTime GetCurrentMediaTime(bool* is_playing,
+                             bool* is_eos_played,
+                             bool* is_underflow) override;
 
  private:
   enum EOSState {
@@ -185,6 +189,10 @@
   SbTime max_drift_ = 0;
   int64_t total_frames_consumed_ = 0;
 #endif  // SB_LOG_MEDIA_TIME_STATS
+
+  // Set to true when there are fewer than |kFramesInBufferBeginUnderflow|
+  // frames in buffer. Set to false when the queue is full or EOS.
+  bool underflow_ = false;
 };
 
 }  // namespace filter
diff --git a/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.cc b/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.cc
index 492b272..099710e 100644
--- a/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.cc
+++ b/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.cc
@@ -462,9 +462,10 @@
     }
     bool is_playing;
     bool is_eos_played;
+    bool is_underflow;
     auto media_time = GetMediaTimeProvider()->GetCurrentMediaTime(
-        &is_playing, &is_eos_played);
-    update_media_info_cb_(media_time, dropped_frames);
+        &is_playing, &is_eos_played, &is_underflow);
+    update_media_info_cb_(media_time, dropped_frames, is_underflow);
   }
 
   update_job_token_ = Schedule(update_job_, kUpdateInterval);
diff --git a/src/starboard/shared/starboard/player/filter/media_time_provider.h b/src/starboard/shared/starboard/player/filter/media_time_provider.h
index d6be5c2..55a71d6 100644
--- a/src/starboard/shared/starboard/player/filter/media_time_provider.h
+++ b/src/starboard/shared/starboard/player/filter/media_time_provider.h
@@ -34,7 +34,9 @@
   virtual void SetPlaybackRate(double playback_rate) = 0;
   virtual void Seek(SbTime seek_to_pts) = 0;
   // This function can be called from *any* thread.
-  virtual SbTime GetCurrentMediaTime(bool* is_playing, bool* is_eos_played) = 0;
+  virtual SbTime GetCurrentMediaTime(bool* is_playing,
+                                     bool* is_eos_played,
+                                     bool* is_underflow) = 0;
 
  protected:
   virtual ~MediaTimeProvider() {}
diff --git a/src/starboard/shared/starboard/player/filter/media_time_provider_impl.cc b/src/starboard/shared/starboard/player/filter/media_time_provider_impl.cc
index b15e7e0..5134d8b 100644
--- a/src/starboard/shared/starboard/player/filter/media_time_provider_impl.cc
+++ b/src/starboard/shared/starboard/player/filter/media_time_provider_impl.cc
@@ -94,7 +94,8 @@
 }
 
 SbTime MediaTimeProviderImpl::GetCurrentMediaTime(bool* is_playing,
-                                                  bool* is_eos_played) {
+                                                  bool* is_eos_played,
+                                                  bool* is_underflow) {
   SB_DCHECK(ended_cb_);
 
   ScopedLock scoped_lock(mutex_);
@@ -105,6 +106,7 @@
   *is_eos_played =
       is_video_end_of_stream_reached_ &&
       (!video_duration_.has_engaged() || current >= video_duration_.value());
+  *is_underflow = false;
 
   Schedule(ended_cb_);
   return current;
diff --git a/src/starboard/shared/starboard/player/filter/media_time_provider_impl.h b/src/starboard/shared/starboard/player/filter/media_time_provider_impl.h
index 1da38e5..77cd1fa 100644
--- a/src/starboard/shared/starboard/player/filter/media_time_provider_impl.h
+++ b/src/starboard/shared/starboard/player/filter/media_time_provider_impl.h
@@ -49,7 +49,9 @@
   void Pause() override;
   void SetPlaybackRate(double playback_rate) override;
   void Seek(SbTime seek_to_time) override;
-  SbTime GetCurrentMediaTime(bool* is_playing, bool* is_eos_played) override;
+  SbTime GetCurrentMediaTime(bool* is_playing,
+                             bool* is_eos_played,
+                             bool* is_underflow) override;
 
   // When video end of stream is reached and the current media time passes the
   // video duration, |is_eos_played| of GetCurrentMediaTime() will return true.
diff --git a/src/starboard/shared/starboard/player/filter/stub_player_components_impl.cc b/src/starboard/shared/starboard/player/filter/stub_player_components_impl.cc
index 51976ea..1f899c7 100644
--- a/src/starboard/shared/starboard/player/filter/stub_player_components_impl.cc
+++ b/src/starboard/shared/starboard/player/filter/stub_player_components_impl.cc
@@ -170,6 +170,7 @@
   }
   size_t GetPrerollFrameCount() const override { return 1; }
   SbTime GetPrerollTimeout() const override { return kSbTimeMax; }
+  size_t GetMaxNumberOfCachedFrames() const override { return 12; }
   void WriteInputBuffer(const scoped_refptr<InputBuffer>& input_buffer)
       override {
     SB_DCHECK(input_buffer);
diff --git a/src/starboard/shared/starboard/player/filter/testing/audio_renderer_internal_test.cc b/src/starboard/shared/starboard/player/filter/testing/audio_renderer_internal_test.cc
index 6d7ecbb..a76aa73 100644
--- a/src/starboard/shared/starboard/player/filter/testing/audio_renderer_internal_test.cc
+++ b/src/starboard/shared/starboard/player/filter/testing/audio_renderer_internal_test.cc
@@ -255,7 +255,9 @@
   EXPECT_FALSE(audio_renderer_->IsSeekingInProgress());
   bool is_playing = true;
   bool is_eos_played = true;
-  EXPECT_EQ(audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played),
+  bool is_underflow = true;
+  EXPECT_EQ(audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played,
+                                                 &is_underflow),
             0);
   EXPECT_FALSE(is_playing);
   EXPECT_FALSE(is_eos_played);
@@ -279,7 +281,9 @@
 
   bool is_playing = true;
   bool is_eos_played = true;
-  EXPECT_EQ(audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played),
+  bool is_underflow = true;
+  EXPECT_EQ(audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played,
+                                                 &is_underflow),
             0);
   EXPECT_FALSE(is_playing);
   EXPECT_FALSE(is_eos_played);
@@ -289,8 +293,8 @@
 
   SendDecoderOutput(new DecodedAudio);
 
-  SbTime media_time =
-      audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played);
+  SbTime media_time = audio_renderer_->GetCurrentMediaTime(
+      &is_playing, &is_eos_played, &is_underflow);
   EXPECT_TRUE(is_playing);
   EXPECT_FALSE(is_eos_played);
 
@@ -312,8 +316,8 @@
   EXPECT_FALSE(audio_renderer_->IsEndOfStreamPlayed());
 
   renderer_callback_->ConsumeFrames(frames_to_consume);
-  new_media_time =
-      audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played);
+  new_media_time = audio_renderer_->GetCurrentMediaTime(
+      &is_playing, &is_eos_played, &is_underflow);
   EXPECT_TRUE(is_playing);
   EXPECT_FALSE(is_eos_played);
   EXPECT_GT(new_media_time, media_time);
@@ -321,8 +325,8 @@
 
   const int remaining_frames = frames_in_buffer - frames_to_consume;
   renderer_callback_->ConsumeFrames(remaining_frames);
-  new_media_time =
-      audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played);
+  new_media_time = audio_renderer_->GetCurrentMediaTime(
+      &is_playing, &is_eos_played, &is_underflow);
   EXPECT_TRUE(is_playing);
   EXPECT_TRUE(is_eos_played);
   EXPECT_GT(new_media_time, media_time);
@@ -357,8 +361,10 @@
   FillRendererWithDecodedAudioAndWriteEOS();
   bool is_playing = false;
   bool is_eos_played = true;
+  bool is_underflow = true;
 
-  EXPECT_EQ(audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played),
+  EXPECT_EQ(audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played,
+                                                 &is_underflow),
             0);
   EXPECT_FALSE(is_playing);
   EXPECT_FALSE(is_eos_played);
@@ -368,8 +374,8 @@
 
   SendDecoderOutput(new DecodedAudio);
 
-  SbTime media_time =
-      audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played);
+  SbTime media_time = audio_renderer_->GetCurrentMediaTime(
+      &is_playing, &is_eos_played, &is_underflow);
 
   int frames_in_buffer;
   int offset_in_frames;
@@ -390,15 +396,15 @@
   EXPECT_FALSE(audio_renderer_->IsEndOfStreamPlayed());
 
   renderer_callback_->ConsumeFrames(frames_to_consume);
-  new_media_time =
-      audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played);
+  new_media_time = audio_renderer_->GetCurrentMediaTime(
+      &is_playing, &is_eos_played, &is_underflow);
   EXPECT_GT(new_media_time, media_time);
   media_time = new_media_time;
 
   const int remaining_frames = frames_in_buffer - frames_to_consume;
   renderer_callback_->ConsumeFrames(remaining_frames);
-  new_media_time =
-      audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played);
+  new_media_time = audio_renderer_->GetCurrentMediaTime(
+      &is_playing, &is_eos_played, &is_underflow);
   EXPECT_GT(new_media_time, media_time);
 
   EXPECT_TRUE(audio_renderer_->IsEndOfStreamPlayed());
@@ -425,8 +431,9 @@
 
   bool is_playing = false;
   bool is_eos_played = true;
-  SbTime media_time =
-      audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played);
+  bool is_underflow = true;
+  SbTime media_time = audio_renderer_->GetCurrentMediaTime(
+      &is_playing, &is_eos_played, &is_underflow);
 
   int frames_in_buffer;
   int offset_in_frames;
@@ -446,8 +453,8 @@
   EXPECT_FALSE(audio_renderer_->IsEndOfStreamPlayed());
 
   renderer_callback_->ConsumeFrames(frames_to_consume);
-  new_media_time =
-      audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played);
+  new_media_time = audio_renderer_->GetCurrentMediaTime(
+      &is_playing, &is_eos_played, &is_underflow);
   EXPECT_TRUE(is_playing);
   EXPECT_FALSE(is_eos_played);
   EXPECT_GE(new_media_time, media_time);
@@ -455,8 +462,8 @@
 
   const int remaining_frames = frames_in_buffer - frames_to_consume;
   renderer_callback_->ConsumeFrames(remaining_frames);
-  new_media_time =
-      audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played);
+  new_media_time = audio_renderer_->GetCurrentMediaTime(
+      &is_playing, &is_eos_played, &is_underflow);
   EXPECT_TRUE(is_playing);
   EXPECT_TRUE(is_eos_played);
   EXPECT_GE(new_media_time, media_time);
@@ -492,7 +499,9 @@
   EXPECT_FALSE(audio_renderer_->IsSeekingInProgress());
   bool is_playing = true;
   bool is_eos_played = false;
-  EXPECT_EQ(audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played),
+  bool is_underflow = true;
+  EXPECT_EQ(audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played,
+                                                 &is_underflow),
             0);
   EXPECT_FALSE(is_playing);
   EXPECT_TRUE(is_eos_played);
@@ -534,7 +543,9 @@
   EXPECT_FALSE(audio_renderer_->IsSeekingInProgress());
   bool is_playing = true;
   bool is_eos_played = false;
-  EXPECT_EQ(audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played),
+  bool is_underflow = true;
+  EXPECT_EQ(audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played,
+                                                 &is_underflow),
             0);
   EXPECT_FALSE(is_playing);
   EXPECT_TRUE(is_eos_played);
@@ -572,7 +583,9 @@
 
   bool is_playing = true;
   bool is_eos_played = true;
-  EXPECT_EQ(audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played),
+  bool is_underflow = true;
+  EXPECT_EQ(audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played,
+                                                 &is_underflow),
             0);
   EXPECT_FALSE(is_playing);
   EXPECT_FALSE(is_eos_played);
@@ -582,8 +595,8 @@
 
   SendDecoderOutput(new DecodedAudio);
 
-  SbTime media_time =
-      audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played);
+  SbTime media_time = audio_renderer_->GetCurrentMediaTime(
+      &is_playing, &is_eos_played, &is_underflow);
 
   int frames_in_buffer;
   int offset_in_frames;
@@ -604,8 +617,8 @@
   EXPECT_FALSE(audio_renderer_->IsEndOfStreamPlayed());
 
   renderer_callback_->ConsumeFrames(frames_to_consume);
-  new_media_time =
-      audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played);
+  new_media_time = audio_renderer_->GetCurrentMediaTime(
+      &is_playing, &is_eos_played, &is_underflow);
   EXPECT_TRUE(is_playing);
   EXPECT_FALSE(is_eos_played);
   EXPECT_GE(new_media_time, media_time);
@@ -613,8 +626,8 @@
 
   const int remaining_frames = frames_in_buffer - frames_to_consume;
   renderer_callback_->ConsumeFrames(remaining_frames);
-  new_media_time =
-      audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played);
+  new_media_time = audio_renderer_->GetCurrentMediaTime(
+      &is_playing, &is_eos_played, &is_underflow);
   EXPECT_TRUE(is_playing);
   EXPECT_TRUE(is_eos_played);
   EXPECT_GE(new_media_time, media_time);
@@ -661,7 +674,9 @@
 
   bool is_playing;
   bool is_eos_played;
-  EXPECT_EQ(audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played),
+  bool is_underflow;
+  EXPECT_EQ(audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played,
+                                                 &is_underflow),
             0);
   EXPECT_FALSE(audio_renderer_->IsSeekingInProgress());
 
@@ -669,8 +684,8 @@
 
   SendDecoderOutput(new DecodedAudio);
 
-  SbTime media_time =
-      audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played);
+  SbTime media_time = audio_renderer_->GetCurrentMediaTime(
+      &is_playing, &is_eos_played, &is_underflow);
 
   int frames_in_buffer;
   int offset_in_frames;
@@ -690,15 +705,15 @@
   EXPECT_FALSE(audio_renderer_->IsEndOfStreamPlayed());
 
   renderer_callback_->ConsumeFrames(frames_to_consume);
-  new_media_time =
-      audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played);
+  new_media_time = audio_renderer_->GetCurrentMediaTime(
+      &is_playing, &is_eos_played, &is_underflow);
   EXPECT_GE(new_media_time, media_time);
   media_time = new_media_time;
 
   const int remaining_frames = frames_in_buffer - frames_to_consume;
   renderer_callback_->ConsumeFrames(remaining_frames);
-  new_media_time =
-      audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played);
+  new_media_time = audio_renderer_->GetCurrentMediaTime(
+      &is_playing, &is_eos_played, &is_underflow);
   EXPECT_GE(new_media_time, media_time);
 
   EXPECT_TRUE(audio_renderer_->IsEndOfStreamPlayed());
@@ -726,7 +741,9 @@
 
   bool is_playing;
   bool is_eos_played;
-  EXPECT_EQ(audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played),
+  bool is_underflow;
+  EXPECT_EQ(audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played,
+                                                 &is_underflow),
             0);
   EXPECT_FALSE(audio_renderer_->IsSeekingInProgress());
 
@@ -734,8 +751,8 @@
 
   SendDecoderOutput(new DecodedAudio);
 
-  SbTime media_time =
-      audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played);
+  SbTime media_time = audio_renderer_->GetCurrentMediaTime(
+      &is_playing, &is_eos_played, &is_underflow);
 
   int frames_in_buffer;
   int offset_in_frames;
@@ -756,14 +773,15 @@
   EXPECT_FALSE(audio_renderer_->IsEndOfStreamPlayed());
 
   renderer_callback_->ConsumeFrames(frames_to_consume);
-  new_media_time =
-      audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played);
+  new_media_time = audio_renderer_->GetCurrentMediaTime(
+      &is_playing, &is_eos_played, &is_underflow);
   EXPECT_GE(new_media_time, media_time);
   Seek(seek_time);
 
   frames_written = FillRendererWithDecodedAudioAndWriteEOS();
 
-  EXPECT_GE(audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played),
+  EXPECT_GE(audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played,
+                                                 &is_underflow),
             seek_time);
   EXPECT_FALSE(audio_renderer_->IsSeekingInProgress());
 
@@ -778,8 +796,8 @@
   EXPECT_TRUE(is_eos_reached);
   const int remaining_frames = frames_in_buffer - offset_in_frames;
   renderer_callback_->ConsumeFrames(remaining_frames);
-  new_media_time =
-      audio_renderer_->GetCurrentMediaTime(&is_playing, &is_eos_played);
+  new_media_time = audio_renderer_->GetCurrentMediaTime(
+      &is_playing, &is_eos_played, &is_underflow);
   EXPECT_GE(new_media_time, seek_time);
 
   EXPECT_TRUE(audio_renderer_->IsEndOfStreamPlayed());
diff --git a/src/starboard/shared/starboard/player/filter/testing/media_time_provider_impl_test.cc b/src/starboard/shared/starboard/player/filter/testing/media_time_provider_impl_test.cc
index ab23eea..9c1637e 100644
--- a/src/starboard/shared/starboard/player/filter/testing/media_time_provider_impl_test.cc
+++ b/src/starboard/shared/starboard/player/filter/testing/media_time_provider_impl_test.cc
@@ -102,64 +102,68 @@
 };
 
 TEST_F(MediaTimeProviderImplTest, DefaultStates) {
-  bool is_playing = true, is_eos_played = true;
+  bool is_playing = true, is_eos_played = true, is_underflow = true;
   EXPECT_TRUE(AlmostEqual(media_time_provider_impl_.GetCurrentMediaTime(
-                              &is_playing, &is_eos_played),
+                              &is_playing, &is_eos_played, &is_underflow),
                           0));
   EXPECT_FALSE(is_playing);
   EXPECT_FALSE(is_eos_played);
+  EXPECT_FALSE(is_underflow);
 }
 
 TEST_F(MediaTimeProviderImplTest, GetCurrentMediaTimeWhileNotPlaying) {
   system_time_provider_->AdvanceTime(kSbTimeSecond);
 
-  bool is_playing = true, is_eos_played = true;
+  bool is_playing = true, is_eos_played = true, is_underflow = true;
   EXPECT_TRUE(AlmostEqual(media_time_provider_impl_.GetCurrentMediaTime(
-                              &is_playing, &is_eos_played),
+                              &is_playing, &is_eos_played, &is_underflow),
                           0));
   EXPECT_FALSE(is_playing);
   EXPECT_FALSE(is_eos_played);
+  EXPECT_FALSE(is_underflow);
 }
 
 TEST_F(MediaTimeProviderImplTest, GetCurrentMediaTimeWhilePlaying) {
   media_time_provider_impl_.Play();
 
-  bool is_playing = false, is_eos_played = true;
+  bool is_playing = false, is_eos_played = true, is_underflow = true;
   EXPECT_TRUE(AlmostEqual(media_time_provider_impl_.GetCurrentMediaTime(
-                              &is_playing, &is_eos_played),
+                              &is_playing, &is_eos_played, &is_underflow),
                           0));
   EXPECT_TRUE(is_playing);
   EXPECT_FALSE(is_eos_played);
+  EXPECT_FALSE(is_underflow);
 
   system_time_provider_->AdvanceTime(kSbTimeSecond);
 
   EXPECT_TRUE(AlmostEqual(media_time_provider_impl_.GetCurrentMediaTime(
-                              &is_playing, &is_eos_played),
+                              &is_playing, &is_eos_played, &is_underflow),
                           kSbTimeSecond));
   EXPECT_TRUE(is_playing);
   EXPECT_FALSE(is_eos_played);
+  EXPECT_FALSE(is_underflow);
 }
 
 TEST_F(MediaTimeProviderImplTest, SetPlaybackRateWhilePlaying) {
   media_time_provider_impl_.Play();
 
   system_time_provider_->AdvanceTime(kSbTimeSecond);
-  bool is_playing = true, is_eos_played = true;
+  bool is_playing = true, is_eos_played = true, is_underflow = true;
   EXPECT_TRUE(AlmostEqual(media_time_provider_impl_.GetCurrentMediaTime(
-                              &is_playing, &is_eos_played),
+                              &is_playing, &is_eos_played, &is_underflow),
                           kSbTimeSecond));
 
   media_time_provider_impl_.SetPlaybackRate(2.0);
 
   system_time_provider_->AdvanceTime(kSbTimeSecond);
   EXPECT_TRUE(AlmostEqual(media_time_provider_impl_.GetCurrentMediaTime(
-                              &is_playing, &is_eos_played),
+                              &is_playing, &is_eos_played, &is_underflow),
                           kSbTimeSecond * 3));
 
   media_time_provider_impl_.SetPlaybackRate(0.0);
   system_time_provider_->AdvanceTime(kSbTimeSecond);
   EXPECT_TRUE(AlmostEqual(media_time_provider_impl_.GetCurrentMediaTime(
-                              &is_playing, &is_eos_played),
+                              &is_playing, &is_eos_played, &is_underflow),
                           kSbTimeSecond * 3));
 }
 
@@ -167,17 +171,18 @@
   const SbTime kSeekToTime = 100 * kSbTimeSecond;
 
   media_time_provider_impl_.Seek(kSeekToTime);
-  bool is_playing = true, is_eos_played = true;
+  bool is_playing = true, is_eos_played = true, is_underflow = true;
   EXPECT_TRUE(AlmostEqual(media_time_provider_impl_.GetCurrentMediaTime(
-                              &is_playing, &is_eos_played),
+                              &is_playing, &is_eos_played, &is_underflow),
                           kSeekToTime));
   EXPECT_FALSE(is_playing);
   EXPECT_FALSE(is_eos_played);
+  EXPECT_FALSE(is_underflow);
 
   system_time_provider_->AdvanceTime(kSbTimeSecond);
 
   EXPECT_TRUE(AlmostEqual(media_time_provider_impl_.GetCurrentMediaTime(
-                              &is_playing, &is_eos_played),
+                              &is_playing, &is_eos_played, &is_underflow),
                           kSeekToTime));
 }
 
@@ -187,20 +192,22 @@
   media_time_provider_impl_.Play();
 
   media_time_provider_impl_.Seek(kSeekToTime);
-  bool is_playing = false, is_eos_played = true;
+  bool is_playing = false, is_eos_played = true, is_underflow = true;
   EXPECT_TRUE(AlmostEqual(media_time_provider_impl_.GetCurrentMediaTime(
-                              &is_playing, &is_eos_played),
+                              &is_playing, &is_eos_played, &is_underflow),
                           kSeekToTime));
   EXPECT_TRUE(is_playing);
   EXPECT_FALSE(is_eos_played);
+  EXPECT_FALSE(is_underflow);
 
   system_time_provider_->AdvanceTime(kSbTimeSecond);
 
   EXPECT_TRUE(AlmostEqual(media_time_provider_impl_.GetCurrentMediaTime(
-                              &is_playing, &is_eos_played),
+                              &is_playing, &is_eos_played, &is_underflow),
                           kSeekToTime + kSbTimeSecond));
   EXPECT_TRUE(is_playing);
   EXPECT_FALSE(is_eos_played);
+  EXPECT_FALSE(is_underflow);
 }
 
 TEST_F(MediaTimeProviderImplTest, SeekBackwardWhilePlaying) {
@@ -208,14 +215,15 @@
 
   system_time_provider_->AdvanceTime(kSbTimeSecond);
 
-  bool is_playing = true, is_eos_played = true;
+  bool is_playing = true, is_eos_played = true, is_underflow = true;
   // Query for media time and ignore the result.
-  media_time_provider_impl_.GetCurrentMediaTime(&is_playing, &is_eos_played);
+  media_time_provider_impl_.GetCurrentMediaTime(&is_playing, &is_eos_played,
+                                                &is_underflow);
 
   const SbTime kSeekToTime = 0;
   media_time_provider_impl_.Seek(kSeekToTime);
   EXPECT_TRUE(AlmostEqual(media_time_provider_impl_.GetCurrentMediaTime(
-                              &is_playing, &is_eos_played),
+                              &is_playing, &is_eos_played, &is_underflow),
                           kSeekToTime));
 }
 
@@ -224,20 +232,21 @@
 
   system_time_provider_->AdvanceTime(kSbTimeSecond);
 
-  bool is_playing = true, is_eos_played = true;
+  bool is_playing = true, is_eos_played = true, is_underflow = true;
   // Query for media time and ignore the result.
-  media_time_provider_impl_.GetCurrentMediaTime(&is_playing, &is_eos_played);
+  media_time_provider_impl_.GetCurrentMediaTime(&is_playing, &is_eos_played,
+                                                &is_underflow);
 
   media_time_provider_impl_.Pause();
   system_time_provider_->AdvanceTime(kSbTimeSecond);
   EXPECT_TRUE(AlmostEqual(media_time_provider_impl_.GetCurrentMediaTime(
-                              &is_playing, &is_eos_played),
+                              &is_playing, &is_eos_played, &is_underflow),
                           kSbTimeSecond));
 
   media_time_provider_impl_.Seek(0);
   system_time_provider_->AdvanceTime(kSbTimeSecond);
   EXPECT_TRUE(AlmostEqual(media_time_provider_impl_.GetCurrentMediaTime(
-                              &is_playing, &is_eos_played),
+                              &is_playing, &is_eos_played, &is_underflow),
                           0));
 }
 
@@ -248,36 +257,45 @@
   media_time_provider_impl_.UpdateVideoDuration(kVideoDuration);
   system_time_provider_->AdvanceTime(kSbTimeSecond);
 
-  bool is_playing = true, is_eos_played = true;
+  bool is_playing = true, is_eos_played = true, is_underflow = true;
   // Query for media time and ignore the result.
-  media_time_provider_impl_.GetCurrentMediaTime(&is_playing, &is_eos_played);
+  media_time_provider_impl_.GetCurrentMediaTime(&is_playing, &is_eos_played,
+                                                &is_underflow);
   EXPECT_FALSE(is_playing);
   EXPECT_FALSE(is_eos_played);
+  EXPECT_FALSE(is_underflow);
 
   media_time_provider_impl_.Play();
   // Advance to 1 millisecond past the |kVideoDuration|.
   system_time_provider_->AdvanceTime(kSbTimeSecond + kSbTimeMillisecond);
-  media_time_provider_impl_.GetCurrentMediaTime(&is_playing, &is_eos_played);
+  media_time_provider_impl_.GetCurrentMediaTime(&is_playing, &is_eos_played,
+                                                &is_underflow);
   EXPECT_TRUE(is_playing);
   EXPECT_FALSE(is_eos_played);
+  EXPECT_FALSE(is_underflow);
 
   media_time_provider_impl_.VideoEndOfStreamReached();
-  media_time_provider_impl_.GetCurrentMediaTime(&is_playing, &is_eos_played);
+  media_time_provider_impl_.GetCurrentMediaTime(&is_playing, &is_eos_played,
+                                                &is_underflow);
   EXPECT_TRUE(is_playing);
   EXPECT_TRUE(is_eos_played);
+  EXPECT_FALSE(is_underflow);
 
   media_time_provider_impl_.Pause();
   media_time_provider_impl_.SetPlaybackRate(0);
   SbTime current_time = media_time_provider_impl_.GetCurrentMediaTime(
-      &is_playing, &is_eos_played);
+      &is_playing, &is_eos_played, &is_underflow);
   EXPECT_FALSE(is_playing);
   EXPECT_TRUE(is_eos_played);
+  EXPECT_FALSE(is_underflow);
 
   // Seek() should clear the EOS state
   media_time_provider_impl_.Seek(current_time);
-  media_time_provider_impl_.GetCurrentMediaTime(&is_playing, &is_eos_played);
+  media_time_provider_impl_.GetCurrentMediaTime(&is_playing, &is_eos_played,
+                                                &is_underflow);
   EXPECT_FALSE(is_playing);
   EXPECT_FALSE(is_eos_played);
+  EXPECT_FALSE(is_underflow);
 }
 
 }  // namespace
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 7d06873..12622c5 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
@@ -646,7 +646,12 @@
       if (SbMediaIsVideoSupported(
               dmp_reader.video_codec(), video_sample_info->frame_width,
               video_sample_info->frame_height, dmp_reader.video_bitrate(),
-              dmp_reader.video_fps())) {
+              dmp_reader.video_fps()
+#if SB_API_VERSION >= 10
+                  ,
+              false
+#endif  // SB_API_VERSION >= 10
+              )) {
         test_params.push_back({output_mode, filename});
       }
     }
diff --git a/src/starboard/shared/starboard/player/filter/video_decoder_internal.h b/src/starboard/shared/starboard/player/filter/video_decoder_internal.h
index c4f400f..ed01773 100644
--- a/src/starboard/shared/starboard/player/filter/video_decoder_internal.h
+++ b/src/starboard/shared/starboard/player/filter/video_decoder_internal.h
@@ -81,8 +81,7 @@
   // of the video pipeline like the VideoRendererSink may also cache frames.  It
   // is the responsibility of the decoder to ensure that this wouldn't result in
   // anything catastrophic.
-  // TODO:  Turn this into pure virtual.
-  virtual size_t GetMaxNumberOfCachedFrames() const { return 12; }
+  virtual size_t GetMaxNumberOfCachedFrames() const = 0;
 
   // Send encoded video frame stored in |input_buffer| to decode.
   virtual void WriteInputBuffer(
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 157b2c4..b54a451 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
@@ -42,8 +42,9 @@
 
   bool is_audio_playing;
   bool is_audio_eos_played;
+  bool is_underflow;
   SbTime media_time = media_time_provider->GetCurrentMediaTime(
-      &is_audio_playing, &is_audio_eos_played);
+      &is_audio_playing, &is_audio_eos_played, &is_underflow);
 
   // Video frames are synced to the audio timestamp. However, the audio
   // timestamp is not queried at a consistent interval. For example, if the
diff --git a/src/starboard/shared/starboard/player/player_create.cc b/src/starboard/shared/starboard/player/player_create.cc
index be82162..725a021 100644
--- a/src/starboard/shared/starboard/player/player_create.cc
+++ b/src/starboard/shared/starboard/player/player_create.cc
@@ -80,7 +80,12 @@
   if (video_codec != kSbMediaVideoCodecNone &&
       !SbMediaIsVideoSupported(video_codec, kDefaultFrameWidth,
                                kDefaultFrameHeight, kDefaultBitRate,
-                               kDefaultFrameRate)) {
+                               kDefaultFrameRate
+#if SB_API_VERSION >= 10
+                               ,
+                               output_mode == kSbPlayerOutputModeDecodeToTexture
+#endif
+                               )) {
     SB_LOG(ERROR) << "Unsupported video codec " << video_codec;
     return kSbPlayerInvalid;
   }
diff --git a/src/starboard/shared/starboard/player/player_internal.cc b/src/starboard/shared/starboard/player/player_internal.cc
index a5898bc..27e2bbc 100644
--- a/src/starboard/shared/starboard/player/player_internal.cc
+++ b/src/starboard/shared/starboard/player/player_internal.cc
@@ -24,6 +24,7 @@
 using std::placeholders::_1;
 using std::placeholders::_2;
 using std::placeholders::_3;
+using std::placeholders::_4;
 
 SbTime GetMediaTime(SbTime media_time,
                     SbTimeMonotonic media_time_update_time,
@@ -49,21 +50,12 @@
     starboard::scoped_ptr<PlayerWorker::Handler> player_worker_handler)
     : sample_deallocate_func_(sample_deallocate_func),
       context_(context),
-      ticket_(SB_PLAYER_INITIAL_TICKET),
-      media_time_(0),
       media_time_updated_at_(SbTimeGetMonotonicNow()),
-      frame_width_(0),
-      frame_height_(0),
-      is_paused_(false),
-      playback_rate_(1.0),
-      volume_(1.0),
-      total_video_frames_(0),
-      dropped_video_frames_(0),
       worker_(new PlayerWorker(
           audio_codec,
           video_codec,
           player_worker_handler.Pass(),
-          std::bind(&SbPlayerPrivate::UpdateMediaInfo, this, _1, _2, _3),
+          std::bind(&SbPlayerPrivate::UpdateMediaInfo, this, _1, _2, _3, _4),
           decoder_status_func,
           player_status_func,
 #if SB_HAS(PLAYER_ERROR_MESSAGE)
@@ -128,7 +120,7 @@
   starboard::ScopedLock lock(mutex_);
 #if SB_API_VERSION < 10
   out_player_info->duration_pts = SB_PLAYER_NO_DURATION;
-  if (is_paused_) {
+  if (is_paused_ || underflow_) {
     out_player_info->current_media_pts = SB_TIME_TO_SB_MEDIA_TIME(media_time_);
   } else {
     out_player_info->current_media_pts = SB_TIME_TO_SB_MEDIA_TIME(
@@ -136,7 +128,7 @@
   }
 #else   // SB_API_VERSION < 10
   out_player_info->duration = SB_PLAYER_NO_DURATION;
-  if (is_paused_) {
+  if (is_paused_ || underflow_) {
     out_player_info->current_media_timestamp = media_time_;
   } else {
     out_player_info->current_media_timestamp =
@@ -171,12 +163,14 @@
 
 void SbPlayerPrivate::UpdateMediaInfo(SbTime media_time,
                                       int dropped_video_frames,
-                                      int ticket) {
+                                      int ticket,
+                                      bool underflow) {
   starboard::ScopedLock lock(mutex_);
   if (ticket_ != ticket) {
     return;
   }
   media_time_ = media_time;
+  underflow_ = underflow;
   media_time_updated_at_ = SbTimeGetMonotonicNow();
   dropped_video_frames_ = dropped_video_frames;
 }
diff --git a/src/starboard/shared/starboard/player/player_internal.h b/src/starboard/shared/starboard/player/player_internal.h
index bd568c1..8e2064c 100644
--- a/src/starboard/shared/starboard/player/player_internal.h
+++ b/src/starboard/shared/starboard/player/player_internal.h
@@ -67,22 +67,26 @@
   static int number_of_players() { return number_of_players_; }
 
  private:
-  void UpdateMediaInfo(SbTime media_time, int dropped_video_frames, int ticket);
+  void UpdateMediaInfo(SbTime media_time,
+                       int dropped_video_frames,
+                       int ticket,
+                       bool underflow);
 
   SbPlayerDeallocateSampleFunc sample_deallocate_func_;
   void* context_;
 
   starboard::Mutex mutex_;
-  int ticket_;
-  SbTime media_time_;
+  int ticket_ = SB_PLAYER_INITIAL_TICKET;
+  SbTime media_time_ = 0;
   SbTimeMonotonic media_time_updated_at_;
-  int frame_width_;
-  int frame_height_;
-  bool is_paused_;
-  double playback_rate_;
-  double volume_;
-  int total_video_frames_;
-  int dropped_video_frames_;
+  int frame_width_ = 0;
+  int frame_height_ = 0;
+  bool is_paused_ = false;
+  double playback_rate_ = 1.0;
+  double volume_ = 1.0;
+  int total_video_frames_ = 0;
+  int dropped_video_frames_ = 0;
+  bool underflow_ = false;
 
   starboard::scoped_ptr<PlayerWorker> worker_;
 
diff --git a/src/starboard/shared/starboard/player/player_worker.cc b/src/starboard/shared/starboard/player/player_worker.cc
index 569fcd7..a55680d 100644
--- a/src/starboard/shared/starboard/player/player_worker.cc
+++ b/src/starboard/shared/starboard/player/player_worker.cc
@@ -30,6 +30,7 @@
 
 using std::placeholders::_1;
 using std::placeholders::_2;
+using std::placeholders::_3;
 
 // 8 ms is enough to ensure that DoWritePendingSamples() is called twice for
 // every frame in HFR.
@@ -101,8 +102,10 @@
   // effects are gone.
 }
 
-void PlayerWorker::UpdateMediaInfo(SbTime time, int dropped_video_frames) {
-  update_media_info_cb_(time, dropped_video_frames, ticket_);
+void PlayerWorker::UpdateMediaInfo(SbTime time,
+                                   int dropped_video_frames,
+                                   bool underflow) {
+  update_media_info_cb_(time, dropped_video_frames, ticket_, underflow);
 }
 
 void PlayerWorker::UpdatePlayerState(SbPlayerState player_state) {
@@ -178,11 +181,11 @@
   update_player_error_cb =
       std::bind(&PlayerWorker::UpdatePlayerError, this, _1, _2);
 #endif  // SB_HAS(PLAYER_ERROR_MESSAGE)
-  if (handler_->Init(player_,
-                     std::bind(&PlayerWorker::UpdateMediaInfo, this, _1, _2),
-                     std::bind(&PlayerWorker::player_state, this),
-                     std::bind(&PlayerWorker::UpdatePlayerState, this, _1),
-                     update_player_error_cb)) {
+  if (handler_->Init(
+          player_, std::bind(&PlayerWorker::UpdateMediaInfo, this, _1, _2, _3),
+          std::bind(&PlayerWorker::player_state, this),
+          std::bind(&PlayerWorker::UpdatePlayerState, this, _1),
+          update_player_error_cb)) {
     UpdatePlayerState(kSbPlayerStateInitialized);
   } else {
 #if SB_HAS(PLAYER_ERROR_MESSAGE)
diff --git a/src/starboard/shared/starboard/player/player_worker.h b/src/starboard/shared/starboard/player/player_worker.h
index 3d04779..1c5b6c4 100644
--- a/src/starboard/shared/starboard/player/player_worker.h
+++ b/src/starboard/shared/starboard/player/player_worker.h
@@ -43,8 +43,10 @@
 // they needn't maintain the thread and queue internally.
 class PlayerWorker {
  public:
-  typedef std::function<
-      void(SbTime media_time, int dropped_video_frames, int ticket)>
+  typedef std::function<void(SbTime media_time,
+                             int dropped_video_frames,
+                             int ticket,
+                             bool underflow)>
       UpdateMediaInfoCB;
 
   struct Bounds {
@@ -58,7 +60,8 @@
   // All functions of this class will be called from the JobQueue thread.
   class Handler {
    public:
-    typedef std::function<void(SbTime media_time, int dropped_video_frames)>
+    typedef std::function<
+        void(SbTime media_time, int dropped_video_frames, bool underflow)>
         UpdateMediaInfoCB;
     typedef std::function<SbPlayerState()> GetPlayerStateCB;
     typedef std::function<void(SbPlayerState player_state)> UpdatePlayerStateCB;
@@ -158,7 +161,7 @@
   }
 
  private:
-  void UpdateMediaInfo(SbTime time, int dropped_video_frames);
+  void UpdateMediaInfo(SbTime time, int dropped_video_frames, bool underflow);
 
   SbPlayerState player_state() const { return player_state_; }
   void UpdatePlayerState(SbPlayerState player_state);
diff --git a/src/starboard/shared/stub/media_is_video_supported.cc b/src/starboard/shared/stub/media_is_video_supported.cc
index 47dc4f4..47501fd 100644
--- a/src/starboard/shared/stub/media_is_video_supported.cc
+++ b/src/starboard/shared/stub/media_is_video_supported.cc
@@ -20,6 +20,11 @@
                                        int /*frame_width*/,
                                        int /*frame_height*/,
                                        int64_t /*bitrate*/,
-                                       int /*fps*/) {
+                                       int /*fps*/
+#if SB_API_VERSION >= 10
+                                       ,
+                                       bool /*decode_to_texture_required*/
+#endif                                      // SB_API_VERSION >= 10
+                                       ) {
   return false;
 }
diff --git a/src/starboard/shared/widevine/drm_create_system.cc b/src/starboard/shared/widevine/drm_create_system.cc
new file mode 100644
index 0000000..0ede5c2
--- /dev/null
+++ b/src/starboard/shared/widevine/drm_create_system.cc
@@ -0,0 +1,80 @@
+// Copyright 2017 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/drm.h"
+
+#include "starboard/log.h"
+#include "starboard/shared/widevine/drm_system_widevine.h"
+#include "starboard/string.h"
+
+#warning "This implementation is meant to use for testing purpose only."
+#warning "|company_name| and |model_name| should be replaced in production."
+
+namespace {
+const char kCompanyName[] = "www";
+const char kModelName[] = "www";
+}  // namespace
+
+SbDrmSystem SbDrmCreateSystem(
+    const char* key_system,
+    void* context,
+    SbDrmSessionUpdateRequestFunc update_request_callback,
+    SbDrmSessionUpdatedFunc session_updated_callback
+#if SB_HAS(DRM_KEY_STATUSES)
+    ,
+    SbDrmSessionKeyStatusesChangedFunc key_statuses_changed_callback
+#endif  // SB_HAS(DRM_KEY_STATUSES)
+#if SB_API_VERSION >= 10
+    ,
+    SbDrmServerCertificateUpdatedFunc server_certificate_updated_callback,
+    SbDrmSessionClosedFunc session_closed_callback
+#endif  // SB_API_VERSION >= 10
+    ) {
+  using starboard::shared::widevine::DrmSystemWidevine;
+  if (!update_request_callback || !session_updated_callback) {
+    return kSbDrmSystemInvalid;
+  }
+#if SB_HAS(DRM_KEY_STATUSES)
+  if (!key_statuses_changed_callback) {
+    return kSbDrmSystemInvalid;
+  }
+#endif  // SB_HAS(DRM_KEY_STATUSES)
+#if SB_API_VERSION >= 10
+  if (!server_certificate_updated_callback || !session_closed_callback) {
+    return kSbDrmSystemInvalid;
+  }
+#endif  // SB_API_VERSION >= 10
+  if (!DrmSystemWidevine::IsKeySystemSupported()) {
+    SB_DLOG(WARNING) << "Invalid key system " << key_system;
+    return kSbDrmSystemInvalid;
+  }
+  SB_LOG(ERROR) << "|company_name| and |model_name| are set to \"www\", "
+                << "premium content playback resolution may be limited.";
+  return new DrmSystemWidevine(context, update_request_callback,
+                               session_updated_callback
+#if SB_HAS(DRM_KEY_STATUSES)
+                               ,
+                               key_statuses_changed_callback
+#endif  // SB_HAS(DRM_KEY_STATUSES)
+#if SB_API_VERSION >= 10
+                               ,
+                               server_certificate_updated_callback
+#endif  // SB_API_VERSION >= 10
+#if SB_HAS(DRM_SESSION_CLOSED)
+                               ,
+                               session_closed_callback
+#endif  // SB_HAS(DRM_SESSION_CLOSED)
+                               ,
+                               kCompanyName, kModelName);
+}
diff --git a/src/starboard/shared/widevine/drm_is_server_certificate_updatable.cc b/src/starboard/shared/widevine/drm_is_server_certificate_updatable.cc
new file mode 100644
index 0000000..91d17dd
--- /dev/null
+++ b/src/starboard/shared/widevine/drm_is_server_certificate_updatable.cc
@@ -0,0 +1,25 @@
+// 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/drm.h"
+
+#if SB_API_VERSION >= 10
+
+bool SbDrmIsServerCertificateUpdatable(SbDrmSystem drm_system) {
+  SB_UNREFERENCED_PARAMETER(drm_system);
+
+  return true;
+}
+
+#endif  // SB_API_VERSION >= 10
diff --git a/src/starboard/shared/widevine/drm_system_widevine.cc b/src/starboard/shared/widevine/drm_system_widevine.cc
new file mode 100644
index 0000000..dda2d03
--- /dev/null
+++ b/src/starboard/shared/widevine/drm_system_widevine.cc
@@ -0,0 +1,691 @@
+// 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/widevine/drm_system_widevine.h"
+
+#include <vector>
+
+#include "starboard/character.h"
+#include "starboard/log.h"
+#include "starboard/memory.h"
+#include "starboard/mutex.h"
+#include "starboard/once.h"
+#include "starboard/shared/widevine/widevine_storage.h"
+#include "starboard/shared/widevine/widevine_timer.h"
+#include "starboard/string.h"
+#include "starboard/time.h"
+#include "third_party/ce_cdm/core/include/log.h"  // for wvcdm::InitLogging();
+#include "third_party/ce_cdm/core/include/string_conversions.h"
+
+using wv3cdm = ::widevine::Cdm;
+
+namespace starboard {
+namespace shared {
+namespace widevine {
+namespace {
+
+const int kInitializationVectorSize = 16;
+const char* kWidevineKeySystem[] = {"com.widevine", "com.widevine.alpha"};
+const char kWidevineStorageFileName[] = "wvcdm.dat";
+
+class WidevineClock : public wv3cdm::IClock {
+ public:
+  int64_t now() override {
+    return SbTimeToPosix(SbTimeGetNow()) / kSbTimeMillisecond;
+  }
+};
+
+std::string GetWidevineStoragePath() {
+  char path[SB_FILE_MAX_PATH + 1] = {0};
+  auto path_size = SB_ARRAY_SIZE_INT(path);
+  SB_CHECK(SbSystemGetPath(kSbSystemPathCacheDirectory, path, path_size) &&
+           SbStringConcat(path, SB_FILE_SEP_STRING, path_size) &&
+           SbStringConcat(path, kWidevineStorageFileName, path_size));
+  return path;
+}
+
+// Converts |::widevine::Cdm::KeyStatus| to starboard's |SbDrmKeyStatus|
+// Note: there is no mapping from any Widevine's Cdm::KeyStatus to
+// starboard's kSbDrmKeyStatusDownscaled.
+SbDrmKeyStatus CdmKeyStatusToSbDrmKeyStatus(
+    const wv3cdm::KeyStatus key_status) {
+  switch (key_status) {
+    case wv3cdm::kUsable:
+      return kSbDrmKeyStatusUsable;
+    case wv3cdm::kExpired:
+      return kSbDrmKeyStatusExpired;
+    case wv3cdm::kOutputRestricted:
+      return kSbDrmKeyStatusRestricted;
+    case wv3cdm::kStatusPending:
+      return kSbDrmKeyStatusPending;
+    case wv3cdm::kInternalError:
+      return kSbDrmKeyStatusError;
+    case wv3cdm::kReleased:
+      return kSbDrmKeyStatusReleased;
+    default:
+      SB_NOTREACHED();
+  }
+  return kSbDrmKeyStatusError;
+}
+
+// Converts |::widevine::Cdm::Status| to starboard's |SbDrmStatus|
+// Note: there is no mapping for few Widevine's Cdm::Status-es that
+// just converted here to starboard's kSbDrmStatusUnknownError.
+SbDrmStatus CdmStatusToSbDrmStatus(const wv3cdm::Status status) {
+  switch (status) {
+    case wv3cdm::kSuccess:
+      return kSbDrmStatusSuccess;
+    case wv3cdm::kTypeError:
+      return kSbDrmStatusTypeError;
+    case wv3cdm::kNotSupported:
+      return kSbDrmStatusNotSupportedError;
+    case wv3cdm::kInvalidState:
+      return kSbDrmStatusInvalidStateError;
+    case wv3cdm::kQuotaExceeded:
+      return kSbDrmStatusQuotaExceededError;
+    case wv3cdm::kNeedsDeviceCertificate:
+    case wv3cdm::kSessionNotFound:
+    case wv3cdm::kDecryptError:
+    case wv3cdm::kNoKey:
+    case wv3cdm::kKeyUsageBlockedByPolicy:
+    case wv3cdm::kRangeError:
+    case wv3cdm::kDeferred:
+    case wv3cdm::kUnexpectedError:
+      return kSbDrmStatusUnknownError;
+    default:
+      SB_NOTREACHED();
+  }
+  return kSbDrmStatusUnknownError;
+}
+
+SB_ONCE_INITIALIZE_FUNCTION(Mutex, GetInitializationMutex);
+
+void EnsureWidevineCdmIsInitialized(const std::string& company_name,
+                                    const std::string& model_name) {
+  static WidevineClock s_clock;
+  static WidevineStorage s_storage(GetWidevineStoragePath());
+  static WidevineTimer s_timer;
+  static bool s_initialized = false;
+
+  ScopedLock scoped_lock(*GetInitializationMutex());
+
+  if (s_initialized) {
+    return;
+  }
+
+  wvcdm::InitLogging();
+
+  wv3cdm::ClientInfo client_info;
+
+  client_info.product_name = "Cobalt";
+  client_info.company_name = company_name;
+  client_info.device_name = "";
+  client_info.model_name = model_name;
+  client_info.arch_name = "";
+  client_info.build_info = wv3cdm::version();
+
+  SB_LOG(INFO) << "Initialize wvcdm using product_name: \""
+               << client_info.product_name << "\", company_name: \""
+               << client_info.company_name << "\", and model_name: \""
+               << client_info.model_name << "\".";
+
+  auto log_level = wv3cdm::kInfo;
+#if COBALT_BUILD_TYPE_GOLD
+  log_level = wv3cdm::kSilent;
+#endif  // COBALT_BUILD_TYPE_GOLD
+  wv3cdm::Status status =
+      wv3cdm::initialize(wv3cdm::kNoSecureOutput, client_info, &s_storage,
+                         &s_clock, &s_timer, log_level);
+  SB_DCHECK(status == wv3cdm::kSuccess);
+  s_initialized = true;
+}
+
+}  // namespace
+
+// static
+const char DrmSystemWidevine::kFirstSbDrmSessionId[] = "initialdrmsessionid";
+
+DrmSystemWidevine::DrmSystemWidevine(
+    void* context,
+    SbDrmSessionUpdateRequestFunc session_update_request_callback,
+    SbDrmSessionUpdatedFunc session_updated_callback
+#if SB_HAS(DRM_KEY_STATUSES)
+    ,
+    SbDrmSessionKeyStatusesChangedFunc key_statuses_changed_callback
+#endif  // SB_HAS(DRM_KEY_STATUSES)
+#if SB_API_VERSION >= 10
+    ,
+    SbDrmServerCertificateUpdatedFunc server_certificate_updated_callback
+#endif  // SB_API_VERSION >= 10
+#if SB_HAS(DRM_SESSION_CLOSED)
+    ,
+    SbDrmSessionClosedFunc session_closed_callback
+#endif  // SB_HAS(DRM_SESSION_CLOSED)
+    ,
+    const std::string& company_name,
+    const std::string& model_name)
+    : context_(context),
+      session_update_request_callback_(session_update_request_callback),
+      session_updated_callback_(session_updated_callback),
+#if SB_HAS(DRM_KEY_STATUSES)
+      key_statuses_changed_callback_(key_statuses_changed_callback),
+#endif  // SB_HAS(DRM_KEY_STATUSES)
+#if SB_API_VERSION >= 10
+      server_certificate_updated_callback_(server_certificate_updated_callback),
+#endif  // SB_API_VERSION >= 10
+#if SB_HAS(DRM_SESSION_CLOSED)
+      session_closed_callback_(session_closed_callback),
+#endif  // SB_HAS(DRM_SESSION_CLOSED)
+      ticket_thread_id_(SbThreadGetId()) {
+  SB_DCHECK(!company_name.empty());
+  SB_DCHECK(!model_name.empty());
+  EnsureWidevineCdmIsInitialized(company_name, model_name);
+#if SB_API_VERSION >= 10
+  const bool kEnablePrivacyMode = true;
+#else   // SB_API_VERSION >= 10
+  const bool kEnablePrivacyMode = false;
+#endif  // SB_API_VERSION >= 10
+  cdm_.reset(wv3cdm::create(this, NULL, kEnablePrivacyMode));
+  SB_DCHECK(cdm_);
+}
+
+DrmSystemWidevine::~DrmSystemWidevine() {}
+
+// static
+bool DrmSystemWidevine::IsKeySystemSupported(const char* key_system) {
+  for (auto wv_key_system : kWidevineKeySystem) {
+    if (SbStringCompareAll(key_system, wv_key_system) == 0) {
+      return true;
+    }
+  }
+  return false;
+}
+
+void DrmSystemWidevine::GenerateSessionUpdateRequest(
+    int ticket,
+    const char* type,
+    const void* initialization_data,
+    int initialization_data_size) {
+  SB_DCHECK(thread_checker_.CalledOnValidThread());
+
+  const std::string init_str(static_cast<const char*>(initialization_data),
+                             initialization_data_size);
+  wv3cdm::InitDataType init_type = wv3cdm::kWebM;
+  if (SbStringCompareAll("cenc", type) == 0) {
+    init_type = wv3cdm::kCenc;
+  } else if (SbStringCompareAll("webm", type) == 0) {
+    init_type = wv3cdm::kWebM;
+  } else {
+    SB_NOTREACHED();
+  }
+
+  if (!is_server_certificate_set_) {
+    // When privacy mode is on and server certificate hasn't been set yet for
+    // the current playback, save the requests and send a server certificate
+    // request instead.
+    bool first_request = pending_generate_session_update_requests_.empty();
+    GenerateSessionUpdateRequestData request_data = {
+        first_request ? kSbDrmTicketInvalid : ticket, init_type, init_str};
+    pending_generate_session_update_requests_.push_back(request_data);
+    if (first_request) {
+      SendServerCertificateRequest(ticket);
+    }
+    return;
+  }
+
+  GenerateSessionUpdateRequestInternal(ticket, init_type, init_str, false);
+}
+
+void DrmSystemWidevine::UpdateSession(int ticket,
+                                      const void* key,
+                                      int key_size,
+                                      const void* sb_drm_session_id,
+                                      int sb_drm_session_id_size) {
+  SB_DCHECK(thread_checker_.CalledOnValidThread());
+  const std::string str_key(static_cast<const char*>(key), key_size);
+
+  wv3cdm::Status status;
+  if (!pending_generate_session_update_requests_.empty()) {
+    status = ProcessServerCertificateResponse(str_key);
+  } else {
+    const std::string wvcdm_session_id = SbDrmSessionIdToWvdmSessionId(
+        sb_drm_session_id, sb_drm_session_id_size);
+    status = cdm_->update(wvcdm_session_id, str_key);
+  }
+  SB_DLOG(INFO) << "Update keys status " << status;
+#if SB_API_VERSION >= 10
+  session_updated_callback_(this, context_, ticket,
+                            CdmStatusToSbDrmStatus(status), "",
+                            sb_drm_session_id, sb_drm_session_id_size);
+#else   // SB_API_VERSION >= 10
+  session_updated_callback_(this, context_, ticket, sb_drm_session_id,
+                            sb_drm_session_id_size, status == wv3cdm::kSuccess);
+#endif  // SB_API_VERSION >= 10
+
+  // It is possible that |key| actually contains a server certificate, in such
+  // case try to process the pending GenerateSessionUpdateRequest() calls.
+  TrySendPendingGenerateSessionUpdateRequests();
+}
+
+void DrmSystemWidevine::CloseSession(const void* sb_drm_session_id,
+                                     int sb_drm_session_id_size) {
+  SB_DCHECK(thread_checker_.CalledOnValidThread());
+  const std::string wvcdm_session_id =
+      SbDrmSessionIdToWvdmSessionId(sb_drm_session_id, sb_drm_session_id_size);
+  cdm_->close(wvcdm_session_id);
+}
+
+#if SB_API_VERSION >= 10
+void DrmSystemWidevine::UpdateServerCertificate(int ticket,
+                                                const void* certificate,
+                                                int certificate_size) {
+  SB_DCHECK(thread_checker_.CalledOnValidThread());
+  const std::string str_certificate(static_cast<const char*>(certificate),
+                                    certificate_size);
+  wv3cdm::Status status = cdm_->setServiceCertificate(str_certificate);
+
+  is_server_certificate_set_ = (status == wv3cdm::kSuccess);
+
+  server_certificate_updated_callback_(this, context_, ticket,
+                                       CdmStatusToSbDrmStatus(status), "");
+}
+#endif  // SB_API_VERSION >= 10
+
+void IncrementIv(uint8_t* iv, size_t block_count) {
+  if (0 == block_count)
+    return;
+  uint8_t carry = 0;
+  uint8_t n = static_cast<uint8_t>(kInitializationVectorSize - 1);
+
+  while (n >= 8) {
+    uint32_t temp = block_count & 0xff;
+    temp += iv[n];
+    temp += carry;
+    iv[n] = temp & 0xff;
+    carry = (temp & 0x100) ? 1 : 0;
+    block_count = block_count >> 8;
+    n--;
+    if (0 == block_count && !carry) {
+      break;
+    }
+  }
+}
+
+SbDrmSystemPrivate::DecryptStatus DrmSystemWidevine::Decrypt(
+    InputBuffer* buffer) {
+  const SbDrmSampleInfo* drm_info = buffer->drm_info();
+
+  if (drm_info == NULL || drm_info->initialization_vector_size == 0) {
+    return kSuccess;
+  }
+
+  // Adapt |buffer| and |drm_info| to a |cdm::InputBuffer|.
+  SB_DCHECK(drm_info->initialization_vector_size == kInitializationVectorSize);
+  std::vector<uint8_t> initialization_vector(
+      drm_info->initialization_vector,
+      drm_info->initialization_vector + drm_info->initialization_vector_size);
+
+  wv3cdm::InputBuffer input;
+  input.data = buffer->data();
+  input.data_length = buffer->size();
+  input.block_offset = 0;
+  input.key_id = drm_info->identifier;
+  input.key_id_length = drm_info->identifier_size;
+  input.iv = initialization_vector.data();
+  input.iv_length = static_cast<uint32_t>(initialization_vector.size());
+  input.is_video = (buffer->sample_type() == kSbMediaTypeVideo);
+
+  std::vector<uint8_t> output_data(buffer->size());
+  wv3cdm::OutputBuffer output;
+  output.data = output_data.data();
+  output.data_length = output_data.size();
+
+  size_t block_counter = 0;
+  size_t encrypted_offset = 0;
+
+  for (size_t i = 0; i < buffer->drm_info()->subsample_count; i++) {
+    const SbDrmSubSampleMapping& subsample =
+        buffer->drm_info()->subsample_mapping[i];
+    if (subsample.clear_byte_count) {
+      input.last_subsample = i + 1 == buffer->drm_info()->subsample_count &&
+                             subsample.encrypted_byte_count == 0;
+      input.encryption_scheme = wv3cdm::EncryptionScheme::kClear;
+      input.data_length = subsample.clear_byte_count;
+
+      wv3cdm::Status status = cdm_->decrypt(input, output);
+      if (status != wv3cdm::kSuccess) {
+        if (status == wv3cdm::kNoKey) {
+          return kRetry;
+        }
+        SB_DLOG(ERROR) << "Decrypt status " << status;
+        SB_DLOG(ERROR) << "Key ID "
+                       << wvcdm::a2bs_hex(
+                              std::string(reinterpret_cast<const char*>(
+                                              &drm_info->identifier[0]),
+                                          drm_info->identifier_size));
+        return kFailure;
+      }
+
+      input.data += subsample.clear_byte_count;
+      output.data += subsample.clear_byte_count;
+      output.data_length -= subsample.clear_byte_count;
+      input.first_subsample = false;
+    }
+
+    if (subsample.encrypted_byte_count) {
+      input.last_subsample = i + 1 == buffer->drm_info()->subsample_count;
+      input.encryption_scheme = wv3cdm::EncryptionScheme::kAesCtr;
+      input.data_length = subsample.encrypted_byte_count;
+
+      wv3cdm::Status status = cdm_->decrypt(input, output);
+      if (status != wv3cdm::kSuccess) {
+        if (status == wv3cdm::kNoKey) {
+          SB_DLOG(ERROR) << "Decrypt status: kNoKey";
+          return kRetry;
+        }
+        SB_DLOG(ERROR) << "Decrypt status " << status;
+        SB_DLOG(ERROR) << "Key ID "
+                       << wvcdm::a2bs_hex(
+                              std::string(reinterpret_cast<const char*>(
+                                              &drm_info->identifier[0]),
+                                          drm_info->identifier_size));
+        return kFailure;
+      }
+
+      input.data += subsample.encrypted_byte_count;
+      output.data += subsample.encrypted_byte_count;
+      output.data_length -= subsample.encrypted_byte_count;
+
+      input.block_offset += subsample.encrypted_byte_count;
+      input.block_offset %= 16;
+
+      encrypted_offset += subsample.encrypted_byte_count;
+
+      // Increase initialization vector for CTR mode.
+      if (input.encryption_scheme == wv3cdm::kAesCtr) {
+        size_t new_block_counter = encrypted_offset / 16;
+        IncrementIv(initialization_vector.data(),
+                    new_block_counter - block_counter);
+        block_counter = new_block_counter;
+      }
+      input.first_subsample = false;
+    }
+  }
+
+  buffer->SetDecryptedContent(output_data.data(), output_data.size());
+  return kSuccess;
+}
+
+void DrmSystemWidevine::GenerateSessionUpdateRequestInternal(
+    int ticket,
+    wv3cdm::InitDataType init_data_type,
+    const std::string& initialization_data,
+    bool is_first_session) {
+  SB_DCHECK(thread_checker_.CalledOnValidThread());
+
+  wv3cdm::SessionType session_type = wv3cdm::kTemporary;
+
+  std::string wvcdm_session_id;
+  // createSession() may return |kDeferred| if individualization is pending.
+  wv3cdm::Status status = cdm_->createSession(session_type, &wvcdm_session_id);
+
+  if (status == wv3cdm::kSuccess) {
+    // Ensure that the session id generated by the cdm is never the same as the
+    // fake id (kFirstSbDrmSessionId).
+    SB_DCHECK(wvcdm_session_id != kFirstSbDrmSessionId);
+    if (is_first_session) {
+      first_wvcdm_session_id_ = wvcdm_session_id;
+    }
+    SetTicket(WvdmSessionIdToSbDrmSessionId(wvcdm_session_id), ticket);
+    SB_DLOG(INFO) << "Calling generateRequest()";
+    status = cdm_->generateRequest(wvcdm_session_id, init_data_type,
+                                   initialization_data);
+    SB_DLOG(INFO) << "generateRequest() returns " << status;
+  } else {
+    // createSession() shouldn't return |kDeferred|, and if it does, the
+    // following if statement will incorrectly assume that there is a follow-up
+    // license request automatically generated after the individualization is
+    // finished, which won't happen.
+    SB_DCHECK(status != wv3cdm::kDeferred);
+  }
+
+  if (status != wv3cdm::kSuccess && status != wv3cdm::kDeferred) {
+    // Reset ticket before invoking user-provided callback to indicate that
+    // no session update request is pending.
+    SetTicket(WvdmSessionIdToSbDrmSessionId(wvcdm_session_id),
+              kSbDrmTicketInvalid);
+
+    SB_DLOG(ERROR) << "GenerateKeyRequest status " << status;
+// Send an empty request to signal an error.
+#if SB_API_VERSION >= 10
+    session_update_request_callback_(
+        this, context_, ticket, CdmStatusToSbDrmStatus(status),
+        kSbDrmSessionRequestTypeLicenseRequest, "", NULL, 0, NULL, 0, NULL);
+#else   // SB_API_VERSION >= 10
+    session_update_request_callback_(this, context_, ticket, NULL, 0, NULL, 0,
+                                     NULL);
+#endif  // SB_API_VERSION >= 10
+  }
+
+  // When |status| is |kDeferred|, it indicates that the cdm requires
+  // individualization.  In such case an individualization request may be sent
+  // if this is the first GenerateSessionUpdateRequest().  We won't send a
+  // generated key request now. Once the individualization response is received
+  // by the cdm, it will call |onMessage| for all pending sessions on the same
+  // thread.
+}
+
+void DrmSystemWidevine::onMessage(const std::string& wvcdm_session_id,
+                                  wv3cdm::MessageType message_type,
+                                  const std::string& message) {
+  const std::string sb_drm_session_id =
+      WvdmSessionIdToSbDrmSessionId(wvcdm_session_id);
+  switch (message_type) {
+    case wv3cdm::kLicenseRequest:
+      SendSessionUpdateRequest(kSbDrmSessionRequestTypeLicenseRequest,
+                               sb_drm_session_id, message);
+      break;
+    case wv3cdm::kLicenseRenewal:
+      SendSessionUpdateRequest(kSbDrmSessionRequestTypeLicenseRenewal,
+                               sb_drm_session_id, message);
+      break;
+    case wv3cdm::kLicenseRelease:
+      SendSessionUpdateRequest(kSbDrmSessionRequestTypeLicenseRelease,
+                               sb_drm_session_id, message);
+      break;
+    case wv3cdm::kIndividualizationRequest:
+      // Not used, onDirectIndividualizationRequest() will be called instead.
+      SB_NOTREACHED();
+      break;
+    case wv3cdm::kLicenseSub:
+      // For loading sub licenses from embedded key data, not used.
+      SB_NOTREACHED();
+      break;
+  }
+}
+
+void DrmSystemWidevine::onKeyStatusesChange(
+    const std::string& wvcdm_session_id) {
+#if SB_HAS(DRM_KEY_STATUSES)
+  wv3cdm::KeyStatusMap key_statuses;
+  wv3cdm::Status status = cdm_->getKeyStatuses(wvcdm_session_id, &key_statuses);
+
+  if (status != wv3cdm::kSuccess) {
+    return;
+  }
+
+  std::vector<SbDrmKeyId> sb_key_ids;
+  std::vector<SbDrmKeyStatus> sb_key_statuses;
+
+  for (auto& key_status : key_statuses) {
+    SbDrmKeyId sb_key_id;
+    SB_DCHECK(key_status.first.size() <= sizeof(sb_key_id.identifier));
+    SbMemoryCopy(sb_key_id.identifier, key_status.first.c_str(),
+                 key_status.first.size());
+    sb_key_id.identifier_size = static_cast<int>(key_status.first.size());
+    sb_key_ids.push_back(sb_key_id);
+    sb_key_statuses.push_back(CdmKeyStatusToSbDrmKeyStatus(key_status.second));
+  }
+
+  const std::string sb_drm_session_id =
+      WvdmSessionIdToSbDrmSessionId(wvcdm_session_id);
+  key_statuses_changed_callback_(this, context_, sb_drm_session_id.c_str(),
+                                 sb_drm_session_id.size(), sb_key_ids.size(),
+                                 sb_key_ids.data(), sb_key_statuses.data());
+#else   // SB_HAS(DRM_KEY_STATUSES)
+  SB_UNREFERENCED_PARAMETER(wvcdm_session_id);
+#endif  // SB_HAS(DRM_KEY_STATUSES)
+}
+
+void DrmSystemWidevine::onRemoveComplete(const std::string& wvcdm_session_id) {
+  SB_UNREFERENCED_PARAMETER(wvcdm_session_id);
+  SB_NOTIMPLEMENTED();
+}
+
+void DrmSystemWidevine::onDeferredComplete(const std::string& wvcdm_session_id,
+                                           wv3cdm::Status result) {
+  SB_UNREFERENCED_PARAMETER(wvcdm_session_id);
+  SB_UNREFERENCED_PARAMETER(result);
+  SB_NOTIMPLEMENTED();
+}
+
+void DrmSystemWidevine::onDirectIndividualizationRequest(
+    const std::string& wvcdm_session_id,
+    const std::string& request) {
+  SendSessionUpdateRequest(kSbDrmSessionRequestTypeIndividualizationRequest,
+                           WvdmSessionIdToSbDrmSessionId(wvcdm_session_id),
+                           request);
+}
+
+void DrmSystemWidevine::SetTicket(const std::string& sb_drm_session_id,
+                                  int ticket) {
+  SB_DCHECK(SbThreadGetId() == ticket_thread_id_)
+      << "Ticket should only be set from the constructor thread.";
+  sb_drm_session_id_to_ticket_map_[sb_drm_session_id] = ticket;
+}
+
+int DrmSystemWidevine::GetAndResetTicket(const std::string& sb_drm_session_id) {
+  // Returning no ticket is a valid way to indicate that a host's method was
+  // called spontaneously by CDM, potentially from the timer thread.
+  if (SbThreadGetId() != ticket_thread_id_) {
+    return kSbDrmTicketInvalid;
+  }
+  auto iter = sb_drm_session_id_to_ticket_map_.find(sb_drm_session_id);
+  if (iter == sb_drm_session_id_to_ticket_map_.end()) {
+    return kSbDrmTicketInvalid;
+  }
+  auto ticket = iter->second;
+  sb_drm_session_id_to_ticket_map_.erase(iter);
+  return ticket;
+}
+
+std::string DrmSystemWidevine::WvdmSessionIdToSbDrmSessionId(
+    const std::string& wvcdm_session_id) {
+#if SB_API_VERSION >= 10
+  SB_DCHECK(wvcdm_session_id != kFirstSbDrmSessionId);
+  if (wvcdm_session_id == first_wvcdm_session_id_) {
+    return kFirstSbDrmSessionId;
+  }
+#endif  // SB_API_VERSION >= 10
+  return wvcdm_session_id;
+}
+
+std::string DrmSystemWidevine::SbDrmSessionIdToWvdmSessionId(
+    const void* sb_drm_session_id,
+    int sb_drm_session_id_size) {
+  const std::string str_sb_drm_session_id(
+      static_cast<const char*>(sb_drm_session_id), sb_drm_session_id_size);
+#if SB_API_VERSION >= 10
+  if (str_sb_drm_session_id == kFirstSbDrmSessionId) {
+    SB_DCHECK(!first_wvcdm_session_id_.empty());
+    return first_wvcdm_session_id_;
+  }
+#endif  // SB_API_VERSION >= 10
+  return str_sb_drm_session_id;
+}
+
+void DrmSystemWidevine::SendServerCertificateRequest(int ticket) {
+  std::string message;
+  auto status = cdm_->getServiceCertificateRequest(&message);
+  if (status == wv3cdm::kSuccess) {
+    SetTicket(kFirstSbDrmSessionId, ticket);
+    // Note that calling createSession() without a server certificate may fail.
+    // So use |kFirstSbDrmSessionId| as the session id.  Once we have a real
+    // session id, we will map it from/to the fake session id.
+    SendSessionUpdateRequest(kSbDrmSessionRequestTypeLicenseRequest,
+                             kFirstSbDrmSessionId, message);
+  } else {
+// Signals failure by sending NULL as the session id.
+#if SB_API_VERSION >= 10
+    session_update_request_callback_(
+        this, context_, ticket, CdmStatusToSbDrmStatus(status),
+        kSbDrmSessionRequestTypeLicenseRequest, "", NULL, 0, NULL, 0, NULL);
+#else   // SB_API_VERSION >= 10
+    session_update_request_callback_(this, context_, ticket, NULL, 0, NULL, 0,
+                                     NULL);
+#endif  // SB_API_VERSION >= 10
+  }
+}
+
+wv3cdm::Status DrmSystemWidevine::ProcessServerCertificateResponse(
+    const std::string& response) {
+  SB_DCHECK(thread_checker_.CalledOnValidThread());
+  is_server_certificate_set_ = false;
+  std::string certificate;
+  auto status = cdm_->parseServiceCertificateResponse(response, &certificate);
+  if (status != wv3cdm::kSuccess) {
+    return status;
+  }
+  status = cdm_->setServiceCertificate(certificate);
+  is_server_certificate_set_ = (status == wv3cdm::kSuccess);
+  return status;
+}
+
+void DrmSystemWidevine::TrySendPendingGenerateSessionUpdateRequests() {
+  SB_DCHECK(thread_checker_.CalledOnValidThread());
+  if (!is_server_certificate_set_) {
+    return;
+  }
+  decltype(pending_generate_session_update_requests_) pending_requests;
+  pending_requests.swap(pending_generate_session_update_requests_);
+  for (auto iter = pending_requests.begin(); iter != pending_requests.end();
+       ++iter) {
+    GenerateSessionUpdateRequestInternal(iter->ticket, iter->init_data_type,
+                                         iter->initialization_data,
+                                         iter == pending_requests.begin());
+  }
+}
+
+void DrmSystemWidevine::SendSessionUpdateRequest(
+    SbDrmSessionRequestType type,
+    const std::string& sb_drm_session_id,
+    const std::string& message) {
+  int ticket = GetAndResetTicket(sb_drm_session_id);
+
+#if SB_API_VERSION >= 10
+  session_update_request_callback_(
+      this, context_, ticket, kSbDrmStatusSuccess, type, "",
+      sb_drm_session_id.c_str(), static_cast<int>(sb_drm_session_id.size()),
+      message.c_str(), static_cast<int>(message.size()), NULL);
+#else   // SB_API_VERSION >= 10
+  session_update_request_callback_(
+      this, context_, ticket, sb_drm_session_id.c_str(),
+      static_cast<int>(sb_drm_session_id.size()), message.c_str(),
+      static_cast<int>(message.size()), NULL);
+#endif  // SB_API_VERSION >= 10
+}
+
+}  // namespace widevine
+}  // namespace shared
+}  // namespace starboard
diff --git a/src/starboard/shared/widevine/drm_system_widevine.h b/src/starboard/shared/widevine/drm_system_widevine.h
new file mode 100644
index 0000000..0d8509b
--- /dev/null
+++ b/src/starboard/shared/widevine/drm_system_widevine.h
@@ -0,0 +1,207 @@
+// 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_WIDEVINE_DRM_SYSTEM_WIDEVINE_H_
+#define STARBOARD_SHARED_WIDEVINE_DRM_SYSTEM_WIDEVINE_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "starboard/common/scoped_ptr.h"
+#include "starboard/shared/starboard/drm/drm_system_internal.h"
+#include "starboard/shared/starboard/thread_checker.h"
+#include "starboard/thread.h"
+#include "third_party/ce_cdm/cdm/include/cdm.h"
+
+namespace starboard {
+namespace shared {
+namespace widevine {
+
+// Adapts Widevine's |Content Decryption Module v 3.5| to Starboard's
+// |SbDrmSystem|.
+//
+// All |SbDrmSystemPrivate| methods except Decrypt() must be called from the
+// constructor thread.
+class DrmSystemWidevine : public SbDrmSystemPrivate,
+                          private ::widevine::Cdm::IEventListener {
+ public:
+  DrmSystemWidevine(
+      void* context,
+      SbDrmSessionUpdateRequestFunc update_request_callback,
+      SbDrmSessionUpdatedFunc session_updated_callback
+#if SB_HAS(DRM_KEY_STATUSES)
+      ,
+      SbDrmSessionKeyStatusesChangedFunc key_statuses_changed_callback
+#endif  // SB_HAS(DRM_KEY_STATUSES)
+#if SB_API_VERSION >= 10
+      ,
+      SbDrmServerCertificateUpdatedFunc server_certificate_updated_callback
+#endif  // SB_API_VERSION >= 10
+#if SB_HAS(DRM_SESSION_CLOSED)
+      ,
+      SbDrmSessionClosedFunc session_closed_callback
+#endif  // SB_HAS(DRM_SESSION_CLOSED)
+      ,
+      const std::string& company_name,
+      const std::string& model_name);
+
+  ~DrmSystemWidevine() override;
+
+  static bool IsKeySystemSupported(const char* key_system);
+
+  // From |SbDrmSystemPrivate|.
+  void GenerateSessionUpdateRequest(int ticket,
+                                    const char* type,
+                                    const void* initialization_data,
+                                    int initialization_data_size) override;
+
+  void UpdateSession(int ticket,
+                     const void* key,
+                     int key_size,
+                     const void* sb_drm_session_id,
+                     int sb_drm_session_id_size) override;
+
+  void CloseSession(const void* sb_drm_session_id,
+                    int sb_drm_session_id_size) override;
+
+  DecryptStatus Decrypt(InputBuffer* buffer) override;
+
+#if SB_API_VERSION >= 10
+  // This function is called by the app to explicitly set the server
+  // certificate.  For an app that supports this feature, it should call this
+  // function before calling any other functions like
+  // GenerateSessionUpdateRequest().  So we needn't process pending requests in
+  // this function.  Note that it is benign if this function is called in
+  // parallel with a server certificate request.
+  void UpdateServerCertificate(int ticket,
+                               const void* certificate,
+                               int certificate_size) override;
+#endif  // SB_API_VERSION >= 10
+
+ private:
+  // Stores the data necessary to call GenerateSessionUpdateRequestInternal().
+  struct GenerateSessionUpdateRequestData {
+    int ticket;
+    ::widevine::Cdm::InitDataType init_data_type;
+    std::string initialization_data;
+  };
+
+  // An unique id to identify the first SbDrm session id when server
+  // certificate is not ready.  This is necessary to send the server
+  // certificate request, as EME requires a session id while wvcdm cannot
+  // generate a session id before having a server certificate.
+  // This works with |first_wvcdm_session_id_| to map the first session id
+  // between wvcdm and SbDrm.
+  static const char kFirstSbDrmSessionId[];
+
+  void GenerateSessionUpdateRequestInternal(
+      int ticket,
+      ::widevine::Cdm::InitDataType init_data_type,
+      const std::string& initialization_data,
+      bool is_first_session);
+
+  // From |cdm::IEventListener|.
+  // A message (license request, renewal, etc.) to be dispatched to the
+  // application's license server. The response, if successful, should be
+  // provided back to the CDM via a call to Cdm::update().
+  void onMessage(const std::string& session_id,
+                 ::widevine::Cdm::MessageType message_type,
+                 const std::string& message) override;
+  // There has been a change in the keys in the session or their status.
+  void onKeyStatusesChange(const std::string& wvcdm_session_id) override;
+  // A remove() operation has been completed.
+  void onRemoveComplete(const std::string& wvcdm_session_id) override;
+  // Called when a deferred action has completed.
+  void onDeferredComplete(const std::string& wvcdm_session_id,
+                          ::widevine::Cdm::Status result) override;
+  // Called when the CDM requires a new device certificate.
+  void onDirectIndividualizationRequest(const std::string& wvcdm_session_id,
+                                        const std::string& request) override;
+
+  void SetTicket(const std::string& sb_drm_session_id, int ticket);
+  int GetAndResetTicket(const std::string& sb_drm_session_id);
+  std::string WvdmSessionIdToSbDrmSessionId(
+      const std::string& wvcdm_session_id);
+  std::string SbDrmSessionIdToWvdmSessionId(const void* sb_drm_session_id,
+                                            int sb_drm_session_id_size);
+
+  // Generates a special key message to ask for the server certificate.  When
+  // the license server receives the request, it will send back the server
+  // certificate.
+  void SendServerCertificateRequest(int ticket);
+  // When this function is called, the update contains the server certificate.
+  // The function parses the special update and pass the server certificate to
+  // the cdm.
+  // Note that the app shouldn't persist the server certificate across playback
+  // or across application instances.
+  ::widevine::Cdm::Status ProcessServerCertificateResponse(
+      const std::string& response);
+  // If server certificate has been set, send all pending requests.
+  void TrySendPendingGenerateSessionUpdateRequests();
+  void SendSessionUpdateRequest(SbDrmSessionRequestType type,
+                                const std::string& sb_drm_session_id,
+                                const std::string& message);
+
+  ::starboard::shared::starboard::ThreadChecker thread_checker_;
+  void* const context_;
+  const SbDrmSessionUpdateRequestFunc session_update_request_callback_;
+  const SbDrmSessionUpdatedFunc session_updated_callback_;
+#if SB_HAS(DRM_KEY_STATUSES)
+  const SbDrmSessionKeyStatusesChangedFunc key_statuses_changed_callback_;
+#endif  // SB_HAS(DRM_KEY_STATUSES)
+#if SB_API_VERSION >= 10
+  const SbDrmServerCertificateUpdatedFunc server_certificate_updated_callback_;
+#endif  // SB_API_VERSION >= 10
+#if SB_HAS(DRM_SESSION_CLOSED)
+  const SbDrmSessionClosedFunc session_closed_callback_;
+#endif  // SB_HAS(DRM_SESSION_CLOSED)
+
+  // Store a map from session id generated by the cdm to its associated ticket
+  // id.  The ticket is a unique id passed to GenerateSessionUpdateRequest() to
+  // allow the caller of GenerateSessionUpdateRequest() to associate the
+  // session id with the session related data specified by the ticket, as both
+  // of them will be passed via session_update_request_callback_ when it is
+  // called for the first time for this paritcular session id.  As this is only
+  // necessary for the first time the callback is called on the particular
+  // session, every time an entry is used, it will be removed from the map.
+  // Note that the first callback is always accessed on the thread specificed
+  // by |ticket_thread_id_|.
+  std::map<std::string, int> sb_drm_session_id_to_ticket_map_;
+
+  // |ticket_| is only valid on the constructor thread within the duration of
+  // call to |GenerateKeyRequest| or |AddKey|, but CDM may invoke host's methods
+  // spontaneously from the timer thread. In that case |GetTicket| need to
+  // return |kSbDrmTicketInvalid|.
+  const SbThreadId ticket_thread_id_;
+
+  std::vector<GenerateSessionUpdateRequestData>
+      pending_generate_session_update_requests_;
+  std::string first_wvcdm_session_id_;
+
+  scoped_ptr<::widevine::Cdm> cdm_;
+#if SB_API_VERSION >= 10
+  bool is_server_certificate_set_ = false;
+#else   // SB_API_VERSION >= 10
+  bool is_server_certificate_set_ = true;
+#endif  // SB_API_VERSION >= 10
+
+  volatile bool quitting_ = false;
+};
+
+}  // namespace widevine
+}  // namespace shared
+}  // namespace starboard
+
+#endif  // STARBOARD_SHARED_WIDEVINE_DRM_SYSTEM_WIDEVINE_H_
diff --git a/src/starboard/shared/widevine/drm_update_server_certificate.cc b/src/starboard/shared/widevine/drm_update_server_certificate.cc
new file mode 100644
index 0000000..b9f29d4
--- /dev/null
+++ b/src/starboard/shared/widevine/drm_update_server_certificate.cc
@@ -0,0 +1,39 @@
+// 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/drm.h"
+
+#include "starboard/log.h"
+#include "starboard/shared/starboard/drm/drm_system_internal.h"
+
+#if SB_API_VERSION >= 10
+
+void SbDrmUpdateServerCertificate(SbDrmSystem drm_system,
+                                  int ticket,
+                                  const void* certificate,
+                                  int certificate_size) {
+  if (!SbDrmSystemIsValid(drm_system)) {
+    SB_DLOG(ERROR) << "Invalid DRM system.";
+    return;
+  }
+
+  if (ticket == kSbDrmTicketInvalid) {
+    SB_DLOG(ERROR) << "Ticket must be specified.";
+    return;
+  }
+
+  drm_system->UpdateServerCertificate(ticket, certificate, certificate_size);
+}
+
+#endif  // SB_API_VERSION >= 10
diff --git a/src/starboard/shared/widevine/media_is_supported.cc b/src/starboard/shared/widevine/media_is_supported.cc
new file mode 100644
index 0000000..f201c68
--- /dev/null
+++ b/src/starboard/shared/widevine/media_is_supported.cc
@@ -0,0 +1,27 @@
+// Copyright 2016 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/media.h"
+#include "starboard/shared/widevine/drm_system_widevine.h"
+
+SB_EXPORT bool SbMediaIsSupported(SbMediaVideoCodec video_codec,
+                                  SbMediaAudioCodec audio_codec,
+                                  const char* key_system) {
+  using starboard::shared::widevine::DrmSystemWidevine;
+
+  SB_UNREFERENCED_PARAMETER(video_codec);
+  SB_UNREFERENCED_PARAMETER(audio_codec);
+
+  return DrmSystemWidevine::IsKeySystemSupported(key_system);
+}
diff --git a/src/starboard/shared/widevine/widevine3.gyp b/src/starboard/shared/widevine/widevine3.gyp
new file mode 100644
index 0000000..77761ae
--- /dev/null
+++ b/src/starboard/shared/widevine/widevine3.gyp
@@ -0,0 +1,77 @@
+# 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.
+{
+  'includes': [
+    # sets defaults for variables expected by cdm.gyp.
+    '<(DEPTH)/third_party/ce_cdm/platforms/x86-64/settings.gypi',
+    # cdm.gyp defines widevine_ce_cdm_static.
+    '<(DEPTH)/third_party/ce_cdm/cdm/cdm.gyp',
+  ],
+  'variables': {
+    'oemcrypto_target': 'oemcrypto',
+
+    # Use the protoc supplied in src/tools as precompiled executable.
+    'protoc_dir': '<(DEPTH)/tools',
+    'protoc_bin': '<(DEPTH)/tools/<(EXECUTABLE_PREFIX)protoc<(EXECUTABLE_SUFFIX)',
+    'protoc': '<(DEPTH)/tools/protoc.exe',
+
+    # Use the chromium target for protobuf.
+    'protobuf_lib_type': 'target',
+    'protobuf_lib': '<(DEPTH)/third_party/protobuf/protobuf.gyp:protobuf_lite',
+
+    'platform_oem_sources': [
+      '<(DEPTH)/starboard/keyboxes/<(sb_widevine_platform)/<(sb_widevine_platform).h',
+      '<(DEPTH)/starboard/keyboxes/<(sb_widevine_platform)/<(sb_widevine_platform)_client.c',
+      '<(DEPTH)/starboard/shared/widevine/wv_keybox.cc',
+    ],
+   },
+  'target_defaults': {
+    'include_dirs': [
+      # Get protobuf headers from the chromium tree.
+      '<(DEPTH)/third_party/protobuf/src',
+    ],
+    'dependencies': [
+      '<(DEPTH)/third_party/openssl/openssl.gyp:openssl',
+      # Depend on the locally-built protoc.
+      #'<(DEPTH)/third_party/protobuf/protobuf.gyp:protoc#host',
+    ],
+  },
+  'targets': [
+    {
+      'target_name': 'oemcrypto',
+      'type': 'static_library',
+      'defines': [
+        'USE_BUILT_OPENSSL',
+        'COBALT_WIDEVINE_KEYBOX_TRANSFORM_FUNCTION=<(sb_widevine_platform)_client',
+        'COBALT_WIDEVINE_KEYBOX_TRANSFORM_INCLUDE="starboard/keyboxes/<(sb_widevine_platform)/<(sb_widevine_platform).h"',
+        'COBALT_WIDEVINE_KEYBOX_INCLUDE="<(DEPTH)/starboard/keyboxes/<(sb_widevine_platform)_widevine_keybox.h"',
+      ],
+      'sources': [
+        '<@(platform_oem_sources)',
+      ],
+      'variables': {
+        'oec_mock_dir': '<(DEPTH)/third_party/ce_cdm/oemcrypto/mock',
+      },
+      'dependencies': [
+        '<(DEPTH)/third_party/ce_cdm/oemcrypto/mock/oec_mock.gyp:oec_mock',
+      ],
+      'direct_dependent_settings': {
+        'include_dirs': [
+          '<(DEPTH)/third_party/ce_cdm/core/include',
+          '<(DEPTH)/third_party/ce_cdm/oemcrypto/include',
+        ],
+      },
+    },
+  ],
+}
diff --git a/src/starboard/shared/widevine/widevine_storage.cc b/src/starboard/shared/widevine/widevine_storage.cc
new file mode 100644
index 0000000..7c3deca
--- /dev/null
+++ b/src/starboard/shared/widevine/widevine_storage.cc
@@ -0,0 +1,183 @@
+// 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/widevine/widevine_storage.h"
+
+#include "starboard/file.h"
+#include "starboard/log.h"
+#include "starboard/types.h"
+
+namespace starboard {
+namespace shared {
+namespace widevine {
+
+namespace {
+
+void ReadFile(const std::string& path_name, std::vector<uint8_t>* content) {
+  SB_DCHECK(content);
+
+  ScopedFile file(path_name.c_str(), kSbFileOpenOnly | kSbFileRead);
+
+  if (!file.IsValid()) {
+    content->clear();
+    SB_LOG(INFO) << "Failed to open " << path_name
+                 << ", returning empty content.";
+    return;
+  }
+
+  auto size = file.GetSize();
+  if (size < 0) {
+    content->clear();
+    SB_LOG(INFO) << "Failed to get size of " << path_name
+                 << ", returning empty content.";
+    return;
+  }
+
+  content->resize(size);
+  if (file.ReadAll(reinterpret_cast<char*>(content->data()), size) != size) {
+    content->clear();
+    SB_LOG(INFO) << "Failed to read content of " << path_name
+                 << ", returning empty content.";
+    return;
+  }
+}
+
+bool WriteFile(const std::string& path_name,
+               const std::vector<uint8_t>& content) {
+  ScopedFile file(path_name.c_str(), kSbFileCreateAlways | kSbFileWrite);
+
+  if (!file.IsValid()) {
+    SB_LOG(INFO) << "Failed to create " << path_name << " for writing.";
+    return false;
+  }
+
+  if (file.WriteAll(reinterpret_cast<const char*>(content.data()),
+                    static_cast<int>(content.size())) != content.size()) {
+    SB_LOG(INFO) << "Failed to write content to " << path_name << '.';
+    return false;
+  }
+
+  file.Flush();
+
+  return true;
+}
+
+bool ReadString(const std::vector<uint8_t>& data,
+                size_t* offset,
+                std::string* str) {
+  if (*offset + sizeof(int) > data.size()) {
+    SB_LOG(ERROR) << "Failed to read the size of string from |data|.";
+    return false;
+  }
+  int size = *reinterpret_cast<const int*>(data.data() + *offset);
+  *offset += sizeof(int);
+  if (*offset + size > data.size()) {
+    SB_LOG(ERROR) << "Failed to read " << size << " bytes from |data|.";
+    return false;
+  }
+  str->assign(reinterpret_cast<const char*>(data.data() + *offset),
+              reinterpret_cast<const char*>(data.data() + *offset + size));
+  *offset += size;
+  return true;
+}
+
+void WriteString(const std::string& str, std::vector<uint8_t>* content) {
+  content->reserve(content->size() + sizeof(int) + str.size());
+  content->resize(content->size() + sizeof(int));
+  *reinterpret_cast<int*>(content->data() + content->size() - sizeof(int)) =
+      static_cast<int>(str.size());
+  content->insert(content->end(), reinterpret_cast<const uint8_t*>(str.c_str()),
+                  reinterpret_cast<const uint8_t*>(str.c_str()) + str.size());
+}
+
+}  // namespace
+
+WidevineStorage::WidevineStorage(const std::string& path_name)
+    : path_name_(path_name) {
+  std::vector<uint8_t> content;
+  ReadFile(path_name_, &content);
+  size_t offset = 0;
+
+  while (offset != content.size()) {
+    std::string name, value;
+    if (!ReadString(content, &offset, &name) ||
+        !ReadString(content, &offset, &value)) {
+      cache_.clear();
+      SB_LOG(WARNING) << path_name_ << " is corrupt, returns empty content.";
+      return;
+    }
+    cache_[name] = value;
+  }
+
+  SB_LOG(INFO) << "Loaded " << cache_.size() << " records from " << path_name_;
+}
+
+bool WidevineStorage::read(const std::string& name, std::string* data) {
+  SB_DCHECK(data);
+  ScopedLock scoped_lock(lock_);
+  auto iter = cache_.find(name);
+  if (iter == cache_.end()) {
+    return false;
+  }
+  *data = iter->second;
+  return true;
+}
+
+bool WidevineStorage::write(const std::string& name, const std::string& data) {
+  ScopedLock scoped_lock(lock_);
+  cache_[name] = data;
+
+  std::vector<uint8_t> content;
+  for (auto iter : cache_) {
+    WriteString(iter.first, &content);
+    WriteString(iter.second, &content);
+  }
+
+  return WriteFile(path_name_, content);
+}
+
+bool WidevineStorage::exists(const std::string& name) {
+  ScopedLock scoped_lock(lock_);
+  return cache_.find(name) != cache_.end();
+}
+
+bool WidevineStorage::remove(const std::string& name) {
+  ScopedLock scoped_lock(lock_);
+  auto iter = cache_.find(name);
+  if (iter == cache_.end()) {
+    return false;
+  }
+  cache_.erase(iter);
+  return true;
+}
+
+int32_t WidevineStorage::size(const std::string& name) {
+  ScopedLock scoped_lock(lock_);
+  auto iter = cache_.find(name);
+  return iter == cache_.end() ? -1 : static_cast<int32_t>(iter->second.size());
+}
+
+bool WidevineStorage::list(std::vector<std::string>* records) {
+  SB_DCHECK(records);
+  ScopedLock scoped_lock(lock_);
+  records->clear();
+  for (auto item : cache_) {
+    records->push_back(item.first);
+  }
+  return !records->empty();
+}
+
+}  // namespace widevine
+}  // namespace shared
+}  // namespace starboard
diff --git a/src/starboard/shared/widevine/widevine_storage.h b/src/starboard/shared/widevine/widevine_storage.h
new file mode 100644
index 0000000..ad40bd7
--- /dev/null
+++ b/src/starboard/shared/widevine/widevine_storage.h
@@ -0,0 +1,56 @@
+// 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_WIDEVINE_WIDEVINE_STORAGE_H_
+#define STARBOARD_SHARED_WIDEVINE_WIDEVINE_STORAGE_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "starboard/mutex.h"
+#include "third_party/ce_cdm/cdm/include/cdm.h"
+
+namespace starboard {
+namespace shared {
+namespace widevine {
+
+// Manages the load and save of name/value pairs in std::string.  It is used by
+// Widevine to store persistent data like device provisioning.
+class WidevineStorage : public ::widevine::Cdm::IStorage {
+ public:
+  explicit WidevineStorage(const std::string& path_name);
+
+  bool read(const std::string& name, std::string* data) override;
+  bool write(const std::string& name, const std::string& data) override;
+  bool exists(const std::string& name) override;
+  bool remove(const std::string& name) override;
+  int32_t size(const std::string& name) override;
+
+  // Populates |file_names| with the name of each file in the file system.
+  // This is assumed to be a flat filename space (top level directory is
+  // unnamed, and there are no subdirectories).
+  bool list(std::vector<std::string>* records) override;
+
+ private:
+  Mutex lock_;
+  std::string path_name_;
+  std::map<std::string, std::string> cache_;
+};
+
+}  // namespace widevine
+}  // namespace shared
+}  // namespace starboard
+
+#endif  // STARBOARD_SHARED_WIDEVINE_WIDEVINE_STORAGE_H_
diff --git a/src/starboard/shared/widevine/widevine_timer.cc b/src/starboard/shared/widevine/widevine_timer.cc
new file mode 100644
index 0000000..141fe08
--- /dev/null
+++ b/src/starboard/shared/widevine/widevine_timer.cc
@@ -0,0 +1,130 @@
+// 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/widevine/widevine_timer.h"
+
+#include "starboard/time.h"
+
+namespace starboard {
+namespace shared {
+namespace widevine {
+
+namespace {
+
+struct ThreadParam {
+  WidevineTimer* timer;
+  ConditionVariable* condition_variable;
+};
+
+}  // namespace
+
+WidevineTimer::~WidevineTimer() {
+  for (auto iter : active_clients_) {
+    delete iter.second;
+  }
+}
+
+void WidevineTimer::setTimeout(int64_t delay_in_milliseconds,
+                               IClient* client,
+                               void* context) {
+  ScopedLock scoped_lock(mutex_);
+  if (active_clients_.empty()) {
+    SB_DCHECK(!SbThreadIsValid(thread_));
+    SB_DCHECK(!job_queue_);
+
+    ConditionVariable condition_variable(mutex_);
+    ThreadParam thread_param = {this, &condition_variable};
+    thread_ =
+        SbThreadCreate(0, kSbThreadNoPriority, kSbThreadNoAffinity, true,
+                       "wv_timer", &WidevineTimer::ThreadFunc, &thread_param);
+    condition_variable.Wait();
+  }
+
+  SB_DCHECK(SbThreadIsValid(thread_));
+  SB_DCHECK(job_queue_);
+
+  auto iter = active_clients_.find(client);
+  if (iter == active_clients_.end()) {
+    iter = active_clients_.emplace(client, new JobQueue::JobOwner(job_queue_))
+               .first;
+  }
+
+  iter->second->Schedule([=]() { client->onTimerExpired(context); },
+                         delay_in_milliseconds * kSbTimeMillisecond);
+}
+
+void WidevineTimer::cancel(IClient* client) {
+  ScopedLock scoped_lock(mutex_);
+  auto iter = active_clients_.find(client);
+  if (iter == active_clients_.end()) {
+    // cancel() can be called before any timer is scheduled.
+    return;
+  }
+
+  SB_DCHECK(job_queue_);
+
+  ConditionVariable condition_variable(mutex_);
+  job_queue_->Schedule(
+      [&]() { CancelAllJobsOnClient(client, &condition_variable); });
+  condition_variable.Wait();
+
+  if (active_clients_.empty()) {
+    // Kill the thread on the last |client|.
+    job_queue_->StopSoon();
+    SbThreadJoin(thread_, NULL);
+    thread_ = kSbThreadInvalid;
+    job_queue_ = NULL;
+  }
+}
+
+// static
+void* WidevineTimer::ThreadFunc(void* param) {
+  SB_DCHECK(param);
+  ThreadParam* thread_param = static_cast<ThreadParam*>(param);
+  thread_param->timer->RunLoop(thread_param->condition_variable);
+  return NULL;
+}
+
+void WidevineTimer::RunLoop(ConditionVariable* condition_variable) {
+  SB_DCHECK(!job_queue_);
+  SB_DCHECK(condition_variable);
+
+  JobQueue job_queue;
+
+  {
+    ScopedLock scoped_lock(mutex_);
+    job_queue_ = &job_queue;
+    condition_variable->Signal();
+  }
+
+  job_queue.RunUntilStopped();
+}
+
+void WidevineTimer::CancelAllJobsOnClient(
+    IClient* client,
+    ConditionVariable* condition_variable) {
+  SB_DCHECK(condition_variable);
+  SB_DCHECK(job_queue_->BelongsToCurrentThread());
+
+  ScopedLock scoped_lock(mutex_);
+  auto iter = active_clients_.find(client);
+  iter->second->CancelPendingJobs();
+  delete iter->second;
+  active_clients_.erase(iter);
+  condition_variable->Signal();
+}
+
+}  // namespace widevine
+}  // namespace shared
+}  // namespace starboard
diff --git a/src/starboard/shared/widevine/widevine_timer.h b/src/starboard/shared/widevine/widevine_timer.h
new file mode 100644
index 0000000..58cebe8
--- /dev/null
+++ b/src/starboard/shared/widevine/widevine_timer.h
@@ -0,0 +1,63 @@
+// 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_WIDEVINE_WIDEVINE_TIMER_H_
+#define STARBOARD_SHARED_WIDEVINE_WIDEVINE_TIMER_H_
+
+#include <map>
+
+#include "starboard/condition_variable.h"
+#include "starboard/mutex.h"
+#include "starboard/shared/starboard/player/job_queue.h"
+#include "starboard/thread.h"
+#include "third_party/ce_cdm/cdm/include/cdm.h"
+
+namespace starboard {
+namespace shared {
+namespace widevine {
+
+// Manages the scheduled callbacks of Widevine.  All its public functions can
+// be called from any threads.
+class WidevineTimer : public ::widevine::Cdm::ITimer {
+ public:
+  ~WidevineTimer() override;
+
+  // Call |client->onTimerExpired(context)| after |delay_in_milliseconds|.
+  void setTimeout(int64_t delay_in_milliseconds,
+                  IClient* client,
+                  void* context) override;
+
+  // Cancel all timers associated with |client|.  No timer should be called on
+  // the specific client after this function returns.
+  void cancel(IClient* client) override;
+
+ private:
+  typedef starboard::player::JobQueue JobQueue;
+
+  static void* ThreadFunc(void* param);
+  void RunLoop(ConditionVariable* condition_variable);
+  void CancelAllJobsOnClient(IClient* client,
+                             ConditionVariable* condition_variable);
+
+  Mutex mutex_;
+  SbThread thread_ = kSbThreadInvalid;
+  JobQueue* job_queue_ = NULL;
+  std::map<IClient*, JobQueue::JobOwner*> active_clients_;
+};
+
+}  // namespace widevine
+}  // namespace shared
+}  // namespace starboard
+
+#endif  // STARBOARD_SHARED_WIDEVINE_WIDEVINE_TIMER_H_
diff --git a/src/starboard/stub/configuration_public.h b/src/starboard/stub/configuration_public.h
index 79d31bb..481b524 100644
--- a/src/starboard/stub/configuration_public.h
+++ b/src/starboard/stub/configuration_public.h
@@ -196,6 +196,9 @@
 
 // --- Extensions Configuration ----------------------------------------------
 
+// Do not use <unordered_map> and <unordered_set> for the hash table types.
+#define SB_HAS_STD_UNORDERED_HASH 0
+
 // GCC/Clang doesn't define a long long hash function, except for Android and
 // Game consoles.
 #define SB_HAS_LONG_LONG_HASH 0
diff --git a/src/starboard/tools/testing/test_runner.py b/src/starboard/tools/testing/test_runner.py
index 05c22f3..4a15ce7 100755
--- a/src/starboard/tools/testing/test_runner.py
+++ b/src/starboard/tools/testing/test_runner.py
@@ -29,8 +29,8 @@
 from starboard.tools import abstract_launcher
 from starboard.tools import build
 from starboard.tools import command_line
-from starboard.tools.testing import test_filter
 from starboard.tools.testing import build_tests
+from starboard.tools.testing import test_filter
 
 _TOTAL_TESTS_REGEX = (r"\[==========\] (.*) tests? from .*"
                       r"test cases? ran. \(.* ms total\)")
@@ -90,11 +90,12 @@
     while not self.stop_event.is_set():
       line = self.read_pipe.readline()
       if line:
+        # Normalize line endings to unix.
+        line = line.replace("\r", "")
         sys.stdout.write(line)
         sys.stdout.flush()
       else:
         break
-
       self.output_lines.write(line)
 
   def Start(self):
@@ -409,6 +410,8 @@
 
     print "\nTEST RUN COMPLETE. RESULTS BELOW:\n"
 
+    failed_test_groups = []
+
     for result_set in results:
 
       target_name = result_set[0]
@@ -425,6 +428,7 @@
       if return_code != 0:
         error = True
         test_status = "FAILED"
+        failed_test_groups.append(target_name)
 
       print "{}: {}.".format(target_name, test_status)
       if run_count == 0:
@@ -459,6 +463,9 @@
       result = False
 
     print "TEST RUN {}.".format(overall_status)
+    if failed_test_groups:
+      failed_test_groups = list(set(failed_test_groups))
+      print "  FAILED TESTS GROUPS: {}".format(", ".join(failed_test_groups))
     print "  TOTAL TESTS RUN: {}".format(total_run_count)
     print "  TOTAL TESTS PASSED: {}".format(total_passed_count)
     print "  TOTAL TESTS FAILED: {}".format(total_failed_count)
diff --git a/src/third_party/angle/src/common/debug.cpp b/src/third_party/angle/src/common/debug.cpp
index 597e9d6..1c7e2c8 100644
--- a/src/third_party/angle/src/common/debug.cpp
+++ b/src/third_party/angle/src/common/debug.cpp
@@ -19,6 +19,10 @@
 #include "common/angleutils.h"
 #include "common/Optional.h"
 
+#if defined(STARBOARD)
+#include "starboard/log.h"
+#endif  // defined(STARBOARD)
+
 namespace gl
 {
 
@@ -138,6 +142,16 @@
 
 void Trace(LogSeverity severity, const char *message)
 {
+#if defined(STARBOARD)
+    if (severity == LOG_WARN)
+    {
+        SB_LOG(WARNING) << "Angle: " << message;
+    }
+    else if (severity == LOG_ERR)
+    {
+        SB_LOG(ERROR) << "Angle: " << message;
+    }
+#endif  // defined(STARBOARD)
     if (!ShouldCreateLogMessage(severity))
     {
         return;
diff --git a/src/third_party/libjpeg-turbo/libjpeg.gyp b/src/third_party/libjpeg-turbo/libjpeg.gyp
index 0937a66..7857d59 100644
--- a/src/third_party/libjpeg-turbo/libjpeg.gyp
+++ b/src/third_party/libjpeg-turbo/libjpeg.gyp
@@ -14,6 +14,12 @@
         'BMP_SUPPORTED',
         'PPM_SUPPORTED'
       ],
+      'variables': {
+        'no_simd_files': [
+          'jsimd.h',
+          'jsimd_none.c',
+        ]
+      },
       'sources': [
         'cdjpeg.h',
         'jaricom.c',
@@ -82,6 +88,7 @@
         'transupp.c',
         'turbojpeg.h',
         'turbojpeg.c',
+        '<@(no_simd_files)',
         # These dependecies are needed for file io
         # and are not currently used by Cobalt.
         #'rdbmp.c',
@@ -92,8 +99,22 @@
         #'jdatadst.c',
       ],
       'conditions': [
-        #x86_64 specific optimizations
+        # arm processor specific optimizations.
+        ['target_arch == "arm" and arm_neon == 1', {
+          'sources!': [
+            '<@(no_simd_files)'
+          ],
+          'sources': [
+            'simd/arm/jsimd.c',
+            'simd/arm/jsimd_neon.S',
+            'simd/jsimd.h',
+          ],
+        }],
+        # x86_64 specific optimizations.
         ['<(yasm_exists) == 1 and target_arch == "x64"', {
+          'sources!': [
+            '<@(no_simd_files)'
+          ],
           'sources': [
             'simd/x86_64/jsimdcpu.asm',
             'simd/x86_64/jfdctflt-sse.asm',
@@ -125,7 +146,7 @@
             'simd/x86_64/jsimd.c',
             'simd/jsimd.h',
           ],
-          #rules for assembling .asm files with yarn
+          # Rules for assembling .asm files with yasm.
           'rules': [
             {
               'rule_name': 'assemble',
@@ -152,13 +173,7 @@
             },
           ],
           },
-          #no optimizations
-          {
-            'sources': [
-              'jsimd.h',
-              'jsimd_none.c'
-            ]
-          }]
+        ]
       ],
     },
   ],
diff --git a/src/third_party/libjpeg-turbo/simd/arm/jsimd.c b/src/third_party/libjpeg-turbo/simd/arm/jsimd.c
index 0fb8197..ade6c63 100644
--- a/src/third_party/libjpeg-turbo/simd/arm/jsimd.c
+++ b/src/third_party/libjpeg-turbo/simd/arm/jsimd.c
@@ -23,9 +23,15 @@
 #include "../../jsimddct.h"
 #include "../jsimd.h"
 
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
+#ifdef STARBOARD
+#include "starboard/client_porting/poem/strings_poem.h"
+#include "starboard/client_porting/poem/string_poem.h"
+#include "starboard/configuration.h"
+#include "starboard/client_porting/poem/stdio_poem.h"
+#include "starboard/character.h"
+#else
+#include "starboard/client_porting/poem/stdio_poem.h"
+#endif
 
 static unsigned int simd_support = ~0;
 static unsigned int simd_huffman = 1;
diff --git a/src/third_party/libxml/src/tree.c b/src/third_party/libxml/src/tree.c
index 00e1b4e..f34fe1e 100644
--- a/src/third_party/libxml/src/tree.c
+++ b/src/third_party/libxml/src/tree.c
@@ -1686,7 +1686,7 @@
             if (inLine) {
                 ret = xmlStrcat(ret, node->content);
             } else {
-                xmlChar *buffer;
+                xmlChar *buffer = NULL;
 
 		if (attr) {
 #ifdef LIBXML_OUTPUT_ENABLED
diff --git a/src/third_party/mozjs-45/js/src/TAGS b/src/third_party/mozjs-45/js/src/TAGS
index caae158..7bc4beff 100644
--- a/src/third_party/mozjs-45/js/src/TAGS
+++ b/src/third_party/mozjs-45/js/src/TAGS
@@ -104644,7 +104644,7 @@
   const char* const nan_symbol_;526,26003
   double StringToIeee(528,26037
 
-devtools/rootAnalysis/build/obj-opt-js/dist/include/mozilla/Endian.h,5894
+devtools/rootAnalysis/build/obj-opt-js/dist/include/mozilla/EndianUtils.h,5894
 #define mozilla_Endian_h65,2400
 #    define MOZ_LITTLE_ENDIAN 85,2873
 #    define MOZ_LITTLE_ENDIAN 91,3000
diff --git a/src/third_party/mozjs-45/js/src/vm/StructuredClone.cpp b/src/third_party/mozjs-45/js/src/vm/StructuredClone.cpp
index 94ebbc7..e1ec72b 100644
--- a/src/third_party/mozjs-45/js/src/vm/StructuredClone.cpp
+++ b/src/third_party/mozjs-45/js/src/vm/StructuredClone.cpp
@@ -29,7 +29,7 @@
 
 #include "js/StructuredClone.h"
 
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include "mozilla/FloatingPoint.h"
 
 #include <algorithm>
diff --git a/src/third_party/mozjs-45/js/src/vm/TraceLoggingGraph.cpp b/src/third_party/mozjs-45/js/src/vm/TraceLoggingGraph.cpp
index 1b7c9cd..e1433f3 100644
--- a/src/third_party/mozjs-45/js/src/vm/TraceLoggingGraph.cpp
+++ b/src/third_party/mozjs-45/js/src/vm/TraceLoggingGraph.cpp
@@ -6,7 +6,7 @@
 
 #include "vm/TraceLoggingGraph.h"
 
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 
 #include "jsstr.h"
 
diff --git a/src/third_party/mozjs-45/js/src/vm/Xdr.h b/src/third_party/mozjs-45/js/src/vm/Xdr.h
index 032eacf..2915779 100644
--- a/src/third_party/mozjs-45/js/src/vm/Xdr.h
+++ b/src/third_party/mozjs-45/js/src/vm/Xdr.h
@@ -7,7 +7,7 @@
 #ifndef vm_Xdr_h
 #define vm_Xdr_h
 
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include "mozilla/TypeTraits.h"
 
 #include "jsatom.h"
diff --git a/src/third_party/mozjs-45/mfbt/Endian.h b/src/third_party/mozjs-45/mfbt/EndianUtils.h
similarity index 100%
rename from src/third_party/mozjs-45/mfbt/Endian.h
rename to src/third_party/mozjs-45/mfbt/EndianUtils.h
diff --git a/src/third_party/mozjs-45/mfbt/SHA1.cpp b/src/third_party/mozjs-45/mfbt/SHA1.cpp
index da4cb16..f8968c3 100644
--- a/src/third_party/mozjs-45/mfbt/SHA1.cpp
+++ b/src/third_party/mozjs-45/mfbt/SHA1.cpp
@@ -5,7 +5,7 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Assertions.h"
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 #include "mozilla/SHA1.h"
 
 #include <string.h>
diff --git a/src/third_party/mozjs-45/mfbt/moz.build b/src/third_party/mozjs-45/mfbt/moz.build
index a071040..2d11c70 100644
--- a/src/third_party/mozjs-45/mfbt/moz.build
+++ b/src/third_party/mozjs-45/mfbt/moz.build
@@ -34,7 +34,7 @@
     'decimal/Decimal.h',
     'double-conversion/double-conversion.h',
     'double-conversion/utils.h',
-    'Endian.h',
+    'EndianUtils.h',
     'EnumeratedArray.h',
     'EnumeratedRange.h',
     'EnumSet.h',
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestEndian.cpp b/src/third_party/mozjs-45/mfbt/tests/TestEndian.cpp
index b5fcd19..0621a80 100644
--- a/src/third_party/mozjs-45/mfbt/tests/TestEndian.cpp
+++ b/src/third_party/mozjs-45/mfbt/tests/TestEndian.cpp
@@ -5,7 +5,7 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Assertions.h"
-#include "mozilla/Endian.h"
+#include "mozilla/EndianUtils.h"
 
 #include <stddef.h>
 
diff --git a/src/third_party/mozjs-45/mozjs-45.gyp b/src/third_party/mozjs-45/mozjs-45.gyp
index 7641497..14b5bd3 100644
--- a/src/third_party/mozjs-45/mozjs-45.gyp
+++ b/src/third_party/mozjs-45/mozjs-45.gyp
@@ -431,7 +431,7 @@
             'mfbt/double-conversion/ieee.h',
             'mfbt/double-conversion/strtod.h',
             'mfbt/double-conversion/utils.h',
-            'mfbt/Endian.h',
+            'mfbt/EndianUtils.h',
             'mfbt/EnumeratedArray.h',
             'mfbt/EnumeratedRange.h',
             'mfbt/EnumSet.h',
diff --git a/src/third_party/opus/celt/float_cast.h b/src/third_party/opus/celt/float_cast.h
index 98b40ab..f7bde78 100644
--- a/src/third_party/opus/celt/float_cast.h
+++ b/src/third_party/opus/celt/float_cast.h
@@ -126,8 +126,8 @@
 
 #if (defined(__GNUC__) && defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L)
         /* supported by gcc in C99 mode, but not by all other compilers */
-        #warning "Don't have the functions lrint() and lrintf ()."
-        #warning "Replacing these functions with a standard C cast."
+        // #warning "Don't have the functions lrint() and lrintf ()."
+        // #warning "Replacing these functions with a standard C cast."
 #endif /* __STDC_VERSION__ >= 199901L */
         #include <math.h>
         #define float2int(flt) ((int)(floor(.5+flt)))
diff --git a/src/third_party/opus/opus.gyp b/src/third_party/opus/opus.gyp
new file mode 100644
index 0000000..4635ac2
--- /dev/null
+++ b/src/third_party/opus/opus.gyp
@@ -0,0 +1,270 @@
+# 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.
+
+{
+  'targets': [
+    {
+      'target_name': 'opus',
+      'type': 'static_library',
+      'include_dirs': [
+        '.',
+        'celt',
+        'include',
+        'silk',
+        'silk/float',
+        'starboard',
+      ],
+      'sources': [
+        'celt/_kiss_fft_guts.h',
+        'celt/arch.h',
+        'celt/bands.c',
+        'celt/bands.h',
+        'celt/celt.c',
+        'celt/celt.h',
+        'celt/celt_decoder.c',
+        'celt/celt_encoder.c',
+        'celt/celt_lpc.c',
+        'celt/celt_lpc.h',
+        'celt/cwrs.c',
+        'celt/cwrs.h',
+        'celt/ecintrin.h',
+        'celt/entcode.c',
+        'celt/entcode.h',
+        'celt/entdec.c',
+        'celt/entdec.h',
+        'celt/entenc.c',
+        'celt/entenc.h',
+        'celt/fixed_c5x.h',
+        'celt/fixed_c6x.h',
+        'celt/fixed_debug.h',
+        'celt/fixed_generic.h',
+        'celt/float_cast.h',
+        'celt/kiss_fft.c',
+        'celt/kiss_fft.h',
+        'celt/laplace.c',
+        'celt/laplace.h',
+        'celt/mathops.c',
+        'celt/mathops.h',
+        'celt/mdct.c',
+        'celt/mdct.h',
+        'celt/mfrngcod.h',
+        'celt/modes.c',
+        'celt/modes.h',
+        'celt/os_support.h',
+        'celt/pitch.c',
+        'celt/pitch.h',
+        'celt/quant_bands.c',
+        'celt/quant_bands.h',
+        'celt/rate.c',
+        'celt/rate.h',
+        'celt/stack_alloc.h',
+        'celt/static_modes_fixed.h',
+        'celt/static_modes_float.h',
+        'celt/vq.c',
+        'celt/vq.h',
+
+        'include/opus.h',
+        'include/opus_defines.h',
+        'include/opus_types.h',
+        'include/opus_multistream.h',
+
+        'src/analysis.h',
+        'src/mlp.h',
+        'src/opus_private.h',
+        'src/tansig_table.h',
+
+        'silk/A2NLSF.c',
+        'silk/ana_filt_bank_1.c',
+        'silk/API.h',
+        'silk/biquad_alt.c',
+        'silk/bwexpander.c',
+        'silk/bwexpander_32.c',
+        'silk/check_control_input.c',
+        'silk/CNG.c',
+        'silk/code_signs.c',
+        'silk/control.h',
+        'silk/control_audio_bandwidth.c',
+        'silk/control_codec.c',
+        'silk/control_SNR.c',
+        'silk/debug.c',
+        'silk/debug.h',
+        'silk/decoder_set_fs.c',
+        'silk/decode_core.c',
+        'silk/decode_frame.c',
+        'silk/decode_indices.c',
+        'silk/decode_parameters.c',
+        'silk/decode_pitch.c',
+        'silk/decode_pulses.c',
+        'silk/dec_API.c',
+        'silk/define.h',
+        'silk/encode_indices.c',
+        'silk/encode_pulses.c',
+        'silk/enc_API.c',
+        'silk/errors.h',
+        'silk/gain_quant.c',
+        'silk/HP_variable_cutoff.c',
+        'silk/init_decoder.c',
+        'silk/init_encoder.c',
+        'silk/Inlines.h',
+        'silk/inner_prod_aligned.c',
+        'silk/interpolate.c',
+        'silk/lin2log.c',
+        'silk/log2lin.c',
+        'silk/LPC_analysis_filter.c',
+        'silk/LPC_fit.c',
+        'silk/LPC_inv_pred_gain.c',
+        'silk/LP_variable_cutoff.c',
+        'silk/macros.h',
+        'silk/MacroCount.h',
+        'silk/MacroDebug.h',
+        'silk/main.h',
+        'silk/NLSF2A.c',
+        'silk/NLSF_decode.c',
+        'silk/NLSF_del_dec_quant.c',
+        'silk/NLSF_encode.c',
+        'silk/NLSF_stabilize.c',
+        'silk/NLSF_unpack.c',
+        'silk/NLSF_VQ.c',
+        'silk/NLSF_VQ_weights_laroia.c',
+        'silk/NSQ.c',
+        'silk/NSQ_del_dec.c',
+        'silk/pitch_est_defines.h',
+        'silk/pitch_est_tables.c',
+        'silk/PLC.c',
+        'silk/PLC.h',
+        'silk/process_NLSFs.c',
+        'silk/quant_LTP_gains.c',
+        'silk/resampler.c',
+        'silk/resampler_down2.c',
+        'silk/resampler_down2_3.c',
+        'silk/resampler_private.h',
+        'silk/resampler_private_AR2.c',
+        'silk/resampler_private_down_FIR.c',
+        'silk/resampler_private_IIR_FIR.c',
+        'silk/resampler_private_up2_HQ.c',
+        'silk/resampler_rom.c',
+        'silk/resampler_rom.h',
+        'silk/resampler_structs.h',
+        'silk/shell_coder.c',
+        'silk/sigm_Q15.c',
+        'silk/sort.c',
+        'silk/stereo_decode_pred.c',
+        'silk/stereo_encode_pred.c',
+        'silk/stereo_find_predictor.c',
+        'silk/stereo_LR_to_MS.c',
+        'silk/stereo_MS_to_LR.c',
+        'silk/stereo_quant_pred.c',
+        'silk/structs.h',
+        'silk/sum_sqr_shift.c',
+        'silk/tables.h',
+        'silk/tables_gain.c',
+        'silk/tables_LTP.c',
+        'silk/tables_NLSF_CB_NB_MB.c',
+        'silk/tables_NLSF_CB_WB.c',
+        'silk/tables_other.c',
+        'silk/tables_pitch_lag.c',
+        'silk/tables_pulses_per_block.c',
+        'silk/table_LSF_cos.c',
+        'silk/tuning_parameters.h',
+        'silk/typedef.h',
+        'silk/VAD.c',
+        'silk/VQ_WMat_EC.c',
+        'src/analysis.c',
+        'src/mlp.c',
+        'src/mlp_data.c',
+        'src/opus.c',
+        'src/opus_compare.c',
+        'src/opus_decoder.c',
+        'src/opus_encoder.c',
+        'src/opus_multistream.c',
+        'src/opus_multistream_decoder.c',
+        'src/opus_multistream_encoder.c',
+        'src/repacketizer.c',
+
+        # Floating point decoding files
+        'silk/float/autocorrelation_FLP.c',
+        'silk/float/burg_modified_FLP.c',
+        'silk/float/bwexpander_FLP.c',
+        'silk/float/corrMatrix_FLP.c',
+        'silk/float/encode_frame_FLP.c',
+        'silk/float/energy_FLP.c',
+        'silk/float/find_LPC_FLP.c',
+        'silk/float/find_LTP_FLP.c',
+        'silk/float/find_pitch_lags_FLP.c',
+        'silk/float/find_pred_coefs_FLP.c',
+        'silk/float/inner_product_FLP.c',
+        'silk/float/k2a_FLP.c',
+        'silk/float/LPC_analysis_filter_FLP.c',
+        'silk/float/LPC_inv_pred_gain_FLP.c',
+        'silk/float/LTP_analysis_filter_FLP.c',
+        'silk/float/LTP_scale_ctrl_FLP.c',
+        'silk/float/main_FLP.h',
+        'silk/float/noise_shape_analysis_FLP.c',
+        'silk/float/pitch_analysis_core_FLP.c',
+        'silk/float/process_gains_FLP.c',
+        'silk/float/regularize_correlations_FLP.c',
+        'silk/float/residual_energy_FLP.c',
+        'silk/float/scale_copy_vector_FLP.c',
+        'silk/float/scale_vector_FLP.c',
+        'silk/float/schur_FLP.c',
+        'silk/float/SigProc_FLP.h',
+        'silk/float/sort_FLP.c',
+        'silk/float/structs_FLP.h',
+        'silk/float/warped_autocorrelation_FLP.c',
+        'silk/float/wrappers_FLP.c',
+
+        'silk/float/apply_sine_window_FLP.c',
+      ],
+      'defines': [
+        'HAVE_CONFIG_H',
+      ],
+      'direct_dependent_settings': {
+        'include_dirs': [
+          '.',
+        ],
+      },
+      'conditions': [
+        ['target_arch == "x86" or target_arch == "x64"', {
+          'sources': [
+            'celt/x86/celt_lpc_sse4_1.c',
+            'celt/x86/celt_lpc_sse.h',
+            'celt/x86/pitch_sse.c',
+            'celt/x86/pitch_sse.h',
+            'celt/x86/pitch_sse2.c',
+            'celt/x86/pitch_sse4_1.c',
+            'celt/x86/vq_sse2.c',
+            'celt/x86/vq_sse.h',
+            'celt/x86/x86cpu.c',
+            'celt/x86/x86cpu.h',
+            'celt/x86/x86_celt_map.c',
+            'silk/x86/main_sse.h',
+            'silk/x86/NSQ_del_dec_sse4_1.c',
+            'silk/x86/NSQ_sse4_1.c',
+            'silk/x86/VAD_sse4_1.c',
+            'silk/x86/VQ_WMat_EC_sse4_1.c',
+            'silk/x86/x86_silk_map.c',
+          ],
+        }],
+        ['target_arch == "arm" or target_arch == "arm64"', {
+          'defines': [
+            # Disabled arm asm.
+            # 'OPUS_ARM_ASM',
+            # 'OPUS_ARM_INLINE_ASM',
+            # 'OPUS_ARM_INLINE_EDSP',
+          ],
+        }],
+      ],
+    },
+  ],
+}
diff --git a/src/third_party/opus/starboard/config.h b/src/third_party/opus/starboard/config.h
new file mode 100644
index 0000000..7c67f29
--- /dev/null
+++ b/src/third_party/opus/starboard/config.h
@@ -0,0 +1,64 @@
+/***********************************************************************
+Copyright (c) 2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+#define USE_ALLOCA            0
+
+/* Comment out the next line for floating-point code */
+/*#define FIXED_POINT           1 */
+
+#define OPUS_BUILD            1
+
+#if defined(_M_IX86) || defined(_M_X64)
+/* Can always compile SSE intrinsics (no special compiler flags necessary) */
+#define OPUS_X86_MAY_HAVE_SSE
+#define OPUS_X86_MAY_HAVE_SSE2
+#define OPUS_X86_MAY_HAVE_SSE4_1
+
+/* Presume SSE functions, if compiled to use SSE/SSE2/AVX (note that AMD64 implies SSE2, and AVX
+   implies SSE4.1) */
+#if defined(_M_X64) || (defined(_M_IX86_FP) && (_M_IX86_FP >= 1)) || defined(__AVX__)
+#define OPUS_X86_PRESUME_SSE 1
+#endif
+#if defined(_M_X64) || (defined(_M_IX86_FP) && (_M_IX86_FP >= 2)) || defined(__AVX__)
+#define OPUS_X86_PRESUME_SSE2 1
+#endif
+#if defined(__AVX__)
+#define OPUS_X86_PRESUME_SSE4_1 1
+#endif
+
+#if !defined(OPUS_X86_PRESUME_SSE4_1) || !defined(OPUS_X86_PRESUME_SSE2) || !defined(OPUS_X86_PRESUME_SSE)
+#define OPUS_HAVE_RTCD 1
+#endif
+
+#endif
+
+#include "version.h"
+
+#endif /* CONFIG_H */
diff --git a/src/third_party/opus/starboard/version.h b/src/third_party/opus/starboard/version.h
new file mode 100644
index 0000000..d95510d
--- /dev/null
+++ b/src/third_party/opus/starboard/version.h
@@ -0,0 +1 @@
+#define OPUS_VERSION "1.3-rc-2-gc1c247d-dirty"

diff --git a/src/third_party/opus/win32/version.h b/src/third_party/opus/win32/version.h
new file mode 100644
index 0000000..d95510d
--- /dev/null
+++ b/src/third_party/opus/win32/version.h
@@ -0,0 +1 @@
+#define OPUS_VERSION "1.3-rc-2-gc1c247d-dirty"

diff --git a/src/third_party/skia/src/sksl/SkSLCPPCodeGenerator.cpp b/src/third_party/skia/src/sksl/SkSLCPPCodeGenerator.cpp
index 235c9d8..021bdb6 100644
--- a/src/third_party/skia/src/sksl/SkSLCPPCodeGenerator.cpp
+++ b/src/third_party/skia/src/sksl/SkSLCPPCodeGenerator.cpp
@@ -39,6 +39,7 @@
         vsprintf(heap.get(), s, copy);
         fOut->write(heap.get(), length);
     }
+    va_end(copy);
 }
 
 void CPPCodeGenerator::writef(const char* s, ...) {
diff --git a/src/third_party/skia/src/sksl/SkSLString.cpp b/src/third_party/skia/src/sksl/SkSLString.cpp
index fb8fd56..18ab25e 100644
--- a/src/third_party/skia/src/sksl/SkSLString.cpp
+++ b/src/third_party/skia/src/sksl/SkSLString.cpp
@@ -21,6 +21,7 @@
     va_start(args, fmt);
     String result;
     result.vappendf(fmt, args);
+    va_end(args);
     return result;
 }
 
@@ -29,6 +30,7 @@
     va_list args;
     va_start(args, fmt);
     this->vappendf(fmt, args);
+    va_end(args);
 }
 #endif
 
@@ -50,6 +52,7 @@
         VSNPRINTF(newBuffer.get(), size + 1, fmt, reuse);
         this->append(newBuffer.get(), size);
     }
+    va_end(reuse);
 }
 
 
diff --git a/src/third_party/skia/src/sksl/SkSLUtil.h b/src/third_party/skia/src/sksl/SkSLUtil.h
index f0951a3..5670ea4 100644
--- a/src/third_party/skia/src/sksl/SkSLUtil.h
+++ b/src/third_party/skia/src/sksl/SkSLUtil.h
@@ -21,6 +21,10 @@
 #include "GrShaderCaps.h"
 #endif
 
+#if defined(STARBOARD)
+#include "starboard/log.h"
+#endif
+
 #ifdef SKSL_STANDALONE
 #if defined(_WIN32) || defined(__SYMBIAN32__)
 #define SKSL_BUILD_FOR_WIN
@@ -287,6 +291,10 @@
 #define SKSL_PRINTF_LIKE(A, B)
 #endif
 
+#if defined(STARBOARD)
+#define ABORT(...) (SbLogFormatF(__VA_ARGS__), sksl_abort())
+#else
 #define ABORT(...) (printf(__VA_ARGS__), sksl_abort())
+#endif
 
 #endif
diff --git a/src/third_party/skia/src/sksl/ir/SkSLLayout.h b/src/third_party/skia/src/sksl/ir/SkSLLayout.h
index 8bf0472..f2c66b6 100644
--- a/src/third_party/skia/src/sksl/ir/SkSLLayout.h
+++ b/src/third_party/skia/src/sksl/ir/SkSLLayout.h
@@ -165,7 +165,7 @@
             separator = ", ";
         }
         if (fInputAttachmentIndex >= 0) {
-            result += separator + "input_attachment_index = " + to_string(fBuiltin);
+            result += separator + "input_attachment_index = " + to_string(fInputAttachmentIndex);
             separator = ", ";
         }
         if (fOriginUpperLeft) {
diff --git a/src/tools/gyp/pylib/gyp/generator/ninja.py b/src/tools/gyp/pylib/gyp/generator/ninja.py
index b075044..9d31595 100755
--- a/src/tools/gyp/pylib/gyp/generator/ninja.py
+++ b/src/tools/gyp/pylib/gyp/generator/ninja.py
@@ -79,9 +79,16 @@
 
 microsoft_flavors = [
     'win', 'win-win32', 'win-win32-lib',
-    'xb1', 'xb1-future', 'xb1-youtubetv', 'xb1-mainappbeta'
 ]
-sony_flavors = ['ps3', 'ps4', 'ps4-vr']
+sony_flavors = []
+
+try:
+  import private_ninja_flavors
+  microsoft_flavors += private_ninja_flavors.PrivateMicrosoftFlavors()
+  sony_flavors += private_ninja_flavors.PrivateSonyFlavors()
+except ImportError:
+  pass
+
 windows_host_flavors = microsoft_flavors + sony_flavors
 
 
diff --git a/src/v8/include/v8.h b/src/v8/include/v8.h
index acb3efb..3b19762 100644
--- a/src/v8/include/v8.h
+++ b/src/v8/include/v8.h
@@ -15,9 +15,11 @@
 #ifndef INCLUDE_V8_H_
 #define INCLUDE_V8_H_
 
+#if !V8_OS_STARBOARD
 #include <stddef.h>
 #include <stdint.h>
 #include <stdio.h>
+#endif // !V8_OS_STARBOARD
 #include <memory>
 #include <utility>
 #include <vector>
diff --git a/src/v8/src/assembler.cc b/src/v8/src/assembler.cc
index 1b83735..34d44e8 100644
--- a/src/v8/src/assembler.cc
+++ b/src/v8/src/assembler.cc
@@ -1423,9 +1423,20 @@
   return ExternalReference(Redirect(isolate, FUNCTION_ADDR(libc_memset)));
 }
 
+#if V8_OS_STARBOARD
+namespace {
+int no_printf(const char *format, ...) {
+  return 0;
+}
+}
+ExternalReference ExternalReference::printf_function(Isolate* isolate) {
+  return ExternalReference(Redirect(isolate, FUNCTION_ADDR(no_printf)));
+}
+#else
 ExternalReference ExternalReference::printf_function(Isolate* isolate) {
   return ExternalReference(Redirect(isolate, FUNCTION_ADDR(std::printf)));
 }
+#endif
 
 template <typename SubjectChar, typename PatternChar>
 ExternalReference ExternalReference::search_string_raw(Isolate* isolate) {
diff --git a/src/v8/src/base/cpu.cc b/src/v8/src/base/cpu.cc
index 22e0511..3c2bf29 100644
--- a/src/v8/src/base/cpu.cc
+++ b/src/v8/src/base/cpu.cc
@@ -33,11 +33,13 @@
 #endif
 
 #include <ctype.h>
+#if !V8_OS_STARBOARD
 #include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <algorithm>
+#endif
 
 #include "src/base/logging.h"
 #if V8_OS_WIN
diff --git a/src/v8/src/base/logging.cc b/src/v8/src/base/logging.cc
index ad5349a..5472d0e 100644
--- a/src/v8/src/base/logging.cc
+++ b/src/v8/src/base/logging.cc
@@ -5,9 +5,11 @@
 #include "src/base/logging.h"
 
 #include <cctype>
+#if !V8_OS_STARBOARD
 #include <cstdarg>
 #include <cstdio>
 #include <cstdlib>
+#endif
 
 #include "src/base/debug/stack_trace.h"
 #include "src/base/platform/platform.h"
@@ -120,8 +122,10 @@
 }  // namespace v8
 
 void V8_Fatal(const char* file, int line, const char* format, ...) {
+#if !V8_OS_STARBOARD
   fflush(stdout);
   fflush(stderr);
+#endif
   v8::base::OS::PrintError("\n\n#\n# Fatal error in %s, line %d\n# ", file,
                            line);
   va_list arguments;
@@ -132,7 +136,9 @@
 
   if (v8::base::g_print_stack_trace) v8::base::g_print_stack_trace();
 
+#if !V8_OS_STARBOARD
   fflush(stderr);
+#endif
   v8::base::OS::Abort();
 }
 
diff --git a/src/v8/src/base/platform/mutex.cc b/src/v8/src/base/platform/mutex.cc
index 10fb58f..511fa90 100644
--- a/src/v8/src/base/platform/mutex.cc
+++ b/src/v8/src/base/platform/mutex.cc
@@ -4,7 +4,9 @@
 
 #include "src/base/platform/mutex.h"
 
+#if !V8_OS_STARBOARD
 #include <errno.h>
+#endif
 
 namespace v8 {
 namespace base {
@@ -273,4 +275,4 @@
 #endif  // V8_OS_POSIX
 
 }  // namespace base
-}  // namespace v8
\ No newline at end of file
+}  // namespace v8
diff --git a/src/v8/src/base/platform/platform-starboard.cc b/src/v8/src/base/platform/platform-starboard.cc
index d3f16a0..6825bd1 100644
--- a/src/v8/src/base/platform/platform-starboard.cc
+++ b/src/v8/src/base/platform/platform-starboard.cc
@@ -334,7 +334,7 @@
 }
 
 int OS::VSNPrintF(char* str, int length, const char* format, va_list args) {
-  int n = vsnprintf(str, length, format, args);
+  int n = SbStringFormat(str, length, format, args);
   if (n < 0 || n >= length) {
     // If the length is zero, the assignment fails.
     if (length > 0) str[length - 1] = '\0';
diff --git a/src/v8/src/base/utils/random-number-generator.cc b/src/v8/src/base/utils/random-number-generator.cc
index afe5a1f..02e1700 100644
--- a/src/v8/src/base/utils/random-number-generator.cc
+++ b/src/v8/src/base/utils/random-number-generator.cc
@@ -4,8 +4,10 @@
 
 #include "src/base/utils/random-number-generator.h"
 
+#if !V8_OS_STARBOARD
 #include <stdio.h>
 #include <stdlib.h>
+#endif  // !V8_OS_STARBOARD
 
 #include <algorithm>
 #include <new>
@@ -41,7 +43,9 @@
     }
   }
 
-#if V8_OS_CYGWIN || V8_OS_WIN
+#if V8_OS_STARBOARD
+  SetSeed(SbSystemGetRandomUInt64());
+#elif V8_OS_CYGWIN || V8_OS_WIN
   // Use rand_s() to gather entropy on Windows. See:
   // https://code.google.com/p/v8/issues/detail?id=2905
   unsigned first_half, second_half;
diff --git a/src/v8/src/flag-definitions.h b/src/v8/src/flag-definitions.h
index 71e33ac..e40e182 100644
--- a/src/v8/src/flag-definitions.h
+++ b/src/v8/src/flag-definitions.h
@@ -612,11 +612,7 @@
 DEFINE_INT(random_gc_interval, 0,
            "Collect garbage after random(0, X) allocations. It overrides "
            "gc_interval.")
-#if defined(COBALT_GC_ZEAL)
-DEFINE_INT(gc_interval, 1200, "garbage collect after <n> allocations")
-#else
 DEFINE_INT(gc_interval, -1, "garbage collect after <n> allocations")
-#endif
 DEFINE_INT(retain_maps_for_n_gc, 2,
            "keeps maps alive for <n> old space garbage collections")
 DEFINE_BOOL(trace_gc, false,
@@ -641,21 +637,11 @@
 DEFINE_BOOL(trace_mutator_utilization, false,
             "print mutator utilization, allocation speed, gc speed")
 DEFINE_BOOL(incremental_marking, true, "use incremental marking")
-#if defined(COBALT)
-// Cobalt's TraceMembers and ScriptValue::*Reference do not currently support
-// incremental tracing.
-DEFINE_BOOL(incremental_marking_wrappers, false,
-            "use incremental marking for marking wrappers")
-#else  // defined(COBALT)
 DEFINE_BOOL(incremental_marking_wrappers, true,
             "use incremental marking for marking wrappers")
-#endif  // defined(COBALT)
 DEFINE_BOOL(parallel_scavenge, true, "parallel scavenge")
 DEFINE_BOOL(trace_parallel_scavenge, false, "trace parallel scavenge")
-#if defined(COBALT)
-// Starboard disallow rwx memory access.
-DEFINE_BOOL(write_protect_code_memory, true, "write protect code memory")
-#endif
+DEFINE_BOOL(write_protect_code_memory, false, "write protect code memory")
 #ifdef V8_CONCURRENT_MARKING
 #define V8_CONCURRENT_MARKING_BOOL true
 #else
diff --git a/src/v8/src/flags.cc b/src/v8/src/flags.cc
index 693e514..1d3f663 100644
--- a/src/v8/src/flags.cc
+++ b/src/v8/src/flags.cc
@@ -498,7 +498,11 @@
 
   if (FLAG_help) {
     PrintHelp();
+#if V8_OS_STARBOARD
+    SbSystemRequestStop(0);
+#else
     exit(0);
+#endif
   }
   // parsed all flags successfully
   return return_code;
diff --git a/src/v8/src/inspector/v8-debugger.cc b/src/v8/src/inspector/v8-debugger.cc
index c86f320..9736b51 100644
--- a/src/v8/src/inspector/v8-debugger.cc
+++ b/src/v8/src/inspector/v8-debugger.cc
@@ -17,6 +17,10 @@
 
 #include "include/v8-util.h"
 
+#if V8_OS_STARBOARD
+#include "starboard/log.h"
+#endif
+
 namespace v8_inspector {
 
 namespace {
@@ -1049,10 +1053,14 @@
 }
 
 void V8Debugger::dumpAsyncTaskStacksStateForTest() {
+#if V8_OS_STARBOARD
+  SB_NOTIMPLEMENTED();
+#else
   fprintf(stdout, "Async stacks count: %d\n", m_asyncStacksCount);
   fprintf(stdout, "Scheduled async tasks: %zu\n", m_asyncTaskStacks.size());
   fprintf(stdout, "Recurring async tasks: %zu\n", m_recurringTasks.size());
   fprintf(stdout, "\n");
+#endif
 }
 
 }  // namespace v8_inspector
diff --git a/src/v8/src/isolate.cc b/src/v8/src/isolate.cc
index e5df1f3..63165eb 100644
--- a/src/v8/src/isolate.cc
+++ b/src/v8/src/isolate.cc
@@ -4,7 +4,9 @@
 
 #include "src/isolate.h"
 
+#if !V8_OS_STARBOARD
 #include <stdlib.h>
+#endif  // V8_OS_STARBOARD
 
 #include <fstream>  // NOLINT(readability/streams)
 #include <sstream>
@@ -1130,6 +1132,9 @@
   Handle<Object> exception_handle(exception, this);
 
   if (FLAG_print_all_exceptions) {
+#if V8_OS_STARBOARD
+    SB_NOTIMPLEMENTED();
+#else
     printf("=========================================================\n");
     printf("Exception thrown:\n");
     if (location) {
@@ -1160,6 +1165,7 @@
     printf("Stack Trace:\n");
     PrintStack(stdout);
     printf("=========================================================\n");
+#endif  // V8_OS_STARBOARD
   }
 
   // Determine whether a message needs to be created for the given exception
diff --git a/src/v8/src/isolate.h b/src/v8/src/isolate.h
index 8eca55f..735a873 100644
--- a/src/v8/src/isolate.h
+++ b/src/v8/src/isolate.h
@@ -1863,6 +1863,9 @@
   };
 
   void OpenFile() {
+#if V8_OS_STARBOARD
+    SB_NOTIMPLEMENTED();
+#else
     if (!ShouldRedirect()) {
       return;
     }
@@ -1872,9 +1875,13 @@
     }
 
     scope_depth_++;
+#endif
   }
 
   void CloseFile() {
+#if V8_OS_STARBOARD
+    SB_NOTIMPLEMENTED();
+#else
     if (!ShouldRedirect()) {
       return;
     }
@@ -1883,6 +1890,7 @@
       fclose(file_);
       file_ = nullptr;
     }
+#endif
   }
 
   FILE* file() const { return file_; }
diff --git a/src/v8/src/log-utils.cc b/src/v8/src/log-utils.cc
index 938a84b..1f88dd5 100644
--- a/src/v8/src/log-utils.cc
+++ b/src/v8/src/log-utils.cc
@@ -11,6 +11,10 @@
 #include "src/utils.h"
 #include "src/version.h"
 
+#if V8_OS_STARBOARD
+#include "starboard/log.h"
+#endif
+
 namespace v8 {
 namespace internal {
 
@@ -66,6 +70,9 @@
 
 FILE* Log::Close() {
   FILE* result = nullptr;
+#if V8_OS_STARBOARD
+  SB_NOTIMPLEMENTED();
+#else
   if (output_handle_ != nullptr) {
     if (strcmp(FLAG_logfile, kLogToTemporaryFile) != 0) {
       fclose(output_handle_);
@@ -73,6 +80,7 @@
       result = output_handle_;
     }
   }
+#endif
   output_handle_ = nullptr;
 
   DeleteArray(format_buffer_);
diff --git a/src/v8/src/log-utils.h b/src/v8/src/log-utils.h
index feb14ea..5ca7113 100644
--- a/src/v8/src/log-utils.h
+++ b/src/v8/src/log-utils.h
@@ -5,7 +5,9 @@
 #ifndef V8_LOG_UTILS_H_
 #define V8_LOG_UTILS_H_
 
+#if !V8_OS_STARBOARD
 #include <stdio.h>
+#endif
 
 #include <cstdarg>
 
diff --git a/src/v8/src/log.cc b/src/v8/src/log.cc
index f5d5be6..dc02dd3 100644
--- a/src/v8/src/log.cc
+++ b/src/v8/src/log.cc
@@ -208,6 +208,7 @@
 }
 
 
+#if !V8_OS_STARBOARD
 // Linux perf tool logging support
 class PerfBasicLogger : public CodeEventLogger {
  public:
@@ -407,6 +408,7 @@
 
   LogWriteBytes(&tag, sizeof(tag));
 }
+#endif  // V8_OS_STARBOARD
 
 class JitLogger : public CodeEventLogger {
  public:
@@ -1756,6 +1758,7 @@
   PrepareLogFileName(log_file_name, isolate, FLAG_logfile);
   log_ = new Log(this, log_file_name.str().c_str());
 
+#if !V8_OS_STARBOARD
   if (FLAG_perf_basic_prof) {
     perf_basic_logger_ = new PerfBasicLogger();
     addCodeEventListener(perf_basic_logger_);
@@ -1770,6 +1773,7 @@
     ll_logger_ = new LowLevelLogger(log_file_name.str().c_str());
     addCodeEventListener(ll_logger_);
   }
+#endif  // !V8_OS_STARBOARD
 
   ticker_ = new Ticker(isolate, FLAG_prof_sampling_interval);
 
@@ -1846,11 +1850,13 @@
   delete ticker_;
   ticker_ = nullptr;
 
+#if !V8_OS_STARBOARD
   if (perf_basic_logger_) {
     removeCodeEventListener(perf_basic_logger_);
     delete perf_basic_logger_;
     perf_basic_logger_ = nullptr;
   }
+#endif  // V8_OS_STARBOARD
 
   if (perf_jit_logger_) {
     removeCodeEventListener(perf_jit_logger_);
@@ -1858,11 +1864,13 @@
     perf_jit_logger_ = nullptr;
   }
 
+#if !V8_OS_STARBOARD
   if (ll_logger_) {
     removeCodeEventListener(ll_logger_);
     delete ll_logger_;
     ll_logger_ = nullptr;
   }
+#endif  // V8_OS_STARBOARD
 
   if (jit_logger_) {
     removeCodeEventListener(jit_logger_);
diff --git a/src/v8/src/ostreams.cc b/src/v8/src/ostreams.cc
index 66b5702..0ff861f 100644
--- a/src/v8/src/ostreams.cc
+++ b/src/v8/src/ostreams.cc
@@ -12,6 +12,10 @@
 #endif
 #endif
 
+#if V8_OS_STARBOARD
+#include "src/poems.h"
+#endif
+
 namespace v8 {
 namespace internal {
 
@@ -22,19 +26,29 @@
 
 
 int OFStreamBase::sync() {
+#if !V8_OS_STARBOARD
   std::fflush(f_);
+#endif
   return 0;
 }
 
 
 OFStreamBase::int_type OFStreamBase::overflow(int_type c) {
+#if V8_OS_STARBOARD
+  return c;
+#else
   return (c != EOF) ? std::fputc(c, f_) : c;
+#endif
 }
 
 
 std::streamsize OFStreamBase::xsputn(const char* s, std::streamsize n) {
+#if V8_OS_STARBOARD
+  return n;
+#else
   return static_cast<std::streamsize>(
       std::fwrite(s, 1, static_cast<size_t>(n), f_));
+#endif
 }
 
 
diff --git a/src/v8/src/ostreams.h b/src/v8/src/ostreams.h
index f2f961e..61d07f1 100644
--- a/src/v8/src/ostreams.h
+++ b/src/v8/src/ostreams.h
@@ -5,9 +5,11 @@
 #ifndef V8_OSTREAMS_H_
 #define V8_OSTREAMS_H_
 
+#if !V8_OS_STARBOARD
 #include <cstddef>
 #include <cstdio>
 #include <cstring>
+#endif
 #include <ostream>  // NOLINT
 #include <streambuf>
 
diff --git a/src/v8/src/poems.h b/src/v8/src/poems.h
index c044558..91c7a98 100644
--- a/src/v8/src/poems.h
+++ b/src/v8/src/poems.h
@@ -36,5 +36,6 @@
 #define memcpy(x, y, z) SbMemoryCopy(x, y, z)
 #define calloc(x, y) SbMemoryCalloc(x, y)
 #define strdup(s) SbStringDuplicate(s)
+#define snprintf(a, b, c, ...) SbStringFormatF(a, b, c, __VA_ARGS__)
 
 #endif  // V8_POEMS_H_
diff --git a/src/v8/src/runtime/runtime-internal.cc b/src/v8/src/runtime/runtime-internal.cc
index f9e9375..22021c0 100644
--- a/src/v8/src/runtime/runtime-internal.cc
+++ b/src/v8/src/runtime/runtime-internal.cc
@@ -568,6 +568,10 @@
     isolate->counters()->runtime_call_stats()->Reset();
     return *result;
   } else {
+#if V8_OS_STARBOARD
+    SB_NOTIMPLEMENTED();
+    return isolate->heap()->undefined_value();
+#else
     DCHECK_LE(args.length(), 2);
     std::FILE* f;
     if (args[0]->IsString()) {
@@ -599,6 +603,7 @@
     else
       std::fflush(f);
     return isolate->heap()->undefined_value();
+#endif
   }
 }
 
diff --git a/src/v8/src/utils.cc b/src/v8/src/utils.cc
index a669c9f..6b01304 100644
--- a/src/v8/src/utils.cc
+++ b/src/v8/src/utils.cc
@@ -144,6 +144,7 @@
 }
 
 
+#if !V8_OS_STARBOARD
 void Flush(FILE* out) {
   fflush(out);
 }
@@ -246,6 +247,7 @@
   char* chars = ReadCharsFromFile(filename, size, 0, verbose);
   return reinterpret_cast<byte*>(chars);
 }
+#endif  // !V8_OS_STARBOARD
 
 
 static Vector<const char> SetVectorContents(char* chars,
@@ -261,6 +263,7 @@
 }
 
 
+#if !V8_OS_STARBOARD
 Vector<const char> ReadFile(const char* filename,
                             bool* exists,
                             bool verbose) {
@@ -277,9 +280,14 @@
   char* result = ReadCharsFromFile(file, &size, 1, verbose, "");
   return SetVectorContents(result, size, exists);
 }
+#endif  // !V8_OS_STARBOARD
 
 
 int WriteCharsToFile(const char* str, int size, FILE* f) {
+#if V8_OS_STARBOARD
+  SB_NOTIMPLEMENTED();
+  return size;
+#else  // V8_OS_STARBOARD
   int total = 0;
   while (total < size) {
     int write = static_cast<int>(fwrite(str, 1, size - total, f));
@@ -290,6 +298,7 @@
     str += write;
   }
   return total;
+#endif  // !V8_OS_STARBOARD
 }
 
 
@@ -297,6 +306,10 @@
                 const char* str,
                 int size,
                 bool verbose) {
+#if V8_OS_STARBOARD
+  SB_NOTIMPLEMENTED();
+  return size;
+#else  // V8_OS_STARBOARD
   FILE* f = base::OS::FOpen(filename, "ab");
   if (f == nullptr) {
     if (verbose) {
@@ -307,6 +320,7 @@
   int written = WriteCharsToFile(str, size, f);
   fclose(f);
   return written;
+#endif  // !V8_OS_STARBOARD
 }
 
 
@@ -314,6 +328,10 @@
                const char* str,
                int size,
                bool verbose) {
+#if V8_OS_STARBOARD
+  SB_NOTIMPLEMENTED();
+  return size;
+#else  // V8_OS_STARBOARD
   FILE* f = base::OS::FOpen(filename, "wb");
   if (f == nullptr) {
     if (verbose) {
@@ -324,6 +342,7 @@
   int written = WriteCharsToFile(str, size, f);
   fclose(f);
   return written;
+#endif  // !V8_OS_STARBOARD
 }
 
 
diff --git a/src/v8/src/wasm/memory-tracing.cc b/src/v8/src/wasm/memory-tracing.cc
index 75a790d..9294e3c 100644
--- a/src/v8/src/wasm/memory-tracing.cc
+++ b/src/v8/src/wasm/memory-tracing.cc
@@ -43,8 +43,13 @@
       eng_c = 'I';
       break;
   }
+#if V8_OS_STARBOARD
+  SbLogFormatF("%c %8d+0x%-6x %s @%08x %s\n", eng_c, func_index, position,
+         info->is_store ? "store" : "load ", info->address, value.start());
+#else
   printf("%c %8d+0x%-6x %s @%08x %s\n", eng_c, func_index, position,
          info->is_store ? "store" : "load ", info->address, value.start());
+#endif
 }
 
 }  // namespace wasm
diff --git a/src/v8/src/x64/disasm-x64.cc b/src/v8/src/x64/disasm-x64.cc
index 247f5e8..538f72b 100644
--- a/src/v8/src/x64/disasm-x64.cc
+++ b/src/v8/src/x64/disasm-x64.cc
@@ -2,9 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#if !V8_OS_STARBOARD
 #include <assert.h>
 #include <stdarg.h>
 #include <stdio.h>
+#endif
 
 #if V8_TARGET_ARCH_X64
 
@@ -2822,6 +2824,9 @@
 
 
 void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
+#if V8_OS_STARBOARD
+  SB_NOTIMPLEMENTED();
+#else
   NameConverter converter;
   Disassembler d(converter);
   for (byte* pc = begin; pc < end;) {
@@ -2840,6 +2845,7 @@
     }
     fprintf(f, "  %s\n", buffer.start());
   }
+#endif
 }
 
 }  // namespace disasm