Bug 649740 - Implement @supports. r=dbaron,bz
authorCameron McCormack <cam@mcc.id.au>
Thu, 02 Aug 2012 10:32:12 +1000
changeset 101171 dd435393e11e901d1cf3dceff0f090d9b7775991
parent 101170 a3221ce758e5fd617634bee751bcd590b196e8aa
child 101172 a01fbe624484f90371a54e62505c4e8b76098ad0
push id12881
push usercmccormack@mozilla.com
push dateThu, 02 Aug 2012 00:32:43 +0000
treeherdermozilla-inbound@dd435393e11e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdbaron, bz
bugs649740
milestone17.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 649740 - Implement @supports. r=dbaron,bz
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfoClasses.h
dom/interfaces/css/Makefile.in
dom/interfaces/css/nsIDOMCSSRule.idl
dom/interfaces/css/nsIDOMCSSSupportsRule.idl
dom/locales/en-US/chrome/layout/css.properties
dom/tests/mochitest/general/test_interfaces.html
layout/inspector/src/inCSSValueSearch.cpp
layout/reftests/w3c-css/submitted/conditional3/css-supports-001.xht
layout/reftests/w3c-css/submitted/conditional3/css-supports-002.xht
layout/reftests/w3c-css/submitted/conditional3/css-supports-003.xht
layout/reftests/w3c-css/submitted/conditional3/css-supports-004.xht
layout/reftests/w3c-css/submitted/conditional3/css-supports-005.xht
layout/reftests/w3c-css/submitted/conditional3/css-supports-006.xht
layout/reftests/w3c-css/submitted/conditional3/css-supports-007.xht
layout/reftests/w3c-css/submitted/conditional3/css-supports-008.xht
layout/reftests/w3c-css/submitted/conditional3/css-supports-009.xht
layout/reftests/w3c-css/submitted/conditional3/css-supports-010.xht
layout/reftests/w3c-css/submitted/conditional3/css-supports-011.xht
layout/reftests/w3c-css/submitted/conditional3/css-supports-012.xht
layout/reftests/w3c-css/submitted/conditional3/css-supports-013.xht
layout/reftests/w3c-css/submitted/conditional3/css-supports-014.xht
layout/reftests/w3c-css/submitted/conditional3/css-supports-015.xht
layout/reftests/w3c-css/submitted/conditional3/css-supports-016.xht
layout/reftests/w3c-css/submitted/conditional3/css-supports-017.xht
layout/reftests/w3c-css/submitted/conditional3/css-supports-018.xht
layout/reftests/w3c-css/submitted/conditional3/css-supports-019.xht
layout/reftests/w3c-css/submitted/conditional3/css-supports-020.xht
layout/reftests/w3c-css/submitted/conditional3/css-supports-021.xht
layout/reftests/w3c-css/submitted/conditional3/css-supports-022.xht
layout/reftests/w3c-css/submitted/conditional3/css-supports-023.xht
layout/reftests/w3c-css/submitted/conditional3/css-supports-024.xht
layout/reftests/w3c-css/submitted/conditional3/css-supports-025.xht
layout/reftests/w3c-css/submitted/conditional3/css-supports-026.xht
layout/reftests/w3c-css/submitted/conditional3/css-supports-027.xht
layout/reftests/w3c-css/submitted/conditional3/css-supports-028.xht
layout/reftests/w3c-css/submitted/conditional3/css-supports-029.xht
layout/reftests/w3c-css/submitted/conditional3/css-supports-030.xht
layout/reftests/w3c-css/submitted/conditional3/css-supports-031.xht
layout/reftests/w3c-css/submitted/conditional3/pass.html
layout/reftests/w3c-css/submitted/conditional3/reftest.list
layout/reftests/w3c-css/submitted/reftest.list
layout/style/Rule.h
layout/style/nsCSSParser.cpp
layout/style/nsCSSRuleProcessor.cpp
layout/style/nsCSSRules.cpp
layout/style/nsCSSRules.h
layout/style/nsCSSScanner.cpp
layout/style/nsCSSScanner.h
layout/style/test/Makefile.in
layout/style/test/test_supports_rules.html
modules/libpref/src/init/all.js
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -135,16 +135,17 @@
 #include "nsIDOMHTMLOptionElement.h"
 #include "nsGenericElement.h"
 
 // Event related includes
 #include "nsEventListenerManager.h"
 #include "nsIDOMEventTarget.h"
 
 // CSS related includes
+#include "nsCSSRules.h"
 #include "nsIDOMStyleSheet.h"
 #include "nsIDOMStyleSheetList.h"
 #include "nsIDOMCSSStyleDeclaration.h"
 #include "nsIDOMCSSRule.h"
 #include "nsICSSRuleList.h"
 #include "nsIDOMRect.h"
 #include "nsIDOMRGBColor.h"
 #include "nsIDOMNSRGBAColor.h"
@@ -284,16 +285,17 @@
 #endif
 #include "nsIDOMProgressEvent.h"
 #include "nsIDOMCSS2Properties.h"
 #include "nsIDOMCSSCharsetRule.h"
 #include "nsIDOMCSSImportRule.h"
 #include "nsIDOMCSSMediaRule.h"
 #include "nsIDOMCSSFontFaceRule.h"
 #include "nsIDOMCSSMozDocumentRule.h"
+#include "nsIDOMCSSSupportsRule.h"
 #include "nsIDOMMozCSSKeyframeRule.h"
 #include "nsIDOMMozCSSKeyframesRule.h"
 #include "nsIDOMCSSPrimitiveValue.h"
 #include "nsIDOMCSSStyleRule.h"
 #include "nsIDOMCSSStyleSheet.h"
 #include "nsDOMCSSValueList.h"
 #define MOZ_GENERATED_EVENTS_INCLUDES
 #include "GeneratedEvents.h"
@@ -1083,16 +1085,19 @@ static nsDOMClassInfoData sClassInfoData
 
   NS_DEFINE_CLASSINFO_DATA(TreeColumns, nsTreeColumnsSH,
                            ARRAY_SCRIPTABLE_FLAGS)
 #endif
 
   NS_DEFINE_CLASSINFO_DATA(CSSMozDocumentRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
+  NS_DEFINE_CLASSINFO_DATA(CSSSupportsRule, nsDOMGenericSH,
+                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
+
   NS_DEFINE_CLASSINFO_DATA(BeforeUnloadEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   // SVG document
   NS_DEFINE_CLASSINFO_DATA(SVGDocument, nsDocumentSH,
                            DOCUMENT_SCRIPTABLE_FLAGS)
 
   // SVG element classes
@@ -3166,16 +3171,20 @@ nsDOMClassInfo::Init()
     DOM_CLASSINFO_MAP_ENTRY(nsITreeColumns)
   DOM_CLASSINFO_MAP_END
 #endif
 
   DOM_CLASSINFO_MAP_BEGIN(CSSMozDocumentRule, nsIDOMCSSMozDocumentRule)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSMozDocumentRule)
   DOM_CLASSINFO_MAP_END
 
+  DOM_CLASSINFO_MAP_BEGIN(CSSSupportsRule, nsIDOMCSSSupportsRule)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSSupportsRule)
+  DOM_CLASSINFO_MAP_END
+
   DOM_CLASSINFO_MAP_BEGIN(BeforeUnloadEvent, nsIDOMBeforeUnloadEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMBeforeUnloadEvent)
     DOM_CLASSINFO_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
 #define DOM_CLASSINFO_SVG_ELEMENT_MAP_ENTRIES                           \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)                          \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGElement)                           \
@@ -6692,16 +6701,23 @@ ConstructorEnabled(const nsGlobalNameStr
 
   // For now don't expose server events unless user has explicitly enabled them
   if (aStruct->mDOMClassInfoID == eDOMClassInfo_EventSource_id) {
     if (!nsEventSource::PrefEnabled()) {
       return false;
     }
   }
 
+  // Don't expose CSSSupportsRule unless @supports processing is enabled.
+  if (aStruct->mDOMClassInfoID == eDOMClassInfo_CSSSupportsRule_id) {
+    if (!CSSSupportsRule::PrefEnabled()) {
+      return false;
+    }
+  }
+
   return true;
 }
 
 // static
 nsresult
 nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
                           JSObject *obj, jsid id, bool *did_resolve)
 {
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -188,16 +188,17 @@ DOMCI_CLASS(XULTreeBuilder)
 DOMCI_CLASS(DOMStringList)
 
 #ifdef MOZ_XUL
 DOMCI_CLASS(TreeColumn)
 DOMCI_CLASS(TreeColumns)
 #endif
 
 DOMCI_CLASS(CSSMozDocumentRule)
+DOMCI_CLASS(CSSSupportsRule)
 
 DOMCI_CLASS(BeforeUnloadEvent)
 
 // The SVG document
 DOMCI_CLASS(SVGDocument)
 
 // SVG element classes
 DOMCI_CLASS(SVGAElement)
--- a/dom/interfaces/css/Makefile.in
+++ b/dom/interfaces/css/Makefile.in
@@ -27,16 +27,17 @@ SDK_XPIDLSRCS = 				\
 
 XPIDLSRCS =					\
 	nsIDOMCSS2Properties.idl		\
 	nsIDOMCSSCharsetRule.idl		\
 	nsIDOMCSSFontFaceRule.idl		\
 	nsIDOMCSSImportRule.idl			\
 	nsIDOMCSSMediaRule.idl			\
 	nsIDOMCSSMozDocumentRule.idl		\
+	nsIDOMCSSSupportsRule.idl		\
 	nsIDOMMozCSSKeyframeRule.idl		\
 	nsIDOMMozCSSKeyframesRule.idl		\
 	nsIDOMCSSPageRule.idl			\
 	nsIDOMCSSStyleRule.idl			\
 	nsIDOMCSSUnknownRule.idl		\
 	nsIDOMCounter.idl			\
 	nsIDOMRGBColor.idl			\
 	nsIDOMRect.idl				\
--- a/dom/interfaces/css/nsIDOMCSSRule.idl
+++ b/dom/interfaces/css/nsIDOMCSSRule.idl
@@ -22,16 +22,17 @@ interface nsIDOMCSSRule : nsISupports
   const unsigned short      CHARSET_RULE                   = 2;
   const unsigned short      IMPORT_RULE                    = 3;
   const unsigned short      MEDIA_RULE                     = 4;
   const unsigned short      FONT_FACE_RULE                 = 5;
   const unsigned short      PAGE_RULE                      = 6;
   const unsigned short      MOZ_KEYFRAMES_RULE             = 7;
   const unsigned short      MOZ_KEYFRAME_RULE              = 8;
   const unsigned short      NAMESPACE_RULE                 = 10;
+  const unsigned short      SUPPORTS_RULE                  = 12;
 
   readonly attribute unsigned short      type;
            attribute DOMString           cssText;
                                         // raises(DOMException) on setting
 
   readonly attribute nsIDOMCSSStyleSheet parentStyleSheet;
   readonly attribute nsIDOMCSSRule       parentRule;
 };
new file mode 100644
--- /dev/null
+++ b/dom/interfaces/css/nsIDOMCSSSupportsRule.idl
@@ -0,0 +1,21 @@
+/* -*- 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/. */
+
+#include "nsIDOMCSSRule.idl"
+
+/**
+ * Interface for @supports rules in the CSS OM.
+ */
+[scriptable, uuid(5f409a4d-92f9-4a62-8e8a-cc1c02c32918)]
+interface nsIDOMCSSSupportsRule : nsIDOMCSSRule
+{
+  readonly attribute nsIDOMCSSRuleList cssRules;
+
+  unsigned long      insertRule(in DOMString rule,
+                                in unsigned long index)
+                                        raises(DOMException);
+  void               deleteRule(in unsigned long index)
+                                        raises(DOMException);
+};
--- a/dom/locales/en-US/chrome/layout/css.properties
+++ b/dom/locales/en-US/chrome/layout/css.properties
@@ -17,17 +17,17 @@ PEUnknownAtRule=Unrecognized at-rule or 
 PECharsetRuleEOF=charset string in @charset rule
 PECharsetRuleNotString=Expected charset string but found '%1$S'.
 PEGatherMediaEOF=end of media list in @import or @media rule
 PEGatherMediaNotComma=Expected ',' in media list but found '%1$S'.
 PEGatherMediaNotIdent=Expected identifier in media list but found '%1$S'.
 PEImportNotURI=Expected URI in @import rule but found '%1$S'.
 PEImportBadURI=Invalid URI in @import rule: '%1$S'.
 PEImportUnexpected=Found unexpected '%1$S' within @import.
-PEGroupRuleEOF=end of @media or @-moz-document rule
+PEGroupRuleEOF2=end of @media, @supports or @-moz-document rule
 PEGroupRuleNestedAtRule=%1$S rule not allowed within @media or @-moz-document rule.
 PEMozDocRuleBadFunc=Expected url(), url-prefix(), or domain() in @-moz-document rule but found '%1$S'.
 PEMozDocRuleNotURI=Expected URI in @-moz-document rule but found '%1$S'.
 PEMozDocRuleNotString=Expected string in @-moz-document rule regexp() function but found '%1$S'.
 PEMozDocRuleEOF=next URI in @-moz-document rule
 PEAtNSPrefixEOF=namespace prefix in @namespace rule
 PEAtNSURIEOF=namespace URI in @namespace rule
 PEAtNSUnexpected=Unexpected token within @namespace: '%1$S'.
@@ -109,8 +109,16 @@ PEMQExpectedExpressionStart=Expected '('
 PEMQExpressionEOF=contents of media query expression
 PEMQExpectedFeatureName=Expected media feature name but found '%1$S'.
 PEMQExpectedFeatureNameEnd=Expected ':' or ')' after media feature name but found '%1$S'.
 PEMQNoMinMaxWithoutValue=Media features with min- or max- must have a value.
 PEMQExpectedFeatureValue=Found invalid value for media feature.
 PEBadFontBlockStart=Expected '{' to begin @font-face rule but found '%1$S'.
 PEBadFontBlockEnd=Expected '}' to end @font-face rule but found '%1$S'.
 PEAnonBoxNotAlone=Did not expect anonymous box.
+PESupportsConditionStartEOF='not' or '('
+PESupportsConditionInParensStartEOF='not', '(' or identifier
+PESupportsConditionNotEOF='not'
+PESupportsConditionExpectedOpenParen=Expected '(' while parsing supports condition but found '%1$S'.
+PESupportsConditionExpectedCloseParen=Expected ')' while parsing supports condition but found '%1$S'.
+PESupportsConditionExpectedStart=Expected 'not' or '(' while parsing supports condition but found '%1$S'.
+PESupportsConditionExpectedNot=Expected 'not' while parsing supports condition but found '%1$S'.
+PESupportsGroupRuleStart=Expected '{' to begin @supports rule but found '%1$S'.
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -522,17 +522,18 @@ var interfaceNamesInGlobalScope =
     "SVGGradientElement",
     "ContactTelephone",
     "ContactEmail",
     "SVGFitToViewBox",
     "SVGAElement",
     "NavigatorCamera",
     "CameraControl",
     "CameraCapabilities",
-    "CameraManager"
+    "CameraManager",
+    "CSSSupportsRule"
   ]
 
 for (var i in Components.interfaces) {
   var s = i.toString();
   var name = null;
   if (s.indexOf("nsIDOM") == 0) {
     name = s.substring("nsIDOM".length);
   } else if (s.indexOf("nsI") == 0) {
--- a/layout/inspector/src/inCSSValueSearch.cpp
+++ b/layout/inspector/src/inCSSValueSearch.cpp
@@ -11,16 +11,17 @@
 #include "nsIDOMDocument.h"
 #include "nsIDOMStyleSheetList.h"
 #include "nsIDOMCSSStyleSheet.h"
 #include "nsIDOMCSSRuleList.h"
 #include "nsIDOMCSSStyleRule.h"
 #include "nsIDOMCSSStyleDeclaration.h"
 #include "nsIDOMCSSImportRule.h"
 #include "nsIDOMCSSMediaRule.h"
+#include "nsIDOMCSSSupportsRule.h"
 #include "nsIURI.h"
 #include "nsIDocument.h"
 #include "nsNetUtil.h"
 
 ///////////////////////////////////////////////////////////////////////////////
 inCSSValueSearch::inCSSValueSearch()
   : mResults(nullptr),
     mProperties(nullptr),
@@ -312,16 +313,22 @@ inCSSValueSearch::SearchRuleList(nsIDOMC
           SearchStyleSheet(childSheet, aBaseURL);
       } break;
       case nsIDOMCSSRule::MEDIA_RULE: {
         nsCOMPtr<nsIDOMCSSMediaRule> mediaRule = do_QueryInterface(rule);
         nsCOMPtr<nsIDOMCSSRuleList> childRules;
         mediaRule->GetCssRules(getter_AddRefs(childRules));
         SearchRuleList(childRules, aBaseURL);
       } break;
+      case nsIDOMCSSRule::SUPPORTS_RULE: {
+        nsCOMPtr<nsIDOMCSSSupportsRule> supportsRule = do_QueryInterface(rule);
+        nsCOMPtr<nsIDOMCSSRuleList> childRules;
+        supportsRule->GetCssRules(getter_AddRefs(childRules));
+        SearchRuleList(childRules, aBaseURL);
+      } break;
       default:
         // XXX handle nsIDOMCSSRule::PAGE_RULE if we ever support it
         break;
     }
   }
   return NS_OK;
 }
 
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/conditional3/css-supports-001.xht
@@ -0,0 +1,18 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>CSS Test: An @supports rule with valid syntax and a passing condition must apply rules inside it</title>
+  <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au" />
+  <link rel="help" href="http://www.w3.org/TR/#at-supports" />
+  <meta name="flags" content="" />
+  <meta name="assert" content="An @supports rule condition with a single, valid property declaration for a supported property must cause the rules inside the @supports rule to apply."/>
+  <link rel="match" href="pass.html" />
+  <style type="text/css"><![CDATA[
+    @supports (color: green) {
+      html { background-color: green }
+    }
+  ]]></style>
+ </head>
+ <body>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/conditional3/css-supports-002.xht
@@ -0,0 +1,19 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>CSS Test: An @supports rule with invalid syntax must not apply rules inside it</title>
+  <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au" />
+  <link rel="help" href="http://www.w3.org/TR/#at-supports" />
+  <meta name="flags" content="" />
+  <meta name="assert" content="Property declarations in an @supports rule condition must be surrounded by parentheses."/>
+  <link rel="match" href="pass.html" />
+  <style type="text/css"><![CDATA[
+    html { background-color: green }
+    @supports color: green {
+      html { background-color: red }
+    }
+  ]]></style>
+ </head>
+ <body>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/conditional3/css-supports-003.xht
@@ -0,0 +1,18 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>CSS Test: An @supports rule with valid syntax and a passing condition must apply rules inside it</title>
+  <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au" />
+  <link rel="help" href="http://www.w3.org/TR/#at-supports" />
+  <meta name="flags" content="" />
+  <meta name="assert" content="Any subexpression in an @supports rule condition can be surrounded by an extra pair of parentheses."/>
+  <link rel="match" href="pass.html" />
+  <style type="text/css"><![CDATA[
+    @supports ((color: green)) {
+      html { background-color: green }
+    }
+  ]]></style>
+ </head>
+ <body>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/conditional3/css-supports-004.xht
@@ -0,0 +1,18 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>CSS Test: An @supports rule with valid syntax and a passing condition must apply rules inside it</title>
+  <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au" />
+  <link rel="help" href="http://www.w3.org/TR/#at-supports" />
+  <meta name="flags" content="" />
+  <meta name="assert" content="Property declarations in an @supports rule can have !important specified."/>
+  <link rel="match" href="pass.html" />
+  <style type="text/css"><![CDATA[
+    @supports (color: green !important) {
+      html { background-color: green }
+    }
+  ]]></style>
+ </head>
+ <body>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/conditional3/css-supports-005.xht
@@ -0,0 +1,19 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>CSS Test: An @supports rule with valid syntax but a failing condition must not apply rules inside it</title>
+  <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au" />
+  <link rel="help" href="http://www.w3.org/TR/#at-supports" />
+  <meta name="flags" content="" />
+  <meta name="assert" content="A supported property with an unsupported value must cause the @supports condition to fail."/>
+  <link rel="match" href="pass.html" />
+  <style type="text/css"><![CDATA[
+    html { background-color: green }
+    @supports (color: rainbow) {
+      html { background-color: red }
+    }
+  ]]></style>
+ </head>
+ <body>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/conditional3/css-supports-006.xht
@@ -0,0 +1,18 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>CSS Test: An @supports rule with valid syntax and a passing condition must apply rules inside it</title>
+  <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au" />
+  <link rel="help" href="http://www.w3.org/TR/#at-supports" />
+  <meta name="flags" content="" />
+  <meta name="assert" content="A disjunction of two @supports conditions must cause the @supports condition to pass if the left condition passes."/>
+  <link rel="match" href="pass.html" />
+  <style type="text/css"><![CDATA[
+    @supports (color: rainbow) or (color: green) {
+      html { background-color: green }
+    }
+  ]]></style>
+ </head>
+ <body>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/conditional3/css-supports-007.xht
@@ -0,0 +1,18 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>CSS Test: An @supports rule with valid syntax and a passing condition must apply rules inside it</title>
+  <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au" />
+  <link rel="help" href="http://www.w3.org/TR/#at-supports" />
+  <meta name="flags" content="" />
+  <meta name="assert" content="A disjunction of two @supports conditions must cause the @supports condition to pass if the right condition passes."/>
+  <link rel="match" href="pass.html" />
+  <style type="text/css"><![CDATA[
+    @supports (color: green) or (color: rainbow) {
+      html { background-color: green }
+    }
+  ]]></style>
+ </head>
+ <body>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/conditional3/css-supports-008.xht
@@ -0,0 +1,18 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>CSS Test: An @supports rule with valid syntax and a passing condition must apply rules inside it</title>
+  <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au" />
+  <link rel="help" href="http://www.w3.org/TR/#at-supports" />
+  <meta name="flags" content="" />
+  <meta name="assert" content="A conjunction of two @supports conditions must cause the @supports condition to pass if both sub-conditions pass."/>
+  <link rel="match" href="pass.html" />
+  <style type="text/css"><![CDATA[
+    @supports (color: green) and (color: blue) {
+      html { background-color: green }
+    }
+  ]]></style>
+ </head>
+ <body>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/conditional3/css-supports-009.xht
@@ -0,0 +1,19 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>CSS Test: An @supports rule with valid syntax but a failing condition must not apply rules inside it</title>
+  <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au" />
+  <link rel="help" href="http://www.w3.org/TR/#at-supports" />
+  <meta name="flags" content="" />
+  <meta name="assert" content="A conjunction of two @supports conditions must cause the @supports condition to fail if the left sub-condition passes."/>
+  <link rel="match" href="pass.html" />
+  <style type="text/css"><![CDATA[
+    html { background-color: green }
+    @supports (color: rainbow) and (color: blue) {
+      html { background-color: red }
+    }
+  ]]></style>
+ </head>
+ <body>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/conditional3/css-supports-010.xht
@@ -0,0 +1,19 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>CSS Test: An @supports rule with valid syntax but a failing condition must not apply rules inside it</title>
+  <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au" />
+  <link rel="help" href="http://www.w3.org/TR/#at-supports" />
+  <meta name="flags" content="" />
+  <meta name="assert" content="A conjunction of two @supports conditions must cause the @supports condition to fail if the right sub-condition passes."/>
+  <link rel="match" href="pass.html" />
+  <style type="text/css"><![CDATA[
+    html { background-color: green }
+    @supports (color: blue) and (color: rainbow) {
+      html { background-color: red }
+    }
+  ]]></style>
+ </head>
+ <body>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/conditional3/css-supports-011.xht
@@ -0,0 +1,18 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>CSS Test: An @supports rule with valid syntax and a passing condition must apply rules inside it</title>
+  <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au" />
+  <link rel="help" href="http://www.w3.org/TR/#at-supports" />
+  <meta name="flags" content="" />
+  <meta name="assert" content="A disjunction of three @supports conditions must cause the @supports condition to pass if at least one of the sub-conditions passes."/>
+  <link rel="match" href="pass.html" />
+  <style type="text/css"><![CDATA[
+    @supports (color: rainbow) or (color: iridescent) or (color: green) {
+      html { background-color: green }
+    }
+  ]]></style>
+ </head>
+ <body>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/conditional3/css-supports-012.xht
@@ -0,0 +1,18 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>CSS Test: An @supports rule with valid syntax and a passing condition must apply rules inside it</title>
+  <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au" />
+  <link rel="help" href="http://www.w3.org/TR/#at-supports" />
+  <meta name="flags" content="" />
+  <meta name="assert" content="A conjunction of three @supports conditions must cause the @supports condition to pass if all three sub-conditions pass."/>
+  <link rel="match" href="pass.html" />
+  <style type="text/css"><![CDATA[
+    @supports (color: red) and (color: green) and (color: blue) {
+      html { background-color: green }
+    }
+  ]]></style>
+ </head>
+ <body>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/conditional3/css-supports-013.xht
@@ -0,0 +1,19 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>CSS Test: An @supports rule with invalid syntax must not apply rules inside it</title>
+  <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au" />
+  <link rel="help" href="http://www.w3.org/TR/#at-supports" />
+  <meta name="flags" content="" />
+  <meta name="assert" content="A disjunction and a conjunction of @supports conditions must not be combined unless one of the two is surrounded by parentheses."/>
+  <link rel="match" href="pass.html" />
+  <style type="text/css"><![CDATA[
+    html { background-color: green }
+    @supports (color: green) and (color: green) or (color: green) {
+      html { background-color: red }
+    }
+  ]]></style>
+ </head>
+ <body>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/conditional3/css-supports-014.xht
@@ -0,0 +1,19 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>CSS Test: An @supports rule with invalid syntax must not apply rules inside it</title>
+  <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au" />
+  <link rel="help" href="http://www.w3.org/TR/#at-supports" />
+  <meta name="flags" content="" />
+  <meta name="assert" content="A disjunction and a conjunction of @supports conditions must not be combined unless one of the two is surrounded by parentheses."/>
+  <link rel="match" href="pass.html" />
+  <style type="text/css"><![CDATA[
+    html { background-color: green }
+    @supports (color: green) or (color: green) and (color: green) {
+      html { background-color: red }
+    }
+  ]]></style>
+ </head>
+ <body>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/conditional3/css-supports-015.xht
@@ -0,0 +1,18 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>CSS Test: An @supports rule with valid syntax and a passing condition must apply rules inside it</title>
+  <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au" />
+  <link rel="help" href="http://www.w3.org/TR/#at-supports" />
+  <meta name="flags" content="" />
+  <meta name="assert" content="There need not be any white space between the '@supports' and open brace of the rule set, not between a declaration's property name and value."/>
+  <link rel="match" href="pass.html" />
+  <style type="text/css"><![CDATA[
+    @supports(color:green){
+      html { background-color: green }
+    }
+  ]]></style>
+ </head>
+ <body>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/conditional3/css-supports-016.xht
@@ -0,0 +1,18 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>CSS Test: An @supports rule with valid syntax and a passing condition must apply rules inside it</title>
+  <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au" />
+  <link rel="help" href="http://www.w3.org/TR/#at-supports" />
+  <meta name="flags" content="" />
+  <meta name="assert" content="A negation of an @supports condition must pass if and only if the sub-condition fails.  The sub-condition here is a supported property name with an unsupported value."/>
+  <link rel="match" href="pass.html" />
+  <style type="text/css"><![CDATA[
+    @supports not (color: rainbow) {
+      html { background-color: green }
+    }
+  ]]></style>
+ </head>
+ <body>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/conditional3/css-supports-017.xht
@@ -0,0 +1,19 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>CSS Test: An @supports rule with invalid syntax must not apply rules inside it</title>
+  <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au" />
+  <link rel="help" href="http://www.w3.org/TR/#at-supports" />
+  <meta name="flags" content="" />
+  <meta name="assert" content="The sub-condition of a negation in an @supports condition must be in parentheses."/>
+  <link rel="match" href="pass.html" />
+  <style type="text/css"><![CDATA[
+    html { background-color: green }
+    @supports not not (color: green) {
+      html { background-color: red }
+    }
+  ]]></style>
+ </head>
+ <body>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/conditional3/css-supports-018.xht
@@ -0,0 +1,18 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>CSS Test: An @supports rule with valid syntax and a passing condition must apply rules inside it</title>
+  <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au" />
+  <link rel="help" href="http://www.w3.org/TR/#at-supports" />
+  <meta name="flags" content="" />
+  <meta name="assert" content="The sub-condition of a negation in an @supports condition must be in parentheses."/>
+  <link rel="match" href="pass.html" />
+  <style type="text/css"><![CDATA[
+    @supports not (not (color: green)) {
+      html { background-color: green }
+    }
+  ]]></style>
+ </head>
+ <body>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/conditional3/css-supports-019.xht
@@ -0,0 +1,19 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>CSS Test: An @supports rule with invalid syntax must not apply rules inside it</title>
+  <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au" />
+  <link rel="help" href="http://www.w3.org/TR/#at-supports" />
+  <meta name="flags" content="" />
+  <meta name="assert" content="A conjunction in an @supports condition must have both sub-conditions enclosed in parentheses."/>
+  <link rel="match" href="pass.html" />
+  <style type="text/css"><![CDATA[
+    html { background-color: green }
+    @supports not (color: rainbow) and not (color: iridescent) {
+      html { background-color: red }
+    }
+  ]]></style>
+ </head>
+ <body>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/conditional3/css-supports-020.xht
@@ -0,0 +1,19 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>CSS Test: An @supports rule with valid syntax but a failing condition must not apply rules inside it</title>
+  <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au" />
+  <link rel="help" href="http://www.w3.org/TR/#at-supports" />
+  <meta name="flags" content="" />
+  <meta name="assert" content="An @supports condition that is a declaration with a supported property name with an unsupported value must fail."/>
+  <link rel="match" href="pass.html" />
+  <style type="text/css"><![CDATA[
+    html { background-color: green }
+    @supports (unknown: green) {
+      html { background-color: red }
+    }
+  ]]></style>
+ </head>
+ <body>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/conditional3/css-supports-021.xht
@@ -0,0 +1,18 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>CSS Test: An @supports rule with valid syntax but a failing condition must not apply rules inside it</title>
+  <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au" />
+  <link rel="help" href="http://www.w3.org/TR/#at-supports" />
+  <meta name="flags" content="" />
+  <meta name="assert" content="A disjunction of two @supports conditions must cause the @supports condition to pass if one condition passes and the other fails due to being an unsupported property."/>
+  <link rel="match" href="pass.html" />
+  <style type="text/css"><![CDATA[
+    @supports (unknown: green) or (color: green) {
+      html { background-color: green }
+    }
+  ]]></style>
+ </head>
+ <body>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/conditional3/css-supports-022.xht
@@ -0,0 +1,18 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>CSS Test: An @supports rule with valid syntax but a failing condition must not apply rules inside it</title>
+  <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au" />
+  <link rel="help" href="http://www.w3.org/TR/#at-supports" />
+  <meta name="flags" content="" />
+  <meta name="assert" content="A disjunction of two @supports conditions must cause the @supports condition to pass if one condition passes and the other fails due to being an unsupported property with an empty property value."/>
+  <link rel="match" href="pass.html" />
+  <style type="text/css"><![CDATA[
+    @supports (unknown:) or (color: green) {
+      html { background-color: green }
+    }
+  ]]></style>
+ </head>
+ <body>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/conditional3/css-supports-023.xht
@@ -0,0 +1,19 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>CSS Test: An @supports rule with invalid syntax must not apply rules inside it</title>
+  <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au" />
+  <link rel="help" href="http://www.w3.org/TR/#at-supports" />
+  <meta name="flags" content="" />
+  <meta name="assert" content="A property declaration in an @supports declaration must not omit the colon between the property name and value."/>
+  <link rel="match" href="pass.html" />
+  <style type="text/css"><![CDATA[
+    html { background-color: green }
+    @supports (unknown) or (color: green) {
+      html { background-color: red }
+    }
+  ]]></style>
+ </head>
+ <body>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/conditional3/css-supports-024.xht
@@ -0,0 +1,18 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>CSS Test: An @supports rule with valid syntax and a passing condition must apply rules inside it</title>
+  <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au" />
+  <link rel="help" href="http://www.w3.org/TR/#at-supports" />
+  <meta name="flags" content="" />
+  <meta name="assert" content="A supported shorthand property declaration must be considered to pass."/>
+  <link rel="match" href="pass.html" />
+  <style type="text/css"><![CDATA[
+    @supports (font: 16px serif) {
+      html { background-color: green }
+    }
+  ]]></style>
+ </head>
+ <body>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/conditional3/css-supports-025.xht
@@ -0,0 +1,20 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>CSS Test: A nested @supports rule with valid syntax and a passing condition must apply rules inside it</title>
+  <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au" />
+  <link rel="help" href="http://www.w3.org/TR/#at-supports" />
+  <meta name="flags" content="" />
+  <meta name="assert" content="An inner @supports rule inside an outer @supports must apply its child rules only if both @supports conditions succeeded."/>
+  <link rel="match" href="pass.html" />
+  <style type="text/css"><![CDATA[
+    @supports (color: green) {
+      @supports (color: blue) {
+        html { background-color: green }
+      }
+    }
+  ]]></style>
+ </head>
+ <body>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/conditional3/css-supports-026.xht
@@ -0,0 +1,21 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>CSS Test: A nested @supports rule with valid syntax and a passing condition must apply rules inside it</title>
+  <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au" />
+  <link rel="help" href="http://www.w3.org/TR/#at-supports" />
+  <link rel="help" href="http://www.w3.org/TR/css3-conditional/#at-media" />
+  <meta name="flags" content="" />
+  <meta name="assert" content="An outer @supports rule with an inner @media rule must apply the rules inside the @media only if both the @supports and @media conditions pass."/>
+  <link rel="match" href="pass.html" />
+  <style type="text/css"><![CDATA[
+    @supports (color: green) {
+      @media all {
+        html { background-color: green }
+      }
+    }
+  ]]></style>
+ </head>
+ <body>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/conditional3/css-supports-027.xht
@@ -0,0 +1,21 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>CSS Test: A nested @supports rule with valid syntax and a passing condition must apply rules inside it</title>
+  <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au" />
+  <link rel="help" href="http://www.w3.org/TR/#at-supports" />
+  <link rel="help" href="http://www.w3.org/TR/css3-conditional/#at-document" />
+  <meta name="flags" content="" />
+  <meta name="assert" content="An outer @document rule with an inner @supports rule must apply the rules inside the @supports only if both the @supports and @document conditions pass."/>
+  <link rel="match" href="pass.html" />
+  <style type="text/css"><![CDATA[
+    @-moz-document url-prefix("") {
+      @supports (color: green) {
+        html { background-color: green }
+      }
+    }
+  ]]></style>
+ </head>
+ <body>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/conditional3/css-supports-028.xht
@@ -0,0 +1,20 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>CSS Test: A nested @supports rule with valid syntax and a passing condition must apply rules inside it</title>
+  <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au" />
+  <link rel="help" href="http://www.w3.org/TR/#at-supports" />
+  <meta name="flags" content="" />
+  <meta name="assert" content="An inner @document rule with an outer @supports rule must apply the rules inside the @document only if both the @supports and @document conditions pass."/>
+  <link rel="match" href="pass.html" />
+  <style type="text/css"><![CDATA[
+    @supports (color: green) {
+      @-moz-document url-prefix("") {
+        html { background-color: green }
+      }
+    }
+  ]]></style>
+ </head>
+ <body>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/conditional3/css-supports-029.xht
@@ -0,0 +1,19 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>CSS Test: An @supports rule with valid syntax and a passing condition must apply rules inside it</title>
+  <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au" />
+  <link rel="help" href="http://www.w3.org/TR/#at-supports" />
+  <meta name="flags" content="" />
+  <meta name="assert" content="A disjunction in an @supports condition must have both sub-conditions enclosed in parentheses." />
+  <link rel="match" href="pass.html" />
+  <style type="text/css"><![CDATA[
+    html { background-color: green }
+    @supports not (color: rainbow) or (color: green) {
+      html { background-color: red }
+    }
+  ]]></style>
+ </head>
+ <body>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/conditional3/css-supports-030.xht
@@ -0,0 +1,19 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>CSS Test: An @supports rule with valid syntax and a passing condition must apply rules inside it</title>
+  <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au" />
+  <link rel="help" href="http://www.w3.org/TR/#at-supports" />
+  <meta name="flags" content="" />
+  <meta name="assert" content="A disjunction in an @supports condition must have both sub-conditions enclosed in parentheses." />
+  <link rel="match" href="pass.html" />
+  <style type="text/css"><![CDATA[
+    html { background-color: green }
+    @supports (not (color: rainbow) or (color: green)) {
+      html { background-color: red }
+    }
+  ]]></style>
+ </head>
+ <body>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/conditional3/css-supports-031.xht
@@ -0,0 +1,20 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>CSS Test: {{ brief but unique descriptive title of what's being tested }}</title>
+  <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au" />
+  <link rel="help" href="http://www.w3.org/TR/#at-supports" />
+  <meta name="flags" content="" />
+  <meta name="assert" content="{{ explain precisely what is asserted when the test passes;
+                                  optional but helps coordination and review }}" />
+  <link rel="match" href="pass.html" />
+  <style type="text/css"><![CDATA[
+    html { background-color: green }
+    @supports (not (color: rainbow) and (color: green)) {
+      html { background-color: red }
+    }
+  ]]></style>
+ </head>
+ <body>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/conditional3/pass.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<style>
+html { background-color: green }
+</style>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/conditional3/reftest.list
@@ -0,0 +1,30 @@
+== css-supports-001.xht pass.html
+== css-supports-002.xht pass.html
+== css-supports-003.xht pass.html
+== css-supports-004.xht pass.html
+== css-supports-005.xht pass.html
+== css-supports-006.xht pass.html
+== css-supports-007.xht pass.html
+== css-supports-008.xht pass.html
+== css-supports-009.xht pass.html
+== css-supports-010.xht pass.html
+== css-supports-011.xht pass.html
+== css-supports-012.xht pass.html
+== css-supports-013.xht pass.html
+== css-supports-014.xht pass.html
+== css-supports-015.xht pass.html
+== css-supports-016.xht pass.html
+== css-supports-017.xht pass.html
+== css-supports-018.xht pass.html
+== css-supports-019.xht pass.html
+== css-supports-020.xht pass.html
+== css-supports-021.xht pass.html
+== css-supports-022.xht pass.html
+== css-supports-023.xht pass.html
+== css-supports-024.xht pass.html
+== css-supports-025.xht pass.html
+== css-supports-026.xht pass.html
+== css-supports-027.xht pass.html
+== css-supports-028.xht pass.html
+== css-supports-029.xht pass.html
+== css-supports-030.xht pass.html
--- a/layout/reftests/w3c-css/submitted/reftest.list
+++ b/layout/reftests/w3c-css/submitted/reftest.list
@@ -11,16 +11,19 @@
 # include css2.1/reftest.list
 
 # Animations
 # include animations/reftest.list
 
 # Backgrounds and Borders Level 3
 # include background3/reftest.list
 
