diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/components/gfx/font_cache_task.rs | 32 | ||||
-rw-r--r-- | src/components/layout/layout_task.rs | 19 | ||||
-rw-r--r-- | src/components/script/dom/element.rs | 17 | ||||
-rw-r--r-- | src/components/script/dom/node.rs | 34 | ||||
-rw-r--r-- | src/components/style/font_face.rs | 27 | ||||
-rw-r--r-- | src/components/style/selector_matching.rs | 12 | ||||
-rw-r--r-- | src/components/style/selectors.rs | 18 | ||||
-rw-r--r-- | src/components/style/style.rs | 12 | ||||
-rw-r--r-- | src/components/style/stylesheets.rs | 16 |
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) +} |