Bug 779917 - Implement CSS.supports(). r=dbaron f=bz

This commit is contained in:
Cameron McCormack 2012-11-25 11:26:07 +11:00
Родитель eaa651ac88
Коммит df75460fb8
10 изменённых файлов: 390 добавлений и 4 удалений

Просмотреть файл

@ -144,6 +144,10 @@ DOMInterfaces = {
'resultNotAddRefed': [ 'item' ]
},
'CSS': {
'concrete': False,
},
'CSS2Properties': {
'nativeType': 'nsDOMCSSDeclaration'
},

20
dom/webidl/CSS.webidl Normal file
Просмотреть файл

@ -0,0 +1,20 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* The origin of this IDL file is
* http://dev.w3.org/csswg/css3-conditional/
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
[PrefControlled]
interface CSS {
[Throws, Pref="layout.css.supports-rule.enabled"]
static boolean supports(DOMString property, DOMString value);
[Throws, Pref="layout.css.supports-rule.enabled"]
static boolean supports(DOMString conditionText);
};

Просмотреть файл

@ -21,6 +21,7 @@ webidl_files = \
Blob.webidl \
CanvasRenderingContext2D.webidl \
ClientRectList.webidl \
CSS.webidl \
CSSPrimitiveValue.webidl \
CSSStyleDeclaration.webidl \
CSSValue.webidl \

81
layout/style/CSS.cpp Normal file
Просмотреть файл

@ -0,0 +1,81 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* DOM object holding utility CSS functions */
#include "CSS.h"
#include "nsCSSParser.h"
#include "nsGlobalWindow.h"
#include "nsIDOMDocument.h"
#include "nsIDocument.h"
#include "nsIPrincipal.h"
#include "nsIURI.h"
namespace mozilla {
namespace dom {
struct SupportsParsingInfo
{
nsIURI* mDocURI;
nsIURI* mBaseURI;
nsIPrincipal* mPrincipal;
};
static nsresult
GetParsingInfo(nsISupports* aGlobal,
SupportsParsingInfo& aInfo)
{
nsGlobalWindow* win = nsGlobalWindow::FromSupports(aGlobal);
nsCOMPtr<nsIDocument> doc = win->GetDoc();
if (!doc) {
return NS_ERROR_FAILURE;
}
aInfo.mDocURI = nsCOMPtr<nsIURI>(doc->GetDocumentURI());
aInfo.mBaseURI = nsCOMPtr<nsIURI>(doc->GetBaseURI());
aInfo.mPrincipal = win->GetPrincipal();
return NS_OK;
}
/* static */ bool
CSS::Supports(nsISupports* aGlobal,
const nsAString& aProperty,
const nsAString& aValue,
ErrorResult& aRv)
{
nsCSSParser parser;
SupportsParsingInfo info;
nsresult rv = GetParsingInfo(aGlobal, info);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return false;
}
return parser.EvaluateSupportsDeclaration(aProperty, aValue, info.mDocURI,
info.mBaseURI, info.mPrincipal);
}
/* static */ bool
CSS::Supports(nsISupports* aGlobal,
const nsAString& aCondition,
ErrorResult& aRv)
{
nsCSSParser parser;
SupportsParsingInfo info;
nsresult rv = GetParsingInfo(aGlobal, info);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return false;
}
return parser.EvaluateSupportsCondition(aCondition, info.mDocURI,
info.mBaseURI, info.mPrincipal);
}
} // dom
} // mozilla

41
layout/style/CSS.h Normal file
Просмотреть файл

@ -0,0 +1,41 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* DOM object holding utility CSS functions */
#ifndef mozilla_dom_CSS_h_
#define mozilla_dom_CSS_h_
#include "mozilla/Attributes.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/Preferences.h"
namespace mozilla {
namespace dom {
class CSS {
private:
CSS() MOZ_DELETE;
public:
static bool Supports(nsISupports* aGlobal,
const nsAString& aProperty,
const nsAString& aValue,
ErrorResult& aRv);
static bool Supports(nsISupports* aGlobal,
const nsAString& aDeclaration,
ErrorResult& aRv);
static bool PrefEnabled()
{
return Preferences::GetBool("layout.css.supports-rule.enabled");
}
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_CSS_h_

Просмотреть файл

@ -43,7 +43,7 @@ EXPORTS = \
nsCSSValue.h \
nsDOMCSSAttrDeclaration.h \
nsDOMCSSDeclaration.h \
nsDOMCSSRGBColor.h \
nsDOMCSSRGBColor.h \
nsDOMMediaQueryList.h \
nsICSSDeclaration.h \
nsICSSLoaderObserver.h \
@ -83,11 +83,13 @@ EXPORTS_mozilla/css = \
$(NULL)
EXPORTS_mozilla/dom = \
CSSValue.h \
$(null)
CSS.h \
CSSValue.h \
$(NULL)
CPPSRCS = \
AnimationCommon.cpp \
CSS.cpp \
nsCSSAnonBoxes.cpp \
nsCSSDataBlock.cpp \
Declaration.cpp \
@ -140,6 +142,7 @@ include $(topsrcdir)/ipc/chromium/chromium-config.mk
LOCAL_INCLUDES += \
-I$(srcdir)/../base \
-I$(topsrcdir)/dom/base \
-I$(srcdir)/../generic \
-I$(srcdir)/../xul/base/src \
-I$(srcdir)/../../content/base/src \

Просмотреть файл

@ -229,6 +229,17 @@ public:
uint32_t aLineNumber, // for error reporting
InfallibleTArray<float>& aSelectorList);
bool EvaluateSupportsDeclaration(const nsAString& aProperty,
const nsAString& aValue,
nsIURI* aDocURL,
nsIURI* aBaseURL,
nsIPrincipal* aDocPrincipal);
bool EvaluateSupportsCondition(const nsAString& aCondition,
nsIURI* aDocURL,
nsIURI* aBaseURL,
nsIPrincipal* aDocPrincipal);
protected:
class nsAutoParseCompoundProperty;
friend class nsAutoParseCompoundProperty;
@ -299,7 +310,7 @@ protected:
class nsAutoSuppressErrors {
public:
nsAutoSuppressErrors(CSSParserImpl* aParser,
bool aSuppressErrors)
bool aSuppressErrors = true)
: mParser(aParser),
mOriginalValue(aParser->mSuppressErrors)
{
@ -1350,6 +1361,55 @@ CSSParserImpl::ParseKeyframeSelectorString(const nsSubstring& aSelectorString,
return success;
}
bool
CSSParserImpl::EvaluateSupportsDeclaration(const nsAString& aProperty,
const nsAString& aValue,
nsIURI* aDocURL,
nsIURI* aBaseURL,
nsIPrincipal* aDocPrincipal)
{
nsCSSProperty propID = nsCSSProps::LookupProperty(aProperty,
nsCSSProps::eEnabled);
if (propID == eCSSProperty_UNKNOWN) {
return false;
}
nsCSSScanner scanner(aValue, 0);
css::ErrorReporter reporter(scanner, mSheet, mChildLoader, aDocURL);
InitScanner(scanner, reporter, aDocURL, aBaseURL, aDocPrincipal);
nsAutoSuppressErrors suppressErrors(this);
bool parsedOK = ParseProperty(propID) && !GetToken(true);
CLEAR_ERROR();
ReleaseScanner();
mTempData.ClearProperty(propID);
mTempData.AssertInitialState();
return parsedOK;
}
bool
CSSParserImpl::EvaluateSupportsCondition(const nsAString& aDeclaration,
nsIURI* aDocURL,
nsIURI* aBaseURL,
nsIPrincipal* aDocPrincipal)
{
nsCSSScanner scanner(aDeclaration, 0);
css::ErrorReporter reporter(scanner, mSheet, mChildLoader, aDocURL);
InitScanner(scanner, reporter, aDocURL, aBaseURL, aDocPrincipal);
nsAutoSuppressErrors suppressErrors(this);
bool conditionMet;
bool parsedOK = ParseSupportsCondition(conditionMet) && !GetToken(true);
CLEAR_ERROR();
ReleaseScanner();
return parsedOK && conditionMet;
}
//----------------------------------------------------------------------
bool
@ -10214,3 +10274,25 @@ nsCSSParser::ParseKeyframeSelectorString(const nsSubstring& aSelectorString,
ParseKeyframeSelectorString(aSelectorString, aURI, aLineNumber,
aSelectorList);
}
bool
nsCSSParser::EvaluateSupportsDeclaration(const nsAString& aProperty,
const nsAString& aValue,
nsIURI* aDocURL,
nsIURI* aBaseURL,
nsIPrincipal* aDocPrincipal)
{
return static_cast<CSSParserImpl*>(mImpl)->
EvaluateSupportsDeclaration(aProperty, aValue, aDocURL, aBaseURL,
aDocPrincipal);
}
bool
nsCSSParser::EvaluateSupportsCondition(const nsAString& aCondition,
nsIURI* aDocURL,
nsIURI* aBaseURL,
nsIPrincipal* aDocPrincipal)
{
return static_cast<CSSParserImpl*>(mImpl)->
EvaluateSupportsCondition(aCondition, aDocURL, aBaseURL, aDocPrincipal);
}

Просмотреть файл

@ -180,6 +180,25 @@ public:
uint32_t aLineNumber,
InfallibleTArray<float>& aSelectorList);
/**
* Parse a property and value and return whether the property/value pair
* is supported.
*/
bool EvaluateSupportsDeclaration(const nsAString& aProperty,
const nsAString& aValue,
nsIURI* aDocURL,
nsIURI* aBaseURL,
nsIPrincipal* aDocPrincipal);
/**
* Parse an @supports condition and returns the result of evaluating the
* condition.
*/
bool EvaluateSupportsCondition(const nsAString& aCondition,
nsIURI* aDocURL,
nsIURI* aBaseURL,
nsIPrincipal* aDocPrincipal);
protected:
// This is a CSSParserImpl*, but if we expose that type name in this
// header, we can't put the type definition (in nsCSSParser.cpp) in

Просмотреть файл

@ -98,6 +98,7 @@ MOCHITEST_FILES = test_acid3_test46.html \
test_default_computed_style.html \
test_css_cross_domain.html \
test_css_eof_handling.html \
test_css_supports.html \
test_default_bidi_css.html \
test_descriptor_storage.html \
test_descriptor_syntax_errors.html \

Просмотреть файл

@ -0,0 +1,134 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=779917
-->
<head>
<title>Test for Bug 779917</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=779917">Mozilla Bug 779917</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 779917 **/
function runTest()
{
var passingConditions = [
"(color: green)",
"((color: green))",
"(color: green !important)",
"(color: rainbow) or (color: green)",
"(color: green) or (color: rainbow)",
"(color: green) and (color: blue)",
"(color: rainbow) or (color: iridescent) or (color: green)",
"(color: red) and (color: green) and (color: blue)",
"(color:green)",
"not (color: rainbow)",
"not (not (color: green))",
"(unknown:) or (color: green)",
"(unknown) or (color: green)",
"(font: 16px serif)",
"(color:) or (color: green)",
"not (@page)",
"not ({ something @with [ balanced ] brackets })",
"an-extension(of some kind) or (color: green)",
"not ()",
"( Font: 20px serif ! Important) ",
"(color: /* comment */ green)",
"(/* comment */ color: green)",
"(color: green /* comment */)",
"(color: green) /* comment */",
"/* comment */ (color: green)",
"(color /* comment */: green)",
"(color: green) /* unclosed comment",
"(color: green",
"(((((((color: green",
"(font-family: 'Helvetica"
];
var failingConditions = [
"(color: rainbow)",
"(color: rainbow) and (color: green)",
"(color: blue) and (color: rainbow)",
"(color: green) and (color: green) or (color: green)",
"(color: green) or (color: green) and (color: green)",
"not not (color: green)",
"not (color: rainbow) and not (color: iridescent)",
"not (color: rainbow) or (color: green)",
"(not (color: rainbow) or (color: green))",
"(unknown: green)",
"not ({ something @with (unbalanced brackets })",
"(color: green) or an-extension(that is [unbalanced)",
"not(unknown: unknown)",
"(color: green) or(color: blue)",
"color: green",
"(color: green;)",
"(font-family: 'Helvetica\n",
"(font-family: 'Helvetica\n')",
"()",
""
];
var passingDeclarations = [
["color", "green"],
["color", " green "],
["Color", "Green"],
["color", "green /* comment */"],
["color", "/* comment */ green"],
["color", "green /* unclosed comment"],
["font", "16px serif"],
["font", "16px /* comment */ serif"],
["font", "16px\nserif"],
["color", "\\0067reen"]
];
var failingDeclarations = [
["color ", "green"],
["color", "rainbow"],
["color", "green green"],
["color", "green !important"],
["\\0063olor", "green"],
["/* comment */color", "green"],
["color/* comment */", "green"],
["font-family", "'Helvetica\n"],
["font-family", "'Helvetica\n'"],
["color", "green;"],
["color", ""],
["unknown", "unknown"],
["", "green"],
["", ""]
];
passingConditions.forEach(function(aCondition) {
is(CSS.supports(aCondition), true, "CSS.supports returns true for passing condition \"" + aCondition + "\"");
});
failingConditions.forEach(function(aCondition) {
is(CSS.supports(aCondition), false, "CSS.supports returns false for failing condition \"" + aCondition + "\"");
});
passingDeclarations.forEach(function(aDeclaration) {
is(CSS.supports(aDeclaration[0], aDeclaration[1]), true, "CSS.supports returns true for supported declaration \"" + aDeclaration.join(":") + "\"");
});
failingDeclarations.forEach(function(aDeclaration) {
is(CSS.supports(aDeclaration[0], aDeclaration[1]), false, "CSS.supports returns false for unsupported declaration \"" + aDeclaration.join(":") + "\"");
});
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({ "set": [["layout.css.supports-rule.enabled", true]] }, runTest);
</script>
</pre>
</body>
</html>