servo/src/components/script/dom/element.rs
2013-05-28 17:13:40 -07:00

262 lines
8.4 KiB
Rust

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Element nodes.
use dom::bindings::utils::DOMString;
use dom::clientrect::ClientRect;
use dom::clientrectlist::ClientRectList;
use dom::node::{ElementNodeTypeId, Node, ScriptView};
use layout_interface::{ContentBoxQuery, ContentBoxResponse, ContentBoxesQuery};
use layout_interface::{ContentBoxesResponse};
use core::cell::Cell;
use core::str::eq_slice;
use std::net::url::Url;
pub struct Element {
parent: Node<ScriptView>,
tag_name: ~str, // TODO: This should be an atom, not a ~str.
attrs: ~[Attr],
}
#[deriving(Eq)]
pub enum ElementTypeId {
HTMLAnchorElementTypeId,
HTMLAsideElementTypeId,
HTMLBRElementTypeId,
HTMLBodyElementTypeId,
HTMLBoldElementTypeId,
HTMLDivElementTypeId,
HTMLFontElementTypeId,
HTMLFormElementTypeId,
HTMLHRElementTypeId,
HTMLHeadElementTypeId,
HTMLHeadingElementTypeId,
HTMLHtmlElementTypeId,
HTMLImageElementTypeId,
HTMLInputElementTypeId,
HTMLItalicElementTypeId,
HTMLLinkElementTypeId,
HTMLListItemElementTypeId,
HTMLMetaElementTypeId,
HTMLOListElementTypeId,
HTMLOptionElementTypeId,
HTMLParagraphElementTypeId,
HTMLScriptElementTypeId,
HTMLSectionElementTypeId,
HTMLSelectElementTypeId,
HTMLSmallElementTypeId,
HTMLSpanElementTypeId,
HTMLStyleElementTypeId,
HTMLTableBodyElementTypeId,
HTMLTableCellElementTypeId,
HTMLTableElementTypeId,
HTMLTableRowElementTypeId,
HTMLTitleElementTypeId,
HTMLUListElementTypeId,
UnknownElementTypeId,
}
//
// Regular old elements
//
pub struct HTMLAnchorElement { parent: Element }
pub struct HTMLAsideElement { parent: Element }
pub struct HTMLBRElement { parent: Element }
pub struct HTMLBodyElement { parent: Element }
pub struct HTMLBoldElement { parent: Element }
pub struct HTMLDivElement { parent: Element }
pub struct HTMLFontElement { parent: Element }
pub struct HTMLFormElement { parent: Element }
pub struct HTMLHRElement { parent: Element }
pub struct HTMLHeadElement { parent: Element }
pub struct HTMLHtmlElement { parent: Element }
pub struct HTMLInputElement { parent: Element }
pub struct HTMLItalicElement { parent: Element }
pub struct HTMLLinkElement { parent: Element }
pub struct HTMLListItemElement { parent: Element }
pub struct HTMLMetaElement { parent: Element }
pub struct HTMLOListElement { parent: Element }
pub struct HTMLOptionElement { parent: Element }
pub struct HTMLParagraphElement { parent: Element }
pub struct HTMLScriptElement { parent: Element }
pub struct HTMLSectionElement { parent: Element }
pub struct HTMLSelectElement { parent: Element }
pub struct HTMLSmallElement { parent: Element }
pub struct HTMLSpanElement { parent: Element }
pub struct HTMLStyleElement { parent: Element }
pub struct HTMLTableBodyElement { parent: Element }
pub struct HTMLTableCellElement { parent: Element }
pub struct HTMLTableElement { parent: Element }
pub struct HTMLTableRowElement { parent: Element }
pub struct HTMLTitleElement { parent: Element }
pub struct HTMLUListElement { parent: Element }
pub struct UnknownElement { parent: Element }
//
// Fancier elements
//
pub struct HTMLHeadingElement {
parent: Element,
level: HeadingLevel,
}
pub struct HTMLImageElement {
parent: Element,
image: Option<Url>,
}
//
// Element methods
//
pub impl<'self> Element {
pub fn new(type_id: ElementTypeId, tag_name: ~str) -> Element {
Element {
parent: Node::new(ElementNodeTypeId(type_id)),
tag_name: tag_name,
attrs: ~[]
}
}
fn get_attr(&'self self, name: &str) -> Option<&'self str> {
// FIXME: Need an each() that links lifetimes in Rust.
for uint::range(0, self.attrs.len()) |i| {
if eq_slice(self.attrs[i].name, name) {
let val: &str = self.attrs[i].value;
return Some(val);
}
}
return None;
}
fn set_attr(&mut self, name: &DOMString, value: &DOMString) {
let name = name.to_str();
let value = value.to_str();
// FIXME: We need a better each_mut in Rust; this is ugly.
let value_cell = Cell(value);
let mut found = false;
for uint::range(0, self.attrs.len()) |i| {
if eq_slice(self.attrs[i].name, name) {
self.attrs[i].value = value_cell.take().clone();
found = true;
break;
}
}
if !found {
self.attrs.push(Attr::new(name.to_str(), value_cell.take().clone()));
}
match self.parent.owner_doc {
Some(owner) => owner.content_changed(),
None => {}
}
}
fn getClientRects(&self) -> Option<@mut ClientRectList> {
let rects = match self.parent.owner_doc {
Some(doc) => {
match doc.window {
Some(win) => {
let node = self.parent.abstract.get();
assert!(node.is_element());
let script_context = unsafe {
&mut *win.script_context
};
match script_context.query_layout(ContentBoxesQuery(node)) {
Ok(rects) => match rects {
ContentBoxesResponse(rects) =>
do rects.map |r| {
ClientRect::new(
r.origin.y.to_f32(),
(r.origin.y + r.size.height).to_f32(),
r.origin.x.to_f32(),
(r.origin.x + r.size.width).to_f32())
},
_ => fail!(~"unexpected layout reply")
},
Err(()) => {
debug!("layout query error");
~[]
}
}
}
None => {
debug!("no window");
~[]
}
}
}
None => {
debug!("no document");
~[]
}
};
Some(ClientRectList::new(rects))
}
fn getBoundingClientRect(&self) -> Option<@mut ClientRect> {
match self.parent.owner_doc {
Some(doc) => {
match doc.window {
Some(win) => {
let node = self.parent.abstract.get();
assert!(node.is_element());
let script_context = unsafe { &mut *win.script_context };
match script_context.query_layout(ContentBoxQuery(node)) {
Ok(rect) => match rect {
ContentBoxResponse(rect) =>
Some(ClientRect::new(
rect.origin.y.to_f32(),
(rect.origin.y + rect.size.height).to_f32(),
rect.origin.x.to_f32(),
(rect.origin.x + rect.size.width).to_f32())),
_ => fail!(~"unexpected layout result")
},
Err(()) => {
debug!("error querying layout");
None
}
}
}
None => {
debug!("no window");
None
}
}
}
None => {
debug!("no document");
None
}
}
}
}
pub struct Attr {
name: ~str,
value: ~str,
}
impl Attr {
pub fn new(name: ~str, value: ~str) -> Attr {
Attr {
name: name,
value: value
}
}
}
pub enum HeadingLevel {
Heading1,
Heading2,
Heading3,
Heading4,
Heading5,
Heading6,
}