+# Conditional Rules Level 3
+skip-if(!prefs.getBoolPref("layout.css.supports-rule.enabled")) include conditional3/reftest.list
+
 # Fonts Level 3
 # include fonts3/reftest.list
 
 # Image Values and Replaced Content Level 3
 # include images3/reftest.list
 
 # Media Queries Level 3
 # include mediaqueries3/reftest.list
--- a/layout/style/Rule.h
+++ b/layout/style/Rule.h
@@ -63,17 +63,18 @@ public:
     IMPORT_RULE,
     NAMESPACE_RULE,
     STYLE_RULE,
     MEDIA_RULE,
     FONT_FACE_RULE,
     PAGE_RULE,
     KEYFRAME_RULE,
     KEYFRAMES_RULE,
-    DOCUMENT_RULE
+    DOCUMENT_RULE,
+    SUPPORTS_RULE
   };
 
   virtual PRInt32 GetType() const = 0;
 
   nsCSSStyleSheet* GetStyleSheet() const { return mSheet; }
 
   virtual void SetStyleSheet(nsCSSStyleSheet* aSheet);
 
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -328,16 +328,27 @@ protected:
   bool ParseFontDescriptorValue(nsCSSFontDesc aDescID,
                                 nsCSSValue& aValue);
 
   bool ParsePageRule(RuleAppendFunc aAppendFunc, void* aProcessData);
   bool ParseKeyframesRule(RuleAppendFunc aAppendFunc, void* aProcessData);
   already_AddRefed<nsCSSKeyframeRule> ParseKeyframeRule();
   bool ParseKeyframeSelectorList(InfallibleTArray<float>& aSelectorList);
 
