html: Handle inline stylesheets. purple.com works now.

This commit is contained in:
Patrick Walton 2012-11-10 15:15:33 -08:00
parent f249396712
commit 7917da2f8c
2 changed files with 86 additions and 22 deletions

View file

@ -2,28 +2,53 @@
Some little helpers for hooking up the HTML parser with the CSS parser
*/
use std::net::url::Url;
use std::cell::Cell;
use resource::resource_task::{ResourceTask, ProgressMsg, Load, Payload, Done};
use core::str;
use newcss::stylesheet::Stylesheet;
use newcss::util::DataStream;
use std::cell::Cell;
use std::net::url::Url;
use std::net::url;
pub fn spawn_css_parser(url: Url, resource_task: ResourceTask) -> comm::Port<Stylesheet> {
/// Where a style sheet comes from.
enum StylesheetProvenance {
UrlProvenance(Url),
InlineProvenance(Url, ~str),
}
pub fn spawn_css_parser(provenance: StylesheetProvenance,
resource_task: ResourceTask) -> comm::Port<Stylesheet> {
let result_port = comm::Port();
let result_chan = comm::Chan(&result_port);
do task::spawn |move url, copy resource_task| {
let sheet = Stylesheet::new(copy url, data_stream(copy url, resource_task));
let provenance_cell = Cell(move provenance);
do task::spawn |move provenance_cell, copy resource_task| {
let url = do provenance_cell.with_ref |p| {
match *p {
UrlProvenance(copy the_url) => move the_url,
InlineProvenance(copy the_url, _) => move the_url
}
};
let sheet = Stylesheet::new(move url, data_stream(provenance_cell.take(), resource_task));
result_chan.send(move sheet);
}
return result_port;
}
fn data_stream(url: Url, resource_task: ResourceTask) -> DataStream {
let input_port = Port();
resource_task.send(Load(move url, input_port.chan()));
resource_port_to_data_stream(input_port)
fn data_stream(provenance: StylesheetProvenance, resource_task: ResourceTask) -> DataStream {
match move provenance {
UrlProvenance(move url) => {
let input_port = Port();
resource_task.send(Load(move url, input_port.chan()));
resource_port_to_data_stream(input_port)
}
InlineProvenance(_, move data) => {
data_to_data_stream(move data)
}
}
}
fn resource_port_to_data_stream(input_port: comm::Port<ProgressMsg>) -> DataStream {
@ -34,3 +59,16 @@ fn resource_port_to_data_stream(input_port: comm::Port<ProgressMsg>) -> DataStre
}
}
}
fn data_to_data_stream(data: ~str) -> DataStream {
let data_cell = Cell(move data);
return |move data_cell| {
if data_cell.is_empty() {
None
} else {
// FIXME: Blech, a copy.
Some(str::to_bytes(data_cell.take()))
}
}
}

View file

@ -1,25 +1,24 @@
use au = gfx::geometry;
use content::content_task::ContentTask;
use newcss::stylesheet::Stylesheet;
use dom::cow;
use dom::element::*;
use dom::event::{Event, ReflowEvent};
use dom::node::{Comment, Doctype, DoctypeData, Text,
Element, Node, NodeScope};
use dom::node::{Comment, Doctype, DoctypeData, Element, Node, NodeScope, Text};
use resource::image_cache_task::ImageCacheTask;
use resource::image_cache_task;
use resource::resource_task::{Done, Load, Payload, ResourceTask};
use core::comm::{Chan, Port};
use cssparse::{InlineProvenance, StylesheetProvenance, UrlProvenance, spawn_css_parser};
use hubbub::Attribute;
use comm::{Chan, Port};
use newcss::stylesheet::Stylesheet;
use std::net::url::Url;
use cssparse::spawn_css_parser;
use std::net::url;
type JSResult = ~[~[u8]];
enum CSSMessage {
CSSTaskNewFile(Url),
CSSTaskNewFile(StylesheetProvenance),
CSSTaskExit
}
@ -49,14 +48,15 @@ spawned, collates them, and sends them to the given result channel.
* `from_parent` - A port on which to receive new links.
*/
fn css_link_listener(to_parent : comm::Chan<Option<Stylesheet>>, from_parent : comm::Port<CSSMessage>,
fn css_link_listener(to_parent : comm::Chan<Option<Stylesheet>>,
from_parent : comm::Port<CSSMessage>,
resource_task: ResourceTask) {
let mut result_vec = ~[];
loop {
match from_parent.recv() {
CSSTaskNewFile(move url) => {
result_vec.push(spawn_css_parser(move url, copy resource_task));
CSSTaskNewFile(move provenance) => {
result_vec.push(spawn_css_parser(move provenance, copy resource_task));
}
CSSTaskExit => {
break;
@ -184,6 +184,31 @@ pub fn parse_html(scope: NodeScope,
debug!("created parser");
parser.set_document_node(cast::transmute(cow::unwrap(root)));
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 append_hook: @fn(Node, Node) = |parent_node, child_node| {
do scope.read(&parent_node) |parent_node_contents| {
do scope.read(&child_node) |child_node_contents| {
match (parent_node_contents.kind, child_node_contents.kind) {
(~Element(ref element), ~Text(ref data)) => {
match element.kind {
~HTMLStyleElement => {
debug!("found inline CSS stylesheet");
let url = url::from_str("http://example.com/"); // FIXME
let provenance = InlineProvenance(result::unwrap(move url),
copy *data);
css_chan.send(CSSTaskNewFile(provenance));
}
_ => {} // Nothing to do.
}
}
_ => {} // Nothing to do.
}
}
}
};
parser.set_tree_handler(@hubbub::TreeHandler {
create_comment: |data: ~str| {
debug!("create comment");
@ -227,8 +252,8 @@ pub fn parse_html(scope: NodeScope,
(Some(move rel), Some(move href)) => {
if rel == ~"stylesheet" {
debug!("found CSS stylesheet: %s", href);
css_chan.send(CSSTaskNewFile(make_url(move href,
Some(copy *url))));
css_chan.send(CSSTaskNewFile(UrlProvenance(make_url(move href,
Some(copy *url)))));
}
}
_ => {}
@ -262,6 +287,7 @@ pub fn parse_html(scope: NodeScope,
let p: Node = cow::wrap(cast::transmute(parent));
let c: Node = cow::wrap(cast::transmute(child));
scope.add_child(p, c);
append_hook(p, c);
}
child
},