Support range media query syntax

This commit is contained in:
Basilisk-Dev 2026-05-11 17:54:07 -04:00 committed by wuggy
commit 667a753448
4 changed files with 62 additions and 6 deletions

View file

@ -283,6 +283,10 @@ nsMediaExpression::Matches(nsPresContext *aPresContext,
return cmp != 1;
case nsMediaExpression::eEqual:
return cmp == 0;
case nsMediaExpression::eMinExclusive:
return cmp == 1;
case nsMediaExpression::eMaxExclusive:
return cmp == -1;
}
NS_NOTREACHED("unexpected mRange");
return false;
@ -487,7 +491,13 @@ nsMediaQuery::AppendToString(nsAString& aString) const
aString.Append(nsDependentAtomString(*feature->mName));
if (expr.mValue.GetUnit() != eCSSUnit_Null) {
aString.AppendLiteral(": ");
if (expr.mRange == nsMediaExpression::eMinExclusive) {
aString.AppendLiteral(" > ");
} else if (expr.mRange == nsMediaExpression::eMaxExclusive) {
aString.AppendLiteral(" < ");
} else {
aString.AppendLiteral(": ");
}
switch (feature->mValueType) {
case nsMediaFeature::eLength:
NS_ASSERTION(expr.mValue.IsLengthUnit(), "bad unit");

View file

@ -3845,9 +3845,7 @@ CSSParserImpl::ParseMediaQueryExpression(nsMediaQuery* aQuery)
break;
}
}
if (!feature->mName ||
(expr->mRange != nsMediaExpression::eEqual &&
feature->mRangeType != nsMediaFeature::eMinMaxAllowed)) {
if (!feature->mName) {
REPORT_UNEXPECTED_TOKEN(PEMQExpectedFeatureName);
SkipUntil(')');
return false;
@ -3865,13 +3863,52 @@ CSSParserImpl::ParseMediaQueryExpression(nsMediaQuery* aQuery)
return true;
}
if (!mToken.IsSymbol(':')) {
bool usesRangeSyntax = false;
if (mToken.IsSymbol('<') || mToken.IsSymbol('>') || mToken.IsSymbol('=')) {
if (expr->mRange != nsMediaExpression::eEqual) {
REPORT_UNEXPECTED_TOKEN(PEMQExpectedFeatureNameEnd);
UngetToken();
SkipUntil(')');
return false;
}
usesRangeSyntax = true;
char16_t rangeSymbol = mToken.mSymbol;
bool inclusive = rangeSymbol == '=';
if (rangeSymbol != '=') {
if (!GetToken(true)) {
REPORT_UNEXPECTED_EOF(PEMQExpressionEOF);
return false;
}
if (mToken.IsSymbol('=')) {
inclusive = true;
} else {
UngetToken();
}
}
if (rangeSymbol == '>') {
expr->mRange = inclusive ? nsMediaExpression::eMin
: nsMediaExpression::eMinExclusive;
} else if (rangeSymbol == '<') {
expr->mRange = inclusive ? nsMediaExpression::eMax
: nsMediaExpression::eMaxExclusive;
}
} else if (!mToken.IsSymbol(':')) {
REPORT_UNEXPECTED_TOKEN(PEMQExpectedFeatureNameEnd);
UngetToken();
SkipUntil(')');
return false;
}
if ((expr->mRange != nsMediaExpression::eEqual || usesRangeSyntax) &&
feature->mRangeType != nsMediaFeature::eMinMaxAllowed) {
REPORT_UNEXPECTED_TOKEN(PEMQExpectedFeatureName);
SkipUntil(')');
return false;
}
bool rv = false;
switch (feature->mValueType) {
case nsMediaFeature::eLength:

View file

@ -33,7 +33,7 @@ class DocumentRule;
} // namespace mozilla
struct nsMediaExpression {
enum Range { eMin, eMax, eEqual };
enum Range { eMin, eMax, eEqual, eMinExclusive, eMaxExclusive };
const nsMediaFeature *mFeature;
Range mRange;

View file

@ -290,6 +290,12 @@ function run() {
should_apply("all and (max-" + feature + ": " + value + "px)");
should_apply("all and (max-" + feature + ": " + (value + 1) + "px)");
should_not_apply("all and (max-" + feature + ": " + (value - 1) + "px)");
should_apply("all and (" + feature + " >= " + value + "px)");
should_not_apply("all and (" + feature + " > " + value + "px)");
should_apply("all and (" + feature + " > " + (value - 1) + "px)");
should_apply("all and (" + feature + " <= " + value + "px)");
should_not_apply("all and (" + feature + " < " + value + "px)");
should_apply("all and (" + feature + " < " + (value + 1) + "px)");
should_not_apply("all and (min-" + feature + ": " +
(Math.ceil(value/em_size) + 1) + "em)");
should_apply("all and (min-" + feature + ": " +
@ -349,6 +355,9 @@ function run() {
should_apply("(orientation: landscape)");
should_not_apply("(orientation: portrait)");
should_apply("not all and (orientation: portrait)");
expression_should_not_be_parseable("orientation > landscape");
expression_should_not_be_parseable("min-width > 1px");
expression_should_not_be_parseable("width >");
// ratio that reduces to 59/80
change_state(function() {
iframe_style.height = "320px";