+  bool ParseSupportsRule(RuleAppendFunc aAppendFunc, void* aProcessData);
+  bool ParseSupportsCondition(bool& aConditionMet);
+  bool ParseSupportsConditionNegation(bool& aConditionMet);
+  bool ParseSupportsConditionInParens(bool& aConditionMet);
+  bool ParseSupportsConditionInParensInsideParens(bool& aConditionMet);
+  bool ParseSupportsConditionTerms(bool& aConditionMet);
+  enum SupportsConditionTermOperator { eAnd, eOr };
+  bool ParseSupportsConditionTermsAfterOperator(
+                                       bool& aConditionMet,
+                                       SupportsConditionTermOperator aOperator);
+
   enum nsSelectorParsingStatus {
     // we have parsed a selector and we saw a token that cannot be
     // part of a selector:
     eSelectorParsingStatus_Done,
     // we should continue parsing the selector:
     eSelectorParsingStatus_Continue,
     // we saw an unexpected token or token value,
     // or we saw end-of-file with an unfinished selector:
@@ -751,21 +762,21 @@ CSSParserImpl::CSSParserImpl()
     mSection(eCSSSection_Charset),
     mNameSpaceMap(nullptr),
     mHavePushBack(false),
     mNavQuirkMode(false),
     mHashlessColorQuirk(false),
     mUnitlessLengthQuirk(false),
     mUnsafeRulesEnabled(false),
     mHTMLMediaMode(false),
-    mParsingCompoundProperty(false)
+    mParsingCompoundProperty(false),
 #ifdef DEBUG
-    , mScannerInited(false)
+    mScannerInited(false),
 #endif
-    , mNextFree(nullptr)
+    mNextFree(nullptr)
 {
 }
 
 CSSParserImpl::~CSSParserImpl()
 {
   mData.AssertInitialState();
   mTempData.AssertInitialState();
 }
@@ -1364,17 +1375,18 @@ bool
 CSSParserImpl::CheckEndProperty()
 {
   if (!GetToken(true)) {
     return true; // properties may end with eof
   }
   if ((eCSSToken_Symbol == mToken.mType) &&
       ((';' == mToken.mSymbol) ||
        ('!' == mToken.mSymbol) ||
-       ('}' == mToken.mSymbol))) {
+       ('}' == mToken.mSymbol) ||
+       (')' == mToken.mSymbol))) {
     // XXX need to verify that ! is only followed by "important [;|}]
     // XXX this requires a multi-token pushback buffer
     UngetToken();
     return true;
   }
   UngetToken();
   return false;
 }
