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