Bug 1267890 part 1 - Add @supports -moz-bool-pref() support for stylo. r?emilio
MozReview-Commit-ID: C9Pq2zLLaGp
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -53,16 +53,17 @@
#include "mozilla/DeclarationBlockInlines.h"
#include "mozilla/EffectCompositor.h"
#include "mozilla/EffectSet.h"
#include "mozilla/EventStates.h"
#include "mozilla/GeckoStyleContext.h"
#include "mozilla/Keyframe.h"
#include "mozilla/Mutex.h"
+#include "mozilla/Preferences.h"
#include "mozilla/ServoElementSnapshot.h"
#include "mozilla/ServoRestyleManager.h"
#include "mozilla/SizeOfState.h"
#include "mozilla/StyleAnimationValue.h"
#include "mozilla/SystemGroup.h"
#include "mozilla/ServoMediaList.h"
#include "mozilla/RWLock.h"
#include "mozilla/dom/Element.h"
@@ -2827,8 +2828,15 @@ Gecko_ContentList_AppendAll(
const nsTArray<Element*>*
Gecko_GetElementsWithId(const nsIDocument* aDocument, nsAtom* aId)
{
MOZ_ASSERT(aDocument);
MOZ_ASSERT(aId);
return aDocument->GetAllElementsForId(nsDependentAtomString(aId));
}
+
+bool
+Gecko_GetBoolPrefValue(const char* aPrefName)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ return Preferences::GetBool(aPrefName);
+}
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -710,11 +710,15 @@ void Gecko_ReportUnexpectedCSSError(mozi
void Gecko_ContentList_AppendAll(nsSimpleContentList* aContentList,
const RawGeckoElement** aElements,
size_t aLength);
const nsTArray<mozilla::dom::Element*>* Gecko_GetElementsWithId(
const nsIDocument* aDocument,
nsAtom* aId);
+// Check the value of the given bool preference. The pref name needs to
+// be null-terminated.
+bool Gecko_GetBoolPrefValue(const char* pref_name);
+
} // extern "C"
#endif // mozilla_ServoBindings_h
--- a/servo/components/style/gecko/generated/bindings.rs
+++ b/servo/components/style/gecko/generated/bindings.rs
@@ -1590,9 +1590,11 @@ extern "C" {
} extern "C" {
pub fn Gecko_DestroyCSSErrorReporter ( reporter : * mut ErrorReporter , ) ;
} extern "C" {
pub fn Gecko_ReportUnexpectedCSSError ( reporter : * mut ErrorReporter , message : * const :: std :: os :: raw :: c_char , param : * const :: std :: os :: raw :: c_char , paramLen : u32 , prefix : * const :: std :: os :: raw :: c_char , prefixParam : * const :: std :: os :: raw :: c_char , prefixParamLen : u32 , suffix : * const :: std :: os :: raw :: c_char , source : * const :: std :: os :: raw :: c_char , sourceLen : u32 , lineNumber : u32 , colNumber : u32 , ) ;
} extern "C" {
pub fn Gecko_ContentList_AppendAll ( aContentList : * mut nsSimpleContentList , aElements : * mut * const RawGeckoElement , aLength : usize , ) ;
} extern "C" {
pub fn Gecko_GetElementsWithId ( aDocument : * const nsIDocument , aId : * mut nsAtom , ) -> * const nsTArray < * mut Element > ;
+} extern "C" {
+ pub fn Gecko_GetBoolPrefValue ( pref_name : * const :: std :: os :: raw :: c_char , ) -> bool ;
}
\ No newline at end of file
--- a/servo/components/style/stylesheets/supports_rule.rs
+++ b/servo/components/style/stylesheets/supports_rule.rs
@@ -8,19 +8,22 @@ use cssparser::{Delimiter, parse_importa
use cssparser::{ParseError as CssParseError, ParserInput};
#[cfg(feature = "gecko")]
use malloc_size_of::{MallocSizeOfOps, MallocUnconditionalShallowSizeOf};
use parser::ParserContext;
use properties::{PropertyId, PropertyDeclaration, SourcePropertyDeclaration};
use selectors::parser::SelectorParseErrorKind;
use servo_arc::Arc;
use shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
+use std::ascii::AsciiExt;
+use std::ffi::{CStr, CString};
use std::fmt;
+use std::str;
use style_traits::{ToCss, ParseError};
-use stylesheets::{CssRuleType, CssRules};
+use stylesheets::{CssRuleType, CssRules, Origin};
/// An [`@supports`][supports] rule.
///
/// [supports]: https://drafts.csswg.org/css-conditional-3/#at-supports
#[derive(Debug)]
pub struct SupportsRule {
/// The parsed condition
pub condition: SupportsCondition,
@@ -78,16 +81,20 @@ pub enum SupportsCondition {
/// `(condition)`
Parenthesized(Box<SupportsCondition>),
/// `(condition) and (condition) and (condition) ..`
And(Vec<SupportsCondition>),
/// `(condition) or (condition) or (condition) ..`
Or(Vec<SupportsCondition>),
/// `property-ident: value` (value can be any tokens)
Declaration(Declaration),
+ /// `-moz-bool-pref("pref-name")`
+ /// Since we need to pass it through FFI to get the pref value,
+ /// we store it as CString directly.
+ MozBoolPref(CString),
/// `(any tokens)` or `func(any tokens)`
FutureSyntax(String),
}
impl SupportsCondition {
/// Parse a condition
///
/// <https://drafts.csswg.org/css-conditional/#supports_condition>
@@ -140,36 +147,70 @@ impl SupportsCondition {
Token::ParenthesisBlock => {
let nested = input.try(|input| {
input.parse_nested_block(|i| parse_condition_or_declaration(i))
});
if nested.is_ok() {
return nested;
}
}
- Token::Function(_) => {}
+ Token::Function(ident) => {
+ // Although this is an internal syntax, it is not necessary to check
+ // parsing context as far as we accept any unexpected token as future
+ // syntax, and evaluate it to false when not in chrome / ua sheet.
+ // See https://drafts.csswg.org/css-conditional-3/#general_enclosed
+ if ident.eq_ignore_ascii_case("-moz-bool-pref") {
+ if let Ok(name) = input.try(|i| {
+ i.parse_nested_block(|i| {
+ i.expect_string()
+ .map(|s| s.to_string())
+ .map_err(CssParseError::<()>::from)
+ }).and_then(|s| {
+ CString::new(s)
+ .map_err(|_| location.new_custom_error(()))
+ })
+ }) {
+ return Ok(SupportsCondition::MozBoolPref(name));
+ }
+ }
+ }
t => return Err(location.new_unexpected_token_error(t)),
}
input.parse_nested_block(|i| consume_any_value(i))?;
Ok(SupportsCondition::FutureSyntax(input.slice_from(pos).to_owned()))
}
/// Evaluate a supports condition
pub fn eval(&self, cx: &ParserContext) -> bool {
match *self {
SupportsCondition::Not(ref cond) => !cond.eval(cx),
SupportsCondition::Parenthesized(ref cond) => cond.eval(cx),
SupportsCondition::And(ref vec) => vec.iter().all(|c| c.eval(cx)),
SupportsCondition::Or(ref vec) => vec.iter().any(|c| c.eval(cx)),
SupportsCondition::Declaration(ref decl) => decl.eval(cx),
+ SupportsCondition::MozBoolPref(ref name) => eval_moz_bool_pref(name, cx),
SupportsCondition::FutureSyntax(_) => false
}
}
}
+#[cfg(feature = "gecko")]
+fn eval_moz_bool_pref(name: &CStr, cx: &ParserContext) -> bool {
+ use gecko_bindings::bindings;
+ if cx.stylesheet_origin != Origin::UserAgent && !cx.chrome_rules_enabled() {
+ return false;
+ }
+ unsafe { bindings::Gecko_GetBoolPrefValue(name.as_ptr()) }
+}
+
+#[cfg(feature = "servo")]
+fn eval_moz_bool_pref(_: &str, _: &ParserContext) -> bool {
+ false
+}
+
/// supports_condition | declaration
/// <https://drafts.csswg.org/css-conditional/#dom-css-supports-conditiontext-conditiontext>
pub fn parse_condition_or_declaration<'i, 't>(input: &mut Parser<'i, 't>)
-> Result<SupportsCondition, ParseError<'i>> {
if let Ok(condition) = input.try(SupportsCondition::parse) {
Ok(SupportsCondition::Parenthesized(Box::new(condition)))
} else {
Declaration::parse(input).map(SupportsCondition::Declaration)
@@ -212,16 +253,23 @@ impl ToCss for SupportsCondition {
}
Ok(())
}
SupportsCondition::Declaration(ref decl) => {
dest.write_str("(")?;
decl.to_css(dest)?;
dest.write_str(")")
}
+ SupportsCondition::MozBoolPref(ref name) => {
+ dest.write_str("-moz-bool-pref(")?;
+ let name = str::from_utf8(name.as_bytes())
+ .expect("Should be parsed from valid UTF-8");
+ name.to_css(dest)?;
+ dest.write_str(")")
+ }
SupportsCondition::FutureSyntax(ref s) => dest.write_str(&s),
}
}
}
#[derive(Clone, Debug)]
/// A possibly-invalid property declaration
pub struct Declaration(pub String);