@@ -1508,16 +1520,21 @@ CSSParserImpl::ParseAtRule(RuleAppendFun
     parseFunc = &CSSParserImpl::ParsePageRule;
     newSection = eCSSSection_General;
 
   } else if (mToken.mIdent.LowerCaseEqualsLiteral("-moz-keyframes") ||
              mToken.mIdent.LowerCaseEqualsLiteral("keyframes")) {
     parseFunc = &CSSParserImpl::ParseKeyframesRule;
     newSection = eCSSSection_General;
 
+  } else if (mToken.mIdent.LowerCaseEqualsLiteral("supports") &&
+             CSSSupportsRule::PrefEnabled()) {
+    parseFunc = &CSSParserImpl::ParseSupportsRule;
+    newSection = eCSSSection_General;
+
   } else {
     if (!NonMozillaVendorIdentifier(mToken.mIdent)) {
       REPORT_UNEXPECTED_TOKEN(PEUnknownAtRule);
       OUTPUT_ERROR();
     }
     // Skip over unsupported at rule, don't advance section
     return SkipAtRule(aInAtRule);
   }
@@ -1952,17 +1969,17 @@ CSSParserImpl::ParseGroupRule(css::Group
   // push rule on stack, loop over children
   PushGroup(aRule);
   nsCSSSection holdSection = mSection;
   mSection = eCSSSection_General;
 
   for (;;) {
     // Get next non-whitespace token
     if (! GetToken(true)) {
-      REPORT_UNEXPECTED_EOF(PEGroupRuleEOF);
+      REPORT_UNEXPECTED_EOF(PEGroupRuleEOF2);
       break;
     }
     if (mToken.IsSymbol('}')) { // done!
       UngetToken();
       break;
     }
     if (eCSSToken_AtKeyword == mToken.mType) {
       // Parse for nested rules
@@ -2329,16 +2346,238 @@ CSSParserImpl::ParseKeyframeSelectorList
     }
     aSelectorList.AppendElement(value);
     if (!ExpectSymbol(',', true)) {
       return true;
     }
   }
 }
 
+// supports_rule
+//   : "@supports" supports_condition group_rule_body
+//   ;
+bool
+CSSParserImpl::ParseSupportsRule(RuleAppendFunc aAppendFunc, void* aProcessData)
+{
+  bool conditionMet = false;
+  nsString condition;
+
+  mScanner.StartRecording();
+  bool parsed = ParseSupportsCondition(conditionMet);
+
+  if (!parsed) {
+    mScanner.StopRecording();
+    return false;
+  }
+
+  if (!ExpectSymbol('{', true)) {
+    REPORT_UNEXPECTED_TOKEN(PESupportsGroupRuleStart);
+    mScanner.StopRecording();
+    return false;
+  }
+
+  UngetToken();
+  mScanner.StopRecording(condition);
+
+  // Remove the "{" that would follow the condition.
+  if (condition.Length() != 0) {
+    condition.Truncate(condition.Length() - 1);
+  }
+
+  // Remove spaces from the start and end of the recorded supports condition.
+  condition.Trim(" ", true, true, false);
+
+  nsRefPtr<css::GroupRule> rule = new CSSSupportsRule(conditionMet, condition);
+  return ParseGroupRule(rule, aAppendFunc, aProcessData);
+}
+
+// supports_condition
+//   : supports_condition_in_parens supports_condition_terms
+//   | supports_condition_negation
+//   ;
+bool
+CSSParserImpl::ParseSupportsCondition(bool& aConditionMet)
+{
+  if (!GetToken(true)) {
+    REPORT_UNEXPECTED_EOF(PESupportsConditionStartEOF);
+    return false;
+  }
+
+  UngetToken();
+
+  if (mToken.IsSymbol('(')) {
+    return ParseSupportsConditionInParens(aConditionMet) &&
+           ParseSupportsConditionTerms(aConditionMet);
+  }
+
+  if (mToken.mType == eCSSToken_Ident &&
+      mToken.mIdent.LowerCaseEqualsLiteral("not")) {
+    return ParseSupportsConditionNegation(aConditionMet);
+  }
+
+  REPORT_UNEXPECTED_TOKEN(PESupportsConditionExpectedStart);
+  return false;
+}
+
+// supports_condition_negation
+//   : 'not' S* supports_condition_in_parens
+//   ;
+bool
+CSSParserImpl::ParseSupportsConditionNegation(bool& aConditionMet)
+{
+  if (!GetToken(true)) {
+    REPORT_UNEXPECTED_EOF(PESupportsConditionNotEOF);
+    return false;
+  }
+
+  if (mToken.mType != eCSSToken_Ident ||
+      !mToken.mIdent.LowerCaseEqualsLiteral("not")) {
+    REPORT_UNEXPECTED_TOKEN(PESupportsConditionExpectedNot);
+    return false;
+  }
+
+  if (ParseSupportsConditionInParens(aConditionMet)) {
+    aConditionMet = !aConditionMet;
+    return true;
+  }
+
+  return false;
+}
+
+// supports_condition_in_parens
+//   : '(' S* supports_condition_in_parens_inside_parens ')' S*
+//   ;
+bool
+CSSParserImpl::ParseSupportsConditionInParens(bool& aConditionMet)
+{
+  if (!ExpectSymbol('(', true)) {
+    REPORT_UNEXPECTED_TOKEN(PESupportsConditionExpectedOpenParen);
+    return false;
+  }
+
+  if (!ParseSupportsConditionInParensInsideParens(aConditionMet)) {
+    return false;
+  }
+
+  if (!(ExpectSymbol(')', true))) {
+    REPORT_UNEXPECTED_TOKEN(PESupportsConditionExpectedCloseParen);
+    SkipUntil(')');
+    return false;
+  }
+
+  return true;
+}
+
+// supports_condition_in_parens_inside_parens
+//   : core_declaration
+//   | supports_condition_negation
+//   | supports_condition_in_parens supports_condition_terms
+//   ;
+bool
+CSSParserImpl::ParseSupportsConditionInParensInsideParens(bool& aConditionMet)
+{
+  if (!GetToken(true)) {
+    REPORT_UNEXPECTED_EOF(PESupportsConditionInParensStartEOF);
+    return false;
+  }
+
+  if (mToken.mType == eCSSToken_Ident) {
+    if (!mToken.mIdent.LowerCaseEqualsLiteral("not")) {
+      nsAutoString propertyName = mToken.mIdent;
+      if (!ExpectSymbol(':', true)) {
+        REPORT_UNEXPECTED_TOKEN(PEParseDeclarationNoColon);
+        return false;
+      }
+
+      nsCSSProperty propID = nsCSSProps::LookupProperty(propertyName,
+                                                        nsCSSProps::eEnabled);
+      if (propID == eCSSProperty_UNKNOWN) {
+        aConditionMet = false;
+        SkipUntil(')');
+        UngetToken();
+      } else {
+        aConditionMet = ParseProperty(propID) &&
+                        ParsePriority() != ePriority_Error;
+        if (!aConditionMet) {
+          SkipUntil(')');
+          UngetToken();
+        }
+        mTempData.ClearProperty(propID);
+        mTempData.AssertInitialState();
+      }
+      return true;
+    }
+
+    UngetToken();
+    return ParseSupportsConditionNegation(aConditionMet);
+  }
+
+  UngetToken();
+  return ParseSupportsConditionInParens(aConditionMet) &&
+         ParseSupportsConditionTerms(aConditionMet);
+}
+
+// supports_condition_terms
+//   : 'and' S* supports_condition_terms_after_operator('and')
+//   | 'or' S* supports_condition_terms_after_operator('or')
+//   |
+//   ;
+bool
+CSSParserImpl::ParseSupportsConditionTerms(bool& aConditionMet)
+{
+  if (!GetToken(true)) {
+    return true;
+  }
+
+  if (mToken.mType != eCSSToken_Ident) {
+    UngetToken();
+    return true;
+  }
+
+  if (mToken.mIdent.LowerCaseEqualsLiteral("and")) {
+    return ParseSupportsConditionTermsAfterOperator(aConditionMet, eAnd);
+  }
+
+  if (mToken.mIdent.LowerCaseEqualsLiteral("or")) {
+    return ParseSupportsConditionTermsAfterOperator(aConditionMet, eOr);
+  }
+
+  UngetToken();
+  return true;
+}
+
+// supports_condition_terms_after_operator(operator)
+//   : supports_condition_in_parens ( <operator> supports_condition_in_parens )*
+//   ;
+bool
+CSSParserImpl::ParseSupportsConditionTermsAfterOperator(
+                         bool& aConditionMet,
+                         CSSParserImpl::SupportsConditionTermOperator aOperator)
+{
+  const char* token = aOperator == eAnd ? "and" : "or";
+  for (;;) {
+    bool termConditionMet = false;
+    if (!ParseSupportsConditionInParens(termConditionMet)) {
+      return false;
+    }
+    aConditionMet = aOperator == eAnd ? aConditionMet && termConditionMet :
+                                        aConditionMet || termConditionMet;
+
+    if (!GetToken(true)) {
+      return true;
+    }
+
+    if (mToken.mType != eCSSToken_Ident ||
+        !mToken.mIdent.LowerCaseEqualsASCII(token)) {
+      UngetToken();
+      return true;
+    }
+  }
+}
+
 void
 CSSParserImpl::SkipUntil(PRUnichar aStopSymbol)
 {
   nsCSSToken* tk = &mToken;
   nsAutoTArray<PRUnichar, 16> stack;
   stack.AppendElement(aStopSymbol);
   for (;;) {
     if (!GetToken(true)) {
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -2999,17 +2999,18 @@ CascadeRuleEnumFunc(css::Rule* aRule, vo
         new (data->mArena) PerWeightDataListItem(styleRule, sel->mSelectors);
       if (newItem) {
         *(entry->data.mTail) = newItem;
         entry->data.mTail = &newItem->mNext;
       }
     }
   }
   else if (css::Rule::MEDIA_RULE == type ||
-           css::Rule::DOCUMENT_RULE == type) {
+           css::Rule::DOCUMENT_RULE == type ||
+           css::Rule::SUPPORTS_RULE == type) {
     css::GroupRule* groupRule = static_cast<css::GroupRule*>(aRule);
     if (groupRule->UseForPresentation(data->mPresContext, data->mCacheKey))
       if (!groupRule->EnumerateRulesForwards(CascadeRuleEnumFunc, aData))
         return false;
   }
   else if (css::Rule::FONT_FACE_RULE == type) {
     nsCSSFontFaceRule *fontFaceRule = static_cast<nsCSSFontFaceRule*>(aRule);
     nsFontFaceRuleContainer *ptr = data->mFontFaceRules.AppendElement();
--- a/layout/style/nsCSSRules.cpp
+++ b/layout/style/nsCSSRules.cpp
@@ -2161,9 +2161,137 @@ nsCSSKeyframesRule::SizeOfIncludingThis(
 
   // Measurement of the following members may be added later if DMD finds it is
   // worthwhile:
   // - mName
 
   return n;
 }
 
+namespace mozilla {
 
+CSSSupportsRule::CSSSupportsRule(bool aConditionMet,
+                                 const nsString& aCondition)
+  : mUseGroup(aConditionMet),
+    mCondition(aCondition)
+{
+}
+
+CSSSupportsRule::CSSSupportsRule(const CSSSupportsRule& aCopy)
+  : css::GroupRule(aCopy),
+    mUseGroup(aCopy.mUseGroup),
+    mCondition(aCopy.mCondition)
+{
+}
+
+#ifdef DEBUG
+/* virtual */ void
+CSSSupportsRule::List(FILE* out, PRInt32 aIndent) const
+{
+  for (PRInt32 indent = aIndent; --indent >= 0; ) fputs("  ", out);
+
+  nsAutoString buffer;
+
+  fputs("@supports ", out);
+
+  fputs(NS_LossyConvertUTF16toASCII(mCondition).get(), out);
+
+  css::GroupRule::List(out, aIndent);
+}
+#endif
+
+/* virtual */ PRInt32
+CSSSupportsRule::GetType() const
+{
+  return Rule::SUPPORTS_RULE;
+}
+
+/* virtual */ already_AddRefed<mozilla::css::Rule>
+CSSSupportsRule::Clone() const
+{
+  nsRefPtr<css::Rule> clone = new CSSSupportsRule(*this);
+  return clone.forget();
+}
+
+/* virtual */ bool
+CSSSupportsRule::UseForPresentation(nsPresContext* aPresContext,
+                                   nsMediaQueryResultCacheKey& aKey)
+{
+  return mUseGroup;
+}
+
+NS_IMPL_ADDREF_INHERITED(CSSSupportsRule, css::GroupRule)
+NS_IMPL_RELEASE_INHERITED(CSSSupportsRule, css::GroupRule)
+
+// QueryInterface implementation for CSSSupportsRule
+NS_INTERFACE_MAP_BEGIN(CSSSupportsRule)
+  NS_INTERFACE_MAP_ENTRY(nsIStyleRule)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRule)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMCSSSupportsRule)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStyleRule)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CSSSupportsRule)
+NS_INTERFACE_MAP_END
+
+// nsIDOMCSSRule methods
+NS_IMETHODIMP
+CSSSupportsRule::GetType(PRUint16* aType)
+{
+  *aType = nsIDOMCSSRule::SUPPORTS_RULE;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+CSSSupportsRule::GetCssText(nsAString& aCssText)
+{
+  aCssText.AssignLiteral("@supports ");
+  aCssText.Append(mCondition);
+  return css::GroupRule::AppendRulesToCssText(aCssText);
+}
+
+NS_IMETHODIMP
+CSSSupportsRule::SetCssText(const nsAString& aCssText)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+CSSSupportsRule::GetParentStyleSheet(nsIDOMCSSStyleSheet** aSheet)
+{
+  return css::GroupRule::GetParentStyleSheet(aSheet);
+}
+
+NS_IMETHODIMP
+CSSSupportsRule::GetParentRule(nsIDOMCSSRule** aParentRule)
+{
+  return css::GroupRule::GetParentRule(aParentRule);
+}
+
+/* virtual */ size_t
+CSSSupportsRule::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  size_t n = aMallocSizeOf(this);
+  n += css::GroupRule::SizeOfExcludingThis(aMallocSizeOf);
+  n += mCondition.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
+  return n;
+}
+
+NS_IMETHODIMP
+CSSSupportsRule::GetCssRules(nsIDOMCSSRuleList* *aRuleList)
+{
+  return css::GroupRule::GetCssRules(aRuleList);
+}
+
+NS_IMETHODIMP
+CSSSupportsRule::InsertRule(const nsAString & aRule, PRUint32 aIndex, PRUint32* _retval)
+{
+  return css::GroupRule::InsertRule(aRule, aIndex, _retval);
+}
+
+NS_IMETHODIMP
+CSSSupportsRule::DeleteRule(PRUint32 aIndex)
+{
+  return css::GroupRule::DeleteRule(aIndex);
+}
+
+} // namespace mozilla
+
+// Must be outside namespace
+DOMCI_DATA(CSSSupportsRule, mozilla::CSSSupportsRule)
--- a/layout/style/nsCSSRules.h
+++ b/layout/style/nsCSSRules.h
@@ -7,19 +7,21 @@
 /* rules in a CSS stylesheet other than style rules (e.g., @import rules) */
 
 #ifndef nsCSSRules_h_
 #define nsCSSRules_h_
 
 #include "mozilla/Attributes.h"
 
 #include "mozilla/css/GroupRule.h"
+#include "mozilla/Preferences.h"
+#include "nsIDOMCSSFontFaceRule.h"
 #include "nsIDOMCSSMediaRule.h"
 #include "nsIDOMCSSMozDocumentRule.h"
-#include "nsIDOMCSSFontFaceRule.h"
+#include "nsIDOMCSSSupportsRule.h"
 #include "nsIDOMMozCSSKeyframeRule.h"
 #include "nsIDOMMozCSSKeyframesRule.h"
 #include "nsIDOMCSSStyleDeclaration.h"
 #include "nsICSSRuleList.h"
 #include "nsAutoPtr.h"
 #include "nsCSSProperty.h"
 #include "nsCSSValue.h"
 #include "nsIDOMCSSCharsetRule.h"
@@ -405,9 +407,55 @@ public:
   virtual size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
 
 private:
   PRUint32 FindRuleIndexForKey(const nsAString& aKey);
 
   nsString                                   mName;
 };
 
+namespace mozilla {
+
+class CSSSupportsRule : public css::GroupRule,
+                        public nsIDOMCSSSupportsRule
+{
+public:
+  CSSSupportsRule(bool aConditionMet, const nsString& aCondition);
+  CSSSupportsRule(const CSSSupportsRule& aCopy);
+
+  // nsIStyleRule methods
+#ifdef DEBUG
+  virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const;
+#endif
+
+  // Rule methods
+  virtual PRInt32 GetType() const;
+  virtual already_AddRefed<mozilla::css::Rule> Clone() const;
+  virtual bool UseForPresentation(nsPresContext* aPresContext,
+                                  nsMediaQueryResultCacheKey& aKey);
+  virtual nsIDOMCSSRule* GetDOMRule()
+  {
+    return this;
+  }
+
+  NS_DECL_ISUPPORTS_INHERITED
+
+  // nsIDOMCSSRule interface
+  NS_DECL_NSIDOMCSSRULE
+
+  // nsIDOMCSSSupportsRule interface
+  NS_DECL_NSIDOMCSSSUPPORTSRULE
+
+  virtual size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
+
+  static bool PrefEnabled()
+  {
+    return Preferences::GetBool("layout.css.supports-rule.enabled");
+  }
+
+protected:
+  bool mUseGroup;
+  nsString mCondition;
+};
+
+} // namespace mozilla
+
 #endif /* !defined(nsCSSRules_h_) */
--- a/layout/style/nsCSSScanner.cpp
+++ b/layout/style/nsCSSScanner.cpp
@@ -342,16 +342,17 @@ nsCSSScanner::Init(const nsAString& aBuf
     }
   }
 #endif // CSS_REPORT_PARSE_ERRORS
   mLineNumber = aLineNumber;
 
   // Reset variables that we use to keep track of our progress through the input
   mOffset = 0;
   mPushbackCount = 0;
+  mRecording = false;
 
 #ifdef CSS_REPORT_PARSE_ERRORS
   mColNumber = 0;
   mSheet = aSheet;
   mLoader = aLoader;
 #endif
 }
 
@@ -636,16 +637,40 @@ nsCSSScanner::Pushback(PRUnichar aChar)
     if (mPushback != mLocalPushback) {
       delete [] mPushback;
     }
     mPushback = newPushback;
   }
   mPushback[mPushbackCount++] = aChar;
 }
 
+void
+nsCSSScanner::StartRecording()
+{
+  NS_ASSERTION(!mRecording, "already started recording");
+  mRecording = true;
+  mRecordStartOffset = mOffset - mPushbackCount;
+}
+
+void
+nsCSSScanner::StopRecording()
+{
+  NS_ASSERTION(mRecording, "haven't started recording");
+  mRecording = false;
+}
+
+void
+nsCSSScanner::StopRecording(nsString& aBuffer)
+{
+  NS_ASSERTION(mRecording, "haven't started recording");
+  mRecording = false;
+  aBuffer.Append(mReadPointer + mRecordStartOffset,
+                 mOffset - mPushbackCount - mRecordStartOffset);
+}
+
 bool
 nsCSSScanner::LookAhead(PRUnichar aChar)
 {
   PRInt32 ch = Read();
   if (ch < 0) {
     return false;
   }
   if (ch == aChar) {
--- a/layout/style/nsCSSScanner.h
+++ b/layout/style/nsCSSScanner.h
@@ -163,16 +163,26 @@ public:
   bool NextURL(nsCSSToken& aTokenResult);
 
   // It's really ugly that we have to expose this, but it's the easiest
   // way to do :nth-child() parsing sanely.  (In particular, in
   // :nth-child(2n-1), "2n-1" is a dimension, and we need to push the
   // "-1" back so we can read it again as a number.)
   void Pushback(PRUnichar aChar);
 
+  // Starts recording the input stream from the current position.
+  void StartRecording();
+
+  // Abandons recording of the input stream.
+  void StopRecording();
+
+  // Stops recording of the input stream and appends the recorded
+  // input to aBuffer.
+  void StopRecording(nsString& aBuffer);
+
 protected:
   PRInt32 Read();
   PRInt32 Peek();
   bool LookAhead(PRUnichar aChar);
   bool LookAheadOrEOF(PRUnichar aChar); // expect either aChar or EOF
   void EatWhiteSpace();
 
   bool ParseAndAppendEscape(nsString& aOutput, bool aInString);
@@ -192,16 +202,19 @@ protected:
   PRUnichar* mPushback;
   PRInt32 mPushbackCount;
   PRInt32 mPushbackSize;
   PRUnichar mLocalPushback[4];
 
   PRUint32 mLineNumber;
   // True if we are in SVG mode; false in "normal" CSS
   bool mSVGMode;
+  bool mRecording;
+  PRUint32 mRecordStartOffset;
+
 #ifdef CSS_REPORT_PARSE_ERRORS
   nsXPIDLCString mFileName;
   nsCOMPtr<nsIURI> mURI;  // Cached so we know to not refetch mFileName
   PRUint32 mErrorLineNumber, mColNumber, mErrorColNumber;
   nsFixedString mError;
   PRUnichar mErrorBuf[200];
   PRUint64 mInnerWindowID;
   bool mWindowIDCached;
--- a/layout/style/test/Makefile.in
+++ b/layout/style/test/Makefile.in
@@ -124,16 +124,17 @@ MOCHITEST_FILES =	test_acid3_test46.html
 		test_property_syntax_errors.html \
 		test_rem_unit.html \
 		test_rule_serialization.html \
 		test_rules_out_of_sheets.html \
 		test_selectors.html \
 		test_selectors_on_anonymous_content.html \
 		test_shorthand_property_getters.html \
 		test_style_struct_copy_constructors.html \
+		test_supports_rules.html \
 		test_system_font_serialization.html \
 		test_transitions_and_zoom.html \
 		test_transitions_cancel_near_end.html \
 		test_transitions_computed_values.html \
 		test_transitions_computed_value_combinations.html \
 		test_transitions_events.html \
 		test_transitions.html \
 		test_transitions_per_property.html \
new file mode 100644
--- /dev/null
+++ b/layout/style/test/test_supports_rules.html
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=649740
+-->
+<head>
+  <title>Test for Bug 649740</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <style id="style">
+    @supports(color: green){ }
+    @supports (color: green) { }
+    @supports ((color: green)) { }
+    @supports (color: green) and (color: blue) { }
+    @supports ( Font:  20px serif ! Important)  { }
+    @supports(a:) { }
+  </style>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=649740">Mozilla Bug 649740</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 649740 **/
+
+function condition(s) {
+  return s.replace(/^@supports\s*/, '').replace(/ \s*{\s*}\s*$/, '');
+}
+
+var sheet = document.getElementById("style").sheet;
+
+is(condition(sheet.cssRules[0].cssText), "(color: green)");
+is(condition(sheet.cssRules[1].cssText), "(color: green)");
+is(condition(sheet.cssRules[2].cssText), "((color: green))");
+is(condition(sheet.cssRules[3].cssText), "(color: green) and (color: blue)");
+is(condition(sheet.cssRules[4].cssText), "( Font:  20px serif ! Important)");
+is(condition(sheet.cssRules[5].cssText), "(a:)");
+</script>
+</pre>
+</body>
+</html>
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -1551,16 +1551,19 @@ pref("layout.css.dpi", -1);
 // Set the number of device pixels per CSS pixel. A value <= 0 means choose
 // automatically based on user settings for the platform (e.g., "UI scale factor"
 // on Mac). A positive value is used as-is. This effectively controls the size
 // of a CSS "px". This is only used for windows on the screen, not for printing.
 // XXX the default value here should be 0, but before we can set it to 0,
 // we have to get this feature working on all platforms.
 pref("layout.css.devPixelsPerPx", "1.0");
 
+// Is support for the the @supports rule enabled?
+pref("layout.css.supports-rule.enabled", true);
+
 // pref for which side vertical scrollbars should be on
 // 0 = end-side in UI direction
 // 1 = end-side in document/content direction
 // 2 = right
 // 3 = left
 pref("layout.scrollbar.side", 0);
 
 // pref to control browser frame rate, in Hz. A value <= 0 means choose