aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/components/gfx/font_cache_task.rs32
-rw-r--r--src/components/layout/layout_task.rs19
-rw-r--r--src/components/script/dom/element.rs17
-rw-r--r--src/components/script/dom/node.rs34
-rw-r--r--src/components/style/font_face.rs27
-rw-r--r--src/components/style/selector_matching.rs12
-rw-r--r--src/components/style/selectors.rs18
-rw-r--r--src/components/style/style.rs12
-rw-r--r--src/components/style/stylesheets.rs16
9 files changed, 103 insertions, 84 deletions
diff --git a/src/components/gfx/font_cache_task.rs b/src/components/gfx/font_cache_task.rs
index 88455f92b2e..8444fead414 100644
--- a/src/components/gfx/font_cache_task.rs
+++ b/src/components/gfx/font_cache_task.rs
@@ -70,7 +70,7 @@ impl FontFamily {
/// Commands that the FontContext sends to the font cache task.
pub enum Command {
GetFontTemplate(String, FontTemplateDescriptor, Sender<Reply>),
- AddWebFont(Vec<Url>, String, Sender<()>),
+ AddWebFont(String, Url, Sender<()>),
Exit(Sender<()>),
}
@@ -105,21 +105,19 @@ impl FontCache {
result.send(GetFontTemplateReply(font_template));
}
- AddWebFont(urls, family_name, result) => {
- for url in urls.iter() {
- let maybe_resource = load_whole_resource(&self.resource_task, url.clone());
- match maybe_resource {
- Ok((_, bytes)) => {
- if !self.web_families.contains_key(&family_name) {
- let family = FontFamily::new();
- self.web_families.insert(family_name.clone(), family);
- }
- let family = self.web_families.get_mut(&family_name);
- family.add_template(format!("{}", url).as_slice(), Some(bytes));
- },
- Err(msg) => {
- fail!("{}: url={}", msg, url);
+ AddWebFont(family_name, url, result) => {
+ let maybe_resource = load_whole_resource(&self.resource_task, url.clone());
+ match maybe_resource {
+ Ok((_, bytes)) => {
+ if !self.web_families.contains_key(&family_name) {
+ let family = FontFamily::new();
+ self.web_families.insert(family_name.clone(), family);
}
+ let family = self.web_families.get_mut(&family_name);
+ family.add_template(format!("{}", url).as_slice(), Some(bytes));
+ },
+ Err(msg) => {
+ fail!("{}: url={}", msg, url);
}
}
result.send(());
@@ -264,9 +262,9 @@ impl FontCacheTask {
}
}
- pub fn add_web_font(&mut self, urls: Vec<Url>, family: &str) {
+ pub fn add_web_font(&mut self, family: String, url: Url) {
let (response_chan, response_port) = channel();
- self.chan.send(AddWebFont(urls, family.to_string(), response_chan));
+ self.chan.send(AddWebFont(family, url, response_chan));
response_port.recv();
}
diff --git a/src/components/layout/layout_task.rs b/src/components/layout/layout_task.rs
index a0e1dd45d89..e4cba397379 100644
--- a/src/components/layout/layout_task.rs
+++ b/src/components/layout/layout_task.rs
@@ -56,7 +56,7 @@ use std::comm::{channel, Sender, Receiver, Select};
use std::mem;
use std::ptr;
use style::{AuthorOrigin, Stylesheet, Stylist};
-use style::CSSFontFaceRule;
+use style::iter_font_face_rules;
use sync::{Arc, Mutex};
use url::Url;
@@ -490,20 +490,9 @@ impl LayoutTask {
fn handle_add_stylesheet(&mut self, sheet: Stylesheet) {
// Find all font-face rules and notify the font cache of them.
// GWTODO: Need to handle unloading web fonts (when we handle unloading stylesheets!)
- // GWTODO: Need to handle font-face nested within media rules.
- for rule in sheet.rules.iter() {
- match rule {
- &CSSFontFaceRule(ref font_face_rule) => {
- let mut font_urls = vec!();
- for source in font_face_rule.sources.iter() {
- font_urls.push(source.url.clone());
- }
- self.font_cache_task.add_web_font(font_urls, font_face_rule.family.as_slice());
- },
- _ => {}
- }
- }
-
+ iter_font_face_rules(&sheet, |family, url| {
+ self.font_cache_task.add_web_font(family.to_string(), url.clone());
+ });
self.stylist.add_stylesheet(sheet, AuthorOrigin);
}
diff --git a/src/components/script/dom/element.rs b/src/components/script/dom/element.rs
index 6213e8c9a6a..cdb2f4f1f2b 100644
--- a/src/components/script/dom/element.rs
+++ b/src/components/script/dom/element.rs
@@ -4,7 +4,6 @@
//! Element nodes.
-use cssparser::tokenize;
use dom::attr::{Attr, ReplacedAttr, FirstSetAttr, AttrHelpersForLayout};
use dom::attr::{AttrValue, StringAttrValue, UIntAttrValue, AtomAttrValue};
use dom::attrlist::AttrList;
@@ -31,7 +30,7 @@ use dom::nodelist::NodeList;
use dom::virtualmethods::{VirtualMethods, vtable_for};
use layout_interface::ContentChangedDocumentDamage;
use layout_interface::MatchSelectorsDocumentDamage;
-use style::{matches_compound_selector, NamespaceMap, parse_selector_list};
+use style::{matches, parse_selector_list_from_str};
use style;
use servo_util::atom::Atom;
use servo_util::namespace;
@@ -775,21 +774,13 @@ impl<'a> ElementMethods for JSRef<'a, Element> {
// http://dom.spec.whatwg.org/#dom-element-matches
fn Matches(&self, selectors: DOMString) -> Fallible<bool> {
- let namespace = NamespaceMap::new();
- match parse_selector_list(tokenize(selectors.as_slice()).map(|(token, _)| token).collect(),
- &namespace) {
- Err(()) => return Err(Syntax),
+ match parse_selector_list_from_str(selectors.as_slice()) {
+ Err(()) => Err(Syntax),
Ok(ref selectors) => {
let root: &JSRef<Node> = NodeCast::from_ref(self);
- for selector in selectors.iter() {
- let mut shareable = false;
- if matches_compound_selector(&*selector.compound_selectors, root, &mut shareable) {
- return Ok(true);
- }
- }
+ Ok(matches(selectors, root))
}
}
- Ok(false)
}
}
diff --git a/src/components/script/dom/node.rs b/src/components/script/dom/node.rs
index 1b0869eb3f2..9ef327f4fa4 100644
--- a/src/components/script/dom/node.rs
+++ b/src/components/script/dom/node.rs
@@ -4,7 +4,6 @@
//! The core DOM types. Defines the basic DOM hierarchy as well as all the HTML elements.
-use cssparser::tokenize;
use dom::attr::Attr;
use dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
use dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods;
@@ -48,7 +47,7 @@ use layout_interface::{ContentBoxQuery, ContentBoxResponse, ContentBoxesQuery, C
LayoutChan, ReapLayoutDataMsg, TrustedNodeAddress, UntrustedNodeAddress};
use servo_util::geometry::Au;
use servo_util::str::{DOMString, null_str_as_empty};
-use style::{parse_selector_list, matches_compound_selector, NamespaceMap};
+use style::{parse_selector_list_from_str, matches};
use js::jsapi::{JSContext, JSObject, JSRuntime};
use js::jsfriendapi;
@@ -611,21 +610,16 @@ impl<'m, 'n> NodeHelpers<'m, 'n> for JSRef<'n, Node> {
// http://dom.spec.whatwg.org/#dom-parentnode-queryselector
fn query_selector(&self, selectors: DOMString) -> Fallible<Option<Temporary<Element>>> {
// Step 1.
- let namespace = NamespaceMap::new();
- match parse_selector_list(tokenize(selectors.as_slice()).map(|(token, _)| token).collect(), &namespace) {
+ match parse_selector_list_from_str(selectors.as_slice()) {
// Step 2.
Err(()) => return Err(Syntax),
// Step 3.
Ok(ref selectors) => {
let root = self.ancestors().last().unwrap_or(self.clone());
- for selector in selectors.iter() {
- assert!(selector.pseudo_element.is_none());
- for node in root.traverse_preorder().filter(|node| node.is_element()) {
- let mut _shareable: bool = false;
- if matches_compound_selector(selector.compound_selectors.deref(), &node, &mut _shareable) {
- let elem: &JSRef<Element> = ElementCast::to_ref(&node).unwrap();
- return Ok(Some(Temporary::from_rooted(elem)));
- }
+ for node in root.traverse_preorder() {
+ if node.is_element() && matches(selectors, &node) {
+ let elem: &JSRef<Element> = ElementCast::to_ref(&node).unwrap();
+ return Ok(Some(Temporary::from_rooted(elem)));
}
}
}
@@ -636,23 +630,15 @@ impl<'m, 'n> NodeHelpers<'m, 'n> for JSRef<'n, Node> {
// http://dom.spec.whatwg.org/#dom-parentnode-queryselectorall
fn query_selector_all(&self, selectors: DOMString) -> Fallible<Temporary<NodeList>> {
// Step 1.
- let mut nodes = vec!();
+ let nodes;
let root = self.ancestors().last().unwrap_or(self.clone());
- let namespace = NamespaceMap::new();
- match parse_selector_list(tokenize(selectors.as_slice()).map(|(token, _)| token).collect(), &namespace) {
+ match parse_selector_list_from_str(selectors.as_slice()) {
// Step 2.
Err(()) => return Err(Syntax),
// Step 3.
Ok(ref selectors) => {
- for selector in selectors.iter() {
- assert!(selector.pseudo_element.is_none());
- for node in root.traverse_preorder().filter(|node| node.is_element()) {
- let mut _shareable: bool = false;
- if matches_compound_selector(selector.compound_selectors.deref(), &node, &mut _shareable) {
- nodes.push(node.clone())
- }
- }
- }
+ nodes = root.traverse_preorder().filter(
+ |node| node.is_element() && matches(selectors, node)).collect()
}
}
let window = window_from_node(self).root();
diff --git a/src/components/style/font_face.rs b/src/components/style/font_face.rs
index 2eafa242baf..81e1dadf0a8 100644
--- a/src/components/style/font_face.rs
+++ b/src/components/style/font_face.rs
@@ -9,10 +9,35 @@ use std::ascii::StrAsciiExt;
use parsing_utils::{BufferedIter, ParserIter, parse_slice_comma_separated};
use properties::longhands::font_family::parse_one_family;
use properties::computed_values::font_family::FamilyName;
-use stylesheets::{CSSRule, CSSFontFaceRule};
+use stylesheets::{CSSRule, CSSFontFaceRule, CSSStyleRule, CSSMediaRule};
+use media_queries::{Device, Screen};
use url::{Url, UrlParser};
+static SUPPORTED_FORMATS: &'static [&'static str] = &["truetype", "opentype"];
+
+
+pub fn iter_font_face_rules_inner(rules: &[CSSRule], callback: |family: &str, source: &Url|) {
+ let device = &Device { media_type: Screen }; // TODO, use Print when printing
+ for rule in rules.iter() {
+ match *rule {
+ CSSStyleRule(_) => {},
+ CSSMediaRule(ref rule) => if rule.media_queries.evaluate(device) {
+ iter_font_face_rules_inner(rule.rules.as_slice(), |f, s| callback(f, s))
+ },
+ CSSFontFaceRule(ref rule) => {
+ for source in rule.sources.iter() {
+ if source.format_hints.is_empty() || source.format_hints.iter().any(
+ |f| SUPPORTED_FORMATS.iter().any(
+ |s| f.as_slice().eq_ignore_ascii_case(*s))) {
+ callback(rule.family.as_slice(), &source.url)
+ }
+ }
+ },
+ }
+ }
+}
+
enum Source {
UrlSource(UrlSource),
LocalSource(String),
diff --git a/src/components/style/selector_matching.rs b/src/components/style/selector_matching.rs
index f36c7bb1f73..9800007c1ab 100644
--- a/src/components/style/selector_matching.rs
+++ b/src/components/style/selector_matching.rs
@@ -18,7 +18,7 @@ use media_queries::{Device, Screen};
use node::{TElement, TNode};
use properties::{PropertyDeclaration, PropertyDeclarationBlock};
use selectors::*;
-use stylesheets::{Stylesheet, iter_style_rules};
+use stylesheets::{Stylesheet, iter_stylesheet_style_rules};
pub enum StylesheetOrigin {
UserAgentOrigin,
@@ -317,7 +317,7 @@ impl Stylist {
);
let device = &Device { media_type: Screen }; // TODO, use Print when printing
- iter_style_rules(stylesheet.rules.as_slice(), device, |style_rule| {
+ iter_stylesheet_style_rules(&stylesheet, device, |style_rule| {
append!(style_rule, normal);
append!(style_rule, important);
rules_source_order += 1;
@@ -449,6 +449,12 @@ impl DeclarationBlock {
}
}
+pub fn matches<E:TElement, N:TNode<E>>(selector_list: &SelectorList, element: &N) -> bool {
+ get_selector_list_selectors(selector_list).iter().any(|selector|
+ selector.pseudo_element.is_none() &&
+ matches_compound_selector(&*selector.compound_selectors, element, &mut false))
+}
+
/// Determines whether the given element matches the given single or compound selector.
///
@@ -456,7 +462,7 @@ impl DeclarationBlock {
/// `shareable` to false unless you are willing to update the style sharing logic. Otherwise things
/// will almost certainly break as nodes will start mistakenly sharing styles. (See the code in
/// `main/css/matching.rs`.)
-pub fn matches_compound_selector<E:TElement,
+fn matches_compound_selector<E:TElement,
N:TNode<E>>(
selector: &CompoundSelector,
element: &N,
diff --git a/src/components/style/selectors.rs b/src/components/style/selectors.rs
index c174d49c314..00dca908c6b 100644
--- a/src/components/style/selectors.rs
+++ b/src/components/style/selectors.rs
@@ -8,7 +8,7 @@ use std::vec;
use sync::Arc;
use cssparser::ast::*;
-use cssparser::parse_nth;
+use cssparser::{tokenize, parse_nth};
use servo_util::atom::Atom;
use servo_util::namespace::Namespace;
@@ -116,6 +116,22 @@ pub enum NamespaceConstraint {
type Iter = iter::Peekable<ComponentValue, vec::MoveItems<ComponentValue>>;
+pub fn parse_selector_list_from_str(input: &str) -> Result<SelectorList, ()> {
+ let namespaces = NamespaceMap::new();
+ let input = tokenize(input).map(|(token, _)| token).collect();
+ parse_selector_list(input, &namespaces).map(|s| SelectorList { selectors: s })
+}
+
+/// Re-exported to script, but opaque.
+pub struct SelectorList {
+ selectors: Vec<Selector>
+}
+
+/// Public to the style crate, but not re-exported to script
+pub fn get_selector_list_selectors<'a>(selector_list: &'a SelectorList) -> &'a [Selector] {
+ selector_list.selectors.as_slice()
+}
+
/// Parse a comma-separated list of Selectors.
/// aka Selector Group in http://www.w3.org/TR/css3-selectors/#grouping
///
diff --git a/src/components/style/style.rs b/src/components/style/style.rs
index 043e83993df..cd3950b3bc2 100644
--- a/src/components/style/style.rs
+++ b/src/components/style/style.rs
@@ -30,21 +30,17 @@ extern crate servo_util = "util";
// Public API
-pub use stylesheets::{Stylesheet, CSSRule, StyleRule, CSSFontFaceRule};
+pub use stylesheets::{Stylesheet, iter_font_face_rules};
pub use selector_matching::{Stylist, StylesheetOrigin, UserAgentOrigin, AuthorOrigin, UserOrigin};
-pub use selector_matching::{DeclarationBlock, matches_compound_selector};
+pub use selector_matching::{DeclarationBlock, matches};
pub use properties::{cascade, cascade_anonymous};
pub use properties::{PropertyDeclaration, ComputedValues, computed_values, style_structs};
pub use properties::{PropertyDeclarationBlock, parse_style_attribute}; // Style attributes
pub use properties::{CSSFloat, DeclaredValue, PropertyDeclarationParseResult};
pub use properties::longhands;
pub use node::{TElement, TNode};
-pub use selectors::{PseudoElement, Before, After, AttrSelector, SpecificNamespace, AnyNamespace};
-pub use selectors::{NamespaceConstraint, Selector, CompoundSelector, SimpleSelector, Combinator};
-pub use selectors::{LocalNameSelector, parse_selector_list};
-pub use namespaces::NamespaceMap;
-pub use media_queries::{MediaRule, MediaQueryList, MediaQuery, Device, MediaType, MediaQueryType};
-pub use font_face::{FontFaceRule};
+pub use selectors::{PseudoElement, Before, After, SelectorList, parse_selector_list_from_str};
+pub use selectors::{AttrSelector, NamespaceConstraint, SpecificNamespace, AnyNamespace};
mod stylesheets;
mod errors;
diff --git a/src/components/style/stylesheets.rs b/src/components/style/stylesheets.rs
index 0071f280f27..790206001d7 100644
--- a/src/components/style/stylesheets.rs
+++ b/src/components/style/stylesheets.rs
@@ -16,13 +16,13 @@ use errors::{ErrorLoggerIterator, log_css_error};
use namespaces::{NamespaceMap, parse_namespace_rule};
use media_queries::{MediaRule, parse_media_rule};
use media_queries;
-use font_face::{FontFaceRule, parse_font_face_rule};
+use font_face::{FontFaceRule, parse_font_face_rule, iter_font_face_rules_inner};
pub struct Stylesheet {
/// List of rules in the order they were found (important for
/// cascading order)
- pub rules: Vec<CSSRule>,
+ rules: Vec<CSSRule>,
}
@@ -164,3 +164,15 @@ pub fn iter_style_rules<'a>(rules: &[CSSRule], device: &media_queries::Device,
}
}
}
+
+#[inline]
+pub fn iter_stylesheet_style_rules(stylesheet: &Stylesheet, device: &media_queries::Device,
+ callback: |&StyleRule|) {
+ iter_style_rules(stylesheet.rules.as_slice(), device, callback)
+}
+
+
+#[inline]
+pub fn iter_font_face_rules(stylesheet: &Stylesheet, callback: |family: &str, sources: &Url|) {
+ iter_font_face_rules_inner(stylesheet.rules.as_slice(), callback)
+}