Fix broken inline CSS parsing and add a iterator for children.

If '\r' appears in an inline <style> element, libhubbub splits the text nodes
there, creating multiple text children. The inline style logic assumed that
each <style> element had only one child.

The logic was moved to trigger when the style element is finished parsing
completely (including the children), and then the children are concatenated
before sending it to the parser.
This commit is contained in:
Jack Moffitt 2013-07-19 15:18:45 -06:00
parent 09acdcc4ec
commit 34106d7e45
3 changed files with 45 additions and 22 deletions

View file

@ -46,6 +46,10 @@ pub struct AbstractNode<View> {
priv obj: *mut Node<View>,
}
pub struct AbstractNodeChildrenIterator<View> {
priv current_node: Option<AbstractNode<View>>,
}
/// An HTML node.
///
/// `View` describes extra data associated with this node that this task has access to. For
@ -200,7 +204,7 @@ impl<View> TreeNodeRef<Node<View>> for AbstractNode<View> {
}
}
impl<View> AbstractNode<View> {
impl<'self, View> AbstractNode<View> {
// Unsafe accessors
/// Returns the layout data, unsafely cast to whatever type layout wishes. Only layout is
@ -396,6 +400,22 @@ impl<View> AbstractNode<View> {
pub fn debug_str(&self) -> ~str {
fmt!("%?", self.type_id())
}
pub fn children(&self) -> AbstractNodeChildrenIterator<View> {
AbstractNodeChildrenIterator {
current_node: self.first_child(),
}
}
}
impl<View> Iterator<AbstractNode<View>> for AbstractNodeChildrenIterator<View> {
pub fn next(&mut self) -> Option<AbstractNode<View>> {
self.current_node = match self.current_node {
None => None,
Some(node) => node.next_sibling(),
};
self.current_node
}
}
impl Node<ScriptView> {

View file

@ -275,24 +275,7 @@ pub fn parse_html(url: Url,
parser.set_document_node(unsafe { root.to_hubbub_node() });
parser.enable_scripting(true);
// Performs various actions necessary after appending has taken place. Currently, this
// consists of processing inline stylesheets, but in the future it might perform
// prefetching, etc.
let css_chan2 = css_chan.clone();
let append_hook: ~fn(AbstractNode<ScriptView>, AbstractNode<ScriptView>) = |parent_node, child_node| {
if parent_node.is_style_element() && child_node.is_text() {
debug!("found inline CSS stylesheet");
let url = url::from_str("http://example.com/"); // FIXME
let url_cell = Cell::new(url);
do child_node.with_imm_text |text_node| {
let data = text_node.parent.data.to_str(); // FIXME: Bad copy.
let provenance = InlineProvenance(result::unwrap(url_cell.take()), data);
css_chan2.send(CSSTaskNewFile(provenance));
}
}
};
let (css_chan2, js_chan2) = (css_chan.clone(), js_chan.clone());
let (css_chan2, css_chan3, js_chan2) = (css_chan.clone(), css_chan.clone(), js_chan.clone());
parser.set_tree_handler(~hubbub::TreeHandler {
create_comment: |data: ~str| {
debug!("create comment");
@ -393,15 +376,34 @@ pub fn parse_html(url: Url,
Node::as_abstract_node(~Text::new(data)).to_hubbub_node()
}
},
ref_node: |_| {},
unref_node: |_| {},
ref_node: |_| { debug!("ref node"); },
unref_node: |node| {
// check for the end of a <style> so we can submit all the text to the parser.
unsafe {
let node: AbstractNode<ScriptView> = NodeWrapping::from_hubbub_node(node);
if node.is_style_element() {
let url = url::from_str("http://example.com/"); // FIXME
let url_cell = Cell::new(url);
let mut data = ~[];
for node.children().advance |child| {
do child.with_imm_text() |text| {
data.push(text.parent.data.to_str()); // FIXME: Bad copy.
}
}
let provenance = InlineProvenance(result::unwrap(url_cell.take()), data.concat());
css_chan3.send(CSSTaskNewFile(provenance));
}
}
},
append_child: |parent: hubbub::NodeDataPtr, child: hubbub::NodeDataPtr| {
unsafe {
debug!("append child %x %x", cast::transmute(parent), cast::transmute(child));
let parent: AbstractNode<ScriptView> = NodeWrapping::from_hubbub_node(parent);
let child: AbstractNode<ScriptView> = NodeWrapping::from_hubbub_node(child);
parent.add_child(child);
append_hook(parent, child);
}
child
},

View file

@ -0,0 +1 @@
<html> <head> <style> p { color: white; } p.blue { background-color: blue; } p.red { background-color: red; } </style> </head> <body> <p class="blue"> I am a paragraph. My background color is blue. </p> <p class="red"> I am a paragraph. My background color is red. </p> </body> </html>