mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
Refactor RCU to use the CamelCase naming convention
This commit is contained in:
parent
6c6f7f99e4
commit
0347e4408c
11 changed files with 155 additions and 160 deletions
|
@ -6,14 +6,15 @@
|
|||
export ControlMsg, PingMsg;
|
||||
export content;
|
||||
|
||||
import result::extensions;
|
||||
import dom::base::NodeScope;
|
||||
import dom::rcu::writer_methods;
|
||||
import dom::rcu::WriterMethods;
|
||||
import dom::style;
|
||||
import dom = dom::base;
|
||||
import layout::layout_task;
|
||||
|
||||
import js::rust::methods;
|
||||
|
||||
import result::extensions;
|
||||
|
||||
enum ControlMsg {
|
||||
ParseMsg(~str),
|
||||
ExecuteMsg(~str),
|
||||
|
@ -40,7 +41,7 @@ fn join_layout(scope: NodeScope, to_layout: chan<layout_task::Msg>) {
|
|||
fn content(to_layout: chan<layout_task::Msg>) -> chan<ControlMsg> {
|
||||
task::spawn_listener::<ControlMsg> {
|
||||
|from_master|
|
||||
let scope = dom::NodeScope();
|
||||
let scope = NodeScope();
|
||||
let rt = js::rust::rt();
|
||||
loop {
|
||||
alt from_master.recv() {
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
import dom::rcu::{writer_methods};
|
||||
#[doc="The core DOM types. Defines the basic DOM hierarchy as well as all the HTML elements."]
|
||||
|
||||
import dom::rcu::WriterMethods;
|
||||
import gfx::geometry::au;
|
||||
import geom::size::Size2D;
|
||||
import layout::base::layout_data;
|
||||
import util::tree;
|
||||
|
||||
import dvec::{dvec, extensions};
|
||||
|
||||
enum NodeData = {
|
||||
|
@ -61,12 +64,12 @@ enum ElementKind {
|
|||
the primary box. Note that there may be multiple boxes per DOM node.
|
||||
"]
|
||||
|
||||
type Node = rcu::handle<NodeData, layout_data>;
|
||||
type Node = rcu::Handle<NodeData, layout_data>;
|
||||
|
||||
type NodeScope = rcu::scope<NodeData, layout_data>;
|
||||
type NodeScope = rcu::Scope<NodeData, layout_data>;
|
||||
|
||||
fn NodeScope() -> NodeScope {
|
||||
rcu::scope()
|
||||
rcu::Scope()
|
||||
}
|
||||
|
||||
impl NodeScope for NodeScope {
|
||||
|
@ -85,7 +88,7 @@ impl of tree::rd_tree_ops<Node> for NodeScope {
|
|||
}
|
||||
|
||||
fn with_tree_fields<R>(node: Node, f: fn(tree::fields<Node>) -> R) -> R {
|
||||
self.rd(node) { |n| f(n.tree) }
|
||||
self.read(node) { |n| f(n.tree) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -95,7 +98,7 @@ impl of tree::wr_tree_ops<Node> for NodeScope {
|
|||
}
|
||||
|
||||
fn with_tree_fields<R>(node: Node, f: fn(tree::fields<Node>) -> R) -> R {
|
||||
self.wr(node) { |n| f(n.tree) }
|
||||
self.write(node) { |n| f(n.tree) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,115 +1,108 @@
|
|||
#[doc(str = "
|
||||
|
||||
Implements the RCU dom-sharing model. This model allows for a single
|
||||
writer and any number of readers, but the writer must be able to
|
||||
control and manage the lifetimes of the reader(s). For simplicity I
|
||||
will describe the impl as though there were a single reader.
|
||||
Implements the RCU DOM-sharing model. This model allows for a single writer and any number of
|
||||
readers, but the writer must be able to control and manage the lifetimes of the reader(s). For
|
||||
simplicity I will describe the implementation as though there were a single reader.
|
||||
|
||||
The basic idea is that every object in the RCU pool has both a reader
|
||||
view and a writer view. The writer always sees the writer view, which
|
||||
contains the most up-to-date values. The reader uses the reader view,
|
||||
which contains the values as of the point where the reader was forked.
|
||||
When the writer joins the reader, the reader view will be synchronized
|
||||
with the writer view.
|
||||
The basic idea is that every object in the RCU pool has both a reader view and a writer view. The
|
||||
writer always sees the writer view, which contains the most up-to-date values. The reader uses the
|
||||
reader view, which contains the values as of the point where the reader was forked. When the
|
||||
writer joins the reader, the reader view will be synchronized with the writer view.
|
||||
|
||||
Internally, the way this works is using a copy-on-write scheme. Each
|
||||
RCU node maintains two pointers (`rd_ptr` and `wr_ptr`). Assuming
|
||||
that readers are active, when a writer wants to modify a node, it
|
||||
first copies the reader's data into a new pointer. Any writes that
|
||||
occur after that point (but before the reader is joined) will operate
|
||||
on this same copy. When the reader is joined, any nodes which the
|
||||
writer modified will free the stale reader data and update the reader
|
||||
Internally, the way this works is using a copy-on-write scheme. Each RCU node maintains two
|
||||
pointers (`read_ptr` and `write_ptr`). Assuming that readers are active, when a writer wants to
|
||||
modify a node, it first copies the reader's data into a new pointer. Any writes that occur after
|
||||
that point (but before the reader is joined) will operate on this same copy. When the reader is
|
||||
joined, any nodes which the writer modified will free the stale reader data and update the reader
|
||||
pointer to be the same as the writer pointer.
|
||||
|
||||
# Using the RCU APIs as a writer
|
||||
|
||||
You must first create a `scope` object. The scope object manages the
|
||||
memory and the RCU operations. RCU'd objects of some sendable type
|
||||
`T` are not referenced directly but rather through a `handle<T>`. To
|
||||
create a new RCU object, you use `scope.handle(t)` where `t` is some
|
||||
initial value of type `T`. To write to an RCU object, use
|
||||
`scope.wr()` and to read from it use `scope.rd()`. Be sure not to use
|
||||
the various `reader_methods`.
|
||||
You must first create a `scope` object. The scope object manages the memory and the RCU
|
||||
operations. RCU'd objects of some sendable type `T` are not referenced directly but rather through
|
||||
a `handle<T>`. To create a new RCU object, you use `scope.handle(t)` where `t` is some initial
|
||||
value of type `T`. To write to an RCU object, use `scope.write()` and to read from it use
|
||||
`scope.read()`. Be sure not to use the various `ReaderMethods`.
|
||||
|
||||
Handles can be freely sent between tasks but the RCU scope cannot. It
|
||||
must stay with the writer task. You are responsible for correctly
|
||||
invoking `reader_forked()` and `reader_joined()` to keep the RCU scope
|
||||
abreast of when the reader is active. Failure to do so will lead to
|
||||
race conditions or worse.
|
||||
Handles can be freely sent between tasks but the RCU scope cannot. It must stay with the writer
|
||||
task. You are responsible for correctly invoking `reader_forked()` and `reader_joined()` to keep
|
||||
the RCU scope abreast of when the reader is active. Failure to do so will lead to race conditions
|
||||
or worse.
|
||||
|
||||
# Using the RCU APIs as a reader
|
||||
|
||||
Import the `reader_methods` impl. When you receive a handle, you can
|
||||
invoke `h.rd { |v| ... }` and so forth. There is also a piece of
|
||||
auxiliary data that can be optionally associated with each handle.
|
||||
Import the `ReaderMethods` impl. When you receive a handle, you can invoke `h.read { |v| ... }`
|
||||
and so forth. There is also a piece of auxiliary data that can be optionally associated with each
|
||||
handle.
|
||||
|
||||
Note: if the type `T` contains mutable fields, then there is nothing
|
||||
to stop the reader from mutating those fields in the `rd()` method.
|
||||
Do not do this. It will lead to race conditions.
|
||||
Note: if the type `T` contains mutable fields, then there is nothing to stop the reader from
|
||||
mutating those fields in the `read()` method. Do not do this. It will lead to race conditions.
|
||||
|
||||
FIXME: We can enforce that this is not done by ensuring that the type `T` contains no mutable
|
||||
fields.
|
||||
|
||||
# Auxiliary data
|
||||
|
||||
Readers can associate a piece of auxiliary data of type `A` along with
|
||||
main nodes. This is convenient but dangerous: it is the reader's job
|
||||
to ensure that this data remains live independent of the RCU nodes
|
||||
themselves.
|
||||
Readers can associate a piece of auxiliary data of type `A` along with main nodes. This is
|
||||
convenient but dangerous: it is the reader's job to ensure that this data remains live independent
|
||||
of the RCU nodes themselves.
|
||||
|
||||
")];
|
||||
|
||||
import ptr::extensions;
|
||||
import core::libc::types::os::arch::c95::size_t;
|
||||
|
||||
export handle;
|
||||
export reader_methods;
|
||||
export writer_methods;
|
||||
export scope;
|
||||
export Handle;
|
||||
export ReaderMethods;
|
||||
export WriterMethods;
|
||||
export Scope;
|
||||
|
||||
type scope_data<T:send,A> = {
|
||||
type ScopeData<T:send,A> = {
|
||||
mut layout_active: bool,
|
||||
mut free_list: [handle<T,A>],
|
||||
mut first_dirty: handle<T,A>
|
||||
mut free_list: [Handle<T,A>],
|
||||
mut first_dirty: Handle<T,A>
|
||||
};
|
||||
|
||||
resource scope_rsrc<T:send,A>(d: scope_data<T,A>) {
|
||||
resource ScopeResource<T:send,A>(d: ScopeData<T,A>) {
|
||||
unsafe {
|
||||
for d.free_list.each { |h| free_handle(h); }
|
||||
}
|
||||
}
|
||||
|
||||
type scope<T:send,A> = @scope_rsrc<T,A>;
|
||||
type Scope<T:send,A> = @ScopeResource<T,A>;
|
||||
|
||||
type handle_data<T:send,A> = {mut rd_ptr: *T,
|
||||
mut wr_ptr: *T,
|
||||
mut rd_aux: *A,
|
||||
mut next_dirty: handle<T,A>};
|
||||
enum handle<T:send,A> {
|
||||
_handle(*handle_data<T,A>)
|
||||
type HandleData<T:send,A> = {mut read_ptr: *T,
|
||||
mut write_ptr: *mut T,
|
||||
mut read_aux: *A,
|
||||
mut next_dirty: Handle<T,A>};
|
||||
enum Handle<T:send,A> {
|
||||
_Handle(*HandleData<T,A>)
|
||||
}
|
||||
|
||||
impl private_methods<T:send,A> for handle<T,A> {
|
||||
fn rd_ptr() -> *T unsafe { (**self).rd_ptr }
|
||||
fn wr_ptr() -> *T unsafe { (**self).wr_ptr }
|
||||
fn rd_aux() -> *A unsafe { (**self).rd_aux }
|
||||
fn next_dirty() -> handle<T,A> unsafe { (**self).next_dirty }
|
||||
impl HandlePrivate<T:send,A> for Handle<T,A> {
|
||||
fn read_ptr() -> *T unsafe { (**self).read_ptr }
|
||||
fn write_ptr() -> *mut T unsafe { (**self).write_ptr }
|
||||
fn read_aux() -> *A unsafe { (**self).read_aux }
|
||||
fn next_dirty() -> Handle<T,A> unsafe { (**self).next_dirty }
|
||||
|
||||
fn set_rd_ptr(t: *T) unsafe { (**self).rd_ptr = t; }
|
||||
fn set_wr_ptr(t: *T) unsafe { (**self).wr_ptr = t; }
|
||||
fn set_rd_aux(t: *A) unsafe { (**self).rd_aux = t; }
|
||||
fn set_next_dirty(+h: handle<T,A>) unsafe { (**self).next_dirty = h; }
|
||||
fn set_read_ptr(t: *T) unsafe { (**self).read_ptr = t; }
|
||||
fn set_write_ptr(t: *mut T) unsafe { (**self).write_ptr = t; }
|
||||
fn set_read_aux(t: *A) unsafe { (**self).read_aux = t; }
|
||||
fn set_next_dirty(+h: Handle<T,A>) unsafe { (**self).next_dirty = h; }
|
||||
|
||||
pure fn is_null() -> bool { (*self).is_null() }
|
||||
fn is_not_null() -> bool { (*self).is_not_null() }
|
||||
}
|
||||
|
||||
impl reader_methods<T:send,A> for handle<T,A> {
|
||||
#[doc(str = "access the reader's view of the handle's data")]
|
||||
fn rd<U>(f: fn(T) -> U) -> U unsafe {
|
||||
f(*self.rd_ptr())
|
||||
impl ReaderMethods<T:send,A> for Handle<T,A> {
|
||||
#[doc(str = "Access the reader's view of the handle's data.")]
|
||||
fn read<U>(f: fn(T) -> U) -> U unsafe {
|
||||
f(*self.read_ptr())
|
||||
}
|
||||
|
||||
#[doc(str = "true if auxiliary data is associated with this handle")]
|
||||
#[doc(str = "True if auxiliary data is associated with this handle.")]
|
||||
fn has_aux() -> bool unsafe {
|
||||
self.rd_aux().is_not_null()
|
||||
self.read_aux().is_not_null()
|
||||
}
|
||||
|
||||
#[doc(str = "set the auxiliary data associated with this handle.
|
||||
|
@ -120,26 +113,24 @@ impl reader_methods<T:send,A> for handle<T,A> {
|
|||
let p2 = p;
|
||||
unsafe::forget(p2); // Bump the reference count.
|
||||
|
||||
(**self).rd_aux = ptr::addr_of(*p);
|
||||
(**self).read_aux = ptr::addr_of(*p);
|
||||
}
|
||||
|
||||
#[doc(str = "access the auxiliary data associated with this handle.")]
|
||||
fn aux<U>(f: fn(A) -> U) -> U unsafe {
|
||||
assert self.has_aux();
|
||||
f(*self.rd_aux())
|
||||
f(*self.read_aux())
|
||||
}
|
||||
}
|
||||
|
||||
impl private_methods<T: copy send,A> for scope<T,A> {
|
||||
impl ScopePrivate<T: copy send,A> for Scope<T,A> {
|
||||
fn clone(v: *T) -> *T unsafe {
|
||||
let n: *mut T =
|
||||
unsafe::reinterpret_cast(
|
||||
libc::calloc(sys::size_of::<T>() as size_t, 1u as size_t));
|
||||
unsafe::reinterpret_cast(libc::calloc(sys::size_of::<T>() as size_t, 1u as size_t));
|
||||
|
||||
// n.b.: this assignment will run the drop glue for <T,A>.
|
||||
// *Hopefully* the fact that everything is initialized to NULL
|
||||
// by calloc will make this ok. We may have to make the take
|
||||
// glue be tolerant.
|
||||
// n.b.: this assignment will run the drop glue for <T,A>. *Hopefully* the fact that
|
||||
// everything is initialized to NULL by calloc will make this ok. We may have to make the
|
||||
// take glue be tolerant of this.
|
||||
*n = unsafe{*v};
|
||||
|
||||
ret unsafe::reinterpret_cast(n);
|
||||
|
@ -151,22 +142,24 @@ unsafe fn free<T:send>(t: *T) {
|
|||
libc::free(unsafe::reinterpret_cast(t));
|
||||
}
|
||||
|
||||
unsafe fn free_handle<T:send,A>(h: handle<T,A>) {
|
||||
free(h.rd_ptr());
|
||||
if h.wr_ptr() != h.rd_ptr() { free(h.wr_ptr()); }
|
||||
unsafe fn free_handle<T:send,A>(h: Handle<T,A>) {
|
||||
free(h.read_ptr());
|
||||
if h.write_ptr() != unsafe::reinterpret_cast(h.read_ptr()) {
|
||||
free(unsafe::reinterpret_cast::<*mut T,*T>(h.write_ptr()));
|
||||
}
|
||||
}
|
||||
|
||||
fn null_handle<T:send,A>() -> handle<T,A> {
|
||||
_handle(ptr::null())
|
||||
fn null_handle<T:send,A>() -> Handle<T,A> {
|
||||
_Handle(ptr::null())
|
||||
}
|
||||
|
||||
fn scope<T:send,A>() -> scope<T,A> {
|
||||
@scope_rsrc({mut layout_active: false,
|
||||
fn Scope<T:send,A>() -> Scope<T,A> {
|
||||
@ScopeResource({mut layout_active: false,
|
||||
mut free_list: [],
|
||||
mut first_dirty: null_handle()})
|
||||
}
|
||||
|
||||
impl writer_methods<T:copy send,A> for scope<T,A> {
|
||||
impl WriterMethods<T:copy send,A> for Scope<T,A> {
|
||||
fn is_reader_forked() -> bool {
|
||||
self.layout_active
|
||||
}
|
||||
|
@ -183,9 +176,9 @@ impl writer_methods<T:copy send,A> for scope<T,A> {
|
|||
if self.first_dirty.is_not_null() {
|
||||
let mut handle = self.first_dirty;
|
||||
while (*handle).is_not_null() {
|
||||
free(handle.rd_ptr());
|
||||
free(handle.read_ptr());
|
||||
|
||||
handle.set_rd_ptr(handle.wr_ptr());
|
||||
handle.set_read_ptr(unsafe::reinterpret_cast(handle.write_ptr()));
|
||||
let next_handle = handle.next_dirty();
|
||||
handle.set_next_dirty(null_handle());
|
||||
handle = next_handle;
|
||||
|
@ -197,31 +190,30 @@ impl writer_methods<T:copy send,A> for scope<T,A> {
|
|||
self.layout_active = false;
|
||||
}
|
||||
|
||||
fn rd<U>(h: handle<T,A>, f: fn(T) -> U) -> U unsafe {
|
||||
// Use the wr_ptr, which may be more up to date than the
|
||||
// rd_ptr or may not
|
||||
f(*h.wr_ptr())
|
||||
fn read<U>(h: Handle<T,A>, f: fn(T) -> U) -> U unsafe {
|
||||
// Use the write_ptr, which may be more up to date than the read_ptr or may not
|
||||
f(*h.write_ptr())
|
||||
}
|
||||
|
||||
fn wr<U>(h: handle<T,A>, f: fn(T) -> U) -> U unsafe {
|
||||
if self.layout_active && h.rd_ptr() == h.wr_ptr() {
|
||||
fn write<U>(h: Handle<T,A>, f: fn(T) -> U) -> U unsafe {
|
||||
if self.layout_active && h.read_ptr() == h.write_ptr() {
|
||||
#debug["marking handle %? as dirty", h];
|
||||
h.set_wr_ptr(self.clone(h.rd_ptr()));
|
||||
h.set_write_ptr(unsafe::reinterpret_cast(self.clone(h.read_ptr())));
|
||||
h.set_next_dirty(self.first_dirty);
|
||||
self.first_dirty = h;
|
||||
}
|
||||
f(*h.wr_ptr())
|
||||
f(*h.write_ptr())
|
||||
}
|
||||
|
||||
fn handle(v: T) -> handle<T,A> unsafe {
|
||||
let d: *handle_data<T,A> =
|
||||
fn handle(v: T) -> Handle<T,A> unsafe {
|
||||
let d: *HandleData<T,A> =
|
||||
unsafe::reinterpret_cast(
|
||||
libc::malloc(sys::size_of::<handle_data<T,A>>() as size_t));
|
||||
(*d).rd_ptr = self.clone(ptr::addr_of(v));
|
||||
(*d).wr_ptr = (*d).rd_ptr;
|
||||
(*d).rd_aux = ptr::null();
|
||||
libc::malloc(sys::size_of::<HandleData<T,A>>() as size_t));
|
||||
(*d).read_ptr = self.clone(ptr::addr_of(v));
|
||||
(*d).write_ptr = unsafe::reinterpret_cast((*d).read_ptr);
|
||||
(*d).read_aux = ptr::null();
|
||||
(*d).next_dirty = null_handle();
|
||||
let h = _handle(d);
|
||||
let h = _Handle(d);
|
||||
self.free_list += [h];
|
||||
ret h;
|
||||
}
|
||||
|
@ -240,11 +232,11 @@ mod test {
|
|||
|
||||
type processed = {flag: bool};
|
||||
|
||||
type animal_scope = scope<animal, processed>;
|
||||
type animal_scope = Scope<animal, processed>;
|
||||
|
||||
#[test]
|
||||
fn handles_get_freed() {
|
||||
let s: animal_scope = scope();
|
||||
let s: animal_scope = Scope();
|
||||
s.handle({name:"henrietta", species:chicken(~{mut eggs_per_day:22u})});
|
||||
s.handle({name:"ferdinand", species:bull(~{mut horns:3u})});
|
||||
}
|
||||
|
@ -265,7 +257,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn interspersed_execution() {
|
||||
let s: animal_scope = scope();
|
||||
let s: animal_scope = Scope();
|
||||
let henrietta =
|
||||
s.handle({name:"henrietta",
|
||||
species:chicken(~{mut eggs_per_day:0u})});
|
||||
|
@ -283,30 +275,30 @@ mod test {
|
|||
s.reader_forked();
|
||||
let wait_chan = task::spawn_listener {|wait_port|
|
||||
for uint::range(0u, iter2) { |_i|
|
||||
comm::send(read_chan, henrietta.rd(read_characteristic));
|
||||
comm::send(read_chan, ferdinand.rd(read_characteristic));
|
||||
comm::send(read_chan, henrietta.read(read_characteristic));
|
||||
comm::send(read_chan, ferdinand.read(read_characteristic));
|
||||
comm::recv(wait_port);
|
||||
}
|
||||
};
|
||||
|
||||
let hrc = henrietta.rd(read_characteristic);
|
||||
let hrc = henrietta.read(read_characteristic);
|
||||
assert hrc == (i * iter2);
|
||||
|
||||
let frc = ferdinand.rd(read_characteristic);
|
||||
let frc = ferdinand.read(read_characteristic);
|
||||
assert frc == i * iter2;
|
||||
|
||||
for uint::range(0u, iter2) { |_i|
|
||||
assert hrc == comm::recv(read_port);
|
||||
s.wr(henrietta, mutate);
|
||||
s.write(henrietta, mutate);
|
||||
assert frc == comm::recv(read_port);
|
||||
s.wr(ferdinand, mutate);
|
||||
s.write(ferdinand, mutate);
|
||||
comm::send(wait_chan, ());
|
||||
}
|
||||
s.reader_joined();
|
||||
}
|
||||
|
||||
assert henrietta.rd(read_characteristic) == iter1 * iter2;
|
||||
assert ferdinand.rd(read_characteristic) == iter1 * iter2;
|
||||
assert henrietta.read(read_characteristic) == iter1 * iter2;
|
||||
assert ferdinand.read(read_characteristic) == iter1 * iter2;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import dom::base::{Element, ElementKind, HTMLDivElement, HTMLImageElement, Node, NodeData};
|
||||
import dom::base::{NodeKind};
|
||||
import dom::rcu;
|
||||
import dom::rcu::reader_methods;
|
||||
import dom::rcu::ReaderMethods;
|
||||
import gfx::geometry;
|
||||
import gfx::geometry::{au, zero_size_au};
|
||||
import geom::point::Point2D;
|
||||
|
@ -62,7 +62,7 @@ impl of tree::rd_tree_ops<Node> for ntree {
|
|||
}
|
||||
|
||||
fn with_tree_fields<R>(&&n: Node, f: fn(tree::fields<Node>) -> R) -> R {
|
||||
n.rd { |n| f(n.tree) }
|
||||
n.read { |n| f(n.tree) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,7 +138,7 @@ impl PrivateNodeMethods for Node {
|
|||
s += " ";
|
||||
}
|
||||
|
||||
s += #fmt("%?", self.rd({ |n| copy n.kind }));
|
||||
s += #fmt("%?", self.read({ |n| copy n.kind }));
|
||||
#debug["%s", s];
|
||||
|
||||
for ntree.each_child(self) { |kid| kid.dump_indent(indent + 1u) }
|
||||
|
@ -156,7 +156,7 @@ impl NodeMethods for Node {
|
|||
mod test {
|
||||
import dom::base::{Element, ElementData, HTMLDivElement, HTMLImageElement, Node, NodeKind};
|
||||
import dom::base::{NodeScope, wr_tree_ops};
|
||||
import dom::rcu::scope;
|
||||
import dom::rcu::Scope;
|
||||
import box_builder::{box_builder_methods};
|
||||
|
||||
/*
|
||||
|
@ -186,7 +186,7 @@ mod test {
|
|||
#[test]
|
||||
#[ignore(reason = "busted")]
|
||||
fn do_layout() {
|
||||
let s = scope();
|
||||
let s = Scope();
|
||||
|
||||
fn mk_img(size: Size2D<au>) -> ~ElementKind {
|
||||
~HTMLImageElement({mut size: size})
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import dom::base::{ElementData, HTMLDivElement, HTMLImageElement, Element, Text, Node};
|
||||
import dom::style::{display_type, di_block, di_inline, di_none};
|
||||
import dom::rcu::reader_methods;
|
||||
import dom::rcu::ReaderMethods;
|
||||
import gfx::geometry;
|
||||
import layout::base::{BlockBox, Box, BoxKind, InlineBox, IntrinsicBox, NodeMethods, TextBox};
|
||||
import layout::base::{appearance, btree, ntree, rd_tree_ops, wr_tree_ops};
|
||||
|
@ -153,7 +153,7 @@ impl box_builder_priv for Node {
|
|||
size.
|
||||
"]
|
||||
fn determine_box_kind() -> BoxKind {
|
||||
alt self.rd({ |n| copy n.kind }) {
|
||||
alt self.read({ |n| copy n.kind }) {
|
||||
~Text(string) {
|
||||
TextBox(@text_box(string))
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#[doc="Inline layout."]
|
||||
|
||||
import dom::rcu;
|
||||
import dom::rcu::reader_methods;
|
||||
import dom::rcu::ReaderMethods;
|
||||
import geom::point::Point2D;
|
||||
import geom::size::Size2D;
|
||||
import gfx::geometry::au;
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
#[doc = "
|
||||
|
||||
The layout task. Performs layout on the dom, builds display lists and sends
|
||||
them to be rendered
|
||||
|
||||
The layout task. Performs layout on the DOM, builds display lists and sends them to be
|
||||
rendered.
|
||||
"];
|
||||
|
||||
import box_builder::box_builder_methods;
|
||||
import dl = display_list;
|
||||
import dom::base::Node;
|
||||
import dom::rcu::scope;
|
||||
import dom::rcu::Scope;
|
||||
import dom::style::stylesheet;
|
||||
import gfx::geometry::{au, au_to_px, box, px_to_au};
|
||||
import gfx::renderer;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#[doc="Applies style to boxes."]
|
||||
import dom::base::{HTMLImageElement, Element, Node};
|
||||
import dom::rcu::reader_methods;
|
||||
#[doc="Applies the appropriate CSS style to boxes."]
|
||||
|
||||
import dom::base::{Element, HTMLImageElement, Node};
|
||||
import dom::rcu::ReaderMethods;
|
||||
import image::base::load;
|
||||
import layout::base::*;
|
||||
import style::style_methods;
|
||||
|
@ -17,7 +18,7 @@ impl ApplyStyleBoxMethods for @Box {
|
|||
#[doc="Applies CSS style."]
|
||||
fn apply_style() {
|
||||
// Right now, we only handle images.
|
||||
self.node.rd {
|
||||
self.node.read {
|
||||
|node|
|
||||
alt node.kind {
|
||||
~Element(element) {
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
#[doc="Perform css selector matching"]
|
||||
#[doc="Performs CSS selector matching."]
|
||||
|
||||
import base::{layout_data};
|
||||
import dom::base::{Element, ElementData, Node, Text};
|
||||
import dom::style::{selector, style_decl, font_size, display, text_color, background_color,
|
||||
stylesheet, element, child, descendant, sibling, attr, exact, exists, includes,
|
||||
starts_with};
|
||||
import dom::rcu::{reader_methods};
|
||||
import dom::rcu::ReaderMethods;
|
||||
import style::{computed_style, default_style_for_node_kind};
|
||||
import base::{layout_data};
|
||||
|
||||
export matching_methods;
|
||||
|
||||
|
@ -72,7 +72,7 @@ impl priv_matching_methods for Node {
|
|||
alt *sel {
|
||||
child(_, _) | descendant(_, _) | sibling(_, _) { ret false; }
|
||||
element(tag, attrs) {
|
||||
alt self.rd { |n| copy *n.kind } {
|
||||
alt self.read { |n| copy *n.kind } {
|
||||
Element(elmt) {
|
||||
if !(tag == "*" || tag == elmt.tag_name) {
|
||||
ret false;
|
||||
|
@ -100,7 +100,7 @@ impl priv_matching_methods for Node {
|
|||
alt *sel {
|
||||
element(str, atts) { ret self.matches_element(sel); }
|
||||
child(sel1, sel2) {
|
||||
alt self.rd { |n| n.tree.parent } {
|
||||
alt self.read { |n| n.tree.parent } {
|
||||
some(parent) {
|
||||
ret self.matches_element(sel2) &&
|
||||
parent.matches_selector(sel1);
|
||||
|
@ -115,7 +115,7 @@ impl priv_matching_methods for Node {
|
|||
|
||||
//loop over all ancestors to check if they are the person
|
||||
//we should be descended from.
|
||||
let mut cur_parent = alt self.rd { |n| n.tree.parent } {
|
||||
let mut cur_parent = alt self.read { |n| n.tree.parent } {
|
||||
some(parent) { parent }
|
||||
none { ret false; }
|
||||
};
|
||||
|
@ -123,7 +123,7 @@ impl priv_matching_methods for Node {
|
|||
loop {
|
||||
if cur_parent.matches_selector(sel1) { ret true; }
|
||||
|
||||
cur_parent = alt cur_parent.rd { |n| n.tree.parent } {
|
||||
cur_parent = alt cur_parent.read { |n| n.tree.parent } {
|
||||
some(parent) { parent }
|
||||
none { ret false; }
|
||||
};
|
||||
|
@ -133,13 +133,13 @@ impl priv_matching_methods for Node {
|
|||
if !self.matches_element(sel2) { ret false; }
|
||||
|
||||
// Loop over this node's previous siblings to see if they match.
|
||||
alt self.rd { |n| n.tree.prev_sibling } {
|
||||
alt self.read { |n| n.tree.prev_sibling } {
|
||||
some(sib) {
|
||||
let mut cur_sib = sib;
|
||||
loop {
|
||||
if cur_sib.matches_selector(sel1) { ret true; }
|
||||
|
||||
cur_sib = alt cur_sib.rd { |n| n.tree.prev_sibling } {
|
||||
cur_sib = alt cur_sib.read { |n| n.tree.prev_sibling } {
|
||||
some(sib) { sib }
|
||||
none { break; }
|
||||
};
|
||||
|
@ -149,13 +149,13 @@ impl priv_matching_methods for Node {
|
|||
}
|
||||
|
||||
// check the rest of the siblings
|
||||
alt self.rd { |n| n.tree.next_sibling } {
|
||||
alt self.read { |n| n.tree.next_sibling } {
|
||||
some(sib) {
|
||||
let mut cur_sib = sib;
|
||||
loop {
|
||||
if cur_sib.matches_selector(sel1) { ret true; }
|
||||
|
||||
cur_sib = alt cur_sib.rd { |n| n.tree.next_sibling } {
|
||||
cur_sib = alt cur_sib.read { |n| n.tree.next_sibling } {
|
||||
some(sib) { sib }
|
||||
none { break; }
|
||||
};
|
||||
|
@ -174,7 +174,7 @@ impl matching_methods for Node {
|
|||
#[doc="Compare an html element to a list of css rules and update its
|
||||
style according to the rules matching it."]
|
||||
fn match_css_style(styles : stylesheet) -> computed_style {
|
||||
let node_kind = self.rd { |n| copy *n.kind };
|
||||
let node_kind = self.read { |n| copy *n.kind };
|
||||
let style =
|
||||
@default_style_for_node_kind(node_kind);
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import dom::style::{display_type, di_block, di_inline, di_none, stylesheet};
|
||||
import dom::base::{Element, HTMLDivElement, HTMLHeadElement, HTMLImageElement, Node, NodeKind};
|
||||
import dom::base::{Text};
|
||||
import dom::rcu::reader_methods;
|
||||
import dom::rcu::ReaderMethods;
|
||||
import layout::base::*; // FIXME: resolve bug requires *
|
||||
import matching::matching_methods;
|
||||
import util::color::{Color, rgb};
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
#[doc="Constructs a DOM tree from an incoming token stream."]
|
||||
|
||||
import dom::rcu::writer_methods;
|
||||
import dom::base::{Attr, Element, ElementData, ElementKind, HTMLDivElement, HTMLHeadElement};
|
||||
import dom::base::{HTMLImageElement, Node, NodeScope, Text, UnknownElement, rd_tree_ops};
|
||||
import dom::base::{wr_tree_ops};
|
||||
import dom = dom::base;
|
||||
import dvec::extensions;
|
||||
import dom::rcu::WriterMethods;
|
||||
import geom::size::Size2D;
|
||||
import gfx::geometry;
|
||||
import gfx::geometry::au;
|
||||
import parser = parser::lexer::html;
|
||||
import parser::token;
|
||||
|
||||
import dvec::extensions;
|
||||
|
||||
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.rd(node) {
|
||||
scope.read(node) {
|
||||
|node_contents|
|
||||
alt *node_contents.kind {
|
||||
Element(element) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue