mirror of
https://github.com/servo/servo.git
synced 2025-08-10 07:55:33 +01:00
auto merge of #1984 : mbrubeck/servo/1959-parser-style, r=jdm
This is a partial fix for #1959. This commit only addresses inline `<style>` elements. Next I will need to move `<link rel="stylesheet">` handling into shared code, but I wanted to get some early feedback on this piece first.
This commit is contained in:
commit
18b5453e09
8 changed files with 83 additions and 46 deletions
|
@ -12,17 +12,17 @@ use dom::bindings::js::JS;
|
||||||
use dom::bindings::utils::{Reflectable, Reflector};
|
use dom::bindings::utils::{Reflectable, Reflector};
|
||||||
use dom::bindings::error::{ErrorResult, Fallible, NamespaceError, InvalidCharacter};
|
use dom::bindings::error::{ErrorResult, Fallible, NamespaceError, InvalidCharacter};
|
||||||
use dom::bindings::utils::{QName, Name, InvalidXMLName, xml_name_type};
|
use dom::bindings::utils::{QName, Name, InvalidXMLName, xml_name_type};
|
||||||
use dom::htmlcollection::HTMLCollection;
|
|
||||||
use dom::clientrect::ClientRect;
|
use dom::clientrect::ClientRect;
|
||||||
use dom::clientrectlist::ClientRectList;
|
use dom::clientrectlist::ClientRectList;
|
||||||
use dom::document::Document;
|
use dom::document::Document;
|
||||||
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
|
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
|
||||||
use dom::node::{ElementNodeTypeId, Node, NodeHelpers, NodeIterator, document_from_node};
|
use dom::htmlcollection::HTMLCollection;
|
||||||
use dom::htmlserializer::serialize;
|
use dom::htmlserializer::serialize;
|
||||||
|
use dom::node::{ElementNodeTypeId, Node, NodeHelpers, NodeIterator, document_from_node};
|
||||||
use dom::virtualmethods::{VirtualMethods, vtable_for};
|
use dom::virtualmethods::{VirtualMethods, vtable_for};
|
||||||
use layout_interface::{ContentBoxQuery, ContentBoxResponse, ContentBoxesQuery};
|
use layout_interface::{ContentBoxQuery, ContentBoxResponse, ContentBoxesQuery};
|
||||||
use layout_interface::{ContentBoxesResponse, ContentChangedDocumentDamage};
|
use layout_interface::{ContentBoxesResponse, ContentChangedDocumentDamage};
|
||||||
use layout_interface::{MatchSelectorsDocumentDamage};
|
use layout_interface::MatchSelectorsDocumentDamage;
|
||||||
use style;
|
use style;
|
||||||
use servo_util::namespace;
|
use servo_util::namespace;
|
||||||
use servo_util::namespace::{Namespace, Null};
|
use servo_util::namespace::{Namespace, Null};
|
||||||
|
|
|
@ -3,14 +3,16 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use dom::bindings::codegen::HTMLStyleElementBinding;
|
use dom::bindings::codegen::HTMLStyleElementBinding;
|
||||||
use dom::bindings::codegen::InheritTypes::HTMLStyleElementDerived;
|
use dom::bindings::codegen::InheritTypes::{HTMLStyleElementDerived, NodeCast};
|
||||||
use dom::bindings::js::JS;
|
use dom::bindings::js::JS;
|
||||||
use dom::bindings::error::ErrorResult;
|
use dom::bindings::error::ErrorResult;
|
||||||
use dom::document::Document;
|
use dom::document::Document;
|
||||||
use dom::element::HTMLStyleElementTypeId;
|
use dom::element::HTMLStyleElementTypeId;
|
||||||
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
|
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
|
||||||
use dom::htmlelement::HTMLElement;
|
use dom::htmlelement::HTMLElement;
|
||||||
use dom::node::{Node, ElementNodeTypeId};
|
use dom::node::{Node, ElementNodeTypeId, window_from_node};
|
||||||
|
use html::cssparse::parse_inline_css;
|
||||||
|
use layout_interface::{AddStylesheetMsg, LayoutChan};
|
||||||
use servo_util::str::DOMString;
|
use servo_util::str::DOMString;
|
||||||
|
|
||||||
#[deriving(Encodable)]
|
#[deriving(Encodable)]
|
||||||
|
@ -72,3 +74,20 @@ impl HTMLStyleElement {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait StyleElementHelpers {
|
||||||
|
fn parse_own_css(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StyleElementHelpers for JS<HTMLStyleElement> {
|
||||||
|
fn parse_own_css(&self) {
|
||||||
|
let node: JS<Node> = NodeCast::from(self);
|
||||||
|
let win = window_from_node(&node);
|
||||||
|
let url = win.get().page().get_url();
|
||||||
|
|
||||||
|
let data = node.get().GetTextContent(&node).expect("Element.textContent must be a string");
|
||||||
|
let sheet = parse_inline_css(url, data);
|
||||||
|
let LayoutChan(ref layout_chan) = win.get().page().layout_chan;
|
||||||
|
layout_chan.send(AddStylesheetMsg(sheet));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
use dom::attr::Attr;
|
use dom::attr::Attr;
|
||||||
use dom::bindings::codegen::InheritTypes::{CommentCast, DocumentCast, DocumentTypeCast};
|
use dom::bindings::codegen::InheritTypes::{CommentCast, DocumentCast, DocumentTypeCast};
|
||||||
use dom::bindings::codegen::InheritTypes::{ElementCast, TextCast, NodeCast};
|
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLStyleElementCast, TextCast, NodeCast};
|
||||||
use dom::bindings::codegen::InheritTypes::{CharacterDataCast, NodeBase, NodeDerived};
|
use dom::bindings::codegen::InheritTypes::{CharacterDataCast, NodeBase, NodeDerived};
|
||||||
use dom::bindings::codegen::InheritTypes::{ProcessingInstructionCast, EventTargetCast};
|
use dom::bindings::codegen::InheritTypes::{ProcessingInstructionCast, EventTargetCast};
|
||||||
use dom::bindings::codegen::NodeBinding::NodeConstants;
|
use dom::bindings::codegen::NodeBinding::NodeConstants;
|
||||||
|
@ -21,6 +21,7 @@ use dom::documentfragment::DocumentFragment;
|
||||||
use dom::documenttype::DocumentType;
|
use dom::documenttype::DocumentType;
|
||||||
use dom::element::{Element, ElementTypeId, HTMLAnchorElementTypeId};
|
use dom::element::{Element, ElementTypeId, HTMLAnchorElementTypeId};
|
||||||
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
|
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
|
||||||
|
use dom::htmlstyleelement::StyleElementHelpers;
|
||||||
use dom::nodelist::{NodeList};
|
use dom::nodelist::{NodeList};
|
||||||
use dom::processinginstruction::ProcessingInstruction;
|
use dom::processinginstruction::ProcessingInstruction;
|
||||||
use dom::text::Text;
|
use dom::text::Text;
|
||||||
|
@ -269,6 +270,8 @@ pub trait NodeHelpers {
|
||||||
fn add_child(&mut self, new_child: &mut JS<Node>, before: Option<JS<Node>>);
|
fn add_child(&mut self, new_child: &mut JS<Node>, before: Option<JS<Node>>);
|
||||||
fn remove_child(&mut self, child: &mut JS<Node>);
|
fn remove_child(&mut self, child: &mut JS<Node>);
|
||||||
|
|
||||||
|
fn child_inserted(&self);
|
||||||
|
|
||||||
fn get_hover_state(&self) -> bool;
|
fn get_hover_state(&self) -> bool;
|
||||||
fn set_hover_state(&mut self, state: bool);
|
fn set_hover_state(&mut self, state: bool);
|
||||||
|
|
||||||
|
@ -408,6 +411,7 @@ impl NodeHelpers for JS<Node> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.parent_node().map(|parent| parent.child_inserted());
|
||||||
document.get().content_changed();
|
document.get().content_changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -499,6 +503,15 @@ impl NodeHelpers for JS<Node> {
|
||||||
child_node.set_parent_node(None);
|
child_node.set_parent_node(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn child_inserted(&self) {
|
||||||
|
// Parse text content added to an inline stylesheet.
|
||||||
|
match HTMLStyleElementCast::to(self) {
|
||||||
|
Some(elem) => elem.parse_own_css(),
|
||||||
|
None => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fn get_hover_state(&self) -> bool {
|
fn get_hover_state(&self) -> bool {
|
||||||
self.get().flags.get_in_hover_state()
|
self.get().flags.get_in_hover_state()
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,34 +18,45 @@ pub enum StylesheetProvenance {
|
||||||
InlineProvenance(Url, ~str),
|
InlineProvenance(Url, ~str),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parses the style data and returns the stylesheet
|
||||||
|
pub fn parse_inline_css(url: Url, data: ~str) -> Stylesheet {
|
||||||
|
let resource_task = ResourceTask(); // Resource task is not used for inline parsing
|
||||||
|
parse_css(InlineProvenance(url, data), resource_task)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_css(provenance: StylesheetProvenance,
|
||||||
|
resource_task: ResourceTask) -> Stylesheet {
|
||||||
|
// TODO: Get the actual value. http://dev.w3.org/csswg/css-syntax/#environment-encoding
|
||||||
|
let environment_encoding = UTF_8 as EncodingRef;
|
||||||
|
|
||||||
|
match provenance {
|
||||||
|
UrlProvenance(url) => {
|
||||||
|
debug!("cssparse: loading style sheet at {:s}", url.to_str());
|
||||||
|
let (input_chan, input_port) = channel();
|
||||||
|
resource_task.send(Load(url, input_chan));
|
||||||
|
let LoadResponse { metadata: metadata, progress_port: progress_port }
|
||||||
|
= input_port.recv();
|
||||||
|
let final_url = &metadata.final_url;
|
||||||
|
let protocol_encoding_label = metadata.charset.as_ref().map(|s| s.as_slice());
|
||||||
|
let iter = ProgressMsgPortIterator { progress_port: progress_port };
|
||||||
|
Stylesheet::from_bytes_iter(
|
||||||
|
iter, final_url.clone(),
|
||||||
|
protocol_encoding_label, Some(environment_encoding))
|
||||||
|
}
|
||||||
|
InlineProvenance(base_url, data) => {
|
||||||
|
debug!("cssparse: loading inline stylesheet {:s}", data);
|
||||||
|
Stylesheet::from_str(data, base_url, environment_encoding)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn spawn_css_parser(provenance: StylesheetProvenance,
|
pub fn spawn_css_parser(provenance: StylesheetProvenance,
|
||||||
resource_task: ResourceTask)
|
resource_task: ResourceTask)
|
||||||
-> Receiver<Stylesheet> {
|
-> Receiver<Stylesheet> {
|
||||||
let (result_chan, result_port) = channel();
|
let (result_chan, result_port) = channel();
|
||||||
|
|
||||||
// TODO: Get the actual value. http://dev.w3.org/csswg/css-syntax/#environment-encoding
|
|
||||||
let environment_encoding = UTF_8 as EncodingRef;
|
|
||||||
|
|
||||||
spawn_named("cssparser", proc() {
|
spawn_named("cssparser", proc() {
|
||||||
let sheet = match provenance {
|
result_chan.send(parse_css(provenance, resource_task));
|
||||||
UrlProvenance(url) => {
|
|
||||||
debug!("cssparse: loading style sheet at {:s}", url.to_str());
|
|
||||||
let (input_chan, input_port) = channel();
|
|
||||||
resource_task.send(Load(url, input_chan));
|
|
||||||
let LoadResponse { metadata: metadata, progress_port: progress_port }
|
|
||||||
= input_port.recv();
|
|
||||||
let final_url = &metadata.final_url;
|
|
||||||
let protocol_encoding_label = metadata.charset.as_ref().map(|s| s.as_slice());
|
|
||||||
let iter = ProgressMsgPortIterator { progress_port: progress_port };
|
|
||||||
Stylesheet::from_bytes_iter(
|
|
||||||
iter, final_url.clone(),
|
|
||||||
protocol_encoding_label, Some(environment_encoding))
|
|
||||||
}
|
|
||||||
InlineProvenance(base_url, data) => {
|
|
||||||
Stylesheet::from_str(data, base_url, environment_encoding)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
result_chan.send(sheet);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return result_port;
|
return result_port;
|
||||||
|
|
|
@ -14,7 +14,7 @@ use dom::htmliframeelement::IFrameSize;
|
||||||
use dom::htmlformelement::HTMLFormElement;
|
use dom::htmlformelement::HTMLFormElement;
|
||||||
use dom::node::{ElementNodeTypeId, INode, NodeHelpers};
|
use dom::node::{ElementNodeTypeId, INode, NodeHelpers};
|
||||||
use dom::types::*;
|
use dom::types::*;
|
||||||
use html::cssparse::{InlineProvenance, StylesheetProvenance, UrlProvenance, spawn_css_parser};
|
use html::cssparse::{StylesheetProvenance, UrlProvenance, spawn_css_parser};
|
||||||
use script_task::Page;
|
use script_task::Page;
|
||||||
|
|
||||||
use hubbub::hubbub;
|
use hubbub::hubbub;
|
||||||
|
@ -298,7 +298,7 @@ pub fn parse_html(page: &Page,
|
||||||
parser.enable_scripting(true);
|
parser.enable_scripting(true);
|
||||||
parser.enable_styling(true);
|
parser.enable_styling(true);
|
||||||
|
|
||||||
let (css_chan2, css_chan3, js_chan2) = (css_chan.clone(), css_chan.clone(), js_chan.clone());
|
let (css_chan2, js_chan2) = (css_chan.clone(), js_chan.clone());
|
||||||
|
|
||||||
let next_subpage_id = RefCell::new(next_subpage_id);
|
let next_subpage_id = RefCell::new(next_subpage_id);
|
||||||
|
|
||||||
|
@ -483,22 +483,8 @@ pub fn parse_html(page: &Page,
|
||||||
}
|
}
|
||||||
debug!("complete script");
|
debug!("complete script");
|
||||||
},
|
},
|
||||||
complete_style: |style| {
|
complete_style: |_| {
|
||||||
// We've reached the end of a <style> so we can submit all the text to the parser.
|
// style parsing is handled in element::notify_child_list_changed.
|
||||||
unsafe {
|
|
||||||
let style: JS<Node> = NodeWrapping::from_hubbub_node(style);
|
|
||||||
let mut data = ~[];
|
|
||||||
debug!("iterating over children {:?}", style.first_child());
|
|
||||||
for child in style.children() {
|
|
||||||
debug!("child = {:?}", child);
|
|
||||||
let text: JS<Text> = TextCast::to(&child).unwrap();
|
|
||||||
data.push(text.get().characterdata.data.to_str()); // FIXME: Bad copy.
|
|
||||||
}
|
|
||||||
|
|
||||||
debug!("style data = {:?}", data);
|
|
||||||
let provenance = InlineProvenance(base_url.clone(), data.concat());
|
|
||||||
css_chan3.send(CSSTaskNewFile(provenance));
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
parser.set_tree_handler(&tree_handler);
|
parser.set_tree_handler(&tree_handler);
|
||||||
|
|
1
src/test/ref/append_style_a.html
Normal file
1
src/test/ref/append_style_a.html
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<div style="background-color: blue">this is the story of a girl</div>
|
6
src/test/ref/append_style_b.html
Normal file
6
src/test/ref/append_style_b.html
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<div id="hello">this is the story of a girl</div>
|
||||||
|
<script>
|
||||||
|
var style = document.createElement('style');
|
||||||
|
style.textContent = "#hello { background-color: blue; }"
|
||||||
|
document.head.appendChild(style);
|
||||||
|
</script>
|
|
@ -35,6 +35,7 @@
|
||||||
!= block_image.html noteq_500x300_white.html
|
!= block_image.html noteq_500x300_white.html
|
||||||
# == simple_iframe.html simple_iframe_ref.html -- disabled due to iframe crashiness
|
# == simple_iframe.html simple_iframe_ref.html -- disabled due to iframe crashiness
|
||||||
== object_element_a.html object_element_b.html
|
== object_element_a.html object_element_b.html
|
||||||
|
== append_style_a.html append_style_b.html
|
||||||
== height_compute_reset.html height_compute.html
|
== height_compute_reset.html height_compute.html
|
||||||
== width_nonreplaced_block_simple_a.html width_nonreplaced_block_simple_b.html
|
== width_nonreplaced_block_simple_a.html width_nonreplaced_block_simple_b.html
|
||||||
== max_width_float_simple_a.html max_width_float_simple_b.html
|
== max_width_float_simple_a.html max_width_float_simple_b.html
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue