mirror of
https://github.com/servo/servo.git
synced 2025-08-07 14:35: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::error::{ErrorResult, Fallible, NamespaceError, InvalidCharacter};
|
||||
use dom::bindings::utils::{QName, Name, InvalidXMLName, xml_name_type};
|
||||
use dom::htmlcollection::HTMLCollection;
|
||||
use dom::clientrect::ClientRect;
|
||||
use dom::clientrectlist::ClientRectList;
|
||||
use dom::document::Document;
|
||||
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::node::{ElementNodeTypeId, Node, NodeHelpers, NodeIterator, document_from_node};
|
||||
use dom::virtualmethods::{VirtualMethods, vtable_for};
|
||||
use layout_interface::{ContentBoxQuery, ContentBoxResponse, ContentBoxesQuery};
|
||||
use layout_interface::{ContentBoxesResponse, ContentChangedDocumentDamage};
|
||||
use layout_interface::{MatchSelectorsDocumentDamage};
|
||||
use layout_interface::MatchSelectorsDocumentDamage;
|
||||
use style;
|
||||
use servo_util::namespace;
|
||||
use servo_util::namespace::{Namespace, Null};
|
||||
|
|
|
@ -3,14 +3,16 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
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::error::ErrorResult;
|
||||
use dom::document::Document;
|
||||
use dom::element::HTMLStyleElementTypeId;
|
||||
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
|
||||
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;
|
||||
|
||||
#[deriving(Encodable)]
|
||||
|
@ -72,3 +74,20 @@ impl HTMLStyleElement {
|
|||
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::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::{ProcessingInstructionCast, EventTargetCast};
|
||||
use dom::bindings::codegen::NodeBinding::NodeConstants;
|
||||
|
@ -21,6 +21,7 @@ use dom::documentfragment::DocumentFragment;
|
|||
use dom::documenttype::DocumentType;
|
||||
use dom::element::{Element, ElementTypeId, HTMLAnchorElementTypeId};
|
||||
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
|
||||
use dom::htmlstyleelement::StyleElementHelpers;
|
||||
use dom::nodelist::{NodeList};
|
||||
use dom::processinginstruction::ProcessingInstruction;
|
||||
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 remove_child(&mut self, child: &mut JS<Node>);
|
||||
|
||||
fn child_inserted(&self);
|
||||
|
||||
fn get_hover_state(&self) -> 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();
|
||||
}
|
||||
|
||||
|
@ -499,6 +503,15 @@ impl NodeHelpers for JS<Node> {
|
|||
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 {
|
||||
self.get().flags.get_in_hover_state()
|
||||
}
|
||||
|
|
|
@ -18,34 +18,45 @@ pub enum StylesheetProvenance {
|
|||
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,
|
||||
resource_task: ResourceTask)
|
||||
-> Receiver<Stylesheet> {
|
||||
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() {
|
||||
let sheet = 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) => {
|
||||
Stylesheet::from_str(data, base_url, environment_encoding)
|
||||
}
|
||||
};
|
||||
result_chan.send(sheet);
|
||||
result_chan.send(parse_css(provenance, resource_task));
|
||||
});
|
||||
|
||||
return result_port;
|
||||
|
|
|
@ -14,7 +14,7 @@ use dom::htmliframeelement::IFrameSize;
|
|||
use dom::htmlformelement::HTMLFormElement;
|
||||
use dom::node::{ElementNodeTypeId, INode, NodeHelpers};
|
||||
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 hubbub::hubbub;
|
||||
|
@ -298,7 +298,7 @@ pub fn parse_html(page: &Page,
|
|||
parser.enable_scripting(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);
|
||||
|
||||
|
@ -483,22 +483,8 @@ pub fn parse_html(page: &Page,
|
|||
}
|
||||
debug!("complete script");
|
||||
},
|
||||
complete_style: |style| {
|
||||
// We've reached the end of a <style> so we can submit all the text to the parser.
|
||||
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));
|
||||
}
|
||||
complete_style: |_| {
|
||||
// style parsing is handled in element::notify_child_list_changed.
|
||||
},
|
||||
};
|
||||
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
|
||||
# == simple_iframe.html simple_iframe_ref.html -- disabled due to iframe crashiness
|
||||
== object_element_a.html object_element_b.html
|
||||
== append_style_a.html append_style_b.html
|
||||
== height_compute_reset.html height_compute.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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue