diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/components/gfx/display_list.rs | 12 | ||||
-rw-r--r-- | src/components/gfx/render_context.rs | 66 | ||||
-rw-r--r-- | src/components/main/layout/box.rs | 67 | ||||
-rw-r--r-- | src/components/script/dom/document.rs | 83 | ||||
-rw-r--r-- | src/components/script/dom/htmldocument.rs | 13 | ||||
-rw-r--r-- | src/components/script/dom/node.rs | 7 | ||||
-rw-r--r-- | src/test/html/test_bindings.html | 2 | ||||
-rw-r--r-- | src/test/html/test_bindings.js | 5 |
8 files changed, 183 insertions, 72 deletions
diff --git a/src/components/gfx/display_list.rs b/src/components/gfx/display_list.rs index 5d6f5188faa..3c220974b9b 100644 --- a/src/components/gfx/display_list.rs +++ b/src/components/gfx/display_list.rs @@ -20,7 +20,7 @@ use render_context::RenderContext; use text::SendableTextRun; use std::cast::transmute_region; -use geom::{Point2D, Rect, Size2D}; +use geom::{Point2D, Rect, Size2D, SideOffsets2D}; use servo_net::image::base::Image; use servo_util::range::Range; use extra::arc::ARC; @@ -99,8 +99,10 @@ pub struct ImageDisplayItem<E> { /// Renders a border. pub struct BorderDisplayItem<E> { base: BaseDisplayItem<E>, - /// The width of the border. - width: Au, + + /// The border widths + border: SideOffsets2D<Au>, + /// The color of the border. color: Color, } @@ -147,7 +149,9 @@ impl<E> DisplayItem<E> { } BorderDisplayItemClass(ref border) => { - render_context.draw_border(&border.base.bounds, border.width, border.color) + render_context.draw_border(&border.base.bounds, + border.border, + border.color) } } } diff --git a/src/components/gfx/render_context.rs b/src/components/gfx/render_context.rs index f36445acf8c..00ccdcabf32 100644 --- a/src/components/gfx/render_context.rs +++ b/src/components/gfx/render_context.rs @@ -14,6 +14,7 @@ use std::libc::types::common::c99::uint16_t; use geom::point::Point2D; use geom::rect::Rect; use geom::size::Size2D; +use geom::side_offsets::SideOffsets2D; use servo_net::image::base::Image; use extra::arc::ARC; @@ -33,21 +34,47 @@ impl<'self> RenderContext<'self> { self.canvas.draw_target.fill_rect(&bounds.to_azure_rect(), &ColorPattern(color)); } - pub fn draw_border(&self, bounds: &Rect<Au>, width: Au, color: Color) { + pub fn draw_border(&self, + bounds: &Rect<Au>, + border: SideOffsets2D<Au>, + color: Color) { let pattern = ColorPattern(color); - let stroke_fields = 2; // CAP_SQUARE - let width_px = width.to_px(); - let rect = if width_px % 2 == 0 { - bounds.to_azure_rect() - } else { - bounds.to_azure_snapped_rect() - }; - - let stroke_opts = StrokeOptions(width_px as AzFloat, 10 as AzFloat, stroke_fields); let draw_opts = DrawOptions(1 as AzFloat, 0 as uint16_t); + let stroke_fields = 2; // CAP_SQUARE + let mut stroke_opts = StrokeOptions(0 as AzFloat, 10 as AzFloat, stroke_fields); + + let rect = bounds.to_azure_rect(); + let border = border.to_float_px(); self.canvas.draw_target.make_current(); - self.canvas.draw_target.stroke_rect(&rect, &pattern, &stroke_opts, &draw_opts); + + // draw top border + stroke_opts.line_width = border.top; + let y = rect.origin.y + border.top * 0.5; + let start = Point2D(rect.origin.x, y); + let end = Point2D(rect.origin.x + rect.size.width, y); + self.canvas.draw_target.stroke_line(start, end, &pattern, &stroke_opts, &draw_opts); + + // draw bottom border + stroke_opts.line_width = border.bottom; + let y = rect.origin.y + rect.size.height - border.bottom * 0.5; + let start = Point2D(rect.origin.x, y); + let end = Point2D(rect.origin.x + rect.size.width, y); + self.canvas.draw_target.stroke_line(start, end, &pattern, &stroke_opts, &draw_opts); + + // draw left border + stroke_opts.line_width = border.left; + let x = rect.origin.x + border.left * 0.5; + let start = Point2D(x, rect.origin.y); + let end = Point2D(x, rect.origin.y + rect.size.height); + self.canvas.draw_target.stroke_line(start, end, &pattern, &stroke_opts, &draw_opts); + + // draw right border + stroke_opts.line_width = border.right; + let x = rect.origin.x + rect.size.width - border.right * 0.5; + let start = Point2D(x, rect.origin.y); + let end = Point2D(x, rect.origin.y + rect.size.height); + self.canvas.draw_target.stroke_line(start, end, &pattern, &stroke_opts, &draw_opts); } pub fn draw_image(&self, bounds: Rect<Au>, image: ARC<~Image>) { @@ -94,7 +121,6 @@ impl to_float for u8 { trait ToAzureRect { fn to_azure_rect(&self) -> Rect<AzFloat>; - fn to_azure_snapped_rect(&self) -> Rect<AzFloat>; } impl ToAzureRect for Rect<Au> { @@ -102,11 +128,17 @@ impl ToAzureRect for Rect<Au> { Rect(Point2D(self.origin.x.to_px() as AzFloat, self.origin.y.to_px() as AzFloat), Size2D(self.size.width.to_px() as AzFloat, self.size.height.to_px() as AzFloat)) } +} + +trait ToSideOffsetsPx { + fn to_float_px(&self) -> SideOffsets2D<AzFloat>; +} - fn to_azure_snapped_rect(&self) -> Rect<AzFloat> { - Rect(Point2D(self.origin.x.to_px() as AzFloat + 0.5f as AzFloat, - self.origin.y.to_px() as AzFloat + 0.5f as AzFloat), - Size2D(self.size.width.to_px() as AzFloat, - self.size.height.to_px() as AzFloat)) +impl ToSideOffsetsPx for SideOffsets2D<Au> { + fn to_float_px(&self) -> SideOffsets2D<AzFloat> { + SideOffsets2D::new(self.top.to_px() as AzFloat, + self.right.to_px() as AzFloat, + self.bottom.to_px() as AzFloat, + self.left.to_px() as AzFloat) } } diff --git a/src/components/main/layout/box.rs b/src/components/main/layout/box.rs index 1839d93dfc0..72271e0cd39 100644 --- a/src/components/main/layout/box.rs +++ b/src/components/main/layout/box.rs @@ -16,7 +16,7 @@ use std::cmp::ApproxEq; use std::managed; use std::num::Zero; use std::uint; -use geom::{Point2D, Rect, Size2D}; +use geom::{Point2D, Rect, Size2D, SideOffsets2D}; use gfx::display_list::{BaseDisplayItem, BorderDisplayItem, BorderDisplayItemClass}; use gfx::display_list::{DisplayList, ImageDisplayItem, ImageDisplayItemClass}; use gfx::display_list::{SolidColorDisplayItem, SolidColorDisplayItemClass, TextDisplayItem}; @@ -629,13 +629,17 @@ impl RenderBox { // should have a real `SERVO_DEBUG` system. debug!("%?", { // Compute the text box bounds and draw a border surrounding them. + let debug_border = SideOffsets2D::new(Au::from_px(1), + Au::from_px(1), + Au::from_px(1), + Au::from_px(1)); do list.with_mut_ref |list| { let border_display_item = ~BorderDisplayItem { base: BaseDisplayItem { bounds: absolute_box_bounds, extra: ExtraDisplayListData::new(*self), }, - width: Au::from_px(1), + border: debug_border, color: rgb(0, 0, 200).to_gfx_color(), }; list.append_item(BorderDisplayItemClass(border_display_item)) @@ -655,7 +659,7 @@ impl RenderBox { bounds: baseline, extra: ExtraDisplayListData::new(*self), }, - width: Au::from_px(1), + border: debug_border, color: rgb(0, 200, 0).to_gfx_color(), }; list.append_item(BorderDisplayItemClass(border_display_item)) @@ -672,13 +676,18 @@ impl RenderBox { // FIXME(pcwalton): This is a bit of an abuse of the logging infrastructure. We // should have a real `SERVO_DEBUG` system. debug!("%?", { + let debug_border = SideOffsets2D::new(Au::from_px(1), + Au::from_px(1), + Au::from_px(1), + Au::from_px(1)); + do list.with_mut_ref |list| { let border_display_item = ~BorderDisplayItem { base: BaseDisplayItem { bounds: absolute_box_bounds, extra: ExtraDisplayListData::new(*self), }, - width: Au::from_px(1), + border: debug_border, color: rgb(0, 0, 200).to_gfx_color(), }; list.append_item(BorderDisplayItemClass(border_display_item)) @@ -896,43 +905,25 @@ impl RenderBox { return } - // Are all the widths equal? - // - // FIXME(pcwalton): Obviously this is wrong. - let borders = [ border.top, border.right, border.bottom ]; - if borders.iter().all(|a| *a == border.left) { - let border_width = border.top; - let bounds = Rect { - origin: Point2D { - x: abs_bounds.origin.x + border_width.scale_by(0.5), - y: abs_bounds.origin.y + border_width.scale_by(0.5), + // FIXME: all colors set to top color. this is obviously not right. + let top_color = self.style().border_top_color(); + let color = top_color.to_gfx_color(); + + // Append the border to the display list. + do list.with_mut_ref |list| { + let border_display_item = ~BorderDisplayItem { + base: BaseDisplayItem { + bounds: *abs_bounds, + extra: ExtraDisplayListData::new(*self), }, - size: Size2D { - width: abs_bounds.size.width - border_width, - height: abs_bounds.size.height - border_width - } + border: SideOffsets2D::new(border.top, + border.right, + border.bottom, + border.left), + color: color, }; - let top_color = self.style().border_top_color(); - let color = top_color.to_gfx_color(); // FIXME - - // Append the border to the display list. - do list.with_mut_ref |list| { - let border_display_item = ~BorderDisplayItem { - base: BaseDisplayItem { - bounds: bounds, - extra: ExtraDisplayListData::new(*self), - }, - width: border_width, - color: color, - }; - - list.append_item(BorderDisplayItemClass(border_display_item)) - } - } else { - warn!("ignoring unimplemented border widths"); + list.append_item(BorderDisplayItemClass(border_display_item)) } } - } - diff --git a/src/components/script/dom/document.rs b/src/components/script/dom/document.rs index 7c41a58134f..e338eee5dae 100644 --- a/src/components/script/dom/document.rs +++ b/src/components/script/dom/document.rs @@ -5,12 +5,12 @@ use dom::bindings::codegen::DocumentBinding; use dom::bindings::utils::{DOMString, WrapperCache, ErrorResult, null_string, str}; use dom::bindings::utils::{BindingObject, CacheableWrapper, rust_box, DerivedWrapper}; -use dom::element::{HTMLHtmlElement, HTMLHtmlElementTypeId}; +use dom::element::{HTMLHtmlElement, HTMLTitleElement, HTMLHtmlElementTypeId, HTMLHeadElementTypeId, HTMLTitleElementTypeId}; use dom::event::Event; use dom::htmlcollection::HTMLCollection; use dom::htmldocument::HTMLDocument; use dom::htmlelement::HTMLElement; -use dom::node::{AbstractNode, ScriptView, Node}; +use dom::node::{AbstractNode, ScriptView, Node, ElementNodeTypeId, Text}; use dom::window::Window; use dom::windowproxy::WindowProxy; @@ -274,14 +274,77 @@ impl Document { } pub fn Title(&self) -> DOMString { - str(self.title.clone()) - } - - pub fn SetTitle(&mut self, title: &DOMString, _rv: &mut ErrorResult) { - self.title = match title { - &str(ref s) => s.clone(), - &null_string => ~"" - }; + let mut title = ~""; + match self.doctype { + SVG => { + fail!("no SVG document yet") + }, + _ => { + let _ = for self.root.traverse_preorder |node| { + if node.type_id() != ElementNodeTypeId(HTMLTitleElementTypeId) { + loop; + } + for node.children().advance |child| { + if child.is_text() { + do child.with_imm_text() |text| { + let s = text.parent.Data(); + title = title + s.to_str(); + } + } + } + break; + }; + } + } + let v: ~[&str] = title.word_iter().collect(); + title = v.connect(" "); + title = title.trim().to_owned(); + str(title) + } + + pub fn SetTitle(&self, title: &DOMString, _rv: &mut ErrorResult) { + match self.doctype { + SVG => { + fail!("no SVG document yet") + }, + _ => { + let (_scope, cx) = self.get_scope_and_cx(); + let _ = for self.root.traverse_preorder |node| { + if node.type_id() != ElementNodeTypeId(HTMLHeadElementTypeId) { + loop; + } + let mut has_title = false; + for node.children().advance |child| { + if child.type_id() != ElementNodeTypeId(HTMLTitleElementTypeId) { + loop; + } + has_title = true; + for child.children().advance |title_child| { + child.remove_child(title_child); + } + let new_text = unsafe { + Node::as_abstract_node(cx, @Text::new(title.to_str())) + }; + child.add_child(new_text); + break; + } + if !has_title { + let new_title = @HTMLTitleElement { + parent: HTMLElement::new(HTMLTitleElementTypeId, ~"title") + }; + let new_title = unsafe { + Node::as_abstract_node(cx, new_title) + }; + let new_text = unsafe { + Node::as_abstract_node(cx, @Text::new(title.to_str())) + }; + new_title.add_child(new_text); + node.add_child(new_title); + } + break; + }; + } + } } pub fn Dir(&self) -> DOMString { diff --git a/src/components/script/dom/htmldocument.rs b/src/components/script/dom/htmldocument.rs index 619390352f8..a102fd8aa81 100644 --- a/src/components/script/dom/htmldocument.rs +++ b/src/components/script/dom/htmldocument.rs @@ -6,9 +6,9 @@ use dom::bindings::codegen::HTMLDocumentBinding; use dom::bindings::utils::{DOMString, ErrorResult, null_string}; use dom::bindings::utils::{CacheableWrapper, BindingObject, WrapperCache}; use dom::document::{AbstractDocument, Document, WrappableDocument, HTML}; -use dom::element::Element; +use dom::element::{Element, HTMLHeadElementTypeId}; use dom::htmlcollection::HTMLCollection; -use dom::node::{AbstractNode, ScriptView}; +use dom::node::{AbstractNode, ScriptView, ElementNodeTypeId}; use dom::window::Window; use js::jsapi::{JSObject, JSContext}; @@ -68,7 +68,14 @@ impl HTMLDocument { } pub fn GetHead(&self) -> Option<AbstractNode<ScriptView>> { - None + let mut headNode: Option<AbstractNode<ScriptView>> = None; + let _ = for self.parent.root.traverse_preorder |child| { + if child.type_id() == ElementNodeTypeId(HTMLHeadElementTypeId) { + headNode = Some(child); + break; + } + }; + headNode } pub fn Images(&self) -> @mut HTMLCollection { diff --git a/src/components/script/dom/node.rs b/src/components/script/dom/node.rs index 6e94d2f8ef0..7bf7e53b7ac 100644 --- a/src/components/script/dom/node.rs +++ b/src/components/script/dom/node.rs @@ -349,6 +349,13 @@ impl<'self, View> AbstractNode<View> { self.transmute(f) } + pub fn with_mut_text<R>(self, f: &fn(&mut Text) -> R) -> R { + if !self.is_text() { + fail!(~"node is not text"); + } + self.transmute_mut(f) + } + pub fn is_element(self) -> bool { match self.type_id() { ElementNodeTypeId(*) => true, diff --git a/src/test/html/test_bindings.html b/src/test/html/test_bindings.html index 60744cafcf1..5d9a0be0d3e 100644 --- a/src/test/html/test_bindings.html +++ b/src/test/html/test_bindings.html @@ -2,6 +2,8 @@ <html> <!-- comment --> <head> + <title>test_binding + page </title> <script src="test_bindings.js"></script> </head> <body> diff --git a/src/test/html/test_bindings.js b/src/test/html/test_bindings.js index 0d62dba7ec4..d50e77b9bbd 100644 --- a/src/test/html/test_bindings.js +++ b/src/test/html/test_bindings.js @@ -96,6 +96,11 @@ window.alert(tags.length); window.alert(tags[0]); window.alert(tags[0].tagName); +window.alert("Document:"); +let head = document.head; +window.alert(head); +window.alert(head.tagName); + window.alert("DOMParser:"); window.alert(DOMParser); let parser = new DOMParser(); |