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 dom::event::{Event, ResizeEvent, ReflowEvent};
use gfx::compositor::Compositor; use gfx::compositor::Compositor;
use html::lexer::spawn_html_lexer_task; use html::lexer::spawn_html_lexer_task;
use html::dom_builder::build_dom;
use layout::layout_task; use layout::layout_task;
use layout_task::{LayoutTask, BuildMsg}; use layout_task::{LayoutTask, BuildMsg};
@ -155,12 +154,6 @@ impl<C:Compositor> Content<C> {
// Note: we can parse the next document in parallel // Note: we can parse the next document in parallel
// with any previous documents. // 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, let result = html::hubbub_html_parser::parse_html(self.scope,
url, url,

View file

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

View file

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

View file

@ -4,7 +4,7 @@ use std::arc::{ARC, get, clone};
use css::values::*; use css::values::*;
use css::values::Stylesheet; 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::{Comment, Doctype, Element, Node, NodeKind, Text};
use dom::base::{LayoutData}; use dom::base::{LayoutData};
use util::color::{Color, rgb}; use util::color::{Color, rgb};
@ -37,6 +37,7 @@ impl NodeKind : DefaultStyleMethods {
} }
} }
/* TODO: this belongs in the UA stylesheet */
fn default_display_type() -> CSSDisplay { fn default_display_type() -> CSSDisplay {
match self { match self {
Text(*) => { DisplayInline } Text(*) => { DisplayInline }
@ -46,7 +47,7 @@ impl NodeKind : DefaultStyleMethods {
HTMLHeadElement => DisplayNone, HTMLHeadElement => DisplayNone,
HTMLImageElement(*) => DisplayInline, HTMLImageElement(*) => DisplayInline,
HTMLScriptElement => DisplayNone, HTMLScriptElement => DisplayNone,
UnknownElement => DisplayInline, _ => DisplayInline,
} }
}, },
Comment(*) | Doctype(*) => DisplayNone 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 comm::{Port, Chan};
use content::content_task::{ControlMsg, Timer}; use content::content_task::{ControlMsg, Timer};
use css::styles::SpecifiedStyle; use css::styles::SpecifiedStyle;
use css::values::Stylesheet; use css::values::Stylesheet;
use dom::element::{Attr, ElementData};
use dom::bindings; use dom::bindings;
use dvec::DVec;
use geom::size::Size2D; use geom::size::Size2D;
use gfx::geometry::au; use gfx::geometry::au;
use js::crust::*; 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, fn define_bindings(compartment: bare_compartment, doc: @Document,
win: @Window) { win: @Window) {
@ -182,14 +141,6 @@ fn define_bindings(compartment: bare_compartment, doc: @Document,
bindings::element::init(compartment); 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, /** The RCU rd_aux data is a (weak) pointer to the layout data,
defined by this `LayoutData` enum. It contains the CSS style object defined by this `LayoutData` enum. It contains the CSS style object

View file

@ -1,4 +1,5 @@
use au = gfx::geometry; use au = gfx::geometry;
use au::au;
use js::rust::{bare_compartment, methods, jsobj}; use js::rust::{bare_compartment, methods, jsobj};
use js::{JS_ARGV, JSCLASS_HAS_RESERVED_SLOTS, JSPROP_ENUMERATE, JSPROP_SHARED, JSVAL_NULL, use js::{JS_ARGV, JSCLASS_HAS_RESERVED_SLOTS, JSPROP_ENUMERATE, JSPROP_SHARED, JSVAL_NULL,
JS_THIS_OBJECT, JS_SET_RVAL, JSPROP_NATIVE_ACCESSORS}; 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 js::crust::{JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ConvertStub};
use dom::base::{Node, NodeScope, Element}; use dom::base::{Node, NodeScope, Element};
use dom::element::*;
use node::NodeBundle; use node::NodeBundle;
use utils::{rust_box, squirrel_away_unique, get_compartment, domstring_to_jsval, str}; use utils::{rust_box, squirrel_away_unique, get_compartment, domstring_to_jsval, str};
use libc::c_uint; use libc::c_uint;
use ptr::null; use ptr::null;
use node::unwrap; use node::unwrap;
use dom::base::{HTMLImageElement, HTMLScriptElement, HTMLHeadElement, HTMLDivElement,
UnknownElement};
extern fn finalize(_fop: *JSFreeOp, obj: *JSObject) { extern fn finalize(_fop: *JSFreeOp, obj: *JSObject) {
#debug("element finalize!"); #debug("element finalize!");
@ -71,13 +72,22 @@ extern fn HTMLImageElement_getWidth(cx: *JSContext, _argc: c_uint, vp: *mut jsva
let bundle = unwrap(obj); let bundle = unwrap(obj);
let width = (*bundle).payload.scope.write((*bundle).payload.node, |nd| { let width = (*bundle).payload.scope.write((*bundle).payload.node, |nd| {
match nd.kind { match nd.kind {
~Element(ed) => { ~Element(ed) => {
match ed.kind { match ed.kind {
~HTMLImageElement(img) => img.size.width, ~HTMLImageElement(*) => {
_ => fail ~"why is this not an image element?" // TODO: this should actually come from rendered dimensions!
} match ed.get_attr(~"width") {
} Some(s) => match int::from_str(s) {
_ => fail ~"why is this not an element?" 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?"
} }
}); });
*vp = RUST_INT_TO_JSVAL( *vp = RUST_INT_TO_JSVAL(
@ -97,9 +107,9 @@ extern fn HTMLImageElement_setWidth(cx: *JSContext, _argc: c_uint, vp: *mut jsva
match nd.kind { match nd.kind {
~Element(ed) => { ~Element(ed) => {
match ed.kind { match ed.kind {
~HTMLImageElement(img) => { ~HTMLImageElement(*) => {
let arg = ptr::offset(JS_ARGV(cx, cast::reinterpret_cast(&vp)), 0); 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?" _ => fail ~"why is this not an image element?"
} }
@ -144,7 +154,7 @@ fn create(cx: *JSContext, node: Node, scope: NodeScope) -> jsobj unsafe {
~HTMLHeadElement(*) => ~"HTMLHeadElement", ~HTMLHeadElement(*) => ~"HTMLHeadElement",
~HTMLImageElement(*) => ~"HTMLImageElement", ~HTMLImageElement(*) => ~"HTMLImageElement",
~HTMLScriptElement(*) => ~"HTMLScriptElement", ~HTMLScriptElement(*) => ~"HTMLScriptElement",
~UnknownElement(*) => ~"HTMLElement" _ => ~"HTMLElement"
} }
} }
_ => fail ~"element::create only handles elements" _ => 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 au = gfx::geometry;
use dom::base::{Attr, Comment, Doctype, DoctypeData, Element, ElementData, ElementKind}; use dom::base::{Comment, Doctype, DoctypeData, Element};
use dom::base::{HTMLDivElement, HTMLHeadElement, HTMLImageElement, HTMLScriptElement}; use dom::element::*;
use dom::base::{Node, NodeScope, Text, UnknownElement}; use dom::base::{Node, NodeScope, Text, UnknownElement};
use css::values::Stylesheet; use css::values::Stylesheet;
use geom::size::Size2D; use geom::size::Size2D;
use html::dom_builder::CSSMessage;
use resource::resource_task::{Done, Load, Payload, ResourceTask}; 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 comm::{Chan, Port};
use str::from_slice; use str::from_slice;
@ -19,6 +13,16 @@ use std::net::url::Url;
type JSResult = ~[~[u8]]; type JSResult = ~[~[u8]];
enum CSSMessage {
CSSTaskNewFile(Url),
CSSTaskExit
}
enum JSMessage {
JSTaskNewFile(Url),
JSTaskExit
}
struct HtmlParserResult { struct HtmlParserResult {
root: Node, root: Node,
style_port: comm::Port<Stylesheet>, style_port: comm::Port<Stylesheet>,
@ -45,7 +49,7 @@ fn css_link_listener(to_parent : comm::Chan<Stylesheet>, from_parent : comm::Por
loop { loop {
match from_parent.recv() { match from_parent.recv() {
CSSFileMessage(url) => { CSSTaskNewFile(url) => {
let result_port = comm::Port(); let result_port = comm::Port();
let result_chan = comm::Chan(result_port); let result_chan = comm::Chan(result_port);
// TODO: change copy to move once we have match move // 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); vec::push(result_vec, result_port);
} }
CSSExitMessage => { CSSTaskExit => {
break; break;
} }
} }
@ -76,7 +80,7 @@ fn js_script_listener(to_parent : comm::Chan<~[~[u8]]>, from_parent : comm::Port
loop { loop {
match from_parent.recv() { match from_parent.recv() {
JSFileMessage(url) => { JSTaskNewFile(url) => {
let result_port = comm::Port(); let result_port = comm::Port();
let result_chan = comm::Chan(result_port); let result_chan = comm::Chan(result_port);
// TODO: change copy to move once we have match move // 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); vec::push(result_vec, result_port);
} }
JSExitMessage => { JSTaskExit => {
break; break;
} }
} }
@ -114,18 +118,47 @@ fn js_script_listener(to_parent : comm::Chan<~[~[u8]]>, from_parent : comm::Port
to_parent.send(js_scripts); to_parent.send(js_scripts);
} }
fn build_element_kind(tag_name: &str) -> ~ElementKind { fn build_element_kind(tag: &str) -> ~ElementKind {
if tag_name == "div" { // TODO: use atoms
~HTMLDivElement if tag == ~"a" { ~HTMLAnchorElement }
} else if tag_name == "img" { else if tag == ~"aside" { ~HTMLAsideElement }
~HTMLImageElement({ mut size: Size2D(au::from_px(100), au::from_px(100)) }) else if tag == ~"br" { ~HTMLBRElement }
} else if tag_name == "script" { else if tag == ~"body" { ~HTMLBodyElement }
~HTMLScriptElement else if tag == ~"bold" { ~HTMLBoldElement }
} else if tag_name == "head" { else if tag == ~"div" { ~HTMLDivElement }
~HTMLHeadElement else if tag == ~"font" { ~HTMLFontElement }
} else { else if tag == ~"form" { ~HTMLFormElement }
~UnknownElement 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 { 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| { create_element: |tag: &hubbub::Tag| {
debug!("create element"); debug!("create element");
let element_kind = build_element_kind(tag.name); let elem_kind = build_element_kind(tag.name);
let node = scope.new_node(Element(ElementData(from_slice(tag.name), element_kind))); let elem = ElementData(from_slice(tag.name), elem_kind);
debug!("attach attrs");
for tag.attributes.each |attribute| { for tag.attributes.each |attribute| {
do scope.read(node) |node_contents| { elem.attrs.push(~Attr(from_slice(attribute.name),
match *node_contents.kind { from_slice(attribute.value)));
Element(element) => {
element.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. // Spawn additional parsing, network loads, etc. from opening tag
do scope.read(node) |node_contents| { match elem.tag_name {
match *node_contents.kind { //Handle CSS style sheets from <link> elements
Element(element) if element.tag_name == ~"link" => { ~"link" => {
match (element.get_attr(~"rel"), element.get_attr(~"href")) { match (elem.get_attr(~"rel"), elem.get_attr(~"href")) {
(Some(rel), Some(href)) if rel == ~"stylesheet" => { (Some(rel), Some(href)) if rel == ~"stylesheet" => {
debug!("found CSS stylesheet: %s", href); 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) } unsafe { reinterpret_cast(&node) }
}, },
create_text: |data| { create_text: |data| {
@ -280,7 +290,7 @@ fn parse_html(scope: NodeScope, url: Url, resource_task: ResourceTask) -> HtmlPa
Some(src) => { Some(src) => {
debug!("found script: %s", src); debug!("found script: %s", src);
let new_url = make_url(src, Some(copy *url)); let new_url = make_url(src, Some(copy *url));
js_chan.send(JSFileMessage(new_url)); js_chan.send(JSTaskNewFile(new_url));
} }
None => {} None => {}
} }
@ -308,8 +318,8 @@ fn parse_html(scope: NodeScope, url: Url, resource_task: ResourceTask) -> HtmlPa
} }
} }
css_chan.send(CSSExitMessage); css_chan.send(CSSTaskExit);
js_chan.send(JSExitMessage); js_chan.send(JSTaskExit);
return HtmlParserResult { root: root, style_port: css_port, js_port: js_port }; 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::styles::SpecifiedStyle;
use css::values::{BoxSizing, Length, Px, CSSDisplay, Specified, BgColor, BgTransparent}; use css::values::{BoxSizing, Length, Px, CSSDisplay, Specified, BgColor, BgTransparent};
use dl = gfx::display_list; use dl = gfx::display_list;
use dom::base::{Element, ElementKind, HTMLDivElement, HTMLImageElement}; use dom::element::{ElementKind, HTMLDivElement, HTMLImageElement};
use dom::base::{Node, NodeData, NodeKind, NodeTree}; use dom::base::{Element, Node, NodeData, NodeKind, NodeTree};
use dom::rcu; use dom::rcu;
use geom::rect::Rect; use geom::rect::Rect;
use geom::size::Size2D; use geom::size::Size2D;

View file

@ -4,7 +4,8 @@ use core::dvec::DVec;
use css::styles::SpecifiedStyle; use css::styles::SpecifiedStyle;
use css::values::{CSSDisplay, DisplayBlock, DisplayInline, DisplayInlineBlock, DisplayNone}; use css::values::{CSSDisplay, DisplayBlock, DisplayInline, DisplayInlineBlock, DisplayNone};
use css::values::{Inherit, Initial, Specified}; 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::{RenderBox, BoxData, GenericBox, ImageBox, TextBox, RenderBoxTree};
use layout::base::{FlowContext, FlowContextData, BlockFlow, InlineFlow, InlineBlockFlow, RootFlow, FlowTree}; use layout::base::{FlowContext, FlowContextData, BlockFlow, InlineFlow, InlineBlockFlow, RootFlow, FlowTree};
use layout::block::BlockFlowData; use layout::block::BlockFlowData;

View file

@ -87,7 +87,7 @@ impl @FlowContext : InlineLayout {
/* Recursively (top-down) determines the actual width of child /* Recursively (top-down) determines the actual width of child
contexts and boxes. When called on this context, the context has contexts and boxes. When called on this context, the context has
had its width set by the parent context. */ 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(); assert self.starts_inline_flow();
/* Perform inline flow with the available width. */ /* Perform inline flow with the available width. */
@ -107,6 +107,13 @@ impl @FlowContext : InlineLayout {
where its chunks ended up. where its chunks ended up.
- Save the dvec of this context's lineboxes. */ - 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 { box.data.position.size.width = match box.kind {
ImageBox(sz) => sz.width, ImageBox(sz) => sz.width,

View file

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