Commit 5e7c6952 authored by Chris Nardi's avatar Chris Nardi Committed by Commit Bot

Support calc() in media queries

calc() was previously unsupported in CSS media queries. This change adds
in support for parsing calc() values in media queries, transitioning
MediaQueryExp.cpp to use CSSParserHelpers functions instead of bare
CSSParserTokens.

Bug: 421909
Change-Id: I81fea4dc6c70caaab79874722f114d261c26c886
Reviewed-on: https://chromium-review.googlesource.com/884571Reviewed-by: default avatarEric Willigers <ericwilligers@chromium.org>
Commit-Queue: Chris Nardi <cnardi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#531825}
parent b8d03518
......@@ -151,10 +151,6 @@ crbug.com/246571 external/wpt/css/css-values/attr-px-valid.html [ WontFix ]
# Failing WPT using ch unit in vertical orientation
crbug.com/759914 external/wpt/css/css-values/ch-unit-002.html [ WontFix ]
# Media queries do not support calc() for internal CSS length values
crbug.com/421909 external/wpt/css/css-values/calc-in-media-queries-001.html [ WontFix ]
crbug.com/421909 external/wpt/css/css-values/calc-in-media-queries-002.html [ WontFix ]
# CSS2 tests that rely on undefined behaviors (height of line-height: normal).
external/wpt/css/CSS2/linebox/inline-formatting-context-002.xht [ WontFix ]
[ Linux Win ] external/wpt/css/CSS2/linebox/inline-formatting-context-003.xht [ WontFix ]
......
......@@ -2427,13 +2427,6 @@ crbug.com/669473 external/wpt/css/css-ui/outline-014.html [ Failure ]
crbug.com/669473 external/wpt/css/css-ui/outline-015.html [ Failure ]
crbug.com/669473 external/wpt/css/css-ui/outline-016.html [ Failure ]
# Media queries do not support calc() for internal CSS length values.
crbug.com/421909 external/wpt/css/mediaqueries/mq-calc-001.html [ Failure ]
crbug.com/421909 external/wpt/css/mediaqueries/mq-calc-002.html [ Failure ]
crbug.com/421909 external/wpt/css/mediaqueries/mq-calc-003.html [ Failure ]
crbug.com/421909 external/wpt/css/mediaqueries/mq-calc-004.html [ Failure ]
crbug.com/421909 external/wpt/css/mediaqueries/mq-calc-005.html [ Failure ]
crbug.com/670024 external/wpt/webmessaging/broadcastchannel/sandbox.html [ Failure ]
crbug.com/660384 external/wpt/webmessaging/with-ports/001.html [ Failure ]
crbug.com/660384 external/wpt/webmessaging/without-ports/001.html [ Failure ]
......
......@@ -431,6 +431,8 @@ function run() {
should_apply("(orientation");
should_not_apply("not all and (orientation");
should_not_apply("(orientation:");
should_not_apply("(orientation:)");
should_not_apply("(orientation: )");
should_apply("all,(orientation:");
should_not_apply("(orientation:,all");
should_apply("not all and (grid");
......
This is a testharness.js-based test.
Found 640 tests; 608 PASS, 32 FAIL, 0 TIMEOUT, 0 NOTRUN.
Found 640 tests; 612 PASS, 28 FAIL, 0 TIMEOUT, 0 NOTRUN.
PASS <img srcset="/images/green-1x1.png?a2 300w, /images/green-16x16.png?a2 301w"> ref sizes="100vw" (standards mode)
PASS <img srcset="/images/green-1x1.png?b2 450w, /images/green-16x16.png?b2 451w"> ref sizes="100vw" (standards mode)
PASS <img srcset="/images/green-1x1.png?c2 600w, /images/green-16x16.png?c2 601w"> ref sizes="100vw" (standards mode)
......@@ -40,7 +40,7 @@ PASS <img srcset="/images/green-1x1.png?e34 50w, /images/green-16x16.png?e34 51w
PASS <img srcset="/images/green-1x1.png?e35 50w, /images/green-16x16.png?e35 51w" sizes="1\p\x"> ref sizes="1px" (standards mode)
PASS <img srcset="/images/green-1x1.png?e36 50w, /images/green-16x16.png?e36 51w" sizes="calc(1px)"> ref sizes="1px" (standards mode)
PASS <img srcset="/images/green-1x1.png?e37 50w, /images/green-16x16.png?e37 51w" sizes="(min-width:0) calc(1px)"> ref sizes="1px" (standards mode)
FAIL <img srcset="/images/green-1x1.png?e38 50w, /images/green-16x16.png?e38 51w" sizes="(min-width:calc(0)) 1px"> ref sizes="1px" (standards mode) assert_equals: expected "http://web-platform.test:8001/images/green-1x1.png" but got "http://web-platform.test:8001/images/green-16x16.png"
PASS <img srcset="/images/green-1x1.png?e38 50w, /images/green-16x16.png?e38 51w" sizes="(min-width:calc(0)) 1px"> ref sizes="1px" (standards mode)
PASS <img srcset="/images/green-1x1.png?e39 50w, /images/green-16x16.png?e39 51w" sizes="(min-width:0) 1px, 100vw"> ref sizes="1px" (standards mode)
PASS <img srcset="/images/green-1x1.png?e40 50w, /images/green-16x16.png?e40 51w" sizes="(min-width:0) 1px, (min-width:0) 100vw, 100vw"> ref sizes="1px" (standards mode)
PASS <img srcset="/images/green-1x1.png?e41 50w, /images/green-16x16.png?e41 51w" sizes="(min-width:0) 1px"> ref sizes="1px" (standards mode)
......@@ -200,7 +200,7 @@ PASS <img srcset="/images/green-1x1.png?e34 50w, /images/green-16x16.png?e34 51w
PASS <img srcset="/images/green-1x1.png?e35 50w, /images/green-16x16.png?e35 51w" sizes="1\p\x"> ref sizes="1px" (quirks mode)
PASS <img srcset="/images/green-1x1.png?e36 50w, /images/green-16x16.png?e36 51w" sizes="calc(1px)"> ref sizes="1px" (quirks mode)
PASS <img srcset="/images/green-1x1.png?e37 50w, /images/green-16x16.png?e37 51w" sizes="(min-width:0) calc(1px)"> ref sizes="1px" (quirks mode)
FAIL <img srcset="/images/green-1x1.png?e38 50w, /images/green-16x16.png?e38 51w" sizes="(min-width:calc(0)) 1px"> ref sizes="1px" (quirks mode) assert_equals: expected "http://web-platform.test:8001/images/green-1x1.png" but got "http://web-platform.test:8001/images/green-16x16.png"
PASS <img srcset="/images/green-1x1.png?e38 50w, /images/green-16x16.png?e38 51w" sizes="(min-width:calc(0)) 1px"> ref sizes="1px" (quirks mode)
PASS <img srcset="/images/green-1x1.png?e39 50w, /images/green-16x16.png?e39 51w" sizes="(min-width:0) 1px, 100vw"> ref sizes="1px" (quirks mode)
PASS <img srcset="/images/green-1x1.png?e40 50w, /images/green-16x16.png?e40 51w" sizes="(min-width:0) 1px, (min-width:0) 100vw, 100vw"> ref sizes="1px" (quirks mode)
PASS <img srcset="/images/green-1x1.png?e41 50w, /images/green-16x16.png?e41 51w" sizes="(min-width:0) 1px"> ref sizes="1px" (quirks mode)
......@@ -360,7 +360,7 @@ PASS <img srcset="/images/green-1x1.png?e34 50w, /images/green-16x16.png?e34 51w
PASS <img srcset="/images/green-1x1.png?e35 50w, /images/green-16x16.png?e35 51w" sizes="1\p\x"> ref sizes="1px" (display:none)
PASS <img srcset="/images/green-1x1.png?e36 50w, /images/green-16x16.png?e36 51w" sizes="calc(1px)"> ref sizes="1px" (display:none)
PASS <img srcset="/images/green-1x1.png?e37 50w, /images/green-16x16.png?e37 51w" sizes="(min-width:0) calc(1px)"> ref sizes="1px" (display:none)
FAIL <img srcset="/images/green-1x1.png?e38 50w, /images/green-16x16.png?e38 51w" sizes="(min-width:calc(0)) 1px"> ref sizes="1px" (display:none) assert_equals: expected "http://web-platform.test:8001/images/green-1x1.png" but got "http://web-platform.test:8001/images/green-16x16.png"
PASS <img srcset="/images/green-1x1.png?e38 50w, /images/green-16x16.png?e38 51w" sizes="(min-width:calc(0)) 1px"> ref sizes="1px" (display:none)
PASS <img srcset="/images/green-1x1.png?e39 50w, /images/green-16x16.png?e39 51w" sizes="(min-width:0) 1px, 100vw"> ref sizes="1px" (display:none)
PASS <img srcset="/images/green-1x1.png?e40 50w, /images/green-16x16.png?e40 51w" sizes="(min-width:0) 1px, (min-width:0) 100vw, 100vw"> ref sizes="1px" (display:none)
PASS <img srcset="/images/green-1x1.png?e41 50w, /images/green-16x16.png?e41 51w" sizes="(min-width:0) 1px"> ref sizes="1px" (display:none)
......@@ -520,7 +520,7 @@ PASS <img srcset="/images/green-1x1.png?e34 50w, /images/green-16x16.png?e34 51w
PASS <img srcset="/images/green-1x1.png?e35 50w, /images/green-16x16.png?e35 51w" sizes="1\p\x"> ref sizes="1px" (width:1000px)
PASS <img srcset="/images/green-1x1.png?e36 50w, /images/green-16x16.png?e36 51w" sizes="calc(1px)"> ref sizes="1px" (width:1000px)
PASS <img srcset="/images/green-1x1.png?e37 50w, /images/green-16x16.png?e37 51w" sizes="(min-width:0) calc(1px)"> ref sizes="1px" (width:1000px)
FAIL <img srcset="/images/green-1x1.png?e38 50w, /images/green-16x16.png?e38 51w" sizes="(min-width:calc(0)) 1px"> ref sizes="1px" (width:1000px) assert_equals: expected "http://web-platform.test:8001/images/green-1x1.png" but got "http://web-platform.test:8001/images/green-16x16.png"
PASS <img srcset="/images/green-1x1.png?e38 50w, /images/green-16x16.png?e38 51w" sizes="(min-width:calc(0)) 1px"> ref sizes="1px" (width:1000px)
PASS <img srcset="/images/green-1x1.png?e39 50w, /images/green-16x16.png?e39 51w" sizes="(min-width:0) 1px, 100vw"> ref sizes="1px" (width:1000px)
PASS <img srcset="/images/green-1x1.png?e40 50w, /images/green-16x16.png?e40 51w" sizes="(min-width:0) 1px, (min-width:0) 100vw, 100vw"> ref sizes="1px" (width:1000px)
PASS <img srcset="/images/green-1x1.png?e41 50w, /images/green-16x16.png?e41 51w" sizes="(min-width:0) 1px"> ref sizes="1px" (width:1000px)
......
......@@ -89,9 +89,11 @@ MediaQueryEvaluatorTestCase g_viewport_test_cases[] = {
{"(min-height: 501px)", 0},
{"(min-height: 500.02px)", 0},
{"(max-height: 500px)", 1},
{"(max-height: calc(500px))", 1},
{"(max-height: 499.98px)", 0},
{"(max-height: 499px)", 0},
{"(height: 500px)", 1},
{"(height: calc(500px))", 1},
{"(height: 500.001px)", 1},
{"(height: 499.999px)", 1},
{"(height: 500.02px)", 0},
......@@ -102,6 +104,7 @@ MediaQueryEvaluatorTestCase g_viewport_test_cases[] = {
{"(width: whatisthis)", 0},
{"screen and (min-width: 400px) and (max-width: 700px)", 1},
{"(max-aspect-ratio: 4294967296/1)", 1},
{"(max-aspect-ratio: calc(4294967296) / calc(1)", 1},
{"(min-aspect-ratio: 1/4294967295)", 1},
{nullptr, 0} // Do not remove the terminator line.
};
......
......@@ -29,7 +29,7 @@
#include "core/css/MediaQueryExp.h"
#include "core/css/parser/CSSParserToken.h"
#include "core/css/parser/CSSParserTokenRange.h"
#include "core/html/parser/HTMLParserIdioms.h"
#include "platform/Decimal.h"
#include "platform/runtime_enabled_features.h"
......@@ -74,11 +74,11 @@ static inline bool FeatureWithValidIdent(const String& media_feature,
return false;
}
static inline bool FeatureWithValidPositiveLength(const String& media_feature,
const CSSParserToken& token) {
if (!(CSSPrimitiveValue::IsLength(token.GetUnitType()) ||
(token.GetType() == kNumberToken && token.NumericValue() == 0)) ||
token.NumericValue() < 0)
static inline bool FeatureWithValidPositiveLength(
const String& media_feature,
const CSSPrimitiveValue* value) {
if (!(value->IsLength() ||
(value->IsNumber() && value->GetDoubleValue() == 0)))
return false;
return media_feature == heightMediaFeature ||
......@@ -96,12 +96,14 @@ static inline bool FeatureWithValidPositiveLength(const String& media_feature,
}
static inline bool FeatureWithValidDensity(const String& media_feature,
const CSSParserToken& token) {
if ((token.GetUnitType() != CSSPrimitiveValue::UnitType::kDotsPerPixel &&
token.GetUnitType() != CSSPrimitiveValue::UnitType::kDotsPerInch &&
token.GetUnitType() !=
const CSSPrimitiveValue* value) {
if ((value->TypeWithCalcResolved() !=
CSSPrimitiveValue::UnitType::kDotsPerPixel &&
value->TypeWithCalcResolved() !=
CSSPrimitiveValue::UnitType::kDotsPerInch &&
value->TypeWithCalcResolved() !=
CSSPrimitiveValue::UnitType::kDotsPerCentimeter) ||
token.NumericValue() <= 0)
value->GetDoubleValue() <= 0)
return false;
return media_feature == resolutionMediaFeature ||
......@@ -109,12 +111,8 @@ static inline bool FeatureWithValidDensity(const String& media_feature,
media_feature == maxResolutionMediaFeature;
}
static inline bool FeatureWithPositiveInteger(const String& media_feature,
const CSSParserToken& token) {
if (token.GetNumericValueType() != kIntegerValueType ||
token.NumericValue() < 0)
return false;
static inline bool FeatureExpectingPositiveInteger(
const String& media_feature) {
return media_feature == colorMediaFeature ||
media_feature == maxColorMediaFeature ||
media_feature == minColorMediaFeature ||
......@@ -126,9 +124,16 @@ static inline bool FeatureWithPositiveInteger(const String& media_feature,
media_feature == minMonochromeMediaFeature;
}
static inline bool FeatureWithPositiveInteger(const String& media_feature,
const CSSPrimitiveValue* value) {
if (value->TypeWithCalcResolved() != CSSPrimitiveValue::UnitType::kInteger)
return false;
return FeatureExpectingPositiveInteger(media_feature);
}
static inline bool FeatureWithPositiveNumber(const String& media_feature,
const CSSParserToken& token) {
if (token.GetType() != kNumberToken || token.NumericValue() < 0)
const CSSPrimitiveValue* value) {
if (!value->IsNumber())
return false;
return media_feature == transform3dMediaFeature ||
......@@ -138,9 +143,9 @@ static inline bool FeatureWithPositiveNumber(const String& media_feature,
}
static inline bool FeatureWithZeroOrOne(const String& media_feature,
const CSSParserToken& token) {
if (token.GetNumericValueType() != kIntegerValueType ||
!(token.NumericValue() == 1 || !token.NumericValue()))
const CSSPrimitiveValue* value) {
if (value->TypeWithCalcResolved() != CSSPrimitiveValue::UnitType::kInteger ||
!(value->GetDoubleValue() == 1 || !value->GetDoubleValue()))
return false;
return media_feature == gridMediaFeature;
......@@ -218,75 +223,63 @@ MediaQueryExp::MediaQueryExp(const String& media_feature,
const MediaQueryExpValue& exp_value)
: media_feature_(media_feature), exp_value_(exp_value) {}
MediaQueryExp MediaQueryExp::Create(
const String& media_feature,
const Vector<CSSParserToken, 4>& token_list) {
MediaQueryExp MediaQueryExp::Create(const String& media_feature,
CSSParserTokenRange& range) {
DCHECK(!media_feature.IsNull());
MediaQueryExpValue exp_value;
String lower_media_feature =
AttemptStaticStringCreation(media_feature.LowerASCII());
CSSPrimitiveValue* value = CSSPropertyParserHelpers::ConsumeInteger(range, 0);
if (!value && !FeatureExpectingPositiveInteger(lower_media_feature) &&
!FeatureWithAspectRatio(lower_media_feature))
value =
CSSPropertyParserHelpers::ConsumeNumber(range, kValueRangeNonNegative);
if (!value)
value = CSSPropertyParserHelpers::ConsumeLength(range, kHTMLStandardMode,
kValueRangeNonNegative);
if (!value)
value = CSSPropertyParserHelpers::ConsumeResolution(range);
// Create value for media query expression that must have 1 or more values.
if (token_list.size() == 0 && FeatureWithoutValue(lower_media_feature)) {
// Valid, creates a MediaQueryExp with an 'invalid' MediaQueryExpValue
} else if (token_list.size() == 1) {
CSSParserToken token = token_list.front();
if (token.GetType() == kIdentToken) {
CSSValueID ident = token.Id();
if (!FeatureWithValidIdent(lower_media_feature, ident))
if (value) {
if (FeatureWithAspectRatio(lower_media_feature)) {
if (value->TypeWithCalcResolved() !=
CSSPrimitiveValue::UnitType::kInteger ||
value->GetDoubleValue() == 0)
return Invalid();
exp_value.id = ident;
exp_value.is_id = true;
} else if (token.GetType() == kNumberToken ||
token.GetType() == kPercentageToken ||
token.GetType() == kDimensionToken) {
// Check for numeric token types since it is only safe for these types to
// call numericValue.
if (FeatureWithValidDensity(lower_media_feature, token) ||
FeatureWithValidPositiveLength(lower_media_feature, token)) {
// Media features that must have non-negative <density>, ie. dppx, dpi
// or dpcm, or Media features that must have non-negative <length> or
// number value.
exp_value.value = token.NumericValue();
exp_value.unit = token.GetUnitType();
exp_value.is_value = true;
} else if (FeatureWithPositiveInteger(lower_media_feature, token) ||
FeatureWithPositiveNumber(lower_media_feature, token) ||
FeatureWithZeroOrOne(lower_media_feature, token)) {
// Media features that must have non-negative integer value,
// or media features that must have non-negative number value,
// or media features that must have (0|1) value.
exp_value.value = token.NumericValue();
exp_value.unit = CSSPrimitiveValue::UnitType::kNumber;
exp_value.is_value = true;
} else {
if (!CSSPropertyParserHelpers::ConsumeSlashIncludingWhitespace(range))
return Invalid();
CSSPrimitiveValue* denominator =
CSSPropertyParserHelpers::ConsumePositiveInteger(range);
if (!denominator)
return Invalid();
}
exp_value.numerator = clampTo<unsigned>(value->GetDoubleValue());
exp_value.denominator = clampTo<unsigned>(denominator->GetDoubleValue());
exp_value.is_ratio = true;
} else if (FeatureWithValidDensity(lower_media_feature, value) ||
FeatureWithValidPositiveLength(lower_media_feature, value) ||
FeatureWithPositiveInteger(lower_media_feature, value) ||
FeatureWithPositiveNumber(lower_media_feature, value) ||
FeatureWithZeroOrOne(lower_media_feature, value)) {
exp_value.value = value->GetDoubleValue();
if (value->IsNumber())
exp_value.unit = CSSPrimitiveValue::UnitType::kNumber;
else
exp_value.unit = value->TypeWithCalcResolved();
exp_value.is_value = true;
} else {
return Invalid();
}
} else if (token_list.size() == 3 &&
FeatureWithAspectRatio(lower_media_feature)) {
// TODO(timloh): <ratio> is supposed to allow whitespace around the '/'
// Applicable to device-aspect-ratio and aspect-ratio.
const CSSParserToken& numerator = token_list[0];
const CSSParserToken& delimiter = token_list[1];
const CSSParserToken& denominator = token_list[2];
if (delimiter.GetType() != kDelimiterToken || delimiter.Delimiter() != '/')
} else if (CSSIdentifierValue* ident = CSSPropertyParserHelpers::ConsumeIdent(range)) {
CSSValueID ident_id = ident->GetValueID();
if (!FeatureWithValidIdent(lower_media_feature, ident_id))
return Invalid();
if (numerator.GetType() != kNumberToken || numerator.NumericValue() <= 0 ||
numerator.GetNumericValueType() != kIntegerValueType)
return Invalid();
if (denominator.GetType() != kNumberToken ||
denominator.NumericValue() <= 0 ||
denominator.GetNumericValueType() != kIntegerValueType)
return Invalid();
exp_value.numerator = clampTo<unsigned>(numerator.NumericValue());
exp_value.denominator = clampTo<unsigned>(denominator.NumericValue());
exp_value.is_ratio = true;
exp_value.id = ident_id;
exp_value.is_id = true;
} else if (FeatureWithoutValue(lower_media_feature)) {
// Valid, creates a MediaQueryExp with an 'invalid' MediaQueryExpValue
} else {
return Invalid();
}
......
......@@ -34,6 +34,7 @@
#include "core/css/CSSPrimitiveValue.h"
#include "core/css/CSSValue.h"
#include "core/css/media_feature_names.h"
#include "core/css/parser/CSSPropertyParserHelpers.h"
#include "platform/wtf/Allocator.h"
namespace blink {
......@@ -82,7 +83,7 @@ class CORE_EXPORT MediaQueryExp {
public:
// Returns an invalid MediaQueryExp if the arguments are invalid.
static MediaQueryExp Create(const String& media_feature,
const Vector<CSSParserToken, 4>&);
CSSParserTokenRange&);
static MediaQueryExp Invalid() {
return MediaQueryExp(String(), MediaQueryExpValue());
}
......
......@@ -68,16 +68,18 @@ void MediaQueryParser::SetStateAndRestrict(
// State machine member functions start here
void MediaQueryParser::ReadRestrictor(CSSParserTokenType type,
const CSSParserToken& token) {
ReadMediaType(type, token);
const CSSParserToken& token,
CSSParserTokenRange& range) {
ReadMediaType(type, token, range);
}
void MediaQueryParser::ReadMediaNot(CSSParserTokenType type,
const CSSParserToken& token) {
const CSSParserToken& token,
CSSParserTokenRange& range) {
if (type == kIdentToken && EqualIgnoringASCIICase(token.Value(), "not"))
SetStateAndRestrict(kReadFeatureStart, MediaQuery::kNot);
else
ReadFeatureStart(type, token);
ReadFeatureStart(type, token, range);
}
static bool IsRestrictorOrLogicalOperator(const CSSParserToken& token) {
......@@ -89,7 +91,8 @@ static bool IsRestrictorOrLogicalOperator(const CSSParserToken& token) {
}
void MediaQueryParser::ReadMediaType(CSSParserTokenType type,
const CSSParserToken& token) {
const CSSParserToken& token,
CSSParserTokenRange& range) {
if (type == kLeftParenthesisToken) {
if (media_query_data_.Restrictor() != MediaQuery::kNone)
state_ = kSkipUntilComma;
......@@ -115,12 +118,13 @@ void MediaQueryParser::ReadMediaType(CSSParserTokenType type,
} else {
state_ = kSkipUntilComma;
if (type == kCommaToken)
SkipUntilComma(type, token);
SkipUntilComma(type, token, range);
}
}
void MediaQueryParser::ReadAnd(CSSParserTokenType type,
const CSSParserToken& token) {
const CSSParserToken& token,
CSSParserTokenRange& range) {
if (type == kIdentToken && EqualIgnoringASCIICase(token.Value(), "and")) {
state_ = kReadFeatureStart;
} else if (type == kCommaToken && parser_type_ != kMediaConditionParser) {
......@@ -134,7 +138,8 @@ void MediaQueryParser::ReadAnd(CSSParserTokenType type,
}
void MediaQueryParser::ReadFeatureStart(CSSParserTokenType type,
const CSSParserToken& token) {
const CSSParserToken& token,
CSSParserTokenRange& range) {
if (type == kLeftParenthesisToken)
state_ = kReadFeature;
else
......@@ -142,7 +147,8 @@ void MediaQueryParser::ReadFeatureStart(CSSParserTokenType type,
}
void MediaQueryParser::ReadFeature(CSSParserTokenType type,
const CSSParserToken& token) {
const CSSParserToken& token,
CSSParserTokenRange& range) {
if (type == kIdentToken) {
media_query_data_.SetMediaFeature(token.Value().ToString());
state_ = kReadFeatureColon;
......@@ -152,45 +158,53 @@ void MediaQueryParser::ReadFeature(CSSParserTokenType type,
}
void MediaQueryParser::ReadFeatureColon(CSSParserTokenType type,
const CSSParserToken& token) {
if (type == kColonToken)
state_ = kReadFeatureValue;
else if (type == kRightParenthesisToken || type == kEOFToken)
ReadFeatureEnd(type, token);
else
const CSSParserToken& token,
CSSParserTokenRange& range) {
if (type == kColonToken) {
while (range.Peek().GetType() == kWhitespaceToken)
range.Consume();
if (range.Peek().GetType() == kRightParenthesisToken || type == kEOFToken)
state_ = kSkipUntilBlockEnd;
else
state_ = kReadFeatureValue;
} else if (type == kRightParenthesisToken || type == kEOFToken) {
media_query_data_.AddExpression(range);
ReadFeatureEnd(type, token, range);
} else {
state_ = kSkipUntilBlockEnd;
}
}
void MediaQueryParser::ReadFeatureValue(CSSParserTokenType type,
const CSSParserToken& token) {
const CSSParserToken& token,
CSSParserTokenRange& range) {
if (type == kDimensionToken &&
token.GetUnitType() == CSSPrimitiveValue::UnitType::kUnknown) {
range.Consume();
state_ = kSkipUntilComma;
} else {
if (media_query_data_.TryAddParserToken(type, token))
state_ = kReadFeatureEnd;
else
state_ = kSkipUntilBlockEnd;
media_query_data_.AddExpression(range);
state_ = kReadFeatureEnd;
}
}
void MediaQueryParser::ReadFeatureEnd(CSSParserTokenType type,
const CSSParserToken& token) {
const CSSParserToken& token,
CSSParserTokenRange& range) {
if (type == kRightParenthesisToken || type == kEOFToken) {
if (media_query_data_.AddExpression())
if (media_query_data_.LastExpressionValid())
state_ = kReadAnd;
else
state_ = kSkipUntilComma;
} else if (type == kDelimiterToken && token.Delimiter() == '/') {
media_query_data_.TryAddParserToken(type, token);
state_ = kReadFeatureValue;
} else {
media_query_data_.RemoveLastExpression();
state_ = kSkipUntilBlockEnd;
}
}
void MediaQueryParser::SkipUntilComma(CSSParserTokenType type,
const CSSParserToken& token) {
const CSSParserToken& token,
CSSParserTokenRange& range) {
if ((type == kCommaToken && !block_watcher_.BlockLevel()) ||
type == kEOFToken) {
state_ = kReadRestrictor;
......@@ -200,14 +214,16 @@ void MediaQueryParser::SkipUntilComma(CSSParserTokenType type,
}
void MediaQueryParser::SkipUntilBlockEnd(CSSParserTokenType type,
const CSSParserToken& token) {
const CSSParserToken& token,
CSSParserTokenRange& range) {
if (token.GetBlockType() == CSSParserToken::kBlockEnd &&
!block_watcher_.BlockLevel())
state_ = kSkipUntilComma;
}
void MediaQueryParser::Done(CSSParserTokenType type,
const CSSParserToken& token) {}
const CSSParserToken& token,
CSSParserTokenRange& range) {}
void MediaQueryParser::HandleBlocks(const CSSParserToken& token) {
if (token.GetBlockType() == CSSParserToken::kBlockStart &&
......@@ -215,26 +231,30 @@ void MediaQueryParser::HandleBlocks(const CSSParserToken& token) {
state_ = kSkipUntilBlockEnd;
}
void MediaQueryParser::ProcessToken(const CSSParserToken& token) {
void MediaQueryParser::ProcessToken(const CSSParserToken& token,
CSSParserTokenRange& range) {
CSSParserTokenType type = token.GetType();
HandleBlocks(token);
block_watcher_.HandleToken(token);
if (state_ != kReadFeatureValue || type == kWhitespaceToken) {
HandleBlocks(token);
block_watcher_.HandleToken(token);
range.Consume();
}
// Call the function that handles current state
if (type != kWhitespaceToken)
((this)->*(state_))(type, token);
((this)->*(state_))(type, token, range);
}
// The state machine loop
scoped_refptr<MediaQuerySet> MediaQueryParser::ParseImpl(
CSSParserTokenRange range) {
while (!range.AtEnd())
ProcessToken(range.Consume());
ProcessToken(range.Peek(), range);
// FIXME: Can we get rid of this special case?
if (parser_type_ == kMediaQuerySetParser)
ProcessToken(CSSParserToken(kEOFToken));
ProcessToken(CSSParserToken(kEOFToken), range);
if (state_ != kReadAnd && state_ != kReadRestrictor && state_ != kDone &&
state_ != kReadMediaNot)
......@@ -255,7 +275,6 @@ void MediaQueryData::Clear() {
media_type_ = MediaTypeNames::all;
media_type_set_ = false;
media_feature_ = String();
value_list_.clear();
expressions_.clear();
}
......@@ -266,23 +285,16 @@ std::unique_ptr<MediaQuery> MediaQueryData::TakeMediaQuery() {
return media_query;
}
bool MediaQueryData::AddExpression() {
MediaQueryExp expression = MediaQueryExp::Create(media_feature_, value_list_);
expressions_.push_back(expression);
value_list_.clear();
return expression.IsValid();
void MediaQueryData::AddExpression(CSSParserTokenRange& range) {
expressions_.push_back(MediaQueryExp::Create(media_feature_, range));
}
bool MediaQueryData::TryAddParserToken(CSSParserTokenType type,
const CSSParserToken& token) {
if (type == kNumberToken || type == kPercentageToken ||
type == kDimensionToken || type == kDelimiterToken ||
type == kIdentToken) {
value_list_.push_back(token);
return true;
}
bool MediaQueryData::LastExpressionValid() {
return expressions_.back().IsValid();
}
return false;
void MediaQueryData::RemoveLastExpression() {
expressions_.pop_back();
}
void MediaQueryData::SetMediaType(const String& media_type) {
......
......@@ -27,14 +27,14 @@ class MediaQueryData {
String media_type_;
ExpressionHeapVector expressions_;
String media_feature_;
Vector<CSSParserToken, 4> value_list_;
bool media_type_set_;
public:
MediaQueryData();
void Clear();
bool AddExpression();
bool TryAddParserToken(CSSParserTokenType, const CSSParserToken&);
void AddExpression(CSSParserTokenRange&);
bool LastExpressionValid();
void RemoveLastExpression();
void SetMediaType(const String&);
std::unique_ptr<MediaQuery> TakeMediaQuery();
......@@ -71,23 +71,44 @@ class CORE_EXPORT MediaQueryParser {
scoped_refptr<MediaQuerySet> ParseImpl(CSSParserTokenRange);
void ProcessToken(const CSSParserToken&);
void ReadRestrictor(CSSParserTokenType, const CSSParserToken&);
void ReadMediaNot(CSSParserTokenType, const CSSParserToken&);
void ReadMediaType(CSSParserTokenType, const CSSParserToken&);
void ReadAnd(CSSParserTokenType, const CSSParserToken&);
void ReadFeatureStart(CSSParserTokenType, const CSSParserToken&);
void ReadFeature(CSSParserTokenType, const CSSParserToken&);
void ReadFeatureColon(CSSParserTokenType, const CSSParserToken&);
void ReadFeatureValue(CSSParserTokenType, const CSSParserToken&);
void ReadFeatureEnd(CSSParserTokenType, const CSSParserToken&);
void SkipUntilComma(CSSParserTokenType, const CSSParserToken&);
void SkipUntilBlockEnd(CSSParserTokenType, const CSSParserToken&);
void Done(CSSParserTokenType, const CSSParserToken&);
void ProcessToken(const CSSParserToken&, CSSParserTokenRange&);
void ReadRestrictor(CSSParserTokenType,
const CSSParserToken&,
CSSParserTokenRange&);
void ReadMediaNot(CSSParserTokenType,
const CSSParserToken&,
CSSParserTokenRange&);
void ReadMediaType(CSSParserTokenType,
const CSSParserToken&,
CSSParserTokenRange&);
void ReadAnd(CSSParserTokenType, const CSSParserToken&, CSSParserTokenRange&);
void ReadFeatureStart(CSSParserTokenType,
const CSSParserToken&,
CSSParserTokenRange&);
void ReadFeature(CSSParserTokenType,
const CSSParserToken&,
CSSParserTokenRange&);
void ReadFeatureColon(CSSParserTokenType,
const CSSParserToken&,
CSSParserTokenRange&);
void ReadFeatureValue(CSSParserTokenType,
const CSSParserToken&,
CSSParserTokenRange&);
void ReadFeatureEnd(CSSParserTokenType,
const CSSParserToken&,
CSSParserTokenRange&);
void SkipUntilComma(CSSParserTokenType,
const CSSParserToken&,
CSSParserTokenRange&);
void SkipUntilBlockEnd(CSSParserTokenType,
const CSSParserToken&,
CSSParserTokenRange&);
void Done(CSSParserTokenType, const CSSParserToken&, CSSParserTokenRange&);
using State = void (MediaQueryParser::*)(CSSParserTokenType,
const CSSParserToken&);
const CSSParserToken&,
CSSParserTokenRange&);
void SetStateAndRestrict(State, MediaQuery::RestrictorType);
void HandleBlocks(const CSSParserToken&);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment