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 ] ...@@ -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 # Failing WPT using ch unit in vertical orientation
crbug.com/759914 external/wpt/css/css-values/ch-unit-002.html [ WontFix ] 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). # CSS2 tests that rely on undefined behaviors (height of line-height: normal).
external/wpt/css/CSS2/linebox/inline-formatting-context-002.xht [ WontFix ] external/wpt/css/CSS2/linebox/inline-formatting-context-002.xht [ WontFix ]
[ Linux Win ] external/wpt/css/CSS2/linebox/inline-formatting-context-003.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 ] ...@@ -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-015.html [ Failure ]
crbug.com/669473 external/wpt/css/css-ui/outline-016.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/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/with-ports/001.html [ Failure ]
crbug.com/660384 external/wpt/webmessaging/without-ports/001.html [ Failure ] crbug.com/660384 external/wpt/webmessaging/without-ports/001.html [ Failure ]
......
...@@ -431,6 +431,8 @@ function run() { ...@@ -431,6 +431,8 @@ function run() {
should_apply("(orientation"); should_apply("(orientation");
should_not_apply("not all and (orientation"); should_not_apply("not all and (orientation");
should_not_apply("(orientation:"); should_not_apply("(orientation:");
should_not_apply("(orientation:)");
should_not_apply("(orientation: )");
should_apply("all,(orientation:"); should_apply("all,(orientation:");
should_not_apply("(orientation:,all"); should_not_apply("(orientation:,all");
should_apply("not all and (grid"); should_apply("not all and (grid");
......
This is a testharness.js-based test. 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?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?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) 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 ...@@ -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?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?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) 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?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?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) 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 ...@@ -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?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?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) 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?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?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) 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 ...@@ -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?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?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) 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?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?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) 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 ...@@ -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?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?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) 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?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?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) 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[] = { ...@@ -89,9 +89,11 @@ MediaQueryEvaluatorTestCase g_viewport_test_cases[] = {
{"(min-height: 501px)", 0}, {"(min-height: 501px)", 0},
{"(min-height: 500.02px)", 0}, {"(min-height: 500.02px)", 0},
{"(max-height: 500px)", 1}, {"(max-height: 500px)", 1},
{"(max-height: calc(500px))", 1},
{"(max-height: 499.98px)", 0}, {"(max-height: 499.98px)", 0},
{"(max-height: 499px)", 0}, {"(max-height: 499px)", 0},
{"(height: 500px)", 1}, {"(height: 500px)", 1},
{"(height: calc(500px))", 1},
{"(height: 500.001px)", 1}, {"(height: 500.001px)", 1},
{"(height: 499.999px)", 1}, {"(height: 499.999px)", 1},
{"(height: 500.02px)", 0}, {"(height: 500.02px)", 0},
...@@ -102,6 +104,7 @@ MediaQueryEvaluatorTestCase g_viewport_test_cases[] = { ...@@ -102,6 +104,7 @@ MediaQueryEvaluatorTestCase g_viewport_test_cases[] = {
{"(width: whatisthis)", 0}, {"(width: whatisthis)", 0},
{"screen and (min-width: 400px) and (max-width: 700px)", 1}, {"screen and (min-width: 400px) and (max-width: 700px)", 1},
{"(max-aspect-ratio: 4294967296/1)", 1}, {"(max-aspect-ratio: 4294967296/1)", 1},
{"(max-aspect-ratio: calc(4294967296) / calc(1)", 1},
{"(min-aspect-ratio: 1/4294967295)", 1}, {"(min-aspect-ratio: 1/4294967295)", 1},
{nullptr, 0} // Do not remove the terminator line. {nullptr, 0} // Do not remove the terminator line.
}; };
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
#include "core/css/MediaQueryExp.h" #include "core/css/MediaQueryExp.h"
#include "core/css/parser/CSSParserToken.h" #include "core/css/parser/CSSParserTokenRange.h"
#include "core/html/parser/HTMLParserIdioms.h" #include "core/html/parser/HTMLParserIdioms.h"
#include "platform/Decimal.h" #include "platform/Decimal.h"
#include "platform/runtime_enabled_features.h" #include "platform/runtime_enabled_features.h"
...@@ -74,11 +74,11 @@ static inline bool FeatureWithValidIdent(const String& media_feature, ...@@ -74,11 +74,11 @@ static inline bool FeatureWithValidIdent(const String& media_feature,
return false; return false;
} }
static inline bool FeatureWithValidPositiveLength(const String& media_feature, static inline bool FeatureWithValidPositiveLength(
const CSSParserToken& token) { const String& media_feature,
if (!(CSSPrimitiveValue::IsLength(token.GetUnitType()) || const CSSPrimitiveValue* value) {
(token.GetType() == kNumberToken && token.NumericValue() == 0)) || if (!(value->IsLength() ||
token.NumericValue() < 0) (value->IsNumber() && value->GetDoubleValue() == 0)))
return false; return false;
return media_feature == heightMediaFeature || return media_feature == heightMediaFeature ||
...@@ -96,12 +96,14 @@ static inline bool FeatureWithValidPositiveLength(const String& media_feature, ...@@ -96,12 +96,14 @@ static inline bool FeatureWithValidPositiveLength(const String& media_feature,
} }
static inline bool FeatureWithValidDensity(const String& media_feature, static inline bool FeatureWithValidDensity(const String& media_feature,
const CSSParserToken& token) { const CSSPrimitiveValue* value) {
if ((token.GetUnitType() != CSSPrimitiveValue::UnitType::kDotsPerPixel && if ((value->TypeWithCalcResolved() !=
token.GetUnitType() != CSSPrimitiveValue::UnitType::kDotsPerInch && CSSPrimitiveValue::UnitType::kDotsPerPixel &&
token.GetUnitType() != value->TypeWithCalcResolved() !=
CSSPrimitiveValue::UnitType::kDotsPerInch &&
value->TypeWithCalcResolved() !=
CSSPrimitiveValue::UnitType::kDotsPerCentimeter) || CSSPrimitiveValue::UnitType::kDotsPerCentimeter) ||
token.NumericValue() <= 0) value->GetDoubleValue() <= 0)
return false; return false;
return media_feature == resolutionMediaFeature || return media_feature == resolutionMediaFeature ||
...@@ -109,12 +111,8 @@ static inline bool FeatureWithValidDensity(const String& media_feature, ...@@ -109,12 +111,8 @@ static inline bool FeatureWithValidDensity(const String& media_feature,
media_feature == maxResolutionMediaFeature; media_feature == maxResolutionMediaFeature;
} }
static inline bool FeatureWithPositiveInteger(const String& media_feature, static inline bool FeatureExpectingPositiveInteger(
const CSSParserToken& token) { const String& media_feature) {
if (token.GetNumericValueType() != kIntegerValueType ||
token.NumericValue() < 0)
return false;
return media_feature == colorMediaFeature || return media_feature == colorMediaFeature ||
media_feature == maxColorMediaFeature || media_feature == maxColorMediaFeature ||
media_feature == minColorMediaFeature || media_feature == minColorMediaFeature ||
...@@ -126,9 +124,16 @@ static inline bool FeatureWithPositiveInteger(const String& media_feature, ...@@ -126,9 +124,16 @@ static inline bool FeatureWithPositiveInteger(const String& media_feature,
media_feature == minMonochromeMediaFeature; 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, static inline bool FeatureWithPositiveNumber(const String& media_feature,
const CSSParserToken& token) { const CSSPrimitiveValue* value) {
if (token.GetType() != kNumberToken || token.NumericValue() < 0) if (!value->IsNumber())
return false; return false;
return media_feature == transform3dMediaFeature || return media_feature == transform3dMediaFeature ||
...@@ -138,9 +143,9 @@ static inline bool FeatureWithPositiveNumber(const String& media_feature, ...@@ -138,9 +143,9 @@ static inline bool FeatureWithPositiveNumber(const String& media_feature,
} }
static inline bool FeatureWithZeroOrOne(const String& media_feature, static inline bool FeatureWithZeroOrOne(const String& media_feature,
const CSSParserToken& token) { const CSSPrimitiveValue* value) {
if (token.GetNumericValueType() != kIntegerValueType || if (value->TypeWithCalcResolved() != CSSPrimitiveValue::UnitType::kInteger ||
!(token.NumericValue() == 1 || !token.NumericValue())) !(value->GetDoubleValue() == 1 || !value->GetDoubleValue()))
return false; return false;
return media_feature == gridMediaFeature; return media_feature == gridMediaFeature;
...@@ -218,75 +223,63 @@ MediaQueryExp::MediaQueryExp(const String& media_feature, ...@@ -218,75 +223,63 @@ MediaQueryExp::MediaQueryExp(const String& media_feature,
const MediaQueryExpValue& exp_value) const MediaQueryExpValue& exp_value)
: media_feature_(media_feature), exp_value_(exp_value) {} : media_feature_(media_feature), exp_value_(exp_value) {}
MediaQueryExp MediaQueryExp::Create( MediaQueryExp MediaQueryExp::Create(const String& media_feature,
const String& media_feature, CSSParserTokenRange& range) {
const Vector<CSSParserToken, 4>& token_list) {
DCHECK(!media_feature.IsNull()); DCHECK(!media_feature.IsNull());
MediaQueryExpValue exp_value; MediaQueryExpValue exp_value;
String lower_media_feature = String lower_media_feature =
AttemptStaticStringCreation(media_feature.LowerASCII()); 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. // Create value for media query expression that must have 1 or more values.
if (token_list.size() == 0 && FeatureWithoutValue(lower_media_feature)) { if (value) {
// Valid, creates a MediaQueryExp with an 'invalid' MediaQueryExpValue if (FeatureWithAspectRatio(lower_media_feature)) {
} else if (token_list.size() == 1) { if (value->TypeWithCalcResolved() !=
CSSParserToken token = token_list.front(); CSSPrimitiveValue::UnitType::kInteger ||
value->GetDoubleValue() == 0)
if (token.GetType() == kIdentToken) {
CSSValueID ident = token.Id();
if (!FeatureWithValidIdent(lower_media_feature, ident))
return Invalid(); return Invalid();
exp_value.id = ident; if (!CSSPropertyParserHelpers::ConsumeSlashIncludingWhitespace(range))
exp_value.is_id = true; return Invalid();
} else if (token.GetType() == kNumberToken || CSSPrimitiveValue* denominator =
token.GetType() == kPercentageToken || CSSPropertyParserHelpers::ConsumePositiveInteger(range);
token.GetType() == kDimensionToken) { if (!denominator)
// 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 {
return Invalid(); 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 { } else {
return Invalid(); return Invalid();
} }
} else if (token_list.size() == 3 && } else if (CSSIdentifierValue* ident = CSSPropertyParserHelpers::ConsumeIdent(range)) {
FeatureWithAspectRatio(lower_media_feature)) { CSSValueID ident_id = ident->GetValueID();
// TODO(timloh): <ratio> is supposed to allow whitespace around the '/' if (!FeatureWithValidIdent(lower_media_feature, ident_id))
// 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() != '/')
return Invalid(); return Invalid();
if (numerator.GetType() != kNumberToken || numerator.NumericValue() <= 0 || exp_value.id = ident_id;
numerator.GetNumericValueType() != kIntegerValueType) exp_value.is_id = true;
return Invalid(); } else if (FeatureWithoutValue(lower_media_feature)) {
if (denominator.GetType() != kNumberToken || // Valid, creates a MediaQueryExp with an 'invalid' MediaQueryExpValue
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;
} else { } else {
return Invalid(); return Invalid();
} }
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include "core/css/CSSPrimitiveValue.h" #include "core/css/CSSPrimitiveValue.h"
#include "core/css/CSSValue.h" #include "core/css/CSSValue.h"
#include "core/css/media_feature_names.h" #include "core/css/media_feature_names.h"
#include "core/css/parser/CSSPropertyParserHelpers.h"
#include "platform/wtf/Allocator.h" #include "platform/wtf/Allocator.h"
namespace blink { namespace blink {
...@@ -82,7 +83,7 @@ class CORE_EXPORT MediaQueryExp { ...@@ -82,7 +83,7 @@ class CORE_EXPORT MediaQueryExp {
public: public:
// Returns an invalid MediaQueryExp if the arguments are invalid. // Returns an invalid MediaQueryExp if the arguments are invalid.
static MediaQueryExp Create(const String& media_feature, static MediaQueryExp Create(const String& media_feature,
const Vector<CSSParserToken, 4>&); CSSParserTokenRange&);
static MediaQueryExp Invalid() { static MediaQueryExp Invalid() {
return MediaQueryExp(String(), MediaQueryExpValue()); return MediaQueryExp(String(), MediaQueryExpValue());
} }
......
...@@ -68,16 +68,18 @@ void MediaQueryParser::SetStateAndRestrict( ...@@ -68,16 +68,18 @@ void MediaQueryParser::SetStateAndRestrict(
// State machine member functions start here // State machine member functions start here
void MediaQueryParser::ReadRestrictor(CSSParserTokenType type, void MediaQueryParser::ReadRestrictor(CSSParserTokenType type,
const CSSParserToken& token) { const CSSParserToken& token,
ReadMediaType(type, token); CSSParserTokenRange& range) {
ReadMediaType(type, token, range);
} }
void MediaQueryParser::ReadMediaNot(CSSParserTokenType type, void MediaQueryParser::ReadMediaNot(CSSParserTokenType type,
const CSSParserToken& token) { const CSSParserToken& token,
CSSParserTokenRange& range) {
if (type == kIdentToken && EqualIgnoringASCIICase(token.Value(), "not")) if (type == kIdentToken && EqualIgnoringASCIICase(token.Value(), "not"))
SetStateAndRestrict(kReadFeatureStart, MediaQuery::kNot); SetStateAndRestrict(kReadFeatureStart, MediaQuery::kNot);
else else
ReadFeatureStart(type, token); ReadFeatureStart(type, token, range);
} }
static bool IsRestrictorOrLogicalOperator(const CSSParserToken& token) { static bool IsRestrictorOrLogicalOperator(const CSSParserToken& token) {
...@@ -89,7 +91,8 @@ static bool IsRestrictorOrLogicalOperator(const CSSParserToken& token) { ...@@ -89,7 +91,8 @@ static bool IsRestrictorOrLogicalOperator(const CSSParserToken& token) {
} }
void MediaQueryParser::ReadMediaType(CSSParserTokenType type, void MediaQueryParser::ReadMediaType(CSSParserTokenType type,
const CSSParserToken& token) { const CSSParserToken& token,
CSSParserTokenRange& range) {
if (type == kLeftParenthesisToken) { if (type == kLeftParenthesisToken) {
if (media_query_data_.Restrictor() != MediaQuery::kNone) if (media_query_data_.Restrictor() != MediaQuery::kNone)
state_ = kSkipUntilComma; state_ = kSkipUntilComma;
...@@ -115,12 +118,13 @@ void MediaQueryParser::ReadMediaType(CSSParserTokenType type, ...@@ -115,12 +118,13 @@ void MediaQueryParser::ReadMediaType(CSSParserTokenType type,
} else { } else {
state_ = kSkipUntilComma; state_ = kSkipUntilComma;
if (type == kCommaToken) if (type == kCommaToken)
SkipUntilComma(type, token); SkipUntilComma(type, token, range);
} }
} }
void MediaQueryParser::ReadAnd(CSSParserTokenType type, void MediaQueryParser::ReadAnd(CSSParserTokenType type,
const CSSParserToken& token) { const CSSParserToken& token,
CSSParserTokenRange& range) {
if (type == kIdentToken && EqualIgnoringASCIICase(token.Value(), "and")) { if (type == kIdentToken && EqualIgnoringASCIICase(token.Value(), "and")) {
state_ = kReadFeatureStart; state_ = kReadFeatureStart;
} else if (type == kCommaToken && parser_type_ != kMediaConditionParser) { } else if (type == kCommaToken && parser_type_ != kMediaConditionParser) {
...@@ -134,7 +138,8 @@ void MediaQueryParser::ReadAnd(CSSParserTokenType type, ...@@ -134,7 +138,8 @@ void MediaQueryParser::ReadAnd(CSSParserTokenType type,
} }
void MediaQueryParser::ReadFeatureStart(CSSParserTokenType type, void MediaQueryParser::ReadFeatureStart(CSSParserTokenType type,
const CSSParserToken& token) { const CSSParserToken& token,
CSSParserTokenRange& range) {
if (type == kLeftParenthesisToken) if (type == kLeftParenthesisToken)
state_ = kReadFeature; state_ = kReadFeature;
else else
...@@ -142,7 +147,8 @@ void MediaQueryParser::ReadFeatureStart(CSSParserTokenType type, ...@@ -142,7 +147,8 @@ void MediaQueryParser::ReadFeatureStart(CSSParserTokenType type,
} }
void MediaQueryParser::ReadFeature(CSSParserTokenType type, void MediaQueryParser::ReadFeature(CSSParserTokenType type,
const CSSParserToken& token) { const CSSParserToken& token,
CSSParserTokenRange& range) {
if (type == kIdentToken) { if (type == kIdentToken) {
media_query_data_.SetMediaFeature(token.Value().ToString()); media_query_data_.SetMediaFeature(token.Value().ToString());
state_ = kReadFeatureColon; state_ = kReadFeatureColon;
...@@ -152,45 +158,53 @@ void MediaQueryParser::ReadFeature(CSSParserTokenType type, ...@@ -152,45 +158,53 @@ void MediaQueryParser::ReadFeature(CSSParserTokenType type,
} }
void MediaQueryParser::ReadFeatureColon(CSSParserTokenType type, void MediaQueryParser::ReadFeatureColon(CSSParserTokenType type,
const CSSParserToken& token) { const CSSParserToken& token,
if (type == kColonToken) CSSParserTokenRange& range) {
state_ = kReadFeatureValue; if (type == kColonToken) {
else if (type == kRightParenthesisToken || type == kEOFToken) while (range.Peek().GetType() == kWhitespaceToken)
ReadFeatureEnd(type, token); range.Consume();
else 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; state_ = kSkipUntilBlockEnd;
}
} }
void MediaQueryParser::ReadFeatureValue(CSSParserTokenType type, void MediaQueryParser::ReadFeatureValue(CSSParserTokenType type,
const CSSParserToken& token) { const CSSParserToken& token,
CSSParserTokenRange& range) {
if (type == kDimensionToken && if (type == kDimensionToken &&
token.GetUnitType() == CSSPrimitiveValue::UnitType::kUnknown) { token.GetUnitType() == CSSPrimitiveValue::UnitType::kUnknown) {
range.Consume();
state_ = kSkipUntilComma; state_ = kSkipUntilComma;
} else { } else {
if (media_query_data_.TryAddParserToken(type, token)) media_query_data_.AddExpression(range);
state_ = kReadFeatureEnd; state_ = kReadFeatureEnd;
else
state_ = kSkipUntilBlockEnd;
} }
} }
void MediaQueryParser::ReadFeatureEnd(CSSParserTokenType type, void MediaQueryParser::ReadFeatureEnd(CSSParserTokenType type,
const CSSParserToken& token) { const CSSParserToken& token,
CSSParserTokenRange& range) {
if (type == kRightParenthesisToken || type == kEOFToken) { if (type == kRightParenthesisToken || type == kEOFToken) {
if (media_query_data_.AddExpression()) if (media_query_data_.LastExpressionValid())
state_ = kReadAnd; state_ = kReadAnd;
else else
state_ = kSkipUntilComma; state_ = kSkipUntilComma;
} else if (type == kDelimiterToken && token.Delimiter() == '/') {
media_query_data_.TryAddParserToken(type, token);
state_ = kReadFeatureValue;
} else { } else {
media_query_data_.RemoveLastExpression();
state_ = kSkipUntilBlockEnd; state_ = kSkipUntilBlockEnd;
} }
} }
void MediaQueryParser::SkipUntilComma(CSSParserTokenType type, void MediaQueryParser::SkipUntilComma(CSSParserTokenType type,
const CSSParserToken& token) { const CSSParserToken& token,
CSSParserTokenRange& range) {
if ((type == kCommaToken && !block_watcher_.BlockLevel()) || if ((type == kCommaToken && !block_watcher_.BlockLevel()) ||
type == kEOFToken) { type == kEOFToken) {
state_ = kReadRestrictor; state_ = kReadRestrictor;
...@@ -200,14 +214,16 @@ void MediaQueryParser::SkipUntilComma(CSSParserTokenType type, ...@@ -200,14 +214,16 @@ void MediaQueryParser::SkipUntilComma(CSSParserTokenType type,
} }
void MediaQueryParser::SkipUntilBlockEnd(CSSParserTokenType type, void MediaQueryParser::SkipUntilBlockEnd(CSSParserTokenType type,
const CSSParserToken& token) { const CSSParserToken& token,
CSSParserTokenRange& range) {
if (token.GetBlockType() == CSSParserToken::kBlockEnd && if (token.GetBlockType() == CSSParserToken::kBlockEnd &&
!block_watcher_.BlockLevel()) !block_watcher_.BlockLevel())
state_ = kSkipUntilComma; state_ = kSkipUntilComma;
} }
void MediaQueryParser::Done(CSSParserTokenType type, void MediaQueryParser::Done(CSSParserTokenType type,
const CSSParserToken& token) {} const CSSParserToken& token,
CSSParserTokenRange& range) {}
void MediaQueryParser::HandleBlocks(const CSSParserToken& token) { void MediaQueryParser::HandleBlocks(const CSSParserToken& token) {
if (token.GetBlockType() == CSSParserToken::kBlockStart && if (token.GetBlockType() == CSSParserToken::kBlockStart &&
...@@ -215,26 +231,30 @@ void MediaQueryParser::HandleBlocks(const CSSParserToken& token) { ...@@ -215,26 +231,30 @@ void MediaQueryParser::HandleBlocks(const CSSParserToken& token) {
state_ = kSkipUntilBlockEnd; state_ = kSkipUntilBlockEnd;
} }
void MediaQueryParser::ProcessToken(const CSSParserToken& token) { void MediaQueryParser::ProcessToken(const CSSParserToken& token,
CSSParserTokenRange& range) {
CSSParserTokenType type = token.GetType(); CSSParserTokenType type = token.GetType();
HandleBlocks(token); if (state_ != kReadFeatureValue || type == kWhitespaceToken) {
block_watcher_.HandleToken(token); HandleBlocks(token);
block_watcher_.HandleToken(token);
range.Consume();
}
// Call the function that handles current state // Call the function that handles current state
if (type != kWhitespaceToken) if (type != kWhitespaceToken)
((this)->*(state_))(type, token); ((this)->*(state_))(type, token, range);
} }
// The state machine loop // The state machine loop
scoped_refptr<MediaQuerySet> MediaQueryParser::ParseImpl( scoped_refptr<MediaQuerySet> MediaQueryParser::ParseImpl(
CSSParserTokenRange range) { CSSParserTokenRange range) {
while (!range.AtEnd()) while (!range.AtEnd())
ProcessToken(range.Consume()); ProcessToken(range.Peek(), range);
// FIXME: Can we get rid of this special case? // FIXME: Can we get rid of this special case?
if (parser_type_ == kMediaQuerySetParser) if (parser_type_ == kMediaQuerySetParser)
ProcessToken(CSSParserToken(kEOFToken)); ProcessToken(CSSParserToken(kEOFToken), range);
if (state_ != kReadAnd && state_ != kReadRestrictor && state_ != kDone && if (state_ != kReadAnd && state_ != kReadRestrictor && state_ != kDone &&
state_ != kReadMediaNot) state_ != kReadMediaNot)
...@@ -255,7 +275,6 @@ void MediaQueryData::Clear() { ...@@ -255,7 +275,6 @@ void MediaQueryData::Clear() {
media_type_ = MediaTypeNames::all; media_type_ = MediaTypeNames::all;
media_type_set_ = false; media_type_set_ = false;
media_feature_ = String(); media_feature_ = String();
value_list_.clear();
expressions_.clear(); expressions_.clear();
} }
...@@ -266,23 +285,16 @@ std::unique_ptr<MediaQuery> MediaQueryData::TakeMediaQuery() { ...@@ -266,23 +285,16 @@ std::unique_ptr<MediaQuery> MediaQueryData::TakeMediaQuery() {
return media_query; return media_query;
} }
bool MediaQueryData::AddExpression() { void MediaQueryData::AddExpression(CSSParserTokenRange& range) {
MediaQueryExp expression = MediaQueryExp::Create(media_feature_, value_list_); expressions_.push_back(MediaQueryExp::Create(media_feature_, range));
expressions_.push_back(expression);
value_list_.clear();
return expression.IsValid();
} }
bool MediaQueryData::TryAddParserToken(CSSParserTokenType type, bool MediaQueryData::LastExpressionValid() {
const CSSParserToken& token) { return expressions_.back().IsValid();
if (type == kNumberToken || type == kPercentageToken || }
type == kDimensionToken || type == kDelimiterToken ||
type == kIdentToken) {
value_list_.push_back(token);
return true;
}
return false; void MediaQueryData::RemoveLastExpression() {
expressions_.pop_back();
} }
void MediaQueryData::SetMediaType(const String& media_type) { void MediaQueryData::SetMediaType(const String& media_type) {
......
...@@ -27,14 +27,14 @@ class MediaQueryData { ...@@ -27,14 +27,14 @@ class MediaQueryData {
String media_type_; String media_type_;
ExpressionHeapVector expressions_; ExpressionHeapVector expressions_;
String media_feature_; String media_feature_;
Vector<CSSParserToken, 4> value_list_;
bool media_type_set_; bool media_type_set_;
public: public:
MediaQueryData(); MediaQueryData();
void Clear(); void Clear();
bool AddExpression(); void AddExpression(CSSParserTokenRange&);
bool TryAddParserToken(CSSParserTokenType, const CSSParserToken&); bool LastExpressionValid();
void RemoveLastExpression();
void SetMediaType(const String&); void SetMediaType(const String&);
std::unique_ptr<MediaQuery> TakeMediaQuery(); std::unique_ptr<MediaQuery> TakeMediaQuery();
...@@ -71,23 +71,44 @@ class CORE_EXPORT MediaQueryParser { ...@@ -71,23 +71,44 @@ class CORE_EXPORT MediaQueryParser {
scoped_refptr<MediaQuerySet> ParseImpl(CSSParserTokenRange); scoped_refptr<MediaQuerySet> ParseImpl(CSSParserTokenRange);
void ProcessToken(const CSSParserToken&); void ProcessToken(const CSSParserToken&, CSSParserTokenRange&);
void ReadRestrictor(CSSParserTokenType, const CSSParserToken&); void ReadRestrictor(CSSParserTokenType,
void ReadMediaNot(CSSParserTokenType, const CSSParserToken&); const CSSParserToken&,
void ReadMediaType(CSSParserTokenType, const CSSParserToken&); CSSParserTokenRange&);
void ReadAnd(CSSParserTokenType, const CSSParserToken&); void ReadMediaNot(CSSParserTokenType,
void ReadFeatureStart(CSSParserTokenType, const CSSParserToken&); const CSSParserToken&,
void ReadFeature(CSSParserTokenType, const CSSParserToken&); CSSParserTokenRange&);
void ReadFeatureColon(CSSParserTokenType, const CSSParserToken&); void ReadMediaType(CSSParserTokenType,
void ReadFeatureValue(CSSParserTokenType, const CSSParserToken&); const CSSParserToken&,
void ReadFeatureEnd(CSSParserTokenType, const CSSParserToken&); CSSParserTokenRange&);
void SkipUntilComma(CSSParserTokenType, const CSSParserToken&); void ReadAnd(CSSParserTokenType, const CSSParserToken&, CSSParserTokenRange&);
void SkipUntilBlockEnd(CSSParserTokenType, const CSSParserToken&); void ReadFeatureStart(CSSParserTokenType,
void Done(CSSParserTokenType, const CSSParserToken&); 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, using State = void (MediaQueryParser::*)(CSSParserTokenType,
const CSSParserToken&); const CSSParserToken&,
CSSParserTokenRange&);
void SetStateAndRestrict(State, MediaQuery::RestrictorType); void SetStateAndRestrict(State, MediaQuery::RestrictorType);
void HandleBlocks(const CSSParserToken&); 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