Parse a bunch more tags; move ElementData enum to its own file; fix some UA style fakery; remove old DOM parser.

This commit is contained in:
Brian J. Burg 2012-09-20 14:20:16 -07:00
parent 754bbeae41
commit 76a43555ac
13 changed files with 217 additions and 419 deletions

View file

@ -16,7 +16,6 @@ use dom::base::{Document, Node, NodeScope, Window, define_bindings};
use dom::event::{Event, ResizeEvent, ReflowEvent};
use gfx::compositor::Compositor;
use html::lexer::spawn_html_lexer_task;
use html::dom_builder::build_dom;
use layout::layout_task;
use layout_task::{LayoutTask, BuildMsg};
@ -155,12 +154,6 @@ impl<C:Compositor> Content<C> {
// Note: we can parse the next document in parallel
// with any previous documents.
/*let stream = spawn_html_lexer_task(copy url, self.resource_task);
let (root, style_port, js_port) = build_dom(self.scope, stream, url,
self.resource_task);
let css_rules = style_port.recv();
let js_scripts = js_port.recv();*/
let result = html::hubbub_html_parser::parse_html(self.scope,
url,

View file

@ -1,6 +1,7 @@
#[doc="Applies the appropriate CSS style to boxes."]
use au = gfx::geometry;
use dom::element::*;
use layout::base::{RenderBox, SpecifiedStyle, RenderBoxTree};
use layout::context::LayoutContext;
use layout::traverse_parallel::top_down_traversal;
@ -121,7 +122,7 @@ impl StyleApplicator {
match node.kind {
~dom::base::Element(element) => {
match element.kind {
~dom::base::HTMLImageElement(*) => {
~HTMLImageElement(*) => {
let url = element.get_attr(~"src");
if url.is_some() {

View file

@ -2,7 +2,8 @@
use dom::base::{LayoutData};
use dom::base;
use base::{ElementData, Node, Text};
use dom::element::ElementData;
use base::{Node, Text};
use values::*;
use styles::{SpecifiedStyle};

View file

@ -4,7 +4,7 @@ use std::arc::{ARC, get, clone};
use css::values::*;
use css::values::Stylesheet;
use dom::base::{HTMLDivElement, HTMLHeadElement, HTMLImageElement, UnknownElement, HTMLScriptElement};
use dom::element::{HTMLDivElement, HTMLHeadElement, HTMLImageElement, UnknownElement, HTMLScriptElement};
use dom::base::{Comment, Doctype, Element, Node, NodeKind, Text};
use dom::base::{LayoutData};
use util::color::{Color, rgb};
@ -37,6 +37,7 @@ impl NodeKind : DefaultStyleMethods {
}
}
/* TODO: this belongs in the UA stylesheet */
fn default_display_type() -> CSSDisplay {
match self {
Text(*) => { DisplayInline }
@ -46,7 +47,7 @@ impl NodeKind : DefaultStyleMethods {
HTMLHeadElement => DisplayNone,
HTMLImageElement(*) => DisplayInline,
HTMLScriptElement => DisplayNone,
UnknownElement => DisplayInline,
_ => DisplayInline,
}
},
Comment(*) | Doctype(*) => DisplayNone

View file

@ -1,11 +1,10 @@
#[doc="The core DOM types. Defines the basic DOM hierarchy as well as all the HTML elements."]
/* The core DOM types. Defines the basic DOM hierarchy as well as all the HTML elements. */
use comm::{Port, Chan};
use content::content_task::{ControlMsg, Timer};
use css::styles::SpecifiedStyle;
use css::values::Stylesheet;
use dom::element::{Attr, ElementData};
use dom::bindings;
use dvec::DVec;
use geom::size::Size2D;
use gfx::geometry::au;
use js::crust::*;
@ -132,47 +131,7 @@ fn DoctypeData(name: ~str, public_id: Option<~str>,
}
}
struct ElementData {
tag_name: ~str,
kind: ~ElementKind,
attrs: DVec<~Attr>,
}
impl ElementData {
fn get_attr(attr_name: ~str) -> Option<~str> {
let mut i = 0u;
while i < self.attrs.len() {
if attr_name == self.attrs[i].name {
return Some(copy self.attrs[i].value);
}
i += 1u;
}
None
}
}
fn ElementData(tag_name: ~str, kind: ~ElementKind) -> ElementData {
ElementData {
tag_name : tag_name,
kind : kind,
attrs : DVec(),
}
}
struct Attr {
name: ~str,
value: ~str,
}
fn Attr(name: ~str, value: ~str) -> Attr {
Attr {
name : name,
value : value,
}
}
fn define_bindings(compartment: bare_compartment, doc: @Document,
win: @Window) {
@ -182,14 +141,6 @@ fn define_bindings(compartment: bare_compartment, doc: @Document,
bindings::element::init(compartment);
}
enum ElementKind {
UnknownElement,
HTMLDivElement,
HTMLHeadElement,
HTMLImageElement({mut size: Size2D<au>}),
HTMLScriptElement
}
/** The RCU rd_aux data is a (weak) pointer to the layout data,
defined by this `LayoutData` enum. It contains the CSS style object

View file

@ -1,4 +1,5 @@
use au = gfx::geometry;
use au::au;
use js::rust::{bare_compartment, methods, jsobj};
use js::{JS_ARGV, JSCLASS_HAS_RESERVED_SLOTS, JSPROP_ENUMERATE, JSPROP_SHARED, JSVAL_NULL,
JS_THIS_OBJECT, JS_SET_RVAL, JSPROP_NATIVE_ACCESSORS};
@ -11,13 +12,13 @@ use js::glue::bindgen::*;
use js::crust::{JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ConvertStub};
use dom::base::{Node, NodeScope, Element};
use dom::element::*;
use node::NodeBundle;
use utils::{rust_box, squirrel_away_unique, get_compartment, domstring_to_jsval, str};
use libc::c_uint;
use ptr::null;
use node::unwrap;
use dom::base::{HTMLImageElement, HTMLScriptElement, HTMLHeadElement, HTMLDivElement,
UnknownElement};
extern fn finalize(_fop: *JSFreeOp, obj: *JSObject) {
#debug("element finalize!");
@ -73,10 +74,19 @@ extern fn HTMLImageElement_getWidth(cx: *JSContext, _argc: c_uint, vp: *mut jsva
match nd.kind {
~Element(ed) => {
match ed.kind {
~HTMLImageElement(img) => img.size.width,
~HTMLImageElement(*) => {
// TODO: this should actually come from rendered dimensions!
match ed.get_attr(~"width") {
Some(s) => match int::from_str(s) {
Some(w) => au::from_px(w),
None => au(0) /* failed to parse a number */
},
None => au(0) /* no width attr. */
}
},
_ => fail ~"why is this not an image element?"
}
}
},
_ => fail ~"why is this not an element?"
}
});
@ -97,9 +107,9 @@ extern fn HTMLImageElement_setWidth(cx: *JSContext, _argc: c_uint, vp: *mut jsva
match nd.kind {
~Element(ed) => {
match ed.kind {
~HTMLImageElement(img) => {
~HTMLImageElement(*) => {
let arg = ptr::offset(JS_ARGV(cx, cast::reinterpret_cast(&vp)), 0);
img.size.width = au::from_px(RUST_JSVAL_TO_INT(*arg) as int)
ed.set_attr(~"width", int::str(RUST_JSVAL_TO_INT(*arg) as int))
},
_ => fail ~"why is this not an image element?"
}
@ -144,7 +154,7 @@ fn create(cx: *JSContext, node: Node, scope: NodeScope) -> jsobj unsafe {
~HTMLHeadElement(*) => ~"HTMLHeadElement",
~HTMLImageElement(*) => ~"HTMLImageElement",
~HTMLScriptElement(*) => ~"HTMLScriptElement",
~UnknownElement(*) => ~"HTMLElement"
_ => ~"HTMLElement"
}
}
_ => fail ~"element::create only handles elements"

96
src/servo/dom/element.rs Normal file
View file

@ -0,0 +1,96 @@
use au = gfx::geometry;
use au::au;
use dvec::DVec;
use geom::size::Size2D;
struct ElementData {
tag_name: ~str,
kind: ~ElementKind,
attrs: DVec<~Attr>,
}
impl ElementData {
fn get_attr(attr_name: ~str) -> Option<~str> {
let mut i = 0u;
while i < self.attrs.len() {
if attr_name == self.attrs[i].name {
return Some(copy self.attrs[i].value);
}
i += 1u;
}
None
}
fn set_attr(_attr_name: ~str, attr_value: ~str) {
// TODO: add new attr of name, or delete old one
}
}
fn ElementData(tag_name: ~str, kind: ~ElementKind) -> ElementData {
ElementData {
tag_name : tag_name,
kind : kind,
attrs : DVec(),
}
}
struct Attr {
name: ~str,
value: ~str,
}
fn Attr(name: ~str, value: ~str) -> Attr {
Attr {
name : name,
value : value,
}
}
enum HeadingLevel {
Heading1,
Heading2,
Heading3,
Heading4,
Heading5,
Heading6,
}
enum ElementKind {
HTMLAnchorElement,
HTMLAsideElement,
HTMLBRElement,
HTMLBodyElement,
HTMLBoldElement,
HTMLDivElement,
HTMLFontElement,
HTMLFormElement,
HTMLHRElement,
HTMLHeadElement,
HTMLHeadingElement(HeadingLevel),
HTMLHtmlElement,
// TODO: should not take this as argument--it is fetched from
// layout task as requested.
HTMLImageElement({mut size: Size2D<au>}),
HTMLInputElement,
HTMLItalicElement,
HTMLLinkElement,
HTMLListItemElement,
HTMLMetaElement,
HTMLOListElement,
HTMLOptionElement,
HTMLParagraphElement,
HTMLScriptElement,
HTMLSectionElement,
HTMLSelectElement,
HTMLSmallElement,
HTMLSpanElement,
HTMLStyleElement,
HTMLTableBodyElement,
HTMLTableCellElement,
HTMLTableElement,
HTMLTableRowElement,
HTMLTitleElement,
HTMLUListElement,
UnknownElement,
}

View file

@ -1,273 +0,0 @@
#[doc="Constructs a DOM tree from an incoming token stream."]
use au = gfx::geometry;
use au::au;
use dom::base::{Attr, Element, ElementData, ElementKind, HTMLDivElement, HTMLHeadElement,
HTMLScriptElement};
use dom::base::{HTMLImageElement, Node, NodeScope, Text, UnknownElement};
use geom::size::Size2D;
use html::lexer;
use html::lexer::Token;
use css::values::Stylesheet;
use vec::{push, push_all_move, flat_map};
use std::net::url::Url;
use resource::resource_task::{ResourceTask, Load, Payload, Done};
use to_str::ToStr;
enum CSSMessage {
File(Url),
Exit
}
enum js_message {
js_file(Url),
js_exit
}
#[allow(non_implicitly_copyable_typarams)]
fn link_up_attribute(scope: NodeScope, node: Node, -key: ~str, -value: ~str) {
// TODO: Implement atoms so that we don't always perform string comparisons.
scope.read(node, |node_contents| {
match *node_contents.kind {
Element(element) => {
element.attrs.push(~Attr(copy key, copy value));
match *element.kind {
HTMLImageElement(img) if key == ~"width" => {
match int::from_str(value) {
None => {
// Drop on the floor.
}
Some(s) => { img.size.width = au::from_px(s); }
}
}
HTMLImageElement(img) if key == ~"height" => {
match int::from_str(value) {
None => {
// Drop on the floor.
}
Some(s) => {
img.size.height = au::from_px(s);
}
}
}
HTMLDivElement | HTMLImageElement(*) | HTMLHeadElement |
HTMLScriptElement | UnknownElement => {
// Drop on the floor.
}
}
}
_ => {
fail ~"attempt to link up an attribute to an unstyleable node"
}
}
})
}
fn build_element_kind(tag_name: ~str) -> ~ElementKind {
match tag_name {
~"div" => ~HTMLDivElement,
~"img" => {
~HTMLImageElement({ mut size: Size2D(au::from_px(100),
au::from_px(100))
})
}
~"script" => ~HTMLScriptElement,
~"head" => ~HTMLHeadElement,
_ => ~UnknownElement
}
}
#[doc="Runs a task that coordinates parsing links to css stylesheets.
This function should be spawned in a separate task and spins waiting
for the html builder to find links to css stylesheets and sends off
tasks to parse each link. When the html process finishes, it notifies
the listener, who then collects the css rules from each task it
spawned, collates them, and sends them to the given result channel.
# Arguments
* `to_parent` - A channel on which to send back the full set of rules.
* `from_parent` - A port on which to receive new links.
"]
fn css_link_listener(to_parent : comm::Chan<Stylesheet>, from_parent : comm::Port<CSSMessage>,
resource_task: ResourceTask) {
let mut result_vec = ~[];
loop {
match from_parent.recv() {
File(url) => {
let result_port = comm::Port();
let result_chan = comm::Chan(result_port);
// TODO: change copy to move once we have match move
let url = copy url;
task::spawn(|| {
// TODO: change copy to move once we can move into closures
let css_stream = css::lexer::spawn_css_lexer_task(copy url, resource_task);
let mut css_rules = css::parser::build_stylesheet(css_stream);
result_chan.send(css_rules);
});
push(result_vec, result_port);
}
Exit => {
break;
}
}
}
let css_rules = flat_map(result_vec, |result_port| { result_port.recv() });
to_parent.send(css_rules);
}
fn js_script_listener(to_parent : comm::Chan<~[~[u8]]>, from_parent : comm::Port<js_message>,
resource_task: ResourceTask) {
let mut result_vec = ~[];
loop {
match from_parent.recv() {
js_file(url) => {
let result_port = comm::Port();
let result_chan = comm::Chan(result_port);
// TODO: change copy to move once we have match move
let url = copy url;
do task::spawn || {
let input_port = Port();
// TODO: change copy to move once we can move into closures
resource_task.send(Load(copy url, input_port.chan()));
let mut buf = ~[];
loop {
match input_port.recv() {
Payload(data) => {
buf += data;
}
Done(Ok(*)) => {
result_chan.send(buf);
break;
}
Done(Err(*)) => {
#error("error loading script %s", url.to_str());
}
}
}
}
push(result_vec, result_port);
}
js_exit => {
break;
}
}
}
let js_scripts = vec::map(result_vec, |result_port| result_port.recv());
to_parent.send(js_scripts);
}
#[allow(non_implicitly_copyable_typarams)]
fn build_dom(scope: NodeScope, stream: comm::Port<Token>, url: Url,
resource_task: ResourceTask) -> (Node, comm::Port<Stylesheet>, comm::Port<~[~[u8]]>) {
// The current reference node.
let mut cur_node = scope.new_node(Element(ElementData(~"html", ~HTMLDivElement)));
// We will spawn a separate task to parse any css that is
// encountered, each link to a stylesheet is sent to the waiting
// task. After the html sheet has been fully read, the spawned
// task will collect the results of all linked style data and send
// it along the returned port.
let style_port = comm::Port();
let child_chan = comm::Chan(style_port);
let style_chan = task::spawn_listener(|child_port| {
css_link_listener(child_chan, child_port, resource_task);
});
let js_port = comm::Port();
let child_chan = comm::Chan(js_port);
let js_chan = task::spawn_listener(|child_port| {
js_script_listener(child_chan, child_port, resource_task);
});
loop {
let token = stream.recv();
match token {
lexer::Eof => { break; }
lexer::StartOpeningTag(tag_name) => {
#debug["starting tag %s", tag_name];
let element_kind = build_element_kind(tag_name);
let new_node = scope.new_node(Element(ElementData(copy tag_name, element_kind)));
scope.add_child(cur_node, new_node);
cur_node = new_node;
}
lexer::Attr(key, value) => {
#debug["attr: %? = %?", key, value];
link_up_attribute(scope, cur_node, copy key, copy value);
}
lexer::EndOpeningTag => {
#debug("end opening tag");
}
// TODO: Fail more gracefully (i.e. according to the HTML5
// spec) if we close more tags than we open.
lexer::SelfCloseTag => {
//TODO: check for things other than the link tag
scope.read(cur_node, |n| {
match *n.kind {
Element(elmt) if elmt.tag_name == ~"link" => {
match elmt.get_attr(~"rel") {
Some(r) if r == ~"stylesheet" => {
match elmt.get_attr(~"href") {
Some(filename) => {
#debug["Linking to a css sheet named: %s", filename];
// FIXME: Need to base the new url on the current url
let new_url = make_url(filename, Some(copy url));
style_chan.send(File(new_url));
}
None => { /* fall through*/ }
}
}
_ => { /* fall through*/ }
}
}
_ => { /* fall through*/ }
}
});
cur_node = scope.get_parent(cur_node).get();
}
lexer::EndTag(*) => {
// TODO: Assert that the closing tag has the right name.
scope.read(cur_node, |n| {
match *n.kind {
Element(elmt) if elmt.tag_name == ~"script" => {
match elmt.get_attr(~"src") {
Some(filename) => {
#debug["Linking to a js script named: %s", filename];
let new_url = make_url(filename, Some(copy url));
js_chan.send(js_file(new_url));
}
None => { /* fall through */ }
}
}
_ => { /* fall though */ }
}
});
cur_node = scope.get_parent(cur_node).get();
}
lexer::Text(s) if !s.is_whitespace() => {
let new_node = scope.new_node(Text(copy s));
scope.add_child(cur_node, new_node);
}
lexer::Text(_) => {
// FIXME: Whitespace should not be ignored.
}
lexer::Doctype => {
// TODO: Do something here...
}
}
}
style_chan.send(Exit);
js_chan.send(js_exit);
return (cur_node, style_port, js_port);
}

View file

@ -1,16 +1,10 @@
use au = gfx::geometry;
use dom::base::{Attr, Comment, Doctype, DoctypeData, Element, ElementData, ElementKind};
use dom::base::{HTMLDivElement, HTMLHeadElement, HTMLImageElement, HTMLScriptElement};
use dom::base::{Comment, Doctype, DoctypeData, Element};
use dom::element::*;
use dom::base::{Node, NodeScope, Text, UnknownElement};
use css::values::Stylesheet;
use geom::size::Size2D;
use html::dom_builder::CSSMessage;
use resource::resource_task::{Done, Load, Payload, ResourceTask};
use CSSExitMessage = html::dom_builder::Exit;
use CSSFileMessage = html::dom_builder::File;
use JSExitMessage = html::dom_builder::js_exit;
use JSFileMessage = html::dom_builder::js_file;
use JSMessage = html::dom_builder::js_message;
use comm::{Chan, Port};
use str::from_slice;
@ -19,6 +13,16 @@ use std::net::url::Url;
type JSResult = ~[~[u8]];
enum CSSMessage {
CSSTaskNewFile(Url),
CSSTaskExit
}
enum JSMessage {
JSTaskNewFile(Url),
JSTaskExit
}
struct HtmlParserResult {
root: Node,
style_port: comm::Port<Stylesheet>,
@ -45,7 +49,7 @@ fn css_link_listener(to_parent : comm::Chan<Stylesheet>, from_parent : comm::Por
loop {
match from_parent.recv() {
CSSFileMessage(url) => {
CSSTaskNewFile(url) => {
let result_port = comm::Port();
let result_chan = comm::Chan(result_port);
// TODO: change copy to move once we have match move
@ -59,7 +63,7 @@ fn css_link_listener(to_parent : comm::Chan<Stylesheet>, from_parent : comm::Por
vec::push(result_vec, result_port);
}
CSSExitMessage => {
CSSTaskExit => {
break;
}
}
@ -76,7 +80,7 @@ fn js_script_listener(to_parent : comm::Chan<~[~[u8]]>, from_parent : comm::Port
loop {
match from_parent.recv() {
JSFileMessage(url) => {
JSTaskNewFile(url) => {
let result_port = comm::Port();
let result_chan = comm::Chan(result_port);
// TODO: change copy to move once we have match move
@ -104,7 +108,7 @@ fn js_script_listener(to_parent : comm::Chan<~[~[u8]]>, from_parent : comm::Port
}
vec::push(result_vec, result_port);
}
JSExitMessage => {
JSTaskExit => {
break;
}
}
@ -114,18 +118,47 @@ fn js_script_listener(to_parent : comm::Chan<~[~[u8]]>, from_parent : comm::Port
to_parent.send(js_scripts);
}
fn build_element_kind(tag_name: &str) -> ~ElementKind {
if tag_name == "div" {
~HTMLDivElement
} else if tag_name == "img" {
~HTMLImageElement({ mut size: Size2D(au::from_px(100), au::from_px(100)) })
} else if tag_name == "script" {
~HTMLScriptElement
} else if tag_name == "head" {
~HTMLHeadElement
} else {
~UnknownElement
}
fn build_element_kind(tag: &str) -> ~ElementKind {
// TODO: use atoms
if tag == ~"a" { ~HTMLAnchorElement }
else if tag == ~"aside" { ~HTMLAsideElement }
else if tag == ~"br" { ~HTMLBRElement }
else if tag == ~"body" { ~HTMLBodyElement }
else if tag == ~"bold" { ~HTMLBoldElement }
else if tag == ~"div" { ~HTMLDivElement }
else if tag == ~"font" { ~HTMLFontElement }
else if tag == ~"form" { ~HTMLFormElement }
else if tag == ~"hr" { ~HTMLHRElement }
else if tag == ~"head" { ~HTMLHeadElement }
else if tag == ~"h1" { ~HTMLHeadingElement(Heading1) }
else if tag == ~"h2" { ~HTMLHeadingElement(Heading2) }
else if tag == ~"h3" { ~HTMLHeadingElement(Heading3) }
else if tag == ~"h4" { ~HTMLHeadingElement(Heading4) }
else if tag == ~"h5" { ~HTMLHeadingElement(Heading5) }
else if tag == ~"h6" { ~HTMLHeadingElement(Heading6) }
else if tag == ~"html" { ~HTMLHtmlElement }
else if tag == ~"img" { ~HTMLImageElement({ mut size: au::zero_size() }) }
else if tag == ~"input" { ~HTMLInputElement }
else if tag == ~"i" { ~HTMLItalicElement }
else if tag == ~"link" { ~HTMLLinkElement }
else if tag == ~"li" { ~HTMLListItemElement }
else if tag == ~"meta" { ~HTMLMetaElement }
else if tag == ~"ol" { ~HTMLOListElement }
else if tag == ~"option" { ~HTMLOptionElement }
else if tag == ~"p" { ~HTMLParagraphElement }
else if tag == ~"script" { ~HTMLScriptElement }
else if tag == ~"section" { ~HTMLSectionElement }
else if tag == ~"select" { ~HTMLSelectElement }
else if tag == ~"small" { ~HTMLSmallElement }
else if tag == ~"span" { ~HTMLSpanElement }
else if tag == ~"style" { ~HTMLStyleElement }
else if tag == ~"tbody" { ~HTMLTableBodyElement }
else if tag == ~"td" { ~HTMLTableCellElement }
else if tag == ~"table" { ~HTMLTableElement }
else if tag == ~"tr" { ~HTMLTableRowElement }
else if tag == ~"title" { ~HTMLTitleElement }
else if tag == ~"ul" { ~HTMLUListElement }
else { ~UnknownElement }
}
fn parse_html(scope: NodeScope, url: Url, resource_task: ResourceTask) -> HtmlParserResult unsafe {
@ -175,53 +208,30 @@ fn parse_html(scope: NodeScope, url: Url, resource_task: ResourceTask) -> HtmlPa
},
create_element: |tag: &hubbub::Tag| {
debug!("create element");
let element_kind = build_element_kind(tag.name);
let node = scope.new_node(Element(ElementData(from_slice(tag.name), element_kind)));
let elem_kind = build_element_kind(tag.name);
let elem = ElementData(from_slice(tag.name), elem_kind);
debug!("attach attrs");
for tag.attributes.each |attribute| {
do scope.read(node) |node_contents| {
match *node_contents.kind {
Element(element) => {
element.attrs.push(~Attr(from_slice(attribute.name),
elem.attrs.push(~Attr(from_slice(attribute.name),
from_slice(attribute.value)));
match *element.kind {
HTMLImageElement(img) if attribute.name == "width" => {
match int::from_str(from_slice(attribute.value)) {
None => {} // Drop on the floor.
Some(s) => img.size.width = au::from_px(s)
}
}
HTMLImageElement(img) if attribute.name == "height" => {
match int::from_str(from_slice(attribute.value)) {
None => {} // Drop on the floor.
Some(s) => img.size.height = au::from_px(s)
}
}
HTMLDivElement | HTMLImageElement(*) | HTMLHeadElement |
HTMLScriptElement | UnknownElement => {} // Drop on the floor.
}
}
_ => fail ~"can't happen: unexpected node type"
}
}
}
// Handle CSS style sheet links.
do scope.read(node) |node_contents| {
match *node_contents.kind {
Element(element) if element.tag_name == ~"link" => {
match (element.get_attr(~"rel"), element.get_attr(~"href")) {
// Spawn additional parsing, network loads, etc. from opening tag
match elem.tag_name {
//Handle CSS style sheets from <link> elements
~"link" => {
match (elem.get_attr(~"rel"), elem.get_attr(~"href")) {
(Some(rel), Some(href)) if rel == ~"stylesheet" => {
debug!("found CSS stylesheet: %s", href);
css_chan.send(CSSFileMessage(make_url(href, Some(copy *url))));
css_chan.send(CSSTaskNewFile(make_url(href, Some(copy *url))));
}
_ => {}
}
}
//TODO: handle inline styles ('style' attr)
_ => {}
}
}
let node = scope.new_node(Element(elem));
unsafe { reinterpret_cast(&node) }
},
create_text: |data| {
@ -280,7 +290,7 @@ fn parse_html(scope: NodeScope, url: Url, resource_task: ResourceTask) -> HtmlPa
Some(src) => {
debug!("found script: %s", src);
let new_url = make_url(src, Some(copy *url));
js_chan.send(JSFileMessage(new_url));
js_chan.send(JSTaskNewFile(new_url));
}
None => {}
}
@ -308,8 +318,8 @@ fn parse_html(scope: NodeScope, url: Url, resource_task: ResourceTask) -> HtmlPa
}
}
css_chan.send(CSSExitMessage);
js_chan.send(JSExitMessage);
css_chan.send(CSSTaskExit);
js_chan.send(JSTaskExit);
return HtmlParserResult { root: root, style_port: css_port, js_port: js_port };
}

View file

@ -10,8 +10,8 @@ use core::rand;
use css::styles::SpecifiedStyle;
use css::values::{BoxSizing, Length, Px, CSSDisplay, Specified, BgColor, BgTransparent};
use dl = gfx::display_list;
use dom::base::{Element, ElementKind, HTMLDivElement, HTMLImageElement};
use dom::base::{Node, NodeData, NodeKind, NodeTree};
use dom::element::{ElementKind, HTMLDivElement, HTMLImageElement};
use dom::base::{Element, Node, NodeData, NodeKind, NodeTree};
use dom::rcu;
use geom::rect::Rect;
use geom::size::Size2D;

View file

@ -4,7 +4,8 @@ use core::dvec::DVec;
use css::styles::SpecifiedStyle;
use css::values::{CSSDisplay, DisplayBlock, DisplayInline, DisplayInlineBlock, DisplayNone};
use css::values::{Inherit, Initial, Specified};
use dom::base::*;
use dom::base::{Node, Comment, Text, Element, Doctype, NodeTree};
use dom::element::*;
use layout::base::{RenderBox, BoxData, GenericBox, ImageBox, TextBox, RenderBoxTree};
use layout::base::{FlowContext, FlowContextData, BlockFlow, InlineFlow, InlineBlockFlow, RootFlow, FlowTree};
use layout::block::BlockFlowData;

View file

@ -87,7 +87,7 @@ impl @FlowContext : InlineLayout {
/* Recursively (top-down) determines the actual width of child
contexts and boxes. When called on this context, the context has
had its width set by the parent context. */
fn assign_widths_inline(_ctx: &LayoutContext) {
fn assign_widths_inline(ctx: &LayoutContext) {
assert self.starts_inline_flow();
/* Perform inline flow with the available width. */
@ -108,6 +108,13 @@ impl @FlowContext : InlineLayout {
- Save the dvec of this context's lineboxes. */
/* hack: until text box splitting is hoisted into this
function, force "reflow" on TextBoxes. */
match box.kind {
TextBox(*) => box.reflow_text(ctx),
_ => {}
}
box.data.position.size.width = match box.kind {
ImageBox(sz) => sz.width,
TextBox(d) => d.runs[0].size().width,

View file

@ -31,6 +31,7 @@ mod dom {
mod node;
mod window;
}
mod element;
mod event;
mod rcu;
}
@ -88,7 +89,6 @@ mod image {
mod html {
mod lexer;
mod lexer_util;
mod dom_builder;
mod hubbub_html_parser;
}