Skip to content

Commit

Permalink
Stylo: Bug 1355408 - add support for @-moz-document
Browse files Browse the repository at this point in the history
  • Loading branch information
ferjm committed May 9, 2017
1 parent 9c9bd17 commit b22e0e9
Show file tree
Hide file tree
Showing 12 changed files with 338 additions and 24 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions components/script/dom/cssrule.rs
Expand Up @@ -85,6 +85,7 @@ impl CSSRule {
StyleCssRule::Viewport(s) => Root::upcast(CSSViewportRule::new(window, parent_stylesheet, s)),
StyleCssRule::Supports(s) => Root::upcast(CSSSupportsRule::new(window, parent_stylesheet, s)),
StyleCssRule::Page(_) => unreachable!(),
StyleCssRule::Document(_) => unimplemented!(), // TODO
}
}

Expand Down
2 changes: 2 additions & 0 deletions components/style/build_gecko.rs
Expand Up @@ -349,6 +349,7 @@ mod bindings {
"mozilla::ServoElementSnapshot.*",
"mozilla::CSSPseudoClassType",
"mozilla::css::SheetParsingMode",
"mozilla::css::URLMatchingFunction",
"mozilla::HalfCorner",
"mozilla::PropertyStyleAnimationValuePair",
"mozilla::TraversalRestyleBehavior",
Expand Down Expand Up @@ -739,6 +740,7 @@ mod bindings {
"UpdateAnimationsTasks",
"LengthParsingMode",
"InheritTarget",
"URLMatchingFunction",
];
struct ArrayType {
cpp_type: &'static str,
Expand Down
176 changes: 176 additions & 0 deletions components/style/document_condition.rs
@@ -0,0 +1,176 @@
/* 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/. */

//! [@document rules](https://www.w3.org/TR/2012/WD-css3-conditional-20120911/#at-document)
//! initially in CSS Conditional Rules Module Level 3, @document has been postponed to the level 4.
//! We implement the prefixed `@-moz-document`.

use cssparser::{Parser, Token, serialize_string};
#[cfg(feature = "gecko")]
use gecko_bindings::bindings::Gecko_DocumentRule_UseForPresentation;
#[cfg(feature = "gecko")]
use gecko_bindings::structs::URLMatchingFunction as GeckoUrlMatchingFunction;
use media_queries::Device;
#[cfg(feature = "gecko")]
use nsstring::nsCString;
use parser::{Parse, ParserContext};
use std::fmt;
use style_traits::ToCss;
use values::specified::url::SpecifiedUrl;

/// A URL matching function for a `@document` rule's condition.
#[derive(Debug)]
pub enum UrlMatchingFunction {
/// Exact URL matching function. It evaluates to true whenever the
/// URL of the document being styled is exactly the URL given.
Url(SpecifiedUrl),
/// URL prefix matching function. It evaluates to true whenever the
/// URL of the document being styled has the argument to the
/// function as an initial substring (which is true when the two
/// strings are equal). When the argument is the empty string,
/// it evaluates to true for all documents.
UrlPrefix(String),
/// Domain matching function. It evaluates to true whenever the URL
/// of the document being styled has a host subcomponent and that
/// host subcomponent is exactly the argument to the ‘domain()’
/// function or a final substring of the host component is a
/// period (U+002E) immediately followed by the argument to the
/// ‘domain()’ function.
Domain(String),
/// Regular expression matching function. It evaluates to true
/// whenever the regular expression matches the entirety of the URL
/// of the document being styled.
RegExp(String),
}

macro_rules! parse_quoted_or_unquoted_string {
($input:ident, $url_matching_function:expr) => {
$input.parse_nested_block(|input| {
let start = input.position();
input.parse_entirely(|input| {
match input.next() {
Ok(Token::QuotedString(value)) =>
Ok($url_matching_function(value.into_owned())),
_ => Err(()),
}
}).or_else(|_| {
while let Ok(_) = input.next() {}
Ok($url_matching_function(input.slice_from(start).to_string()))
})
})
}
}

impl UrlMatchingFunction {
/// Parse a URL matching function for a`@document` rule's condition.
pub fn parse(context: &ParserContext, input: &mut Parser)
-> Result<UrlMatchingFunction, ()> {
if input.try(|input| input.expect_function_matching("url-prefix")).is_ok() {
parse_quoted_or_unquoted_string!(input, UrlMatchingFunction::UrlPrefix)
} else if input.try(|input| input.expect_function_matching("domain")).is_ok() {
parse_quoted_or_unquoted_string!(input, UrlMatchingFunction::Domain)
} else if input.try(|input| input.expect_function_matching("regexp")).is_ok() {
input.parse_nested_block(|input| {
Ok(UrlMatchingFunction::RegExp(input.expect_string()?.into_owned()))
})
} else if let Ok(url) = input.try(|input| SpecifiedUrl::parse(context, input)) {
Ok(UrlMatchingFunction::Url(url))
} else {
Err(())
}
}

#[cfg(feature = "gecko")]
/// Evaluate a URL matching function.
pub fn evaluate(&self, device: &Device) -> bool {
let func = match *self {
UrlMatchingFunction::Url(_) => GeckoUrlMatchingFunction::eURL,
UrlMatchingFunction::UrlPrefix(_) => GeckoUrlMatchingFunction::eURLPrefix,
UrlMatchingFunction::Domain(_) => GeckoUrlMatchingFunction::eDomain,
UrlMatchingFunction::RegExp(_) => GeckoUrlMatchingFunction::eRegExp,
};
let pattern = nsCString::from(match *self {
UrlMatchingFunction::Url(ref url) => url.as_str(),
UrlMatchingFunction::UrlPrefix(ref pat) |
UrlMatchingFunction::Domain(ref pat) |
UrlMatchingFunction::RegExp(ref pat) => pat,
});
unsafe {
Gecko_DocumentRule_UseForPresentation(&*device.pres_context, &*pattern, func)
}
}

#[cfg(not(feature = "gecko"))]
/// Evaluate a URL matching function.
pub fn evaluate(&self, _: &Device) -> bool {
false
}
}

impl ToCss for UrlMatchingFunction {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
where W: fmt::Write {
match *self {
UrlMatchingFunction::Url(ref url) => {
url.to_css(dest)
},
UrlMatchingFunction::UrlPrefix(ref url_prefix) => {
dest.write_str("url-prefix(")?;
serialize_string(url_prefix, dest)?;
dest.write_str(")")
},
UrlMatchingFunction::Domain(ref domain) => {
dest.write_str("domain(")?;
serialize_string(domain, dest)?;
dest.write_str(")")
},
UrlMatchingFunction::RegExp(ref regex) => {
dest.write_str("regexp(")?;
serialize_string(regex, dest)?;
dest.write_str(")")
},
}
}
}

/// A `@document` rule's condition.
///
/// https://www.w3.org/TR/2012/WD-css3-conditional-20120911/#at-document
///
/// The `@document` rule's condition is written as a comma-separated list of
/// URL matching functions, and the condition evaluates to true whenever any
/// one of those functions evaluates to true.
#[derive(Debug)]
pub struct DocumentCondition(Vec<UrlMatchingFunction>);

impl DocumentCondition {
/// Parse a document condition.
pub fn parse(context: &ParserContext, input: &mut Parser)
-> Result<Self, ()> {
input.parse_comma_separated(|input| UrlMatchingFunction::parse(context, input))
.map(DocumentCondition)
}

/// Evaluate a document condition.
pub fn evaluate(&self, device: &Device) -> bool {
self.0.iter().any(|ref url_matching_function|
url_matching_function.evaluate(device)
)
}
}

impl ToCss for DocumentCondition {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
where W: fmt::Write {
let mut iter = self.0.iter();
let first = iter.next()
.expect("Empty DocumentCondition, should contain at least one URL matching function");
first.to_css(dest)?;
for url_matching_function in iter {
dest.write_str(", ")?;
url_matching_function.to_css(dest)?;
}
Ok(())
}
}
9 changes: 9 additions & 0 deletions components/style/gecko/generated/bindings.rs
Expand Up @@ -194,6 +194,7 @@ use gecko_bindings::structs::EffectCompositor_CascadeLevel;
use gecko_bindings::structs::UpdateAnimationsTasks;
use gecko_bindings::structs::LengthParsingMode;
use gecko_bindings::structs::InheritTarget;
use gecko_bindings::structs::URLMatchingFunction;
pub type nsTArrayBorrowed_uintptr_t<'a> = &'a mut ::gecko_bindings::structs::nsTArray<usize>;
pub type ServoCssRulesStrong = ::gecko_bindings::sugar::ownership::Strong<ServoCssRules>;
pub type ServoCssRulesBorrowed<'a> = &'a ServoCssRules;
Expand Down Expand Up @@ -1549,6 +1550,14 @@ extern "C" {
extern "C" {
pub fn Gecko_UnregisterProfilerThread();
}
extern "C" {
pub fn Gecko_DocumentRule_UseForPresentation(arg1:
RawGeckoPresContextBorrowed,
aPattern: *const nsACString,
aURLMatchingFunction:
URLMatchingFunction)
-> bool;
}
extern "C" {
pub fn Servo_Element_ClearData(node: RawGeckoElementBorrowed);
}
Expand Down
12 changes: 12 additions & 0 deletions components/style/gecko/generated/structs_debug.rs
Expand Up @@ -2130,6 +2130,18 @@ pub mod root {
ComplexColorValue ) , "::" , stringify ! (
_mOwningThread ) ));
}
#[repr(i32)]
/**
* Enum defining the type of URL matching function for a @-moz-document rule
* condition.
*/
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum URLMatchingFunction {
eURL = 0,
eURLPrefix = 1,
eDomain = 2,
eRegExp = 3,
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct DocumentRule {
Expand Down
12 changes: 12 additions & 0 deletions components/style/gecko/generated/structs_release.rs
Expand Up @@ -2036,6 +2036,18 @@ pub mod root {
ComplexColorValue ) , "::" , stringify ! ( mRefCnt
) ));
}
#[repr(i32)]
/**
* Enum defining the type of URL matching function for a @-moz-document rule
* condition.
*/
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum URLMatchingFunction {
eURL = 0,
eURLPrefix = 1,
eDomain = 2,
eRegExp = 3,
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct DocumentRule {
Expand Down
1 change: 1 addition & 0 deletions components/style/lib.rs
Expand Up @@ -93,6 +93,7 @@ pub mod context;
pub mod counter_style;
pub mod custom_properties;
pub mod data;
pub mod document_condition;
pub mod dom;
pub mod element_state;
#[cfg(feature = "servo")] mod encoding_support;
Expand Down

0 comments on commit b22e0e9

Please sign in to comment.