aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/components/gfx/display_list.rs12
-rw-r--r--src/components/gfx/render_context.rs66
-rw-r--r--src/components/main/layout/box.rs67
-rw-r--r--src/components/script/dom/document.rs83
-rw-r--r--src/components/script/dom/htmldocument.rs13
-rw-r--r--src/components/script/dom/node.rs7
-rw-r--r--src/test/html/test_bindings.html2
-rw-r--r--src/test/html/test_bindings.js5
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();