mirror of
https://github.com/servo/servo.git
synced 2025-08-08 06:55:31 +01:00
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:
parent
754bbeae41
commit
76a43555ac
13 changed files with 217 additions and 419 deletions
|
@ -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,
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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!");
|
||||
|
@ -71,13 +72,22 @@ extern fn HTMLImageElement_getWidth(cx: *JSContext, _argc: c_uint, vp: *mut jsva
|
|||
let bundle = unwrap(obj);
|
||||
let width = (*bundle).payload.scope.write((*bundle).payload.node, |nd| {
|
||||
match nd.kind {
|
||||
~Element(ed) => {
|
||||
match ed.kind {
|
||||
~HTMLImageElement(img) => img.size.width,
|
||||
_ => fail ~"why is this not an image element?"
|
||||
}
|
||||
}
|
||||
_ => fail ~"why is this not an element?"
|
||||
~Element(ed) => {
|
||||
match ed.kind {
|
||||
~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?"
|
||||
}
|
||||
});
|
||||
*vp = RUST_INT_TO_JSVAL(
|
||||
|
@ -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
96
src/servo/dom/element.rs
Normal 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,
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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),
|
||||
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"
|
||||
}
|
||||
}
|
||||
elem.attrs.push(~Attr(from_slice(attribute.name),
|
||||
from_slice(attribute.value)));
|
||||
}
|
||||
|
||||
// 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")) {
|
||||
(Some(rel), Some(href)) if rel == ~"stylesheet" => {
|
||||
debug!("found CSS stylesheet: %s", href);
|
||||
css_chan.send(CSSFileMessage(make_url(href, Some(copy *url))));
|
||||
}
|
||||
_ => {}
|
||||
// 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(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 };
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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. */
|
||||
|
@ -107,6 +107,13 @@ impl @FlowContext : InlineLayout {
|
|||
where its chunks ended up.
|
||||
|
||||
- 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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue