Upgrade to latest Rust.

This commit is contained in:
Jack Moffitt 2013-12-20 22:04:46 -07:00
parent 728fb9a7de
commit a7ef1cd35e
127 changed files with 1892 additions and 2501 deletions

4
.gitmodules vendored
View file

@ -66,7 +66,7 @@
url = https://github.com/mozilla-servo/skia.git url = https://github.com/mozilla-servo/skia.git
[submodule "src/compiler/rust"] [submodule "src/compiler/rust"]
path = src/compiler/rust path = src/compiler/rust
url = https://github.com/mozilla/rust.git url = https://github.com/mozilla-servo/rust.git
[submodule "src/support/alert/rust-alert"] [submodule "src/support/alert/rust-alert"]
path = src/support/alert/rust-alert path = src/support/alert/rust-alert
url = https://github.com/mozilla-servo/rust-alert.git url = https://github.com/mozilla-servo/rust-alert.git
@ -112,7 +112,7 @@
branch = rust-servo branch = rust-servo
[submodule "src/support/egl/rust-egl"] [submodule "src/support/egl/rust-egl"]
path = src/support/egl/rust-egl path = src/support/egl/rust-egl
url = https://github.com/webconvforge/rust-egl.git url = https://github.com/mozilla-servo/rust-egl.git
[submodule "src/platform/android/servo-android-glue"] [submodule "src/platform/android/servo-android-glue"]
path = src/platform/android/servo-android-glue path = src/platform/android/servo-android-glue
url = https://github.com/webconvforge/servo-android-glue.git url = https://github.com/webconvforge/servo-android-glue.git

2
configure vendored
View file

@ -615,7 +615,7 @@ then
cd ${CFG_BUILD_DIR}src/compiler/rust cd ${CFG_BUILD_DIR}src/compiler/rust
RUST_CONFIGURE_ARGS="--enable-debug" RUST_CONFIGURE_ARGS="--enable-debug"
if [ $CFG_OSTYPE = "linux-androideabi" ]; then if [ $CFG_OSTYPE = "linux-androideabi" ]; then
RUST_CONFIGURE_ARGS="--target-triples=arm-linux-androideabi --android-cross-path=${CFG_ANDROID_CROSS_PATH}" RUST_CONFIGURE_ARGS="--target=arm-linux-androideabi --android-cross-path=${CFG_ANDROID_CROSS_PATH}"
fi fi
${CFG_SRC_DIR}src/compiler/rust/configure ${RUST_CONFIGURE_ARGS} ${CFG_SRC_DIR}src/compiler/rust/configure ${RUST_CONFIGURE_ARGS}
cd ${CFG_BUILD_DIR} cd ${CFG_BUILD_DIR}

@ -1 +1 @@
Subproject commit f6b236b9d2780edc1336ea5f62c2ba0fed6e34c5 Subproject commit d3b3c66a3a54a0455b068ede8fe2f48ed99ca908

View file

@ -1,4 +1,4 @@
# If this file is modified, then rust will be forcibly cleaned and then rebuilt. # If this file is modified, then rust will be forcibly cleaned and then rebuilt.
# The actual contents of this file do not matter, but to trigger a change on the # The actual contents of this file do not matter, but to trigger a change on the
# build bots then the contents should be changed so git updates the mtime. # build bots then the contents should be changed so git updates the mtime.
2014-01-02 2014-01-08

View file

@ -150,14 +150,14 @@ pub struct ClipDisplayItem<E> {
need_clip: bool need_clip: bool
} }
pub enum DisplayItemIterator<'self,E> { pub enum DisplayItemIterator<'a,E> {
EmptyDisplayItemIterator, EmptyDisplayItemIterator,
ParentDisplayItemIterator(VecIterator<'self,DisplayItem<E>>), ParentDisplayItemIterator(VecIterator<'a,DisplayItem<E>>),
} }
impl<'self,E> Iterator<&'self DisplayItem<E>> for DisplayItemIterator<'self,E> { impl<'a,E> Iterator<&'a DisplayItem<E>> for DisplayItemIterator<'a,E> {
#[inline] #[inline]
fn next(&mut self) -> Option<&'self DisplayItem<E>> { fn next(&mut self) -> Option<&'a DisplayItem<E>> {
match *self { match *self {
EmptyDisplayItemIterator => None, EmptyDisplayItemIterator => None,
ParentDisplayItemIterator(ref mut subiterator) => subiterator.next(), ParentDisplayItemIterator(ref mut subiterator) => subiterator.next(),
@ -192,12 +192,12 @@ impl<E> DisplayItem<E> {
let text_run = text.text_run.get(); let text_run = text.text_run.get();
let font = render_context.font_ctx.get_font_by_descriptor(&text_run.font_descriptor).unwrap(); let font = render_context.font_ctx.get_font_by_descriptor(&text_run.font_descriptor).unwrap();
let font_metrics = font.with_borrow( |font| { let font_metrics = font.borrow().with(|font| {
font.metrics.clone() font.metrics.clone()
}); });
let origin = text.base.bounds.origin; let origin = text.base.bounds.origin;
let baseline_origin = Point2D(origin.x, origin.y + font_metrics.ascent); let baseline_origin = Point2D(origin.x, origin.y + font_metrics.ascent);
font.with_mut_borrow( |font| { font.borrow().with_mut(|font| {
font.draw_text_into_context(render_context, font.draw_text_into_context(render_context,
text.text_run.get(), text.text_run.get(),
&text.range, &text.range,
@ -264,10 +264,10 @@ impl<E> DisplayItem<E> {
pub fn children<'a>(&'a self) -> DisplayItemIterator<'a,E> { pub fn children<'a>(&'a self) -> DisplayItemIterator<'a,E> {
match *self { match *self {
ClipDisplayItemClass(ref clip) => ParentDisplayItemIterator(clip.child_list.iter()), ClipDisplayItemClass(ref clip) => ParentDisplayItemIterator(clip.child_list.iter()),
SolidColorDisplayItemClass(*) | SolidColorDisplayItemClass(..) |
TextDisplayItemClass(*) | TextDisplayItemClass(..) |
ImageDisplayItemClass(*) | ImageDisplayItemClass(..) |
BorderDisplayItemClass(*) => EmptyDisplayItemIterator, BorderDisplayItemClass(..) => EmptyDisplayItemIterator,
} }
} }

View file

@ -10,13 +10,11 @@ use geom::{Point2D, Rect, Size2D};
use std::cast; use std::cast;
use std::ptr; use std::ptr;
use std::str; use std::str;
use std::vec; use std::rc::Rc;
use std::rc::RcMut; use std::cell::RefCell;
use servo_util::cache::{Cache, HashCache}; use servo_util::cache::{Cache, HashCache};
use servo_util::range::Range; use servo_util::range::Range;
use servo_util::time::ProfilerChan;
use style::computed_values::{text_decoration, font_weight, font_style}; use style::computed_values::{text_decoration, font_weight, font_style};
use color::Color; use color::Color;
use font_context::FontContext; use font_context::FontContext;
use servo_util::geometry::Au; use servo_util::geometry::Au;
@ -73,7 +71,7 @@ impl FontTableTagConversions for FontTableTag {
} }
pub trait FontTableMethods { pub trait FontTableMethods {
fn with_buffer(&self, &fn(*u8, uint)); fn with_buffer(&self, |*u8, uint|);
} }
#[deriving(Clone)] #[deriving(Clone)]
@ -108,12 +106,6 @@ pub struct FontStyle {
pub type SpecifiedFontStyle = FontStyle; pub type SpecifiedFontStyle = FontStyle;
pub type UsedFontStyle = FontStyle; pub type UsedFontStyle = FontStyle;
// FIXME: move me to layout
struct ResolvedFont {
group: @FontGroup,
style: SpecifiedFontStyle,
}
// FontDescriptor serializes a specific font and used font style // FontDescriptor serializes a specific font and used font style
// options, such as point size. // options, such as point size.
@ -153,11 +145,11 @@ pub struct FontGroup {
// style of the first western font in group, which is // style of the first western font in group, which is
// used for purposes of calculating text run metrics. // used for purposes of calculating text run metrics.
style: UsedFontStyle, style: UsedFontStyle,
fonts: ~[RcMut<Font>] fonts: ~[Rc<RefCell<Font>>]
} }
impl FontGroup { impl FontGroup {
pub fn new(families: ~[~str], style: &UsedFontStyle, fonts: ~[RcMut<Font>]) -> FontGroup { pub fn new(families: ~[~str], style: &UsedFontStyle, fonts: ~[Rc<RefCell<Font>>]) -> FontGroup {
FontGroup { FontGroup {
families: families, families: families,
style: (*style).clone(), style: (*style).clone(),
@ -173,7 +165,7 @@ impl FontGroup {
assert!(self.fonts.len() > 0); assert!(self.fonts.len() > 0);
// TODO(Issue #177): Actually fall back through the FontGroup when a font is unsuitable. // TODO(Issue #177): Actually fall back through the FontGroup when a font is unsuitable.
self.fonts[0].with_mut_borrow(|font| { self.fonts[0].borrow().with_mut(|font| {
TextRun::new(font, text.clone(), decoration) TextRun::new(font, text.clone(), decoration)
}) })
} }
@ -218,18 +210,16 @@ pub struct Font {
style: UsedFontStyle, style: UsedFontStyle,
metrics: FontMetrics, metrics: FontMetrics,
backend: BackendType, backend: BackendType,
profiler_chan: ProfilerChan,
shape_cache: HashCache<~str, Arc<GlyphStore>>, shape_cache: HashCache<~str, Arc<GlyphStore>>,
glyph_advance_cache: HashCache<u32, FractionalPixel>, glyph_advance_cache: HashCache<u32, FractionalPixel>,
} }
impl<'self> Font { impl<'a> Font {
pub fn new_from_buffer(ctx: &FontContext, pub fn new_from_buffer(ctx: &FontContext,
buffer: ~[u8], buffer: ~[u8],
style: &SpecifiedFontStyle, style: &SpecifiedFontStyle,
backend: BackendType, backend: BackendType)
profiler_chan: ProfilerChan) -> Result<Rc<RefCell<Font>>, ()> {
-> Result<RcMut<Font>, ()> {
let handle = FontHandleMethods::new_from_buffer(&ctx.handle, buffer, style); let handle = FontHandleMethods::new_from_buffer(&ctx.handle, buffer, style);
let handle: FontHandle = if handle.is_ok() { let handle: FontHandle = if handle.is_ok() {
handle.unwrap() handle.unwrap()
@ -240,22 +230,21 @@ impl<'self> Font {
let metrics = handle.get_metrics(); let metrics = handle.get_metrics();
// TODO(Issue #179): convert between specified and used font style here? // TODO(Issue #179): convert between specified and used font style here?
return Ok(RcMut::new(Font { return Ok(Rc::from_mut(RefCell::new(Font {
handle: handle, handle: handle,
azure_font: None, azure_font: None,
shaper: None, shaper: None,
style: (*style).clone(), style: (*style).clone(),
metrics: metrics, metrics: metrics,
backend: backend, backend: backend,
profiler_chan: profiler_chan,
shape_cache: HashCache::new(), shape_cache: HashCache::new(),
glyph_advance_cache: HashCache::new(), glyph_advance_cache: HashCache::new(),
})); })));
} }
pub fn new_from_adopted_handle(_fctx: &FontContext, handle: FontHandle, pub fn new_from_adopted_handle(_fctx: &FontContext, handle: FontHandle,
style: &SpecifiedFontStyle, backend: BackendType, style: &SpecifiedFontStyle, backend: BackendType)
profiler_chan: ProfilerChan) -> Font { -> Font {
let metrics = handle.get_metrics(); let metrics = handle.get_metrics();
Font { Font {
@ -265,15 +254,14 @@ impl<'self> Font {
style: (*style).clone(), style: (*style).clone(),
metrics: metrics, metrics: metrics,
backend: backend, backend: backend,
profiler_chan: profiler_chan,
shape_cache: HashCache::new(), shape_cache: HashCache::new(),
glyph_advance_cache: HashCache::new(), glyph_advance_cache: HashCache::new(),
} }
} }
pub fn new_from_existing_handle(fctx: &FontContext, handle: &FontHandle, pub fn new_from_existing_handle(fctx: &FontContext, handle: &FontHandle,
style: &SpecifiedFontStyle, backend: BackendType, style: &SpecifiedFontStyle, backend: BackendType)
profiler_chan: ProfilerChan) -> Result<RcMut<Font>,()> { -> Result<Rc<RefCell<Font>>,()> {
// TODO(Issue #179): convert between specified and used font style here? // TODO(Issue #179): convert between specified and used font style here?
let styled_handle = match handle.clone_with_style(&fctx.handle, style) { let styled_handle = match handle.clone_with_style(&fctx.handle, style) {
@ -281,15 +269,15 @@ impl<'self> Font {
Err(()) => return Err(()) Err(()) => return Err(())
}; };
return Ok(RcMut::new(Font::new_from_adopted_handle(fctx, styled_handle, style, backend, profiler_chan))); return Ok(Rc::from_mut(RefCell::new(Font::new_from_adopted_handle(fctx, styled_handle, style, backend))));
} }
fn make_shaper(&'self mut self) -> &'self Shaper { fn make_shaper(&'a mut self) -> &'a Shaper {
// fast path: already created a shaper // fast path: already created a shaper
match self.shaper { match self.shaper {
Some(ref shaper) => { Some(ref shaper) => {
let s: &'self Shaper = shaper; let s: &'a Shaper = shaper;
return s; return s;
}, },
None => {} None => {}
} }
@ -349,7 +337,6 @@ impl<'self> Font {
impl Font { impl Font {
#[fixed_stack_segment]
pub fn draw_text_into_context(&mut self, pub fn draw_text_into_context(&mut self,
rctx: &RenderContext, rctx: &RenderContext,
run: &~TextRun, run: &~TextRun,
@ -399,8 +386,8 @@ impl Font {
if azglyph_buf_len == 0 { return; } // Otherwise the Quartz backend will assert. if azglyph_buf_len == 0 { return; } // Otherwise the Quartz backend will assert.
let glyphbuf = struct__AzGlyphBuffer { let glyphbuf = struct__AzGlyphBuffer {
mGlyphs: vec::raw::to_ptr(azglyphs), mGlyphs: azglyphs.as_ptr(),
mNumGlyphs: azglyph_buf_len as uint32_t mNumGlyphs: azglyph_buf_len as uint32_t
}; };
unsafe { unsafe {
@ -441,11 +428,11 @@ impl Font {
//FIXME (ksh8281) //FIXME (ksh8281)
self.make_shaper(); self.make_shaper();
do self.shape_cache.find_or_create(&text) |txt| { self.shape_cache.find_or_create(&text, |txt| {
let mut glyphs = GlyphStore::new(text.char_len(), is_whitespace); let mut glyphs = GlyphStore::new(text.char_len(), is_whitespace);
self.shaper.get_ref().shape_text(*txt, &mut glyphs); self.shaper.get_ref().shape_text(*txt, &mut glyphs);
Arc::new(glyphs) Arc::new(glyphs)
} })
} }
pub fn get_descriptor(&self) -> FontDescriptor { pub fn get_descriptor(&self) -> FontDescriptor {
@ -457,12 +444,12 @@ impl Font {
} }
pub fn glyph_h_advance(&mut self, glyph: GlyphIndex) -> FractionalPixel { pub fn glyph_h_advance(&mut self, glyph: GlyphIndex) -> FractionalPixel {
do self.glyph_advance_cache.find_or_create(&glyph) |glyph| { self.glyph_advance_cache.find_or_create(&glyph, |glyph| {
match self.handle.glyph_h_advance(*glyph) { match self.handle.glyph_h_advance(*glyph) {
Some(adv) => adv, Some(adv) => adv,
None => /* FIXME: Need fallback strategy */ 10f64 as FractionalPixel None => /* FIXME: Need fallback strategy */ 10f64 as FractionalPixel
} }
} })
} }
} }

View file

@ -15,7 +15,8 @@ use platform::font_context::FontContextHandle;
use azure::azure_hl::BackendType; use azure::azure_hl::BackendType;
use std::hashmap::HashMap; use std::hashmap::HashMap;
use std::rc::RcMut; use std::rc::Rc;
use std::cell::RefCell;
pub trait FontContextHandleMethods { pub trait FontContextHandleMethods {
@ -23,16 +24,16 @@ pub trait FontContextHandleMethods {
} }
pub struct FontContext { pub struct FontContext {
instance_cache: LRUCache<FontDescriptor, RcMut<Font>>, instance_cache: LRUCache<FontDescriptor, Rc<RefCell<Font>>>,
font_list: Option<FontList>, // only needed by layout font_list: Option<FontList>, // only needed by layout
group_cache: LRUCache<SpecifiedFontStyle, RcMut<FontGroup>>, group_cache: LRUCache<SpecifiedFontStyle, Rc<RefCell<FontGroup>>>,
handle: FontContextHandle, handle: FontContextHandle,
backend: BackendType, backend: BackendType,
generic_fonts: HashMap<~str,~str>, generic_fonts: HashMap<~str,~str>,
profiler_chan: ProfilerChan, profiler_chan: ProfilerChan,
} }
impl<'self> FontContext { impl FontContext {
pub fn new(backend: BackendType, pub fn new(backend: BackendType,
needs_font_list: bool, needs_font_list: bool,
profiler_chan: ProfilerChan) profiler_chan: ProfilerChan)
@ -61,11 +62,8 @@ impl<'self> FontContext {
} }
} }
fn get_font_list(&'self self) -> &'self FontList { pub fn get_resolved_font_for_style(&mut self, style: &SpecifiedFontStyle)
self.font_list.get_ref() -> Rc<RefCell<FontGroup>> {
}
pub fn get_resolved_font_for_style(&mut self, style: &SpecifiedFontStyle) -> RcMut<FontGroup> {
match self.group_cache.find(style) { match self.group_cache.find(style) {
Some(fg) => { Some(fg) => {
debug!("font group cache hit"); debug!("font group cache hit");
@ -80,7 +78,8 @@ impl<'self> FontContext {
} }
} }
pub fn get_font_by_descriptor(&mut self, desc: &FontDescriptor) -> Result<RcMut<Font>, ()> { pub fn get_font_by_descriptor(&mut self, desc: &FontDescriptor)
-> Result<Rc<RefCell<Font>>, ()> {
match self.instance_cache.find(desc) { match self.instance_cache.find(desc) {
Some(f) => { Some(f) => {
debug!("font cache hit"); debug!("font cache hit");
@ -107,7 +106,7 @@ impl<'self> FontContext {
} }
} }
fn create_font_group(&mut self, style: &SpecifiedFontStyle) -> RcMut<FontGroup> { fn create_font_group(&mut self, style: &SpecifiedFontStyle) -> Rc<RefCell<FontGroup>> {
let mut fonts = ~[]; let mut fonts = ~[];
debug!("(create font group) --- starting ---"); debug!("(create font group) --- starting ---");
@ -140,8 +139,7 @@ impl<'self> FontContext {
Some(ref result) => { Some(ref result) => {
found = true; found = true;
let instance = self.get_font_by_descriptor(result); let instance = self.get_font_by_descriptor(result);
instance.map(|font| fonts.push(font.clone()));
for font in instance.iter() { fonts.push(font.clone()); }
}, },
_ => {} _ => {}
} }
@ -179,10 +177,7 @@ impl<'self> FontContext {
match font_desc { match font_desc {
Some(ref fd) => { Some(ref fd) => {
let instance = self.get_font_by_descriptor(fd); let instance = self.get_font_by_descriptor(fd);
instance.map(|font| fonts.push(font.clone()));
for font in instance.iter() {
fonts.push(font.clone());
}
}, },
None => { } None => { }
}; };
@ -194,22 +189,28 @@ impl<'self> FontContext {
debug!("(create font group) --- finished ---"); debug!("(create font group) --- finished ---");
unsafe { RcMut::new_unchecked(FontGroup::new(style.families.clone(), &used_style, fonts)) } unsafe {
Rc::new_unchecked(
RefCell::new(
FontGroup::new(style.families.to_owned(), &used_style, fonts)))
}
} }
fn create_font_instance(&self, desc: &FontDescriptor) -> Result<RcMut<Font>, ()> { fn create_font_instance(&self, desc: &FontDescriptor) -> Result<Rc<RefCell<Font>>, ()> {
return match &desc.selector { return match &desc.selector {
// TODO(Issue #174): implement by-platform-name font selectors. // TODO(Issue #174): implement by-platform-name font selectors.
&SelectorPlatformIdentifier(ref identifier) => { &SelectorPlatformIdentifier(ref identifier) => {
let result_handle = self.handle.create_font_from_identifier((*identifier).clone(), let result_handle = self.handle.create_font_from_identifier((*identifier).clone(),
desc.style.clone()); desc.style.clone());
do result_handle.and_then |handle| { result_handle.and_then(|handle| {
Ok(RcMut::new(Font::new_from_adopted_handle(self, Ok(
handle, Rc::from_mut(
&desc.style, RefCell::new(
self.backend, Font::new_from_adopted_handle(self,
self.profiler_chan.clone()))) handle,
} &desc.style,
self.backend))))
})
} }
}; };
} }

View file

@ -29,7 +29,7 @@ pub struct FontList {
prof_chan: ProfilerChan, prof_chan: ProfilerChan,
} }
impl<'self> FontList { impl FontList {
pub fn new(fctx: &FontContextHandle, pub fn new(fctx: &FontContextHandle,
prof_chan: ProfilerChan) prof_chan: ProfilerChan)
-> FontList { -> FontList {
@ -48,20 +48,20 @@ impl<'self> FontList {
// changed. Does OSX have a notification for this event? // changed. Does OSX have a notification for this event?
// //
// Should font families with entries be invalidated/refreshed too? // Should font families with entries be invalidated/refreshed too?
do profile(time::GfxRegenAvailableFontsCategory, self.prof_chan.clone()) { profile(time::GfxRegenAvailableFontsCategory, self.prof_chan.clone(), || {
self.family_map = self.handle.get_available_families(); self.family_map = self.handle.get_available_families();
} });
} }
pub fn find_font_in_family(&'self mut self, pub fn find_font_in_family<'a>(&'a mut self,
family_name: &~str, family_name: &~str,
style: &SpecifiedFontStyle) -> Option<&'self FontEntry> { style: &SpecifiedFontStyle) -> Option<&'a FontEntry> {
// TODO(Issue #188): look up localized font family names if canonical name not found // TODO(Issue #188): look up localized font family names if canonical name not found
// look up canonical name // look up canonical name
if self.family_map.contains_key(family_name) { if self.family_map.contains_key(family_name) {
//FIXME call twice!(ksh8281) //FIXME call twice!(ksh8281)
debug!("FontList: Found font family with name={:s}", family_name.to_str()); debug!("FontList: Found font family with name={:s}", family_name.to_str());
let s: &'self mut FontFamily = self.family_map.get_mut(family_name); let s: &'a mut FontFamily = self.family_map.get_mut(family_name);
// TODO(Issue #192: handle generic font families, like 'serif' and 'sans-serif'. // TODO(Issue #192: handle generic font families, like 'serif' and 'sans-serif'.
// if such family exists, try to match style to a font // if such family exists, try to match style to a font
let result = s.find_font_for_style(&mut self.handle, style); let result = s.find_font_for_style(&mut self.handle, style);
@ -82,13 +82,13 @@ impl<'self> FontList {
} }
} }
// Holds a specific font family, and the various // Holds a specific font family, and the various
pub struct FontFamily<'self> { pub struct FontFamily {
family_name: ~str, family_name: ~str,
entries: ~[FontEntry], entries: ~[FontEntry],
} }
impl<'self> FontFamily { impl FontFamily {
pub fn new(family_name: &str) -> FontFamily { pub fn new(family_name: &str) -> FontFamily {
FontFamily { FontFamily {
family_name: family_name.to_str(), family_name: family_name.to_str(),
@ -104,8 +104,8 @@ impl<'self> FontFamily {
assert!(self.entries.len() > 0) assert!(self.entries.len() > 0)
} }
pub fn find_font_for_style(&'self mut self, list: &FontListHandle, style: &SpecifiedFontStyle) pub fn find_font_for_style<'a>(&'a mut self, list: &FontListHandle, style: &SpecifiedFontStyle)
-> Option<&'self FontEntry> { -> Option<&'a FontEntry> {
self.load_family_variations(list); self.load_family_variations(list);
// TODO(Issue #189): optimize lookup for // TODO(Issue #189): optimize lookup for

View file

@ -2,10 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#[link(name = "gfx", #[crate_id = "github.com/mozilla/servo#gfx:0.1"];
vers = "0.1",
uuid = "0106bb54-6ea9-45bf-a39e-a738621f15e5",
url = "http://servo.org/")];
#[crate_type = "lib"]; #[crate_type = "lib"];
#[feature(globs, managed_boxes, macro_rules)]; #[feature(globs, managed_boxes, macro_rules)];
@ -16,10 +13,10 @@ extern mod geom;
extern mod layers; extern mod layers;
extern mod stb_image; extern mod stb_image;
extern mod png; extern mod png;
extern mod servo_net (name = "net"); extern mod servo_net = "net";
extern mod servo_util (name = "util"); extern mod servo_util = "util";
extern mod style; extern mod style;
extern mod servo_msg (name = "msg"); extern mod servo_msg = "msg";
// Eventually we would like the shaper to be pluggable, as many operating systems have their own // Eventually we would like the shaper to be pluggable, as many operating systems have their own
// shapers. For now, however, this is a hard dependency. // shapers. For now, however, this is a hard dependency.

View file

@ -113,9 +113,9 @@ pub fn from_cmdline_args(args: &[~str]) -> Opts {
}; };
// if only flag is present, default to 5 second period // if only flag is present, default to 5 second period
let profiler_period = do opt_match.opt_default("p", "5").map |period| { let profiler_period = opt_match.opt_default("p", "5").map(|period| {
from_str(period).unwrap() from_str(period).unwrap()
}; });
let cpu_painting = opt_match.opt_present("c"); let cpu_painting = opt_match.opt_present("c");

View file

@ -41,7 +41,7 @@ pub struct FontTable {
} }
impl FontTableMethods for FontTable { impl FontTableMethods for FontTable {
fn with_buffer(&self, _blk: &fn(*u8, uint)) { fn with_buffer(&self, _blk: |*u8, uint|) {
fail!() fail!()
} }
} }
@ -61,7 +61,6 @@ pub struct FontHandle {
#[unsafe_destructor] #[unsafe_destructor]
impl Drop for FontHandle { impl Drop for FontHandle {
#[fixed_stack_segment]
fn drop(&mut self) { fn drop(&mut self) {
assert!(self.face.is_not_null()); assert!(self.face.is_not_null());
unsafe { unsafe {
@ -80,9 +79,7 @@ impl FontHandleMethods for FontHandle {
let ft_ctx: FT_Library = fctx.ctx.borrow().ctx; let ft_ctx: FT_Library = fctx.ctx.borrow().ctx;
if ft_ctx.is_null() { return Err(()); } if ft_ctx.is_null() { return Err(()); }
let face_result = do buf.as_imm_buf |bytes: *u8, len: uint| { let face_result = create_face_from_buffer(ft_ctx, buf.as_ptr(), buf.len(), style.pt_size);
create_face_from_buffer(ft_ctx, bytes, len, style.pt_size)
};
// TODO: this could be more simply written as result::chain // TODO: this could be more simply written as result::chain
// and moving buf into the struct ctor, but cant' move out of // and moving buf into the struct ctor, but cant' move out of
@ -99,7 +96,6 @@ impl FontHandleMethods for FontHandle {
Err(()) => Err(()) Err(()) => Err(())
}; };
#[fixed_stack_segment]
fn create_face_from_buffer(lib: FT_Library, cbuf: *u8, cbuflen: uint, pt_size: f64) fn create_face_from_buffer(lib: FT_Library, cbuf: *u8, cbuflen: uint, pt_size: f64)
-> Result<FT_Face, ()> { -> Result<FT_Face, ()> {
unsafe { unsafe {
@ -129,14 +125,12 @@ impl FontHandleMethods for FontHandle {
fn family_name(&self) -> ~str { fn family_name(&self) -> ~str {
unsafe { str::raw::from_c_str((*self.face).family_name) } unsafe { str::raw::from_c_str((*self.face).family_name) }
} }
#[fixed_stack_segment]
fn face_name(&self) -> ~str { fn face_name(&self) -> ~str {
unsafe { str::raw::from_c_str(FT_Get_Postscript_Name(self.face)) } unsafe { str::raw::from_c_str(FT_Get_Postscript_Name(self.face)) }
} }
fn is_italic(&self) -> bool { fn is_italic(&self) -> bool {
unsafe { (*self.face).style_flags & FT_STYLE_FLAG_ITALIC != 0 } unsafe { (*self.face).style_flags & FT_STYLE_FLAG_ITALIC != 0 }
} }
#[fixed_stack_segment]
fn boldness(&self) -> font_weight::T { fn boldness(&self) -> font_weight::T {
let default_weight = font_weight::Weight400; let default_weight = font_weight::Weight400;
if unsafe { (*self.face).style_flags & FT_STYLE_FLAG_BOLD == 0 } { if unsafe { (*self.face).style_flags & FT_STYLE_FLAG_BOLD == 0 } {
@ -179,7 +173,6 @@ impl FontHandleMethods for FontHandle {
} }
} }
#[fixed_stack_segment]
fn glyph_index(&self, fn glyph_index(&self,
codepoint: char) -> Option<GlyphIndex> { codepoint: char) -> Option<GlyphIndex> {
assert!(self.face.is_not_null()); assert!(self.face.is_not_null());
@ -194,7 +187,6 @@ impl FontHandleMethods for FontHandle {
} }
} }
#[fixed_stack_segment]
fn glyph_h_advance(&self, fn glyph_h_advance(&self,
glyph: GlyphIndex) -> Option<FractionalPixel> { glyph: GlyphIndex) -> Option<FractionalPixel> {
assert!(self.face.is_not_null()); assert!(self.face.is_not_null());
@ -216,7 +208,6 @@ impl FontHandleMethods for FontHandle {
} }
} }
#[fixed_stack_segment]
fn get_metrics(&self) -> FontMetrics { fn get_metrics(&self) -> FontMetrics {
/* TODO(Issue #76): complete me */ /* TODO(Issue #76): complete me */
let face = self.get_face_rec(); let face = self.get_face_rec();
@ -272,8 +263,7 @@ impl FontHandleMethods for FontHandle {
} }
} }
impl<'self> FontHandle { impl<'a> FontHandle {
#[fixed_stack_segment]
fn set_char_size(face: FT_Face, pt_size: f64) -> Result<(), ()>{ fn set_char_size(face: FT_Face, pt_size: f64) -> Result<(), ()>{
let char_width = float_to_fixed_ft(pt_size) as FT_F26Dot6; let char_width = float_to_fixed_ft(pt_size) as FT_F26Dot6;
let char_height = float_to_fixed_ft(pt_size) as FT_F26Dot6; let char_height = float_to_fixed_ft(pt_size) as FT_F26Dot6;
@ -286,7 +276,6 @@ impl<'self> FontHandle {
} }
} }
#[fixed_stack_segment]
pub fn new_from_file(fctx: &FontContextHandle, file: &str, pub fn new_from_file(fctx: &FontContextHandle, file: &str,
style: &SpecifiedFontStyle) -> Result<FontHandle, ()> { style: &SpecifiedFontStyle) -> Result<FontHandle, ()> {
unsafe { unsafe {
@ -295,10 +284,10 @@ impl<'self> FontHandle {
let mut face: FT_Face = ptr::null(); let mut face: FT_Face = ptr::null();
let face_index = 0 as FT_Long; let face_index = 0 as FT_Long;
do file.to_c_str().with_ref |file_str| { file.to_c_str().with_ref(|file_str| {
FT_New_Face(ft_ctx, file_str, FT_New_Face(ft_ctx, file_str,
face_index, ptr::to_mut_unsafe_ptr(&mut face)); face_index, ptr::to_mut_unsafe_ptr(&mut face));
} });
if face.is_null() { if face.is_null() {
return Err(()); return Err(());
} }
@ -314,7 +303,6 @@ impl<'self> FontHandle {
} }
} }
#[fixed_stack_segment]
pub fn new_from_file_unstyled(fctx: &FontContextHandle, file: ~str) pub fn new_from_file_unstyled(fctx: &FontContextHandle, file: ~str)
-> Result<FontHandle, ()> { -> Result<FontHandle, ()> {
unsafe { unsafe {
@ -323,10 +311,10 @@ impl<'self> FontHandle {
let mut face: FT_Face = ptr::null(); let mut face: FT_Face = ptr::null();
let face_index = 0 as FT_Long; let face_index = 0 as FT_Long;
do file.to_c_str().with_ref |file_str| { file.to_c_str().with_ref(|file_str| {
FT_New_Face(ft_ctx, file_str, FT_New_Face(ft_ctx, file_str,
face_index, ptr::to_mut_unsafe_ptr(&mut face)); face_index, ptr::to_mut_unsafe_ptr(&mut face));
} });
if face.is_null() { if face.is_null() {
return Err(()); return Err(());
} }
@ -339,7 +327,7 @@ impl<'self> FontHandle {
} }
} }
fn get_face_rec(&'self self) -> &'self FT_FaceRec { fn get_face_rec(&'a self) -> &'a FT_FaceRec {
unsafe { unsafe {
&(*self.face) &(*self.face)
} }

View file

@ -24,7 +24,6 @@ pub struct FontContextHandle {
} }
impl Drop for FreeTypeLibraryHandle { impl Drop for FreeTypeLibraryHandle {
#[fixed_stack_segment]
fn drop(&mut self) { fn drop(&mut self) {
assert!(self.ctx.is_not_null()); assert!(self.ctx.is_not_null());
unsafe { FT_Done_FreeType(self.ctx) }; unsafe { FT_Done_FreeType(self.ctx) };
@ -32,7 +31,6 @@ impl Drop for FreeTypeLibraryHandle {
} }
impl FontContextHandle { impl FontContextHandle {
#[fixed_stack_segment]
pub fn new() -> FontContextHandle { pub fn new() -> FontContextHandle {
unsafe { unsafe {
let ctx: FT_Library = ptr::null(); let ctx: FT_Library = ptr::null();
@ -49,10 +47,10 @@ impl FontContextHandleMethods for FontContextHandle {
fn create_font_from_identifier(&self, name: ~str, style: UsedFontStyle) fn create_font_from_identifier(&self, name: ~str, style: UsedFontStyle)
-> Result<FontHandle, ()> { -> Result<FontHandle, ()> {
debug!("Creating font handle for {:s}", name); debug!("Creating font handle for {:s}", name);
do path_from_identifier(name, &style).and_then |file_name| { path_from_identifier(name, &style).and_then(|file_name| {
debug!("Opening font face {:s}", file_name); debug!("Opening font face {:s}", file_name);
FontHandle::new_from_file(self, file_name.to_owned(), &style) FontHandle::new_from_file(self, file_name.to_owned(), &style)
} })
} }
} }

View file

@ -40,7 +40,6 @@ impl FontListHandle {
FontListHandle { fctx: fctx.clone() } FontListHandle { fctx: fctx.clone() }
} }
#[fixed_stack_segment]
pub fn get_available_families(&self) -> FontFamilyMap { pub fn get_available_families(&self) -> FontFamilyMap {
let mut family_map : FontFamilyMap = HashMap::new(); let mut family_map : FontFamilyMap = HashMap::new();
unsafe { unsafe {
@ -50,7 +49,7 @@ impl FontListHandle {
let font = (*fontSet).fonts.offset(i); let font = (*fontSet).fonts.offset(i);
let family: *FcChar8 = ptr::null(); let family: *FcChar8 = ptr::null();
let mut v: c_int = 0; let mut v: c_int = 0;
do "family".to_c_str().with_ref |FC_FAMILY| { "family".to_c_str().with_ref(|FC_FAMILY| {
while FcPatternGetString(*font, FC_FAMILY, v, &family) == FcResultMatch { while FcPatternGetString(*font, FC_FAMILY, v, &family) == FcResultMatch {
let family_name = str::raw::from_c_str(family as *c_char); let family_name = str::raw::from_c_str(family as *c_char);
debug!("Creating new FontFamily for family: {:s}", family_name); debug!("Creating new FontFamily for family: {:s}", family_name);
@ -58,13 +57,12 @@ impl FontListHandle {
family_map.insert(family_name, new_family); family_map.insert(family_name, new_family);
v += 1; v += 1;
} }
} });
} }
} }
return family_map; return family_map;
} }
#[fixed_stack_segment]
pub fn load_variations_for_family(&self, family: &mut FontFamily) { pub fn load_variations_for_family(&self, family: &mut FontFamily) {
debug!("getting variations for {:?}", family); debug!("getting variations for {:?}", family);
unsafe { unsafe {
@ -73,22 +71,22 @@ impl FontListHandle {
let font_set_array_ptr = ptr::to_unsafe_ptr(&font_set); let font_set_array_ptr = ptr::to_unsafe_ptr(&font_set);
let pattern = FcPatternCreate(); let pattern = FcPatternCreate();
assert!(pattern.is_not_null()); assert!(pattern.is_not_null());
do "family".to_c_str().with_ref |FC_FAMILY| { "family".to_c_str().with_ref(|FC_FAMILY| {
do family.family_name.to_c_str().with_ref |family_name| { family.family_name.to_c_str().with_ref(|family_name| {
let ok = FcPatternAddString(pattern, FC_FAMILY, family_name as *FcChar8); let ok = FcPatternAddString(pattern, FC_FAMILY, family_name as *FcChar8);
assert!(ok != 0); assert!(ok != 0);
} });
} });
let object_set = FcObjectSetCreate(); let object_set = FcObjectSetCreate();
assert!(object_set.is_not_null()); assert!(object_set.is_not_null());
do "file".to_c_str().with_ref |FC_FILE| { "file".to_c_str().with_ref(|FC_FILE| {
FcObjectSetAdd(object_set, FC_FILE); FcObjectSetAdd(object_set, FC_FILE);
} });
do "index".to_c_str().with_ref |FC_INDEX| { "index".to_c_str().with_ref(|FC_INDEX| {
FcObjectSetAdd(object_set, FC_INDEX); FcObjectSetAdd(object_set, FC_INDEX);
} });
let matches = FcFontSetList(config, font_set_array_ptr, 1, pattern, object_set); let matches = FcFontSetList(config, font_set_array_ptr, 1, pattern, object_set);
@ -96,22 +94,22 @@ impl FontListHandle {
for i in range(0, (*matches).nfont as int) { for i in range(0, (*matches).nfont as int) {
let font = (*matches).fonts.offset(i); let font = (*matches).fonts.offset(i);
let file = do "file".to_c_str().with_ref |FC_FILE| { let file = "file".to_c_str().with_ref(|FC_FILE| {
let file: *FcChar8 = ptr::null(); let file: *FcChar8 = ptr::null();
if FcPatternGetString(*font, FC_FILE, 0, &file) == FcResultMatch { if FcPatternGetString(*font, FC_FILE, 0, &file) == FcResultMatch {
str::raw::from_c_str(file as *libc::c_char) str::raw::from_c_str(file as *libc::c_char)
} else { } else {
fail!(); fail!();
} }
}; });
let index = do "index".to_c_str().with_ref |FC_INDEX| { let index = "index".to_c_str().with_ref(|FC_INDEX| {
let index: libc::c_int = 0; let index: libc::c_int = 0;
if FcPatternGetInteger(*font, FC_INDEX, 0, &index) == FcResultMatch { if FcPatternGetInteger(*font, FC_INDEX, 0, &index) == FcResultMatch {
index index
} else { } else {
fail!(); fail!();
} }
}; });
debug!("variation file: {}", file); debug!("variation file: {}", file);
debug!("variation index: {}", index); debug!("variation index: {}", index);
@ -141,7 +139,6 @@ struct AutoPattern {
} }
impl Drop for AutoPattern { impl Drop for AutoPattern {
#[fixed_stack_segment]
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
FcPatternDestroy(self.pattern); FcPatternDestroy(self.pattern);
@ -149,17 +146,16 @@ impl Drop for AutoPattern {
} }
} }
#[fixed_stack_segment]
pub fn path_from_identifier(name: ~str, style: &UsedFontStyle) -> Result<~str, ()> { pub fn path_from_identifier(name: ~str, style: &UsedFontStyle) -> Result<~str, ()> {
unsafe { unsafe {
let config = FcConfigGetCurrent(); let config = FcConfigGetCurrent();
let wrapper = AutoPattern { pattern: FcPatternCreate() }; let wrapper = AutoPattern { pattern: FcPatternCreate() };
let pattern = wrapper.pattern; let pattern = wrapper.pattern;
let res = do "family".to_c_str().with_ref |FC_FAMILY| { let res = "family".to_c_str().with_ref(|FC_FAMILY| {
do name.to_c_str().with_ref |family| { name.to_c_str().with_ref(|family| {
FcPatternAddString(pattern, FC_FAMILY, family as *FcChar8) FcPatternAddString(pattern, FC_FAMILY, family as *FcChar8)
} })
}; });
if res != 1 { if res != 1 {
debug!("adding family to pattern failed"); debug!("adding family to pattern failed");
return Err(()); return Err(());
@ -168,18 +164,18 @@ pub fn path_from_identifier(name: ~str, style: &UsedFontStyle) -> Result<~str, (
match style.style { match style.style {
font_style::normal => (), font_style::normal => (),
font_style::italic => { font_style::italic => {
let res = do "slant".to_c_str().with_ref |FC_SLANT| { let res = "slant".to_c_str().with_ref(|FC_SLANT| {
FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC) FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC)
}; });
if res != 1 { if res != 1 {
debug!("adding slant to pattern failed"); debug!("adding slant to pattern failed");
return Err(()); return Err(());
} }
}, },
font_style::oblique => { font_style::oblique => {
let res = do "slant".to_c_str().with_ref |FC_SLANT| { let res = "slant".to_c_str().with_ref(|FC_SLANT| {
FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_OBLIQUE) FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_OBLIQUE)
}; });
if res != 1 { if res != 1 {
debug!("adding slant(oblique) to pattern failed"); debug!("adding slant(oblique) to pattern failed");
return Err(()); return Err(());
@ -188,9 +184,9 @@ pub fn path_from_identifier(name: ~str, style: &UsedFontStyle) -> Result<~str, (
} }
if style.weight.is_bold() { if style.weight.is_bold() {
let res = do "weight".to_c_str().with_ref |FC_WEIGHT| { let res = "weight".to_c_str().with_ref(|FC_WEIGHT| {
FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD) FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD)
}; });
if res != 1 { if res != 1 {
debug!("adding weight to pattern failed"); debug!("adding weight to pattern failed");
return Err(()); return Err(());
@ -211,9 +207,9 @@ pub fn path_from_identifier(name: ~str, style: &UsedFontStyle) -> Result<~str, (
} }
let file: *FcChar8 = ptr::null(); let file: *FcChar8 = ptr::null();
let res = do "file".to_c_str().with_ref |FC_FILE| { let res = "file".to_c_str().with_ref(|FC_FILE| {
FcPatternGetString(result_pattern, FC_FILE, 0, &file) FcPatternGetString(result_pattern, FC_FILE, 0, &file)
}; });
if res != FcResultMatch { if res != FcResultMatch {
debug!("getting filename for font failed"); debug!("getting filename for font failed");
return Err(()); return Err(());

View file

@ -41,7 +41,7 @@ pub struct FontTable {
} }
impl FontTableMethods for FontTable { impl FontTableMethods for FontTable {
fn with_buffer(&self, _blk: &fn(*u8, uint)) { fn with_buffer(&self, _blk: |*u8, uint|) {
fail!() fail!()
} }
} }
@ -61,7 +61,6 @@ pub struct FontHandle {
#[unsafe_destructor] #[unsafe_destructor]
impl Drop for FontHandle { impl Drop for FontHandle {
#[fixed_stack_segment]
fn drop(&mut self) { fn drop(&mut self) {
assert!(self.face.is_not_null()); assert!(self.face.is_not_null());
unsafe { unsafe {
@ -80,9 +79,7 @@ impl FontHandleMethods for FontHandle {
let ft_ctx: FT_Library = fctx.ctx.borrow().ctx; let ft_ctx: FT_Library = fctx.ctx.borrow().ctx;
if ft_ctx.is_null() { return Err(()); } if ft_ctx.is_null() { return Err(()); }
let face_result = do buf.as_imm_buf |bytes: *u8, len: uint| { let face_result = create_face_from_buffer(ft_ctx, buf.as_ptr(), buf.len(), style.pt_size);
create_face_from_buffer(ft_ctx, bytes, len, style.pt_size)
};
// TODO: this could be more simply written as result::chain // TODO: this could be more simply written as result::chain
// and moving buf into the struct ctor, but cant' move out of // and moving buf into the struct ctor, but cant' move out of
@ -99,7 +96,6 @@ impl FontHandleMethods for FontHandle {
Err(()) => Err(()) Err(()) => Err(())
}; };
#[fixed_stack_segment]
fn create_face_from_buffer(lib: FT_Library, cbuf: *u8, cbuflen: uint, pt_size: f64) fn create_face_from_buffer(lib: FT_Library, cbuf: *u8, cbuflen: uint, pt_size: f64)
-> Result<FT_Face, ()> { -> Result<FT_Face, ()> {
unsafe { unsafe {
@ -129,14 +125,12 @@ impl FontHandleMethods for FontHandle {
fn family_name(&self) -> ~str { fn family_name(&self) -> ~str {
unsafe { str::raw::from_c_str((*self.face).family_name) } unsafe { str::raw::from_c_str((*self.face).family_name) }
} }
#[fixed_stack_segment]
fn face_name(&self) -> ~str { fn face_name(&self) -> ~str {
unsafe { str::raw::from_c_str(FT_Get_Postscript_Name(self.face)) } unsafe { str::raw::from_c_str(FT_Get_Postscript_Name(self.face)) }
} }
fn is_italic(&self) -> bool { fn is_italic(&self) -> bool {
unsafe { (*self.face).style_flags & FT_STYLE_FLAG_ITALIC != 0 } unsafe { (*self.face).style_flags & FT_STYLE_FLAG_ITALIC != 0 }
} }
#[fixed_stack_segment]
fn boldness(&self) -> font_weight::T { fn boldness(&self) -> font_weight::T {
let default_weight = font_weight::Weight400; let default_weight = font_weight::Weight400;
if unsafe { (*self.face).style_flags & FT_STYLE_FLAG_BOLD == 0 } { if unsafe { (*self.face).style_flags & FT_STYLE_FLAG_BOLD == 0 } {
@ -179,7 +173,6 @@ impl FontHandleMethods for FontHandle {
} }
} }
#[fixed_stack_segment]
fn glyph_index(&self, fn glyph_index(&self,
codepoint: char) -> Option<GlyphIndex> { codepoint: char) -> Option<GlyphIndex> {
assert!(self.face.is_not_null()); assert!(self.face.is_not_null());
@ -194,7 +187,6 @@ impl FontHandleMethods for FontHandle {
} }
} }
#[fixed_stack_segment]
fn glyph_h_advance(&self, fn glyph_h_advance(&self,
glyph: GlyphIndex) -> Option<FractionalPixel> { glyph: GlyphIndex) -> Option<FractionalPixel> {
assert!(self.face.is_not_null()); assert!(self.face.is_not_null());
@ -216,7 +208,6 @@ impl FontHandleMethods for FontHandle {
} }
} }
#[fixed_stack_segment]
fn get_metrics(&self) -> FontMetrics { fn get_metrics(&self) -> FontMetrics {
/* TODO(Issue #76): complete me */ /* TODO(Issue #76): complete me */
let face = self.get_face_rec(); let face = self.get_face_rec();
@ -272,8 +263,7 @@ impl FontHandleMethods for FontHandle {
} }
} }
impl<'self> FontHandle { impl<'a> FontHandle {
#[fixed_stack_segment]
fn set_char_size(face: FT_Face, pt_size: f64) -> Result<(), ()>{ fn set_char_size(face: FT_Face, pt_size: f64) -> Result<(), ()>{
let char_width = float_to_fixed_ft(pt_size) as FT_F26Dot6; let char_width = float_to_fixed_ft(pt_size) as FT_F26Dot6;
let char_height = float_to_fixed_ft(pt_size) as FT_F26Dot6; let char_height = float_to_fixed_ft(pt_size) as FT_F26Dot6;
@ -286,7 +276,6 @@ impl<'self> FontHandle {
} }
} }
#[fixed_stack_segment]
pub fn new_from_file(fctx: &FontContextHandle, file: &str, pub fn new_from_file(fctx: &FontContextHandle, file: &str,
style: &SpecifiedFontStyle) -> Result<FontHandle, ()> { style: &SpecifiedFontStyle) -> Result<FontHandle, ()> {
unsafe { unsafe {
@ -295,10 +284,10 @@ impl<'self> FontHandle {
let mut face: FT_Face = ptr::null(); let mut face: FT_Face = ptr::null();
let face_index = 0 as FT_Long; let face_index = 0 as FT_Long;
do file.to_c_str().with_ref |file_str| { file.to_c_str().with_ref(|file_str| {
FT_New_Face(ft_ctx, file_str, FT_New_Face(ft_ctx, file_str,
face_index, ptr::to_mut_unsafe_ptr(&mut face)); face_index, ptr::to_mut_unsafe_ptr(&mut face));
} });
if face.is_null() { if face.is_null() {
return Err(()); return Err(());
} }
@ -314,7 +303,6 @@ impl<'self> FontHandle {
} }
} }
#[fixed_stack_segment]
pub fn new_from_file_unstyled(fctx: &FontContextHandle, file: ~str) pub fn new_from_file_unstyled(fctx: &FontContextHandle, file: ~str)
-> Result<FontHandle, ()> { -> Result<FontHandle, ()> {
unsafe { unsafe {
@ -323,10 +311,10 @@ impl<'self> FontHandle {
let mut face: FT_Face = ptr::null(); let mut face: FT_Face = ptr::null();
let face_index = 0 as FT_Long; let face_index = 0 as FT_Long;
do file.to_c_str().with_ref |file_str| { file.to_c_str().with_ref(|file_str| {
FT_New_Face(ft_ctx, file_str, FT_New_Face(ft_ctx, file_str,
face_index, ptr::to_mut_unsafe_ptr(&mut face)); face_index, ptr::to_mut_unsafe_ptr(&mut face));
} });
if face.is_null() { if face.is_null() {
return Err(()); return Err(());
} }
@ -339,7 +327,7 @@ impl<'self> FontHandle {
} }
} }
fn get_face_rec(&'self self) -> &'self FT_FaceRec { fn get_face_rec(&'a self) -> &'a FT_FaceRec {
unsafe { unsafe {
&(*self.face) &(*self.face)
} }

View file

@ -24,7 +24,6 @@ pub struct FontContextHandle {
} }
impl Drop for FreeTypeLibraryHandle { impl Drop for FreeTypeLibraryHandle {
#[fixed_stack_segment]
fn drop(&mut self) { fn drop(&mut self) {
assert!(self.ctx.is_not_null()); assert!(self.ctx.is_not_null());
unsafe { FT_Done_FreeType(self.ctx) }; unsafe { FT_Done_FreeType(self.ctx) };
@ -32,7 +31,6 @@ impl Drop for FreeTypeLibraryHandle {
} }
impl FontContextHandle { impl FontContextHandle {
#[fixed_stack_segment]
pub fn new() -> FontContextHandle { pub fn new() -> FontContextHandle {
unsafe { unsafe {
let ctx: FT_Library = ptr::null(); let ctx: FT_Library = ptr::null();
@ -49,10 +47,10 @@ impl FontContextHandleMethods for FontContextHandle {
fn create_font_from_identifier(&self, name: ~str, style: UsedFontStyle) fn create_font_from_identifier(&self, name: ~str, style: UsedFontStyle)
-> Result<FontHandle, ()> { -> Result<FontHandle, ()> {
debug!("Creating font handle for {:s}", name); debug!("Creating font handle for {:s}", name);
do path_from_identifier(name, &style).and_then |file_name| { path_from_identifier(name, &style).and_then(|file_name| {
debug!("Opening font face {:s}", file_name); debug!("Opening font face {:s}", file_name);
FontHandle::new_from_file(self, file_name.to_owned(), &style) FontHandle::new_from_file(self, file_name.to_owned(), &style)
} })
} }
} }

View file

@ -40,7 +40,6 @@ impl FontListHandle {
FontListHandle { fctx: fctx.clone() } FontListHandle { fctx: fctx.clone() }
} }
#[fixed_stack_segment]
pub fn get_available_families(&self) -> FontFamilyMap { pub fn get_available_families(&self) -> FontFamilyMap {
let mut family_map : FontFamilyMap = HashMap::new(); let mut family_map : FontFamilyMap = HashMap::new();
unsafe { unsafe {
@ -50,7 +49,7 @@ impl FontListHandle {
let font = (*fontSet).fonts.offset(i); let font = (*fontSet).fonts.offset(i);
let family: *FcChar8 = ptr::null(); let family: *FcChar8 = ptr::null();
let mut v: c_int = 0; let mut v: c_int = 0;
do "family".to_c_str().with_ref |FC_FAMILY| { "family".to_c_str().with_ref(|FC_FAMILY| {
while FcPatternGetString(*font, FC_FAMILY, v, &family) == FcResultMatch { while FcPatternGetString(*font, FC_FAMILY, v, &family) == FcResultMatch {
let family_name = str::raw::from_c_str(family as *c_char); let family_name = str::raw::from_c_str(family as *c_char);
debug!("Creating new FontFamily for family: {:s}", family_name); debug!("Creating new FontFamily for family: {:s}", family_name);
@ -58,13 +57,12 @@ impl FontListHandle {
family_map.insert(family_name, new_family); family_map.insert(family_name, new_family);
v += 1; v += 1;
} }
} });
} }
} }
return family_map; return family_map;
} }
#[fixed_stack_segment]
pub fn load_variations_for_family(&self, family: &mut FontFamily) { pub fn load_variations_for_family(&self, family: &mut FontFamily) {
debug!("getting variations for {:?}", family); debug!("getting variations for {:?}", family);
unsafe { unsafe {
@ -73,22 +71,22 @@ impl FontListHandle {
let font_set_array_ptr = ptr::to_unsafe_ptr(&font_set); let font_set_array_ptr = ptr::to_unsafe_ptr(&font_set);
let pattern = FcPatternCreate(); let pattern = FcPatternCreate();
assert!(pattern.is_not_null()); assert!(pattern.is_not_null());
do "family".to_c_str().with_ref |FC_FAMILY| { "family".to_c_str().with_ref(|FC_FAMILY| {
do family.family_name.to_c_str().with_ref |family_name| { family.family_name.to_c_str().with_ref(|family_name| {
let ok = FcPatternAddString(pattern, FC_FAMILY, family_name as *FcChar8); let ok = FcPatternAddString(pattern, FC_FAMILY, family_name as *FcChar8);
assert!(ok != 0); assert!(ok != 0);
} });
} });
let object_set = FcObjectSetCreate(); let object_set = FcObjectSetCreate();
assert!(object_set.is_not_null()); assert!(object_set.is_not_null());
do "file".to_c_str().with_ref |FC_FILE| { "file".to_c_str().with_ref(|FC_FILE| {
FcObjectSetAdd(object_set, FC_FILE); FcObjectSetAdd(object_set, FC_FILE);
} });
do "index".to_c_str().with_ref |FC_INDEX| { "index".to_c_str().with_ref(|FC_INDEX| {
FcObjectSetAdd(object_set, FC_INDEX); FcObjectSetAdd(object_set, FC_INDEX);
} });
let matches = FcFontSetList(config, font_set_array_ptr, 1, pattern, object_set); let matches = FcFontSetList(config, font_set_array_ptr, 1, pattern, object_set);
@ -96,22 +94,22 @@ impl FontListHandle {
for i in range(0, (*matches).nfont as int) { for i in range(0, (*matches).nfont as int) {
let font = (*matches).fonts.offset(i); let font = (*matches).fonts.offset(i);
let file = do "file".to_c_str().with_ref |FC_FILE| { let file = "file".to_c_str().with_ref(|FC_FILE| {
let file: *FcChar8 = ptr::null(); let file: *FcChar8 = ptr::null();
if FcPatternGetString(*font, FC_FILE, 0, &file) == FcResultMatch { if FcPatternGetString(*font, FC_FILE, 0, &file) == FcResultMatch {
str::raw::from_c_str(file as *libc::c_char) str::raw::from_c_str(file as *libc::c_char)
} else { } else {
fail!(); fail!();
} }
}; });
let index = do "index".to_c_str().with_ref |FC_INDEX| { let index = "index".to_c_str().with_ref(|FC_INDEX| {
let index: libc::c_int = 0; let index: libc::c_int = 0;
if FcPatternGetInteger(*font, FC_INDEX, 0, &index) == FcResultMatch { if FcPatternGetInteger(*font, FC_INDEX, 0, &index) == FcResultMatch {
index index
} else { } else {
fail!(); fail!();
} }
}; });
debug!("variation file: {}", file); debug!("variation file: {}", file);
debug!("variation index: {}", index); debug!("variation index: {}", index);
@ -141,7 +139,6 @@ struct AutoPattern {
} }
impl Drop for AutoPattern { impl Drop for AutoPattern {
#[fixed_stack_segment]
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
FcPatternDestroy(self.pattern); FcPatternDestroy(self.pattern);
@ -149,17 +146,16 @@ impl Drop for AutoPattern {
} }
} }
#[fixed_stack_segment]
pub fn path_from_identifier(name: ~str, style: &UsedFontStyle) -> Result<~str, ()> { pub fn path_from_identifier(name: ~str, style: &UsedFontStyle) -> Result<~str, ()> {
unsafe { unsafe {
let config = FcConfigGetCurrent(); let config = FcConfigGetCurrent();
let wrapper = AutoPattern { pattern: FcPatternCreate() }; let wrapper = AutoPattern { pattern: FcPatternCreate() };
let pattern = wrapper.pattern; let pattern = wrapper.pattern;
let res = do "family".to_c_str().with_ref |FC_FAMILY| { let res = "family".to_c_str().with_ref(|FC_FAMILY| {
do name.to_c_str().with_ref |family| { name.to_c_str().with_ref(|family| {
FcPatternAddString(pattern, FC_FAMILY, family as *FcChar8) FcPatternAddString(pattern, FC_FAMILY, family as *FcChar8)
} })
}; });
if res != 1 { if res != 1 {
debug!("adding family to pattern failed"); debug!("adding family to pattern failed");
return Err(()); return Err(());
@ -168,18 +164,18 @@ pub fn path_from_identifier(name: ~str, style: &UsedFontStyle) -> Result<~str, (
match style.style { match style.style {
font_style::normal => (), font_style::normal => (),
font_style::italic => { font_style::italic => {
let res = do "slant".to_c_str().with_ref |FC_SLANT| { let res = "slant".to_c_str().with_ref(|FC_SLANT| {
FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC) FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC)
}; });
if res != 1 { if res != 1 {
debug!("adding slant to pattern failed"); debug!("adding slant to pattern failed");
return Err(()); return Err(());
} }
}, },
font_style::oblique => { font_style::oblique => {
let res = do "slant".to_c_str().with_ref |FC_SLANT| { let res = "slant".to_c_str().with_ref(|FC_SLANT| {
FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_OBLIQUE) FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_OBLIQUE)
}; });
if res != 1 { if res != 1 {
debug!("adding slant(oblique) to pattern failed"); debug!("adding slant(oblique) to pattern failed");
return Err(()); return Err(());
@ -188,9 +184,9 @@ pub fn path_from_identifier(name: ~str, style: &UsedFontStyle) -> Result<~str, (
} }
if style.weight.is_bold() { if style.weight.is_bold() {
let res = do "weight".to_c_str().with_ref |FC_WEIGHT| { let res = "weight".to_c_str().with_ref(|FC_WEIGHT| {
FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD) FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD)
}; });
if res != 1 { if res != 1 {
debug!("adding weight to pattern failed"); debug!("adding weight to pattern failed");
return Err(()); return Err(());
@ -211,9 +207,9 @@ pub fn path_from_identifier(name: ~str, style: &UsedFontStyle) -> Result<~str, (
} }
let file: *FcChar8 = ptr::null(); let file: *FcChar8 = ptr::null();
let res = do "file".to_c_str().with_ref |FC_FILE| { let res = "file".to_c_str().with_ref(|FC_FILE| {
FcPatternGetString(result_pattern, FC_FILE, 0, &file) FcPatternGetString(result_pattern, FC_FILE, 0, &file)
}; });
if res != FcResultMatch { if res != FcResultMatch {
debug!("getting filename for font failed"); debug!("getting filename for font failed");
return Err(()); return Err(());

View file

@ -29,7 +29,6 @@ use core_text::font_descriptor::{kCTFontDefaultOrientation};
use core_text; use core_text;
use std::ptr; use std::ptr;
use std::vec;
pub struct FontTable { pub struct FontTable {
data: CFData, data: CFData,
@ -47,8 +46,8 @@ impl FontTable {
} }
impl FontTableMethods for FontTable { impl FontTableMethods for FontTable {
fn with_buffer(&self, blk: &fn(*u8, uint)) { fn with_buffer(&self, blk: |*u8, uint|) {
blk(vec::raw::to_ptr(self.data.bytes()), self.data.len() as uint); blk(self.data.bytes().as_ptr(), self.data.len() as uint);
} }
} }
@ -185,9 +184,9 @@ impl FontHandleMethods for FontHandle {
fn get_table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> { fn get_table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> {
let result: Option<CFData> = self.ctfont.get_font_table(tag); let result: Option<CFData> = self.ctfont.get_font_table(tag);
do result.and_then |data| { result.and_then(|data| {
Some(FontTable::wrap(data)) Some(FontTable::wrap(data))
} })
} }
fn face_identifier(&self) -> ~str { fn face_identifier(&self) -> ~str {

View file

@ -27,8 +27,8 @@ impl FontContextHandleMethods for FontContextHandle {
style: UsedFontStyle) style: UsedFontStyle)
-> Result<FontHandle, ()> { -> Result<FontHandle, ()> {
let ctfont_result = core_text::font::new_from_name(name, style.pt_size); let ctfont_result = core_text::font::new_from_name(name, style.pt_size);
do ctfont_result.and_then |ctfont| { ctfont_result.and_then(|ctfont| {
FontHandle::new_from_CTFont(self, ctfont) FontHandle::new_from_CTFont(self, ctfont)
} })
} }
} }

View file

@ -18,14 +18,13 @@ use geom::side_offsets::SideOffsets2D;
use servo_net::image::base::Image; use servo_net::image::base::Image;
use png::{RGBA8, K8, KA8}; use png::{RGBA8, K8, KA8};
use servo_util::geometry::Au; use servo_util::geometry::Au;
use std::vec;
use std::libc::types::common::c99::uint16_t; use std::libc::types::common::c99::uint16_t;
use std::libc::size_t; use std::libc::size_t;
pub struct RenderContext<'self> { pub struct RenderContext<'a> {
draw_target: &'self DrawTarget, draw_target: &'a DrawTarget,
font_ctx: &'self mut ~FontContext, font_ctx: &'a mut ~FontContext,
opts: &'self Opts, opts: &'a Opts,
/// The rectangle that this context encompasses in page coordinates. /// The rectangle that this context encompasses in page coordinates.
page_rect: Rect<f32>, page_rect: Rect<f32>,
/// The rectangle that this context encompasses in screen coordinates (pixels). /// The rectangle that this context encompasses in screen coordinates (pixels).
@ -39,8 +38,8 @@ enum Direction {
Bottom Bottom
} }
impl<'self> RenderContext<'self> { impl<'a> RenderContext<'a> {
pub fn get_draw_target(&self) -> &'self DrawTarget { pub fn get_draw_target(&self) -> &'a DrawTarget {
self.draw_target self.draw_target
} }
@ -167,7 +166,7 @@ impl<'self> RenderContext<'self> {
stroke_opts.line_width = border_width; stroke_opts.line_width = border_width;
dash[0] = border_width * 3 as AzFloat; dash[0] = border_width * 3 as AzFloat;
dash[1] = border_width * 3 as AzFloat; dash[1] = border_width * 3 as AzFloat;
stroke_opts.mDashPattern = vec::raw::to_ptr(dash); stroke_opts.mDashPattern = dash.as_ptr();
stroke_opts.mDashLength = dash.len() as size_t; stroke_opts.mDashLength = dash.len() as size_t;
let (start, end) = match direction { let (start, end) = match direction {

View file

@ -20,7 +20,6 @@ use servo_util::time::{ProfilerChan, profile};
use servo_util::time; use servo_util::time;
use std::comm::{Chan, Port, SharedChan}; use std::comm::{Chan, Port, SharedChan};
use std::task::spawn_with;
use extra::arc::Arc; use extra::arc::Arc;
use buffer_map::BufferMap; use buffer_map::BufferMap;
@ -63,24 +62,32 @@ pub fn BufferRequest(screen_rect: Rect<uint>, page_rect: Rect<f32>) -> BufferReq
// FIXME(rust#9155): this should be a newtype struct, but // FIXME(rust#9155): this should be a newtype struct, but
// generic newtypes ICE when compiled cross-crate // generic newtypes ICE when compiled cross-crate
#[deriving(Clone)]
pub struct RenderChan<T> { pub struct RenderChan<T> {
chan: SharedChan<Msg<T>>, chan: SharedChan<Msg<T>>,
} }
impl<T: Send> RenderChan<T> {
pub fn new(chan: Chan<Msg<T>>) -> RenderChan<T> { impl<T: Send> Clone for RenderChan<T> {
fn clone(&self) -> RenderChan<T> {
RenderChan { RenderChan {
chan: SharedChan::new(chan), chan: self.chan.clone(),
} }
} }
} }
impl<T: Send> GenericChan<Msg<T>> for RenderChan<T> {
fn send(&self, msg: Msg<T>) { impl<T: Send> RenderChan<T> {
pub fn new() -> (Port<Msg<T>>, RenderChan<T>) {
let (port, chan) = SharedChan::new();
let render_chan = RenderChan {
chan: chan,
};
(port, render_chan)
}
pub fn send(&self, msg: Msg<T>) {
assert!(self.try_send(msg), "RenderChan.send: render port closed") assert!(self.try_send(msg), "RenderChan.send: render port closed")
} }
}
impl<T: Send> GenericSmartChan<Msg<T>> for RenderChan<T> { pub fn try_send(&self, msg: Msg<T>) -> bool {
fn try_send(&self, msg: Msg<T>) -> bool {
self.chan.try_send(msg) self.chan.try_send(msg)
} }
} }
@ -138,9 +145,7 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
opts: Opts, opts: Opts,
profiler_chan: ProfilerChan, profiler_chan: ProfilerChan,
shutdown_chan: Chan<()>) { shutdown_chan: Chan<()>) {
do spawn_with((port, compositor, constellation_chan, opts, profiler_chan, shutdown_chan)) spawn(proc() {
|(port, compositor, constellation_chan, opts, profiler_chan, shutdown_chan)| {
{ // Ensures RenderTask and graphics context are destroyed before shutdown msg { // Ensures RenderTask and graphics context are destroyed before shutdown msg
let native_graphics_context = compositor.get_graphics_metadata().map( let native_graphics_context = compositor.get_graphics_metadata().map(
|md| NativePaintingGraphicsContext::from_metadata(&md)); |md| NativePaintingGraphicsContext::from_metadata(&md));
@ -153,8 +158,8 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
compositor: compositor, compositor: compositor,
constellation_chan: constellation_chan, constellation_chan: constellation_chan,
font_ctx: ~FontContext::new(opts.render_backend.clone(), font_ctx: ~FontContext::new(opts.render_backend.clone(),
false, false,
profiler_chan.clone()), profiler_chan.clone()),
opts: opts, opts: opts,
profiler_chan: profiler_chan, profiler_chan: profiler_chan,
@ -176,13 +181,12 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
render_task.start(); render_task.start();
// Destroy all the buffers. // Destroy all the buffers.
render_task.native_graphics_context.as_ref().map(|ctx| render_task.native_graphics_context.as_ref().map(
render_task.buffer_map.clear(ctx) |ctx| render_task.buffer_map.clear(ctx));
);
} }
shutdown_chan.send(()); shutdown_chan.send(());
} });
} }
fn start(&mut self) { fn start(&mut self) {
@ -243,12 +247,12 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
} }
self.compositor.set_render_state(RenderingRenderState); self.compositor.set_render_state(RenderingRenderState);
do time::profile(time::RenderingCategory, self.profiler_chan.clone()) { time::profile(time::RenderingCategory, self.profiler_chan.clone(), || {
// FIXME: Try not to create a new array here. // FIXME: Try not to create a new array here.
let mut new_buffers = ~[]; let mut new_buffers = ~[];
// Divide up the layer into tiles. // Divide up the layer into tiles.
do time::profile(time::RenderingPrepBuffCategory, self.profiler_chan.clone()) { time::profile(time::RenderingPrepBuffCategory, self.profiler_chan.clone(), || {
for tile in tiles.iter() { for tile in tiles.iter() {
let width = tile.screen_rect.size.width; let width = tile.screen_rect.size.width;
let height = tile.screen_rect.size.height; let height = tile.screen_rect.size.height;
@ -293,10 +297,10 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
ctx.clear(); ctx.clear();
// Draw the display list. // Draw the display list.
do profile(time::RenderingDrawingCategory, self.profiler_chan.clone()) { profile(time::RenderingDrawingCategory, self.profiler_chan.clone(), || {
render_layer.display_list.get().draw_into_context(&mut ctx); render_layer.display_list.get().draw_into_context(&mut ctx);
ctx.draw_target.flush(); ctx.draw_target.flush();
} });
} }
// Extract the texture from the draw target and place it into its slot in the // Extract the texture from the draw target and place it into its slot in the
@ -335,11 +339,11 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
} }
}; };
do draw_target.snapshot().get_data_surface().with_data |data| { draw_target.snapshot().get_data_surface().with_data(|data| {
buffer.native_surface.upload(native_graphics_context!(self), data); buffer.native_surface.upload(native_graphics_context!(self), data);
debug!("RENDERER uploading to native surface {:d}", debug!("RENDERER uploading to native surface {:d}",
buffer.native_surface.get_id() as int); buffer.native_surface.get_id() as int);
} });
buffer buffer
} }
@ -367,7 +371,7 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
new_buffers.push(buffer); new_buffers.push(buffer);
} }
} });
let layer_buffer_set = ~LayerBufferSet { let layer_buffer_set = ~LayerBufferSet {
buffers: new_buffers, buffers: new_buffers,
@ -380,7 +384,7 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
self.constellation_chan.send(RendererReadyMsg(self.id)); self.constellation_chan.send(RendererReadyMsg(self.id));
} }
self.compositor.set_render_state(IdleRenderState); self.compositor.set_render_state(IdleRenderState);
} })
} }
} }

View file

@ -14,7 +14,6 @@ use std::vec;
use std::util; use std::util;
use std::iter; use std::iter;
use geom::point::Point2D; use geom::point::Point2D;
use extra::sort;
/// GlyphEntry is a port of Gecko's CompressedGlyph scheme for storing glyph data compactly. /// GlyphEntry is a port of Gecko's CompressedGlyph scheme for storing glyph data compactly.
/// ///
@ -149,8 +148,8 @@ static FLAG_NOT_LIGATURE_GROUP_START: u32 = 0x00000004;
static FLAG_CHAR_IS_TAB: u32 = 0x00000008; static FLAG_CHAR_IS_TAB: u32 = 0x00000008;
static FLAG_CHAR_IS_NEWLINE: u32 = 0x00000010; static FLAG_CHAR_IS_NEWLINE: u32 = 0x00000010;
static FLAG_CHAR_IS_LOW_SURROGATE: u32 = 0x00000020; //static FLAG_CHAR_IS_LOW_SURROGATE: u32 = 0x00000020;
static CHAR_IDENTITY_FLAGS_MASK: u32 = 0x00000038; //static CHAR_IDENTITY_FLAGS_MASK: u32 = 0x00000038;
fn is_simple_glyph_id(glyphId: GlyphIndex) -> bool { fn is_simple_glyph_id(glyphId: GlyphIndex) -> bool {
((glyphId as u32) & GLYPH_ID_MASK) == glyphId ((glyphId as u32) & GLYPH_ID_MASK) == glyphId
@ -176,10 +175,6 @@ impl GlyphEntry {
self.value & GLYPH_ID_MASK self.value & GLYPH_ID_MASK
} }
fn offset(&self) -> Point2D<Au> {
Point2D(Au(0), Au(0))
}
fn is_ligature_start(&self) -> bool { fn is_ligature_start(&self) -> bool {
self.has_flag(!FLAG_NOT_LIGATURE_GROUP_START) self.has_flag(!FLAG_NOT_LIGATURE_GROUP_START)
} }
@ -312,7 +307,7 @@ struct DetailedGlyphStore {
lookup_is_sorted: bool, lookup_is_sorted: bool,
} }
impl<'self> DetailedGlyphStore { impl<'a> DetailedGlyphStore {
fn new() -> DetailedGlyphStore { fn new() -> DetailedGlyphStore {
DetailedGlyphStore { DetailedGlyphStore {
detail_buffer: ~[], // TODO: default size? detail_buffer: ~[], // TODO: default size?
@ -345,8 +340,8 @@ impl<'self> DetailedGlyphStore {
self.lookup_is_sorted = false; self.lookup_is_sorted = false;
} }
fn get_detailed_glyphs_for_entry(&'self self, entry_offset: uint, count: u16) fn get_detailed_glyphs_for_entry(&'a self, entry_offset: uint, count: u16)
-> &'self [DetailedGlyph] { -> &'a [DetailedGlyph] {
debug!("Requesting detailed glyphs[n={:u}] for entry[off={:u}]", count as uint, entry_offset); debug!("Requesting detailed glyphs[n={:u}] for entry[off={:u}]", count as uint, entry_offset);
// FIXME: Is this right? --pcwalton // FIXME: Is this right? --pcwalton
@ -375,10 +370,10 @@ impl<'self> DetailedGlyphStore {
} }
} }
fn get_detailed_glyph_with_index(&'self self, fn get_detailed_glyph_with_index(&'a self,
entry_offset: uint, entry_offset: uint,
detail_offset: u16) detail_offset: u16)
-> &'self DetailedGlyph { -> &'a DetailedGlyph {
assert!((detail_offset as uint) <= self.detail_buffer.len()); assert!((detail_offset as uint) <= self.detail_buffer.len());
assert!(self.lookup_is_sorted); assert!(self.lookup_is_sorted);
@ -411,7 +406,13 @@ impl<'self> DetailedGlyphStore {
let mut unsorted_records: ~[DetailedGlyphRecord] = ~[]; let mut unsorted_records: ~[DetailedGlyphRecord] = ~[];
util::swap(&mut self.detail_lookup, &mut unsorted_records); util::swap(&mut self.detail_lookup, &mut unsorted_records);
let mut mut_records : ~[DetailedGlyphRecord] = unsorted_records; let mut mut_records : ~[DetailedGlyphRecord] = unsorted_records;
sort::quick_sort3(mut_records); mut_records.sort_by(|a, b| {
if a < b {
Less
} else {
Greater
}
});
let mut sorted_records = mut_records; let mut sorted_records = mut_records;
util::swap(&mut self.detail_lookup, &mut sorted_records); util::swap(&mut self.detail_lookup, &mut sorted_records);
@ -458,12 +459,12 @@ impl GlyphData {
// through glyphs (either for a particular TextRun offset, or all glyphs). // through glyphs (either for a particular TextRun offset, or all glyphs).
// Rather than eagerly assembling and copying glyph data, it only retrieves // Rather than eagerly assembling and copying glyph data, it only retrieves
// values as they are needed from the GlyphStore, using provided offsets. // values as they are needed from the GlyphStore, using provided offsets.
enum GlyphInfo<'self> { enum GlyphInfo<'a> {
SimpleGlyphInfo(&'self GlyphStore, uint), SimpleGlyphInfo(&'a GlyphStore, uint),
DetailGlyphInfo(&'self GlyphStore, uint, u16) DetailGlyphInfo(&'a GlyphStore, uint, u16)
} }
impl<'self> GlyphInfo<'self> { impl<'a> GlyphInfo<'a> {
pub fn index(self) -> GlyphIndex { pub fn index(self) -> GlyphIndex {
match self { match self {
SimpleGlyphInfo(store, entry_i) => store.entry_buffer[entry_i].index(), SimpleGlyphInfo(store, entry_i) => store.entry_buffer[entry_i].index(),
@ -492,20 +493,6 @@ impl<'self> GlyphInfo<'self> {
} }
} }
} }
pub fn is_ligature_start(self) -> bool {
match self {
SimpleGlyphInfo(store, entry_i) => store.entry_buffer[entry_i].is_ligature_start(),
DetailGlyphInfo(store, entry_i, _) => store.entry_buffer[entry_i].is_ligature_start()
}
}
pub fn is_cluster_start(self) -> bool {
match self {
SimpleGlyphInfo(store, entry_i) => store.entry_buffer[entry_i].is_cluster_start(),
DetailGlyphInfo(store, entry_i, _) => store.entry_buffer[entry_i].is_cluster_start()
}
}
} }
// Public data structure and API for storing and retrieving glyph data // Public data structure and API for storing and retrieving glyph data
@ -519,7 +506,7 @@ pub struct GlyphStore {
is_whitespace: bool, is_whitespace: bool,
} }
impl<'self> GlyphStore { impl<'a> GlyphStore {
// Initializes the glyph store, but doesn't actually shape anything. // Initializes the glyph store, but doesn't actually shape anything.
// Use the set_glyph, set_glyphs() methods to store glyph data. // Use the set_glyph, set_glyphs() methods to store glyph data.
pub fn new(length: uint, is_whitespace: bool) -> GlyphStore { pub fn new(length: uint, is_whitespace: bool) -> GlyphStore {
@ -606,12 +593,12 @@ impl<'self> GlyphStore {
self.entry_buffer[i] = entry; self.entry_buffer[i] = entry;
} }
pub fn iter_glyphs_for_char_index(&'self self, i: uint) -> GlyphIterator<'self> { pub fn iter_glyphs_for_char_index(&'a self, i: uint) -> GlyphIterator<'a> {
self.iter_glyphs_for_char_range(&Range::new(i, 1)) self.iter_glyphs_for_char_range(&Range::new(i, 1))
} }
#[inline] #[inline]
pub fn iter_glyphs_for_char_range(&'self self, rang: &Range) -> GlyphIterator<'self> { pub fn iter_glyphs_for_char_range(&'a self, rang: &Range) -> GlyphIterator<'a> {
if rang.begin() >= self.entry_buffer.len() { if rang.begin() >= self.entry_buffer.len() {
fail!("iter_glyphs_for_range: range.begin beyond length!"); fail!("iter_glyphs_for_range: range.begin beyond length!");
} }
@ -684,17 +671,17 @@ impl<'self> GlyphStore {
} }
} }
pub struct GlyphIterator<'self> { pub struct GlyphIterator<'a> {
priv store: &'self GlyphStore, priv store: &'a GlyphStore,
priv char_index: uint, priv char_index: uint,
priv char_range: iter::Range<uint>, priv char_range: iter::Range<uint>,
priv glyph_range: Option<iter::Range<uint>>, priv glyph_range: Option<iter::Range<uint>>,
} }
impl<'self> GlyphIterator<'self> { impl<'a> GlyphIterator<'a> {
// Slow path when there is a glyph range. // Slow path when there is a glyph range.
#[inline(never)] #[inline(never)]
fn next_glyph_range(&mut self) -> Option<(uint, GlyphInfo<'self>)> { fn next_glyph_range(&mut self) -> Option<(uint, GlyphInfo<'a>)> {
match self.glyph_range.get_mut_ref().next() { match self.glyph_range.get_mut_ref().next() {
Some(j) => Some((self.char_index, Some(j) => Some((self.char_index,
DetailGlyphInfo(self.store, self.char_index, j as u16))), DetailGlyphInfo(self.store, self.char_index, j as u16))),
@ -709,14 +696,14 @@ impl<'self> GlyphIterator<'self> {
// Slow path when there is a complex glyph. // Slow path when there is a complex glyph.
#[inline(never)] #[inline(never)]
fn next_complex_glyph(&mut self, entry: &GlyphEntry, i: uint) fn next_complex_glyph(&mut self, entry: &GlyphEntry, i: uint)
-> Option<(uint, GlyphInfo<'self>)> { -> Option<(uint, GlyphInfo<'a>)> {
let glyphs = self.store.detail_store.get_detailed_glyphs_for_entry(i, entry.glyph_count()); let glyphs = self.store.detail_store.get_detailed_glyphs_for_entry(i, entry.glyph_count());
self.glyph_range = Some(range(0, glyphs.len())); self.glyph_range = Some(range(0, glyphs.len()));
self.next() self.next()
} }
} }
impl<'self> Iterator<(uint, GlyphInfo<'self>)> for GlyphIterator<'self> { impl<'a> Iterator<(uint, GlyphInfo<'a>)> for GlyphIterator<'a> {
// I tried to start with something simpler and apply FlatMap, but the // I tried to start with something simpler and apply FlatMap, but the
// inability to store free variables in the FlatMap struct was problematic. // inability to store free variables in the FlatMap struct was problematic.
// //
@ -724,7 +711,7 @@ impl<'self> Iterator<(uint, GlyphInfo<'self>)> for GlyphIterator<'self> {
// slow paths, which should not be inlined, are `next_glyph_range()` and // slow paths, which should not be inlined, are `next_glyph_range()` and
// `next_complex_glyph()`. // `next_complex_glyph()`.
#[inline(always)] #[inline(always)]
fn next(&mut self) -> Option<(uint, GlyphInfo<'self>)> { fn next(&mut self) -> Option<(uint, GlyphInfo<'a>)> {
// Would use 'match' here but it borrows contents in a way that // Would use 'match' here but it borrows contents in a way that
// interferes with mutation. // interferes with mutation.
if self.glyph_range.is_some() { if self.glyph_range.is_some() {

View file

@ -10,15 +10,14 @@ use platform::font::FontTable;
use text::glyph::{GlyphStore, GlyphIndex, GlyphData}; use text::glyph::{GlyphStore, GlyphIndex, GlyphData};
use text::shaping::ShaperMethods; use text::shaping::ShaperMethods;
use servo_util::range::Range; use servo_util::range::Range;
use text::util::{float_to_fixed, fixed_to_float, fixed_to_rounded_int}; use text::util::{float_to_fixed, fixed_to_float};
use std::cast::transmute; use std::cast::transmute;
use std::char; use std::char;
use std::libc::{c_uint, c_int, c_void, c_char}; use std::libc::{c_uint, c_int, c_void, c_char};
use std::ptr; use std::ptr;
use std::ptr::null; use std::ptr::null;
use std::uint; use std::num;
use std::util::ignore;
use std::vec; use std::vec;
use geom::Point2D; use geom::Point2D;
use harfbuzz::{hb_blob_create, hb_face_create_for_tables}; use harfbuzz::{hb_blob_create, hb_face_create_for_tables};
@ -63,7 +62,6 @@ pub struct ShapedGlyphEntry {
} }
impl ShapedGlyphData { impl ShapedGlyphData {
#[fixed_stack_segment]
pub fn new(buffer: *hb_buffer_t) -> ShapedGlyphData { pub fn new(buffer: *hb_buffer_t) -> ShapedGlyphData {
unsafe { unsafe {
let glyph_count = 0; let glyph_count = 0;
@ -143,7 +141,6 @@ pub struct Shaper {
#[unsafe_destructor] #[unsafe_destructor]
impl Drop for Shaper { impl Drop for Shaper {
#[fixed_stack_segment]
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
assert!(self.hb_face.is_not_null()); assert!(self.hb_face.is_not_null());
@ -159,7 +156,6 @@ impl Drop for Shaper {
} }
impl Shaper { impl Shaper {
#[fixed_stack_segment]
pub fn new(font: &mut Font) -> Shaper { pub fn new(font: &mut Font) -> Shaper {
unsafe { unsafe {
// Indirection for Rust Issue #6248, dynamic freeze scope artifically extended // Indirection for Rust Issue #6248, dynamic freeze scope artifically extended
@ -200,29 +196,22 @@ impl Shaper {
fn fixed_to_float(i: hb_position_t) -> f64 { fn fixed_to_float(i: hb_position_t) -> f64 {
fixed_to_float(16, i) fixed_to_float(16, i)
} }
fn fixed_to_rounded_int(f: hb_position_t) -> int {
fixed_to_rounded_int(16, f)
}
} }
impl ShaperMethods for Shaper { impl ShaperMethods for Shaper {
/// Calculate the layout metrics associated with the given text when rendered in a specific /// Calculate the layout metrics associated with the given text when rendered in a specific
/// font. /// font.
#[fixed_stack_segment]
fn shape_text(&self, text: &str, glyphs: &mut GlyphStore) { fn shape_text(&self, text: &str, glyphs: &mut GlyphStore) {
unsafe { unsafe {
let hb_buffer: *hb_buffer_t = hb_buffer_create(); let hb_buffer: *hb_buffer_t = hb_buffer_create();
hb_buffer_set_direction(hb_buffer, HB_DIRECTION_LTR); hb_buffer_set_direction(hb_buffer, HB_DIRECTION_LTR);
// Using as_imm_buf because it never does a copy - we don't need the trailing null // Using as_imm_buf because it never does a copy - we don't need the trailing null
do text.as_imm_buf |ctext: *u8, _: uint| { hb_buffer_add_utf8(hb_buffer,
hb_buffer_add_utf8(hb_buffer, text.as_ptr() as *c_char,
ctext as *c_char, text.len() as c_int,
text.len() as c_int, 0,
0, text.len() as c_int);
text.len() as c_int);
}
hb_shape(self.hb_font, hb_buffer, null(), 0); hb_shape(self.hb_font, hb_buffer, null(), 0);
self.save_glyph_results(text, glyphs, hb_buffer); self.save_glyph_results(text, glyphs, hb_buffer);
@ -261,7 +250,7 @@ impl Shaper {
byteToGlyph = vec::from_elem(byte_max, NO_GLYPH); byteToGlyph = vec::from_elem(byte_max, NO_GLYPH);
} else { } else {
byteToGlyph = vec::from_elem(byte_max, CONTINUATION_BYTE); byteToGlyph = vec::from_elem(byte_max, CONTINUATION_BYTE);
for (i, _) in text.char_offset_iter() { for (i, _) in text.char_indices() {
byteToGlyph[i] = NO_GLYPH; byteToGlyph[i] = NO_GLYPH;
} }
} }
@ -283,7 +272,7 @@ impl Shaper {
debug!("text: {:s}", text); debug!("text: {:s}", text);
debug!("(char idx): char->(glyph index):"); debug!("(char idx): char->(glyph index):");
for (i, ch) in text.char_offset_iter() { for (i, ch) in text.char_indices() {
debug!("{:u}: {} --> {:d}", i, ch, byteToGlyph[i] as int); debug!("{:u}: {} --> {:d}", i, ch, byteToGlyph[i] as int);
} }
@ -309,7 +298,7 @@ impl Shaper {
// any trailing chars that do not have associated glyphs. // any trailing chars that do not have associated glyphs.
while char_byte_span.end() < byte_max { while char_byte_span.end() < byte_max {
let range = text.char_range_at(char_byte_span.end()); let range = text.char_range_at(char_byte_span.end());
ignore(range.ch); drop(range.ch);
char_byte_span.extend_to(range.next); char_byte_span.extend_to(range.next);
debug!("Processing char byte span: off={:u}, len={:u} for glyph idx={:u}", debug!("Processing char byte span: off={:u}, len={:u} for glyph idx={:u}",
@ -320,7 +309,7 @@ impl Shaper {
debug!("Extending char byte span to include byte offset={:u} with no associated \ debug!("Extending char byte span to include byte offset={:u} with no associated \
glyph", char_byte_span.end()); glyph", char_byte_span.end());
let range = text.char_range_at(char_byte_span.end()); let range = text.char_range_at(char_byte_span.end());
ignore(range.ch); drop(range.ch);
char_byte_span.extend_to(range.next); char_byte_span.extend_to(range.next);
} }
@ -329,7 +318,7 @@ impl Shaper {
let mut max_glyph_idx = glyph_span.end(); let mut max_glyph_idx = glyph_span.end();
for i in char_byte_span.eachi() { for i in char_byte_span.eachi() {
if byteToGlyph[i] > NO_GLYPH { if byteToGlyph[i] > NO_GLYPH {
max_glyph_idx = uint::max(byteToGlyph[i] as uint + 1, max_glyph_idx); max_glyph_idx = num::max(byteToGlyph[i] as uint + 1, max_glyph_idx);
} }
} }
@ -390,7 +379,7 @@ impl Shaper {
while covered_byte_span.end() < byte_max while covered_byte_span.end() < byte_max
&& byteToGlyph[covered_byte_span.end()] == NO_GLYPH { && byteToGlyph[covered_byte_span.end()] == NO_GLYPH {
let range = text.char_range_at(covered_byte_span.end()); let range = text.char_range_at(covered_byte_span.end());
ignore(range.ch); drop(range.ch);
covered_byte_span.extend_to(range.next); covered_byte_span.extend_to(range.next);
} }
@ -404,7 +393,7 @@ impl Shaper {
// clamp to end of text. (I don't think this will be necessary, but..) // clamp to end of text. (I don't think this will be necessary, but..)
let end = covered_byte_span.end(); // FIXME: borrow checker workaround let end = covered_byte_span.end(); // FIXME: borrow checker workaround
covered_byte_span.extend_to(uint::min(end, byte_max)); covered_byte_span.extend_to(num::min(end, byte_max));
// fast path: 1-to-1 mapping of single char and single glyph. // fast path: 1-to-1 mapping of single char and single glyph.
if glyph_span.length() == 1 { if glyph_span.length() == 1 {
@ -443,7 +432,7 @@ impl Shaper {
let mut i = covered_byte_span.begin(); let mut i = covered_byte_span.begin();
loop { loop {
let range = text.char_range_at(i); let range = text.char_range_at(i);
ignore(range.ch); drop(range.ch);
i = range.next; i = range.next;
if i >= covered_byte_span.end() { break; } if i >= covered_byte_span.end() { break; }
char_idx += 1; char_idx += 1;
@ -514,14 +503,14 @@ extern fn get_font_table_func(_: *hb_face_t, tag: hb_tag_t, user_data: *c_void)
let skinny_font_table_ptr: *FontTable = font_table; // private context let skinny_font_table_ptr: *FontTable = font_table; // private context
let mut blob: *hb_blob_t = null(); let mut blob: *hb_blob_t = null();
do (*skinny_font_table_ptr).with_buffer |buf: *u8, len: uint| { (*skinny_font_table_ptr).with_buffer(|buf: *u8, len: uint| {
// HarfBuzz calls `destroy_blob_func` when the buffer is no longer needed. // HarfBuzz calls `destroy_blob_func` when the buffer is no longer needed.
blob = hb_blob_create(buf as *c_char, blob = hb_blob_create(buf as *c_char,
len as c_uint, len as c_uint,
HB_MEMORY_MODE_READONLY, HB_MEMORY_MODE_READONLY,
transmute(skinny_font_table_ptr), transmute(skinny_font_table_ptr),
destroy_blob_func); destroy_blob_func);
} });
assert!(blob.is_not_null()); assert!(blob.is_not_null());
blob blob

View file

@ -22,16 +22,16 @@ pub struct TextRun {
glyphs: Arc<~[Arc<GlyphStore>]>, glyphs: Arc<~[Arc<GlyphStore>]>,
} }
pub struct SliceIterator<'self> { pub struct SliceIterator<'a> {
priv glyph_iter: VecIterator<'self, Arc<GlyphStore>>, priv glyph_iter: VecIterator<'a, Arc<GlyphStore>>,
priv range: Range, priv range: Range,
priv offset: uint, priv offset: uint,
} }
impl<'self> Iterator<(&'self GlyphStore, uint, Range)> for SliceIterator<'self> { impl<'a> Iterator<(&'a GlyphStore, uint, Range)> for SliceIterator<'a> {
// inline(always) due to the inefficient rt failures messing up inline heuristics, I think. // inline(always) due to the inefficient rt failures messing up inline heuristics, I think.
#[inline(always)] #[inline(always)]
fn next(&mut self) -> Option<(&'self GlyphStore, uint, Range)> { fn next(&mut self) -> Option<(&'a GlyphStore, uint, Range)> {
loop { loop {
let slice_glyphs = self.glyph_iter.next(); let slice_glyphs = self.glyph_iter.next();
if slice_glyphs.is_none() { if slice_glyphs.is_none() {
@ -52,13 +52,13 @@ impl<'self> Iterator<(&'self GlyphStore, uint, Range)> for SliceIterator<'self>
} }
} }
pub struct LineIterator<'self> { pub struct LineIterator<'a> {
priv range: Range, priv range: Range,
priv clump: Option<Range>, priv clump: Option<Range>,
priv slices: SliceIterator<'self>, priv slices: SliceIterator<'a>,
} }
impl<'self> Iterator<Range> for LineIterator<'self> { impl<'a> Iterator<Range> for LineIterator<'a> {
fn next(&mut self) -> Option<Range> { fn next(&mut self) -> Option<Range> {
// Loop until we hit whitespace and are in a clump. // Loop until we hit whitespace and are in a clump.
loop { loop {
@ -96,7 +96,7 @@ impl<'self> Iterator<Range> for LineIterator<'self> {
} }
} }
impl<'self> TextRun { impl<'a> TextRun {
pub fn new(font: &mut Font, text: ~str, decoration: text_decoration::T) -> TextRun { pub fn new(font: &mut Font, text: ~str, decoration: text_decoration::T) -> TextRun {
let glyphs = TextRun::break_and_shape(font, text); let glyphs = TextRun::break_and_shape(font, text);
@ -170,12 +170,12 @@ impl<'self> TextRun {
} }
pub fn char_len(&self) -> uint { pub fn char_len(&self) -> uint {
do self.glyphs.get().iter().fold(0u) |len, slice_glyphs| { self.glyphs.get().iter().fold(0u, |len, slice_glyphs| {
len + slice_glyphs.get().char_len() len + slice_glyphs.get().char_len()
} })
} }
pub fn glyphs(&'self self) -> &'self ~[Arc<GlyphStore>] { pub fn glyphs(&'a self) -> &'a ~[Arc<GlyphStore>] {
self.glyphs.get() self.glyphs.get()
} }
@ -216,7 +216,7 @@ impl<'self> TextRun {
max_piece_width max_piece_width
} }
pub fn iter_slices_for_range(&'self self, range: &Range) -> SliceIterator<'self> { pub fn iter_slices_for_range(&'a self, range: &Range) -> SliceIterator<'a> {
SliceIterator { SliceIterator {
glyph_iter: self.glyphs.get().iter(), glyph_iter: self.glyphs.get().iter(),
range: *range, range: *range,
@ -224,7 +224,7 @@ impl<'self> TextRun {
} }
} }
pub fn iter_natural_lines_for_range(&'self self, range: &Range) -> LineIterator<'self> { pub fn iter_natural_lines_for_range(&'a self, range: &Range) -> LineIterator<'a> {
LineIterator { LineIterator {
range: *range, range: *range,
clump: None, clump: None,

View file

@ -24,7 +24,7 @@ pub fn transform_text(text: &str, mode: CompressionMode, incoming_whitespace: bo
let mut out_str: ~str = ~""; let mut out_str: ~str = ~"";
let out_whitespace = match mode { let out_whitespace = match mode {
CompressNone | DiscardNewline => { CompressNone | DiscardNewline => {
for ch in text.iter() { for ch in text.chars() {
if is_discardable_char(ch, mode) { if is_discardable_char(ch, mode) {
// TODO: record skipped char // TODO: record skipped char
} else { } else {
@ -40,7 +40,7 @@ pub fn transform_text(text: &str, mode: CompressionMode, incoming_whitespace: bo
CompressWhitespace | CompressWhitespaceNewline => { CompressWhitespace | CompressWhitespaceNewline => {
let mut in_whitespace: bool = incoming_whitespace; let mut in_whitespace: bool = incoming_whitespace;
for ch in text.iter() { for ch in text.chars() {
// TODO: discard newlines between CJK chars // TODO: discard newlines between CJK chars
let mut next_in_whitespace: bool = is_in_whitespace(ch, mode); let mut next_in_whitespace: bool = is_in_whitespace(ch, mode);

View file

@ -34,13 +34,11 @@ use png;
use servo_msg::compositor_msg::{Epoch, IdleRenderState, LayerBufferSet, RenderState}; use servo_msg::compositor_msg::{Epoch, IdleRenderState, LayerBufferSet, RenderState};
use servo_msg::constellation_msg::{ConstellationChan, NavigateMsg, ResizedWindowMsg, LoadUrlMsg, PipelineId}; use servo_msg::constellation_msg::{ConstellationChan, NavigateMsg, ResizedWindowMsg, LoadUrlMsg, PipelineId};
use servo_msg::constellation_msg; use servo_msg::constellation_msg;
use servo_util::time::{profile, ProfilerChan}; use servo_util::time::{profile, ProfilerChan, Timer};
use servo_util::{time, url}; use servo_util::{time, url};
use std::comm::Port; use std::comm::Port;
use std::num::Orderable; use std::num::Orderable;
use std::path::Path; use std::path::Path;
use std::rt::io::timer::Timer;
use std::vec;
pub struct IOCompositor { pub struct IOCompositor {
@ -157,11 +155,17 @@ impl IOCompositor {
self.constellation_chan.send(ResizedWindowMsg(self.window_size)); self.constellation_chan.send(ResizedWindowMsg(self.window_size));
// Enter the main event loop. // Enter the main event loop.
let mut tm = Timer::new().unwrap();
while !self.done { while !self.done {
// Check for new messages coming from the rendering task. // Check for new messages coming from the rendering task.
self.handle_message(); self.handle_message();
if (self.done) {
// We have exited the compositor and passing window
// messages to script may crash.
debug!("Exiting the compositor due to a request from script.");
break;
}
// Check for messages coming from the windowing system. // Check for messages coming from the windowing system.
self.handle_window_message(self.window.recv()); self.handle_window_message(self.window.recv());
@ -171,7 +175,7 @@ impl IOCompositor {
self.composite(); self.composite();
} }
tm.sleep(10); Timer::sleep(10);
// If a pinch-zoom happened recently, ask for tiles at the new resolution // If a pinch-zoom happened recently, ask for tiles at the new resolution
if self.zoom_action && precise_time_s() - self.zoom_time > 0.3 { if self.zoom_action && precise_time_s() - self.zoom_time > 0.3 {
@ -189,62 +193,65 @@ impl IOCompositor {
// Drain compositor port, sometimes messages contain channels that are blocking // Drain compositor port, sometimes messages contain channels that are blocking
// another task from finishing (i.e. SetIds) // another task from finishing (i.e. SetIds)
while self.port.peek() { self.port.recv(); } while self.port.try_recv().is_some() {}
} }
fn handle_message(&mut self) { fn handle_message(&mut self) {
while self.port.peek() { loop {
match self.port.recv() { match self.port.try_recv() {
Exit => { None => break,
self.done = true
},
ChangeReadyState(ready_state) => { Some(Exit(chan)) => {
self.done = true;
chan.send(());
}
Some(ChangeReadyState(ready_state)) => {
self.window.set_ready_state(ready_state); self.window.set_ready_state(ready_state);
} }
ChangeRenderState(render_state) => { Some(ChangeRenderState(render_state)) => {
self.change_render_state(render_state); self.change_render_state(render_state);
} }
SetUnRenderedColor(_id, color) => { Some(SetUnRenderedColor(_id, color)) => {
self.set_unrendered_color(_id, color); self.set_unrendered_color(_id, color);
} }
SetIds(frame_tree, response_chan, new_constellation_chan) => { Some(SetIds(frame_tree, response_chan, new_constellation_chan)) => {
self.set_ids(frame_tree, response_chan, new_constellation_chan); self.set_ids(frame_tree, response_chan, new_constellation_chan);
} }
GetGraphicsMetadata(chan) => { Some(GetGraphicsMetadata(chan)) => {
chan.send(Some(azure_hl::current_graphics_metadata())); chan.send(Some(azure_hl::current_graphics_metadata()));
} }
NewLayer(_id, new_size) => { Some(NewLayer(_id, new_size)) => {
self.create_new_layer(_id, new_size); self.create_new_layer(_id, new_size);
} }
SetLayerPageSize(id, new_size, epoch) => { Some(SetLayerPageSize(id, new_size, epoch)) => {
self.set_layer_page_size(id, new_size, epoch); self.set_layer_page_size(id, new_size, epoch);
} }
SetLayerClipRect(id, new_rect) => { Some(SetLayerClipRect(id, new_rect)) => {
self.set_layer_clip_rect(id, new_rect); self.set_layer_clip_rect(id, new_rect);
} }
DeleteLayer(id) => { Some(DeleteLayer(id)) => {
self.delete_layer(id); self.delete_layer(id);
} }
Paint(id, new_layer_buffer_set, epoch) => { Some(Paint(id, new_layer_buffer_set, epoch)) => {
self.paint(id, new_layer_buffer_set, epoch); self.paint(id, new_layer_buffer_set, epoch);
} }
InvalidateRect(id, rect) => { Some(InvalidateRect(id, rect)) => {
self.invalidate_rect(id, rect); self.invalidate_rect(id, rect);
} }
ScrollFragmentPoint(id, point) => { Some(ScrollFragmentPoint(id, point)) => {
self.scroll_fragment_to_point(id, point); self.scroll_fragment_to_point(id, point);
} }
} }
@ -601,7 +608,7 @@ impl IOCompositor {
} }
fn composite(&mut self) { fn composite(&mut self) {
do profile(time::CompositingCategory, self.profiler_chan.clone()) { profile(time::CompositingCategory, self.profiler_chan.clone(), || {
debug!("compositor: compositing"); debug!("compositor: compositing");
// Adjust the layer dimensions as necessary to correspond to the size of the window. // Adjust the layer dimensions as necessary to correspond to the size of the window.
self.scene.size = self.window.size(); self.scene.size = self.window.size();
@ -616,7 +623,7 @@ impl IOCompositor {
None => {} None => {}
} }
rendergl::render_scene(self.context, &self.scene); rendergl::render_scene(self.context, &self.scene);
} });
// Render to PNG. We must read from the back buffer (ie, before // Render to PNG. We must read from the back buffer (ie, before
// self.window.present()) as OpenGL ES 2 does not have glReadBuffer(). // self.window.present()) as OpenGL ES 2 does not have glReadBuffer().
@ -634,9 +641,10 @@ impl IOCompositor {
for y in range(0, height) { for y in range(0, height) {
let dst_start = y * stride; let dst_start = y * stride;
let src_start = (height - y - 1) * stride; let src_start = (height - y - 1) * stride;
vec::bytes::copy_memory(pixels.mut_slice(dst_start, dst_start + stride), unsafe {
orig_pixels.slice(src_start, src_start + stride), pixels.mut_slice(dst_start, dst_start + stride)
stride); .copy_memory(orig_pixels.slice(src_start, src_start + stride).slice_to(stride));
}
} }
let img = png::Image { let img = png::Image {
width: width as u32, width: width as u32,

View file

@ -22,7 +22,6 @@ use script::dom::event::{ClickEvent, MouseDownEvent, MouseUpEvent};
use script::script_task::SendEventMsg; use script::script_task::SendEventMsg;
use servo_msg::compositor_msg::{LayerBuffer, LayerBufferSet, Epoch, Tile}; use servo_msg::compositor_msg::{LayerBuffer, LayerBufferSet, Epoch, Tile};
use servo_msg::constellation_msg::PipelineId; use servo_msg::constellation_msg::PipelineId;
use std::cell::Cell;
use windowing::{MouseWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEvent}; use windowing::{MouseWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEvent};
use windowing::{MouseWindowMouseUpEvent}; use windowing::{MouseWindowMouseUpEvent};
use azure::azure_hl::Color; use azure::azure_hl::Color;
@ -141,7 +140,7 @@ impl CompositorLayer {
-> CompositorLayer { -> CompositorLayer {
let SendableFrameTree { pipeline, children } = frame_tree; let SendableFrameTree { pipeline, children } = frame_tree;
let mut layer = CompositorLayer::new(pipeline, None, tile_size, max_mem, cpu_painting); let mut layer = CompositorLayer::new(pipeline, None, tile_size, max_mem, cpu_painting);
layer.children = (do children.move_iter().map |child| { layer.children = (children.move_iter().map(|child| {
let SendableChildFrameTree { frame_tree, rect } = child; let SendableChildFrameTree { frame_tree, rect } = child;
let container = @mut ContainerLayer(); let container = @mut ContainerLayer();
match rect { match rect {
@ -165,7 +164,7 @@ impl CompositorLayer {
child: child_layer, child: child_layer,
container: container, container: container,
} }
}).collect(); })).collect();
layer.set_occlusions(); layer.set_occlusions();
layer layer
} }
@ -267,7 +266,7 @@ impl CompositorLayer {
let mut redisplay: bool; let mut redisplay: bool;
{ // block here to prevent double mutable borrow of self { // block here to prevent double mutable borrow of self
let quadtree = match self.quadtree { let quadtree = match self.quadtree {
NoTree(*) => fail!("CompositorLayer: cannot get buffer request for {:?}, NoTree(..) => fail!("CompositorLayer: cannot get buffer request for {:?},
no quadtree initialized", self.pipeline.id), no quadtree initialized", self.pipeline.id),
Tree(ref mut quadtree) => quadtree, Tree(ref mut quadtree) => quadtree,
}; };
@ -327,7 +326,7 @@ impl CompositorLayer {
let old_rect = con.scissor; let old_rect = con.scissor;
con.scissor = Some(new_rect); con.scissor = Some(new_rect);
match self.quadtree { match self.quadtree {
NoTree(*) => {} // Nothing to do NoTree(..) => {} // Nothing to do
Tree(ref mut quadtree) => { Tree(ref mut quadtree) => {
match old_rect { match old_rect {
Some(old_rect) => { Some(old_rect) => {
@ -494,15 +493,15 @@ impl CompositorLayer {
// Delete old layer. // Delete old layer.
while current_layer_child.is_some() { while current_layer_child.is_some() {
let trash = current_layer_child.unwrap(); let trash = current_layer_child.unwrap();
do current_layer_child.unwrap().with_common |common| { current_layer_child.unwrap().with_common(|common| {
current_layer_child = common.next_sibling; current_layer_child = common.next_sibling;
} });
self.root_layer.remove_child(trash); self.root_layer.remove_child(trash);
} }
// Add new tiles. // Add new tiles.
let quadtree = match self.quadtree { let quadtree = match self.quadtree {
NoTree(*) => fail!("CompositorLayer: cannot build layer tree for {:?}, NoTree(..) => fail!("CompositorLayer: cannot build layer tree for {:?},
no quadtree initialized", self.pipeline.id), no quadtree initialized", self.pipeline.id),
Tree(ref mut quadtree) => quadtree, Tree(ref mut quadtree) => quadtree,
}; };
@ -544,9 +543,9 @@ impl CompositorLayer {
buffer.native_surface.bind_to_texture(graphics_context, texture, size); buffer.native_surface.bind_to_texture(graphics_context, texture, size);
// Move on to the next sibling. // Move on to the next sibling.
do current_layer_child.unwrap().with_common |common| { current_layer_child.unwrap().with_common(|common| {
common.next_sibling common.next_sibling
} })
} }
Some(_) => fail!(~"found unexpected layer kind"), Some(_) => fail!(~"found unexpected layer kind"),
}; };
@ -584,29 +583,29 @@ impl CompositorLayer {
pub fn add_buffers(&mut self, pub fn add_buffers(&mut self,
graphics_context: &NativeCompositingGraphicsContext, graphics_context: &NativeCompositingGraphicsContext,
pipeline_id: PipelineId, pipeline_id: PipelineId,
new_buffers: ~LayerBufferSet, mut new_buffers: ~LayerBufferSet,
epoch: Epoch) epoch: Epoch)
-> Option<~LayerBufferSet> { -> Option<~LayerBufferSet> {
let cell = Cell::new(new_buffers);
if self.pipeline.id == pipeline_id { if self.pipeline.id == pipeline_id {
if self.epoch != epoch { if self.epoch != epoch {
debug!("compositor epoch mismatch: {:?} != {:?}, id: {:?}", debug!("compositor epoch mismatch: {:?} != {:?}, id: {:?}",
self.epoch, self.epoch,
epoch, epoch,
self.pipeline.id); self.pipeline.id);
self.pipeline.render_chan.send(UnusedBufferMsg(cell.take().buffers)); self.pipeline.render_chan.send(UnusedBufferMsg(new_buffers.buffers));
return None; return None;
} }
{ {
// Block here to prevent double mutable borrow of self. // Block here to prevent double mutable borrow of self.
let quadtree = match self.quadtree { let quadtree = match self.quadtree {
NoTree(*) => fail!("CompositorLayer: cannot add buffers, no quadtree initialized"), NoTree(..) => fail!("CompositorLayer: cannot add buffers, no quadtree initialized"),
Tree(ref mut quadtree) => quadtree, Tree(ref mut quadtree) => quadtree,
}; };
let mut unused_tiles = ~[]; let mut unused_tiles = ~[];
// move_rev_iter is more efficient // move_rev_iter is more efficient
for buffer in cell.take().buffers.move_rev_iter() { for buffer in new_buffers.buffers.move_rev_iter() {
unused_tiles.push_all_move(quadtree.add_tile_pixel(buffer.screen_pos.origin.x, unused_tiles.push_all_move(quadtree.add_tile_pixel(buffer.screen_pos.origin.x,
buffer.screen_pos.origin.y, buffer.screen_pos.origin.y,
buffer.resolution, buffer)); buffer.resolution, buffer));
@ -623,15 +622,15 @@ impl CompositorLayer {
for child_layer in self.children.mut_iter() { for child_layer in self.children.mut_iter() {
match child_layer.child.add_buffers(graphics_context, match child_layer.child.add_buffers(graphics_context,
pipeline_id, pipeline_id,
cell.take(), new_buffers,
epoch) { epoch) {
None => return None, None => return None,
Some(buffers) => cell.put_back(buffers), Some(buffers) => new_buffers = buffers,
} }
} }
// Not found. Give the caller the buffers back. // Not found. Give the caller the buffers back.
Some(cell.take()) Some(new_buffers)
} }
// Deletes a specified sublayer, including hidden children. Returns false if the layer is not found. // Deletes a specified sublayer, including hidden children. Returns false if the layer is not found.
@ -643,7 +642,7 @@ impl CompositorLayer {
Some(i) => { Some(i) => {
let mut child = self.children.remove(i); let mut child = self.children.remove(i);
match self.quadtree { match self.quadtree {
NoTree(*) => {} // Nothing to do NoTree(..) => {} // Nothing to do
Tree(ref mut quadtree) => { Tree(ref mut quadtree) => {
match child.container.scissor { match child.container.scissor {
Some(rect) => { Some(rect) => {
@ -670,7 +669,7 @@ impl CompositorLayer {
pub fn invalidate_rect(&mut self, pipeline_id: PipelineId, rect: Rect<f32>) -> bool { pub fn invalidate_rect(&mut self, pipeline_id: PipelineId, rect: Rect<f32>) -> bool {
if self.pipeline.id == pipeline_id { if self.pipeline.id == pipeline_id {
let quadtree = match self.quadtree { let quadtree = match self.quadtree {
NoTree(*) => return true, // Nothing to do NoTree(..) => return true, // Nothing to do
Tree(ref mut quadtree) => quadtree, Tree(ref mut quadtree) => quadtree,
}; };
quadtree.set_status_page(rect, Invalid, true); quadtree.set_status_page(rect, Invalid, true);
@ -681,32 +680,11 @@ impl CompositorLayer {
} }
} }
// Adds a child.
pub fn add_child(&mut self, pipeline: CompositionPipeline, page_size: Option<Size2D<f32>>, tile_size: uint,
max_mem: Option<uint>, clipping_rect: Rect<f32>) {
let container = @mut ContainerLayer();
container.scissor = Some(clipping_rect);
container.common.set_transform(identity().translate(clipping_rect.origin.x,
clipping_rect.origin.y,
0.0));
let child = ~CompositorLayer::new(pipeline,
page_size,
tile_size,
max_mem,
self.cpu_painting);
container.add_child_start(ContainerLayerKind(child.root_layer));
self.children.push(CompositorLayerChild {
child: child,
container: container,
});
self.set_occlusions();
}
// Recursively sets occluded portions of quadtrees to Hidden, so that they do not ask for // Recursively sets occluded portions of quadtrees to Hidden, so that they do not ask for
// tile requests. If layers are moved, resized, or deleted, these portions may be updated. // tile requests. If layers are moved, resized, or deleted, these portions may be updated.
fn set_occlusions(&mut self) { fn set_occlusions(&mut self) {
let quadtree = match self.quadtree { let quadtree = match self.quadtree {
NoTree(*) => return, // Cannot calculate occlusions NoTree(..) => return, // Cannot calculate occlusions
Tree(ref mut quadtree) => quadtree, Tree(ref mut quadtree) => quadtree,
}; };
for child in self.children.iter().filter(|x| !x.child.hidden) { for child in self.children.iter().filter(|x| !x.child.hidden) {
@ -726,7 +704,7 @@ impl CompositorLayer {
/// reused. /// reused.
fn clear(&mut self) { fn clear(&mut self) {
match self.quadtree { match self.quadtree {
NoTree(*) => {} NoTree(..) => {}
Tree(ref mut quadtree) => { Tree(ref mut quadtree) => {
let mut tiles = quadtree.collect_tiles(); let mut tiles = quadtree.collect_tiles();
@ -759,7 +737,7 @@ impl CompositorLayer {
/// This is used during shutdown, when we know the render task is going away. /// This is used during shutdown, when we know the render task is going away.
pub fn forget_all_tiles(&mut self) { pub fn forget_all_tiles(&mut self) {
match self.quadtree { match self.quadtree {
NoTree(*) => {} NoTree(..) => {}
Tree(ref mut quadtree) => { Tree(ref mut quadtree) => {
let tiles = quadtree.collect_tiles(); let tiles = quadtree.collect_tiles();
for tile in tiles.move_iter() { for tile in tiles.move_iter() {

View file

@ -19,7 +19,6 @@ use servo_msg::compositor_msg::{ScriptListener, Tile};
use servo_msg::constellation_msg::{ConstellationChan, PipelineId, ExitMsg}; use servo_msg::constellation_msg::{ConstellationChan, PipelineId, ExitMsg};
use servo_util::time::ProfilerChan; use servo_util::time::ProfilerChan;
use std::comm::{Chan, SharedChan, Port}; use std::comm::{Chan, SharedChan, Port};
use std::comm;
use std::num::Orderable; use std::num::Orderable;
#[cfg(target_os="linux")] #[cfg(target_os="linux")]
@ -54,7 +53,9 @@ impl ScriptListener for CompositorChan {
} }
fn close(&self) { fn close(&self) {
self.chan.send(Exit); let (port, chan) = Chan::new();
self.chan.send(Exit(chan));
port.recv();
} }
} }
@ -62,7 +63,7 @@ impl ScriptListener for CompositorChan {
/// Implementation of the abstract `RenderListener` interface. /// Implementation of the abstract `RenderListener` interface.
impl RenderListener for CompositorChan { impl RenderListener for CompositorChan {
fn get_graphics_metadata(&self) -> Option<NativeGraphicsMetadata> { fn get_graphics_metadata(&self) -> Option<NativeGraphicsMetadata> {
let (port, chan) = comm::stream(); let (port, chan) = Chan::new();
self.chan.send(GetGraphicsMetadata(chan)); self.chan.send(GetGraphicsMetadata(chan));
port.recv() port.recv()
} }
@ -99,10 +100,12 @@ impl RenderListener for CompositorChan {
} }
impl CompositorChan { impl CompositorChan {
pub fn new(chan: Chan<Msg>) -> CompositorChan { pub fn new() -> (Port<Msg>, CompositorChan) {
CompositorChan { let (port, chan) = SharedChan::new();
chan: SharedChan::new(chan), let compositor_chan = CompositorChan {
} chan: chan,
};
(port, compositor_chan)
} }
pub fn send(&self, msg: Msg) { pub fn send(&self, msg: Msg) {
@ -113,7 +116,7 @@ impl CompositorChan {
/// Messages from the painting task and the constellation task to the compositor task. /// Messages from the painting task and the constellation task to the compositor task.
pub enum Msg { pub enum Msg {
/// Requests that the compositor shut down. /// Requests that the compositor shut down.
Exit, Exit(Chan<()>),
/// Requests the compositor's graphics metadata. Graphics metadata is what the renderer needs /// Requests the compositor's graphics metadata. Graphics metadata is what the renderer needs
/// to create surfaces that the compositor can see. On Linux this is the X display; on Mac this /// to create surfaces that the compositor can see. On Linux this is the X display; on Mac this
/// is the pixel format. /// is the pixel format.

View file

@ -38,7 +38,10 @@ impl NullCompositor {
fn handle_message(&self) { fn handle_message(&self) {
loop { loop {
match self.port.recv() { match self.port.recv() {
Exit => break, Exit(chan) => {
chan.send(());
break
}
GetGraphicsMetadata(chan) => { GetGraphicsMetadata(chan) => {
chan.send(None); chan.send(None);
@ -52,9 +55,9 @@ impl NullCompositor {
// we'll notice and think about whether it needs a response, like // we'll notice and think about whether it needs a response, like
// SetIds. // SetIds.
NewLayer(*) | SetLayerPageSize(*) | SetLayerClipRect(*) | DeleteLayer(*) | NewLayer(..) | SetLayerPageSize(..) | SetLayerClipRect(..) | DeleteLayer(..) |
Paint(*) | InvalidateRect(*) | ChangeReadyState(*) | ChangeRenderState(*)| Paint(..) | InvalidateRect(..) | ChangeReadyState(..) | ChangeRenderState(..)|
ScrollFragmentPoint(*) | SetUnRenderedColor(*) ScrollFragmentPoint(..) | SetUnRenderedColor(..)
=> () => ()
} }
} }

View file

@ -18,8 +18,6 @@ use servo_msg::compositor_msg::Tile;
#[cfg(test)] #[cfg(test)]
use layers::platform::surface::NativePaintingGraphicsContext; use layers::platform::surface::NativePaintingGraphicsContext;
static HEADER: &'static str = "<!DOCTYPE html><html>";
/// Parent to all quadtree nodes. Stores variables needed at all levels. All method calls /// Parent to all quadtree nodes. Stores variables needed at all levels. All method calls
/// at this level are in pixel coordinates. /// at this level are in pixel coordinates.
pub struct Quadtree<T> { pub struct Quadtree<T> {
@ -101,20 +99,6 @@ impl<T: Tile> Quadtree<T> {
} }
} }
/// Return the maximum allowed tile size
pub fn get_tile_size(&self) -> uint {
self.max_tile_size
}
/// Get a tile at a given pixel position and scale.
pub fn get_tile_pixel<'r>(&'r self, x: uint, y: uint, scale: f32) -> &'r Option<T> {
self.root.get_tile(x as f32 / scale, y as f32 / scale)
}
/// Get a tile at a given page position.
pub fn get_tile_page<'r>(&'r self, x: f32, y: f32) -> &'r Option<T> {
self.root.get_tile(x, y)
}
/// Add a tile associated with a given pixel position and scale. /// Add a tile associated with a given pixel position and scale.
/// If the tile pushes the total memory over its maximum, tiles will be removed /// If the tile pushes the total memory over its maximum, tiles will be removed
/// until total memory is below the maximum again. These tiles are returned. /// until total memory is below the maximum again. These tiles are returned.
@ -137,73 +121,17 @@ impl<T: Tile> Quadtree<T> {
tiles tiles
} }
/// Add a tile associated with a given page position.
/// If the tile pushes the total memory over its maximum, tiles will be removed
/// until total memory is below the maximum again. These tiles are returned.
pub fn add_tile_page(&mut self, x: f32, y: f32, scale: f32, tile: T) -> ~[T] {
let (_, tiles) = self.root.add_tile(x, y, tile, self.max_tile_size as f32 / scale);
let mut tiles = tiles;
match self.max_mem {
Some(max) => {
while self.root.tile_mem > max {
let r = self.root.remove_tile(x, y);
match r {
(Some(tile), _, _) => tiles.push(tile),
_ => fail!("Quadtree: No valid tiles to remove"),
}
}
}
None => {} // Nothing to do
}
tiles
}
/// Get the tile rect in screen and page coordinates for a given pixel position.
pub fn get_tile_rect_pixel(&mut self, x: uint, y: uint, scale: f32) -> BufferRequest {
self.root.get_tile_rect(x as f32 / scale, y as f32 / scale,
self.clip_size.width as f32,
self.clip_size.height as f32,
scale, self.max_tile_size as f32 / scale)
}
/// Get the tile rect in screen and page coordinates for a given page position.
pub fn get_tile_rect_page(&mut self, x: f32, y: f32, scale: f32) -> BufferRequest {
self.root.get_tile_rect(x, y,
self.clip_size.width as f32,
self.clip_size.height as f32,
scale, self.max_tile_size as f32 / scale)
}
/// Get all the tiles in the tree. /// Get all the tiles in the tree.
pub fn get_all_tiles<'r>(&'r self) -> ~[&'r T] { pub fn get_all_tiles<'r>(&'r self) -> ~[&'r T] {
self.root.get_all_tiles() self.root.get_all_tiles()
} }
/// Ask a tile to be deleted from the quadtree. This tries to delete a tile that is far from the
/// given point in pixel coordinates.
pub fn remove_tile_pixel(&mut self, x: uint, y: uint, scale: f32) -> T {
let r = self.root.remove_tile(x as f32 / scale, y as f32 / scale);
match r {
(Some(tile), _, _) => tile,
_ => fail!("Quadtree: No valid tiles to remove"),
}
}
/// Ask a tile to be deleted from the quadtree. This tries to delete a tile that is far from the
/// given point in page coordinates.
pub fn remove_tile_page(&mut self, x: f32, y: f32) -> T {
let r = self.root.remove_tile(x, y);
match r {
(Some(tile), _, _) => tile,
_ => fail!("Quadtree: No valid tiles to remove"),
}
}
/// Given a window rect in pixel coordinates, this function returns a list of BufferRequests for tiles that /// Given a window rect in pixel coordinates, this function returns a list of BufferRequests for tiles that
/// need to be rendered. It also returns a vector of tiles if the window needs to be redisplayed, i.e. if /// need to be rendered. It also returns a vector of tiles if the window needs to be redisplayed, i.e. if
/// no tiles need to be rendered, but the display tree needs to be rebuilt. This can occur when the /// no tiles need to be rendered, but the display tree needs to be rebuilt. This can occur when the
/// user zooms out and cached tiles need to be displayed on top of higher resolution tiles. /// user zooms out and cached tiles need to be displayed on top of higher resolution tiles.
/// When this happens, higher resolution tiles will be removed from the quadtree. /// When this happens, higher resolution tiles will be removed from the quadtree.
#[cfg(test)]
pub fn get_tile_rects_pixel(&mut self, window: Rect<int>, scale: f32) -> (~[BufferRequest], ~[T]) { pub fn get_tile_rects_pixel(&mut self, window: Rect<int>, scale: f32) -> (~[BufferRequest], ~[T]) {
let (ret, unused, _) = self.root.get_tile_rects( let (ret, unused, _) = self.root.get_tile_rects(
Rect(Point2D(window.origin.x as f32 / scale, window.origin.y as f32 / scale), Rect(Point2D(window.origin.x as f32 / scale, window.origin.y as f32 / scale),
@ -245,6 +173,7 @@ impl<T: Tile> Quadtree<T> {
/// Resize the underlying quadtree without removing tiles already in place. /// Resize the underlying quadtree without removing tiles already in place.
/// Might be useful later on, but resize() should be used for now. /// Might be useful later on, but resize() should be used for now.
/// TODO: return tiles after shrinking /// TODO: return tiles after shrinking
#[cfg(test)]
pub fn bad_resize(&mut self, width: uint, height: uint) { pub fn bad_resize(&mut self, width: uint, height: uint) {
self.clip_size = Size2D(width, height); self.clip_size = Size2D(width, height);
let longer = width.max(&height); let longer = width.max(&height);
@ -301,11 +230,6 @@ impl<T: Tile> Quadtree<T> {
pub fn collect_tiles(&mut self) -> ~[T] { pub fn collect_tiles(&mut self) -> ~[T] {
self.root.collect_tiles() self.root.collect_tiles()
} }
/// Generate html to visualize the tree. For debugging purposes only.
pub fn get_html(&self) -> ~str {
format!("{:s}<body>{:s}</body></html>", HEADER, self.root.get_html())
}
} }
impl<T: Tile> QuadtreeNode<T> { impl<T: Tile> QuadtreeNode<T> {
@ -336,20 +260,6 @@ impl<T: Tile> QuadtreeNode<T> {
} }
} }
/// Get the lowest-level (highest resolution) tile associated with a given position in page coords.
fn get_tile<'r> (&'r self, x: f32, y: f32) -> &'r Option<T> {
if x >= self.origin.x + self.size || x < self.origin.x
|| y >= self.origin.y + self.size || y < self.origin.y {
fail!("Quadtree: Tried to get a tile outside of range");
}
let index = self.get_quadrant(x, y) as int;
match self.quadrants[index] {
None => &'r self.tile,
Some(ref child) => child.get_tile(x, y),
}
}
/// Get all tiles in the tree, parents first. /// Get all tiles in the tree, parents first.
fn get_all_tiles<'r>(&'r self) -> ~[&'r T] { fn get_all_tiles<'r>(&'r self) -> ~[&'r T] {
let mut ret = ~[]; let mut ret = ~[];
@ -602,7 +512,7 @@ impl<T: Tile> QuadtreeNode<T> {
let w_br_quad = self.get_quadrant(w_x + w_width, w_y + w_height); let w_br_quad = self.get_quadrant(w_x + w_width, w_y + w_height);
// Figure out which quadrants the window is in // Figure out which quadrants the window is in
let builder = |push: &fn(Quadrant)| { let builder = |push: |Quadrant|| {
match (w_tl_quad, w_br_quad) { match (w_tl_quad, w_br_quad) {
(tl, br) if tl as int == br as int => { (tl, br) if tl as int == br as int => {
push(tl); push(tl);
@ -734,44 +644,6 @@ impl<T: Tile> QuadtreeNode<T> {
} }
} }
} }
/// Generate html to visualize the tree.
/// This is really inefficient, but it's for testing only.
fn get_html(&self) -> ~str {
let mut ret = ~"";
match self.tile {
Some(ref tile) => {
ret = format!("{:s}{:?}", ret, tile);
}
None => {
ret = format!("{:s}NO TILE", ret);
}
}
match self.quadrants {
[None, None, None, None] => {}
_ => {
ret = format!("{:s}<table border=1><tr>", ret);
// FIXME: This should be inline, but currently won't compile
let quads = [TL, TR, BL, BR];
for quad in quads.iter() {
match self.quadrants[*quad as int] {
Some(ref child) => {
ret = format!("{:s}<td>{:s}</td>", ret, child.get_html());
}
None => {
ret = format!("{:s}<td>EMPTY CHILD</td>", ret);
}
}
match *quad {
TR => ret = format!("{:s}</tr><tr>", ret),
_ => {}
}
}
ret = format!("{:s}</table>\n", ret);
}
}
return ret;
}
} }
#[test] #[test]

View file

@ -20,10 +20,7 @@ use servo_net::resource_task::ResourceTask;
use servo_net::resource_task; use servo_net::resource_task;
use servo_util::time::ProfilerChan; use servo_util::time::ProfilerChan;
use servo_util::url::make_url; use servo_util::url::make_url;
use std::comm::Port;
use std::comm;
use std::hashmap::{HashMap, HashSet}; use std::hashmap::{HashMap, HashSet};
use std::task::spawn_with;
use std::util::replace; use std::util::replace;
/// Maintains the pipelines and navigation context and grants permission to composite /// Maintains the pipelines and navigation context and grants permission to composite
@ -53,9 +50,9 @@ struct FrameTree {
// Need to clone the FrameTrees, but _not_ the Pipelines // Need to clone the FrameTrees, but _not_ the Pipelines
impl Clone for FrameTree { impl Clone for FrameTree {
fn clone(&self) -> FrameTree { fn clone(&self) -> FrameTree {
let mut children = do self.children.iter().map |child_frame_tree| { let mut children = self.children.iter().map(|child_frame_tree| {
child_frame_tree.clone() child_frame_tree.clone()
}; });
FrameTree { FrameTree {
pipeline: self.pipeline, pipeline: self.pipeline,
parent: self.parent.clone(), parent: self.parent.clone(),
@ -90,41 +87,46 @@ pub struct SendableChildFrameTree {
rect: Option<Rect<f32>>, rect: Option<Rect<f32>>,
} }
impl SendableFrameTree { // impl SendableFrameTree {
fn contains(&self, id: PipelineId) -> bool { // fn contains(&self, id: PipelineId) -> bool {
self.pipeline.id == id || // self.pipeline.id == id ||
do self.children.iter().any |&SendableChildFrameTree { frame_tree: ref frame_tree, _ }| { // self.children.iter().any(|&SendableChildFrameTree { frame_tree: ref frame_tree, .. }| {
frame_tree.contains(id) // frame_tree.contains(id)
} // })
} // }
// }
enum ReplaceResult {
ReplacedNode(@mut FrameTree),
OriginalNode(@mut FrameTree),
} }
impl FrameTree { impl FrameTree {
fn contains(@mut self, id: PipelineId) -> bool { fn contains(@mut self, id: PipelineId) -> bool {
do self.iter().any |frame_tree| { self.iter().any(|frame_tree| {
id == frame_tree.pipeline.id id == frame_tree.pipeline.id
} })
} }
/// Returns the frame tree whose key is id /// Returns the frame tree whose key is id
fn find(@mut self, id: PipelineId) -> Option<@mut FrameTree> { fn find(@mut self, id: PipelineId) -> Option<@mut FrameTree> {
do self.iter().find |frame_tree| { self.iter().find(|frame_tree| {
id == frame_tree.pipeline.id id == frame_tree.pipeline.id
} })
} }
/// Replaces a node of the frame tree in place. Returns the node that was removed or the original node /// Replaces a node of the frame tree in place. Returns the node that was removed or the original node
/// if the node to replace could not be found. /// if the node to replace could not be found.
fn replace_child(@mut self, id: PipelineId, new_child: @mut FrameTree) -> Either<@mut FrameTree, @mut FrameTree> { fn replace_child(@mut self, id: PipelineId, new_child: @mut FrameTree) -> ReplaceResult {
for frame_tree in self.iter() { for frame_tree in self.iter() {
let mut child = frame_tree.children.mut_iter() let mut child = frame_tree.children.mut_iter()
.find(|child| child.frame_tree.pipeline.id == id); .find(|child| child.frame_tree.pipeline.id == id);
for child in child.mut_iter() { for child in child.mut_iter() {
new_child.parent = child.frame_tree.parent; new_child.parent = child.frame_tree.parent;
return Left(replace(&mut child.frame_tree, new_child)); return ReplacedNode(replace(&mut child.frame_tree, new_child));
} }
} }
Right(new_child) OriginalNode(new_child)
} }
fn to_sendable(&self) -> SendableFrameTree { fn to_sendable(&self) -> SendableFrameTree {
@ -162,7 +164,7 @@ impl Iterator<@mut FrameTree> for FrameTreeIterator {
fn next(&mut self) -> Option<@mut FrameTree> { fn next(&mut self) -> Option<@mut FrameTree> {
if !self.stack.is_empty() { if !self.stack.is_empty() {
let next = self.stack.pop(); let next = self.stack.pop();
for &ChildFrameTree { frame_tree, _ } in next.children.rev_iter() { for &ChildFrameTree { frame_tree, .. } in next.children.rev_iter() {
self.stack.push(frame_tree); self.stack.push(frame_tree);
} }
Some(next) Some(next)
@ -223,15 +225,15 @@ impl NavigationContext {
/// Returns the frame trees whose keys are pipeline_id. /// Returns the frame trees whose keys are pipeline_id.
pub fn find_all(&mut self, pipeline_id: PipelineId) -> ~[@mut FrameTree] { pub fn find_all(&mut self, pipeline_id: PipelineId) -> ~[@mut FrameTree] {
let from_current = do self.current.iter().filter_map |frame_tree| { let from_current = self.current.iter().filter_map(|frame_tree| {
frame_tree.find(pipeline_id) frame_tree.find(pipeline_id)
}; });
let from_next = do self.next.iter().filter_map |frame_tree| { let from_next = self.next.iter().filter_map(|frame_tree| {
frame_tree.find(pipeline_id) frame_tree.find(pipeline_id)
}; });
let from_prev = do self.previous.iter().filter_map |frame_tree| { let from_prev = self.previous.iter().filter_map(|frame_tree| {
frame_tree.find(pipeline_id) frame_tree.find(pipeline_id)
}; });
from_prev.chain(from_current).chain(from_next).collect() from_prev.chain(from_current).chain(from_next).collect()
} }
@ -241,36 +243,25 @@ impl NavigationContext {
let from_prev = self.previous.iter(); let from_prev = self.previous.iter();
let mut all_contained = from_prev.chain(from_current).chain(from_next); let mut all_contained = from_prev.chain(from_current).chain(from_next);
do all_contained.any |frame_tree| { all_contained.any(|frame_tree| {
frame_tree.contains(pipeline_id) frame_tree.contains(pipeline_id)
} })
} }
} }
impl Constellation { impl Constellation {
pub fn start(constellation_port: Port<Msg>, pub fn start(compositor_chan: CompositorChan,
constellation_chan: ConstellationChan,
compositor_chan: CompositorChan,
opts: &Opts, opts: &Opts,
resource_task: ResourceTask, resource_task: ResourceTask,
image_cache_task: ImageCacheTask, image_cache_task: ImageCacheTask,
profiler_chan: ProfilerChan) { profiler_chan: ProfilerChan)
do spawn_with((constellation_port, -> ConstellationChan {
constellation_chan.clone(), let (constellation_port, constellation_chan) = ConstellationChan::new();
compositor_chan, let constellation_chan_clone = constellation_chan.clone();
resource_task, let opts_clone = opts.clone();
image_cache_task, spawn(proc() {
profiler_chan,
opts.clone()))
|(constellation_port,
constellation_chan,
compositor_chan,
resource_task,
image_cache_task,
profiler_chan,
opts)| {
let mut constellation = Constellation { let mut constellation = Constellation {
chan: constellation_chan, chan: constellation_chan_clone,
request_port: constellation_port, request_port: constellation_port,
compositor_chan: compositor_chan, compositor_chan: compositor_chan,
resource_task: resource_task, resource_task: resource_task,
@ -282,10 +273,11 @@ impl Constellation {
pending_sizes: HashMap::new(), pending_sizes: HashMap::new(),
profiler_chan: profiler_chan, profiler_chan: profiler_chan,
window_size: Size2D(500u, 500u), window_size: Size2D(500u, 500u),
opts: opts opts: opts_clone,
}; };
constellation.run(); constellation.run();
} });
constellation_chan
} }
fn run(&mut self) { fn run(&mut self) {
@ -313,9 +305,9 @@ impl Constellation {
/// Returns both the navigation context and pending frame trees whose keys are pipeline_id. /// Returns both the navigation context and pending frame trees whose keys are pipeline_id.
pub fn find_all(&mut self, pipeline_id: PipelineId) -> ~[@mut FrameTree] { pub fn find_all(&mut self, pipeline_id: PipelineId) -> ~[@mut FrameTree] {
let matching_navi_frames = self.navigation_context.find_all(pipeline_id); let matching_navi_frames = self.navigation_context.find_all(pipeline_id);
let matching_pending_frames = do self.pending_frames.iter().filter_map |frame_change| { let matching_pending_frames = self.pending_frames.iter().filter_map(|frame_change| {
frame_change.after.find(pipeline_id) frame_change.after.find(pipeline_id)
}; });
matching_navi_frames.move_iter().chain(matching_pending_frames).collect() matching_navi_frames.move_iter().chain(matching_pending_frames).collect()
} }
@ -323,6 +315,7 @@ impl Constellation {
fn handle_request(&mut self, request: Msg) -> bool { fn handle_request(&mut self, request: Msg) -> bool {
match request { match request {
ExitMsg(sender) => { ExitMsg(sender) => {
debug!("constellation exiting");
self.handle_exit(sender); self.handle_exit(sender);
return false; return false;
} }
@ -499,9 +492,9 @@ impl Constellation {
// and add the new pipeline to their sub frames. // and add the new pipeline to their sub frames.
let frame_trees: ~[@mut FrameTree] = { let frame_trees: ~[@mut FrameTree] = {
let matching_navi_frames = self.navigation_context.find_all(source_pipeline_id); let matching_navi_frames = self.navigation_context.find_all(source_pipeline_id);
let matching_pending_frames = do self.pending_frames.iter().filter_map |frame_change| { let matching_pending_frames = self.pending_frames.iter().filter_map(|frame_change| {
frame_change.after.find(source_pipeline_id) frame_change.after.find(source_pipeline_id)
}; });
matching_navi_frames.move_iter().chain(matching_pending_frames).collect() matching_navi_frames.move_iter().chain(matching_pending_frames).collect()
}; };
@ -681,9 +674,9 @@ impl Constellation {
// Find the pending frame change whose new pipeline id is pipeline_id. // Find the pending frame change whose new pipeline id is pipeline_id.
// If it is not found, it simply means that this pipeline will not receive // If it is not found, it simply means that this pipeline will not receive
// permission to paint. // permission to paint.
let pending_index = do self.pending_frames.iter().rposition |frame_change| { let pending_index = self.pending_frames.iter().rposition(|frame_change| {
frame_change.after.pipeline.id == pipeline_id frame_change.after.pipeline.id == pipeline_id
}; });
for &pending_index in pending_index.iter() { for &pending_index in pending_index.iter() {
let frame_change = self.pending_frames.swap_remove(pending_index); let frame_change = self.pending_frames.swap_remove(pending_index);
let to_add = frame_change.after; let to_add = frame_change.after;
@ -742,9 +735,9 @@ impl Constellation {
/// Called when the window is resized. /// Called when the window is resized.
fn handle_resized_window_msg(&mut self, new_size: Size2D<uint>) { fn handle_resized_window_msg(&mut self, new_size: Size2D<uint>) {
let mut already_seen = HashSet::new(); let mut already_seen = HashSet::new();
for &@FrameTree { pipeline: pipeline, _ } in self.current_frame().iter() { for &@FrameTree { pipeline: pipeline, .. } in self.current_frame().iter() {
debug!("constellation sending resize message to active frame"); debug!("constellation sending resize message to active frame");
pipeline.script_chan.send(ResizeMsg(pipeline.id, new_size)); pipeline.script_chan.try_send(ResizeMsg(pipeline.id, new_size));
already_seen.insert(pipeline.id); already_seen.insert(pipeline.id);
} }
for frame_tree in self.navigation_context.previous.iter() for frame_tree in self.navigation_context.previous.iter()
@ -752,7 +745,7 @@ impl Constellation {
let pipeline = &frame_tree.pipeline; let pipeline = &frame_tree.pipeline;
if !already_seen.contains(&pipeline.id) { if !already_seen.contains(&pipeline.id) {
debug!("constellation sending resize message to inactive frame"); debug!("constellation sending resize message to inactive frame");
pipeline.script_chan.send(ResizeInactiveMsg(pipeline.id, new_size)); pipeline.script_chan.try_send(ResizeInactiveMsg(pipeline.id, new_size));
already_seen.insert(pipeline.id); already_seen.insert(pipeline.id);
} }
} }
@ -774,7 +767,7 @@ impl Constellation {
fn close_pipelines(&mut self, frame_tree: @mut FrameTree) { fn close_pipelines(&mut self, frame_tree: @mut FrameTree) {
// TODO(tkuehn): should only exit once per unique script task, // TODO(tkuehn): should only exit once per unique script task,
// and then that script task will handle sub-exits // and then that script task will handle sub-exits
for @FrameTree { pipeline, _ } in frame_tree.iter() { for @FrameTree { pipeline, .. } in frame_tree.iter() {
pipeline.exit(); pipeline.exit();
self.pipelines.remove(&pipeline.id); self.pipelines.remove(&pipeline.id);
} }
@ -809,9 +802,9 @@ impl Constellation {
} }
fn set_ids(&self, frame_tree: @mut FrameTree) { fn set_ids(&self, frame_tree: @mut FrameTree) {
let (port, chan) = comm::stream(); let (port, chan) = Chan::new();
self.compositor_chan.send(SetIds(frame_tree.to_sendable(), chan, self.chan.clone())); self.compositor_chan.send(SetIds(frame_tree.to_sendable(), chan, self.chan.clone()));
match port.try_recv() { match port.recv_opt() {
Some(()) => { Some(()) => {
for frame in frame_tree.iter() { for frame in frame_tree.iter() {
frame.pipeline.grant_paint_permission(); frame.pipeline.grant_paint_permission();

View file

@ -11,11 +11,8 @@ use layout::wrapper::LayoutNode;
use extra::arc::{Arc, RWArc}; use extra::arc::{Arc, RWArc};
use std::cast; use std::cast;
use std::cell::Cell;
use std::comm;
use std::libc::uintptr_t; use std::libc::uintptr_t;
use std::rt; use std::rt;
use std::task;
use std::vec; use std::vec;
use style::{TNode, Stylist, cascade}; use style::{TNode, Stylist, cascade};
use style::{Before, After}; use style::{Before, After};
@ -27,22 +24,23 @@ pub trait MatchMethods {
fn cascade_subtree(&self, parent: Option<LayoutNode>); fn cascade_subtree(&self, parent: Option<LayoutNode>);
} }
impl<'self> MatchMethods for LayoutNode<'self> { impl<'ln> MatchMethods for LayoutNode<'ln> {
fn match_node(&self, stylist: &Stylist) { fn match_node(&self, stylist: &Stylist) {
let style_attribute = do self.with_element |element| { let style_attribute = self.with_element(|element| {
match *element.style_attribute() { match *element.style_attribute() {
None => None, None => None,
Some(ref style_attribute) => Some(style_attribute) Some(ref style_attribute) => Some(style_attribute)
} }
}; });
match *self.mutate_layout_data().ptr { let mut layout_data_ref = self.mutate_layout_data();
match *layout_data_ref.get() {
Some(ref mut layout_data) => { Some(ref mut layout_data) => {
layout_data.applicable_declarations = stylist.get_applicable_declarations( layout_data.data.applicable_declarations = stylist.get_applicable_declarations(
self, style_attribute, None); self, style_attribute, None);
layout_data.before_applicable_declarations = stylist.get_applicable_declarations( layout_data.data.before_applicable_declarations = stylist.get_applicable_declarations(
self, None, Some(Before)); self, None, Some(Before));
layout_data.after_applicable_declarations = stylist.get_applicable_declarations( layout_data.data.after_applicable_declarations = stylist.get_applicable_declarations(
self, None, Some(After)); self, None, Some(After));
} }
None => fail!("no layout data") None => fail!("no layout data")
@ -60,8 +58,7 @@ impl<'self> MatchMethods for LayoutNode<'self> {
} }
} }
let (port, chan) = comm::stream(); let (port, chan) = SharedChan::new();
let chan = comm::SharedChan::new(chan);
let mut num_spawned = 0; let mut num_spawned = 0;
for nodes in nodes_per_task.move_iter() { for nodes in nodes_per_task.move_iter() {
@ -77,20 +74,20 @@ impl<'self> MatchMethods for LayoutNode<'self> {
cast::transmute(nodes) cast::transmute(nodes)
}; };
do task::spawn_with((evil, stylist)) |(evil, stylist)| { let evil = Some(evil);
spawn(proc() {
let mut evil = evil;
let nodes: ~[LayoutNode] = unsafe { let nodes: ~[LayoutNode] = unsafe {
cast::transmute(evil) cast::transmute(evil.take_unwrap())
}; };
let nodes = Cell::new(nodes); stylist.read(|stylist| {
do stylist.read |stylist| {
let nodes = nodes.take();
for node in nodes.iter() { for node in nodes.iter() {
node.match_node(stylist); node.match_node(stylist);
} }
} });
chan.send(()); chan.send(());
} });
num_spawned += 1; num_spawned += 1;
} }
} }
@ -100,9 +97,6 @@ impl<'self> MatchMethods for LayoutNode<'self> {
} }
fn cascade_subtree(&self, parent: Option<LayoutNode>) { fn cascade_subtree(&self, parent: Option<LayoutNode>) {
let layout_data = unsafe {
self.borrow_layout_data_unchecked().as_ref().unwrap()
};
macro_rules! cascade_node( macro_rules! cascade_node(
($applicable_declarations: ident, $style: ident) => {{ ($applicable_declarations: ident, $style: ident) => {{
let parent_style = match parent { let parent_style = match parent {
@ -110,18 +104,21 @@ impl<'self> MatchMethods for LayoutNode<'self> {
None => None None => None
}; };
let computed_values = Arc::new(cascade( let computed_values = {
layout_data.$applicable_declarations, let layout_data_ref = self.borrow_layout_data();
parent_style.map(|parent_style| parent_style.get()))); let layout_data = layout_data_ref.get().as_ref().unwrap();
Arc::new(cascade(layout_data.data.$applicable_declarations, parent_style.map(|parent_style| parent_style.get())))
};
match *self.mutate_layout_data().ptr { let mut layout_data_ref = self.mutate_layout_data();
match *layout_data_ref.get() {
None => fail!("no layout data"), None => fail!("no layout data"),
Some(ref mut layout_data) => { Some(ref mut layout_data) => {
let style = &mut layout_data.$style; let style = &mut layout_data.data.$style;
match *style { match *style {
None => (), None => (),
Some(ref previous_style) => { Some(ref previous_style) => {
layout_data.restyle_damage = Some(incremental::compute_damage( layout_data.data.restyle_damage = Some(incremental::compute_damage(
previous_style.get(), computed_values.get()).to_int()) previous_style.get(), computed_values.get()).to_int())
} }
} }
@ -131,14 +128,22 @@ impl<'self> MatchMethods for LayoutNode<'self> {
}} }}
); );
unsafe { {
if self.borrow_layout_data_unchecked().as_ref().unwrap().before_applicable_declarations.len() > 0 { let before_len = {
let layout_data_ref = self.borrow_layout_data();
layout_data_ref.get().as_ref().unwrap().data.before_applicable_declarations.len()
};
if before_len > 0 {
cascade_node!(before_applicable_declarations, before_style); cascade_node!(before_applicable_declarations, before_style);
} }
} }
cascade_node!(applicable_declarations, style); cascade_node!(applicable_declarations, style);
unsafe { {
if self.borrow_layout_data_unchecked().as_ref().unwrap().after_applicable_declarations.len() > 0 { let after_len = {
let layout_data_ref = self.borrow_layout_data();
layout_data_ref.get().as_ref().unwrap().data.after_applicable_declarations.len()
};
if after_len > 0 {
cascade_node!(after_applicable_declarations, after_style); cascade_node!(after_applicable_declarations, after_style);
} }
} }

View file

@ -17,7 +17,7 @@ pub trait StyledNode {
fn restyle_damage(&self) -> RestyleDamage; fn restyle_damage(&self) -> RestyleDamage;
} }
impl<'self> StyledNode for LayoutNode<'self> { impl<'ln> StyledNode for LayoutNode<'ln> {
#[inline] #[inline]
fn style<'a>(&'a self) -> &'a Arc<ComputedValues> { fn style<'a>(&'a self) -> &'a Arc<ComputedValues> {
self.get_css_select_results() self.get_css_select_results()

View file

@ -18,7 +18,7 @@ pub trait NodeUtil {
fn set_restyle_damage(self, damage: RestyleDamage); fn set_restyle_damage(self, damage: RestyleDamage);
} }
impl<'self> NodeUtil for LayoutNode<'self> { impl<'ln> NodeUtil for LayoutNode<'ln> {
/** /**
* Provides the computed style for the given node. If CSS selector * Provides the computed style for the given node. If CSS selector
* Returns the style results for the given node. If CSS selector * Returns the style results for the given node. If CSS selector
@ -27,18 +27,15 @@ impl<'self> NodeUtil for LayoutNode<'self> {
#[inline] #[inline]
fn get_css_select_results<'a>(&'a self) -> &'a Arc<ComputedValues> { fn get_css_select_results<'a>(&'a self) -> &'a Arc<ComputedValues> {
unsafe { unsafe {
cast::transmute_region(self.borrow_layout_data_unchecked() let layout_data_ref = self.borrow_layout_data();
.as_ref() cast::transmute_region(layout_data_ref.get().as_ref().unwrap().data.style.as_ref().unwrap())
.unwrap()
.style
.as_ref()
.unwrap())
} }
} }
/// Does this node have a computed style yet? /// Does this node have a computed style yet?
fn have_css_select_results(self) -> bool { fn have_css_select_results(self) -> bool {
self.borrow_layout_data().ptr.as_ref().unwrap().style.is_some() let layout_data_ref = self.borrow_layout_data();
layout_data_ref.get().get_ref().data.style.is_some()
} }
/// Get the description of how to account for recent style changes. /// Get the description of how to account for recent style changes.
@ -52,10 +49,11 @@ impl<'self> NodeUtil for LayoutNode<'self> {
RestyleDamage::none() RestyleDamage::none()
}; };
self.borrow_layout_data() let layout_data_ref = self.borrow_layout_data();
.ptr layout_data_ref
.as_ref() .get()
.unwrap() .get_ref()
.data
.restyle_damage .restyle_damage
.map(|x| RestyleDamage::from_int(x)) .map(|x| RestyleDamage::from_int(x))
.unwrap_or(default) .unwrap_or(default)
@ -63,10 +61,10 @@ impl<'self> NodeUtil for LayoutNode<'self> {
/// Set the restyle damage field. /// Set the restyle damage field.
fn set_restyle_damage(self, damage: RestyleDamage) { fn set_restyle_damage(self, damage: RestyleDamage) {
match *self.mutate_layout_data().ptr { let mut layout_data_ref = self.mutate_layout_data();
Some(ref mut data) => data.restyle_damage = Some(damage.to_int()), match *layout_data_ref.get() {
Some(ref mut layout_data) => layout_data.data.restyle_damage = Some(damage.to_int()),
_ => fail!("no layout data for this node"), _ => fail!("no layout data for this node"),
} }
} }
} }

View file

@ -4,7 +4,7 @@
//! CSS block formatting contexts. //! CSS block formatting contexts.
use layout::box::Box; use layout::box_::Box;
use layout::context::LayoutContext; use layout::context::LayoutContext;
use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData}; use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData};
use layout::flow::{BlockFlowClass, FlowClass, Flow, FlowData, ImmutableFlowUtils}; use layout::flow::{BlockFlowClass, FlowClass, Flow, FlowData, ImmutableFlowUtils};
@ -12,7 +12,7 @@ use layout::flow;
use layout::model::{MaybeAuto, Specified, Auto, specified_or_none, specified}; use layout::model::{MaybeAuto, Specified, Auto, specified_or_none, specified};
use layout::float_context::{FloatContext, PlacementInfo, Invalid, FloatType}; use layout::float_context::{FloatContext, PlacementInfo, Invalid, FloatType};
use std::cell::Cell; use std::cell::RefCell;
use geom::{Point2D, Rect, SideOffsets2D}; use geom::{Point2D, Rect, SideOffsets2D};
use gfx::display_list::DisplayList; use gfx::display_list::DisplayList;
use servo_util::geometry::Au; use servo_util::geometry::Au;
@ -53,7 +53,7 @@ pub struct BlockFlow {
base: FlowData, base: FlowData,
/// The associated box. /// The associated box.
box: Option<Box>, box_: Option<Box>,
/// Whether this block flow is the root flow. /// Whether this block flow is the root flow.
is_root: bool, is_root: bool,
@ -66,25 +66,25 @@ impl BlockFlow {
pub fn new(base: FlowData) -> BlockFlow { pub fn new(base: FlowData) -> BlockFlow {
BlockFlow { BlockFlow {
base: base, base: base,
box: None, box_: None,
is_root: false, is_root: false,
float: None float: None
} }
} }
pub fn from_box(base: FlowData, box: Box) -> BlockFlow { pub fn from_box(base: FlowData, box_: Box) -> BlockFlow {
BlockFlow { BlockFlow {
base: base, base: base,
box: Some(box), box_: Some(box_),
is_root: false, is_root: false,
float: None float: None
} }
} }
pub fn float_from_box(base: FlowData, float_type: FloatType, box: Box) -> BlockFlow { pub fn float_from_box(base: FlowData, float_type: FloatType, box_: Box) -> BlockFlow {
BlockFlow { BlockFlow {
base: base, base: base,
box: Some(box), box_: Some(box_),
is_root: false, is_root: false,
float: Some(~FloatedBlockInfo::new(float_type)) float: Some(~FloatedBlockInfo::new(float_type))
} }
@ -93,7 +93,7 @@ impl BlockFlow {
pub fn new_root(base: FlowData) -> BlockFlow { pub fn new_root(base: FlowData) -> BlockFlow {
BlockFlow { BlockFlow {
base: base, base: base,
box: None, box_: None,
is_root: true, is_root: true,
float: None float: None
} }
@ -102,7 +102,7 @@ impl BlockFlow {
pub fn new_float(base: FlowData, float_type: FloatType) -> BlockFlow { pub fn new_float(base: FlowData, float_type: FloatType) -> BlockFlow {
BlockFlow { BlockFlow {
base: base, base: base,
box: None, box_: None,
is_root: false, is_root: false,
float: Some(~FloatedBlockInfo::new(float_type)) float: Some(~FloatedBlockInfo::new(float_type))
} }
@ -113,10 +113,10 @@ impl BlockFlow {
} }
pub fn teardown(&mut self) { pub fn teardown(&mut self) {
for box in self.box.iter() { for box_ in self.box_.iter() {
box.teardown(); box_.teardown();
} }
self.box = None; self.box_ = None;
self.float = None; self.float = None;
} }
@ -172,9 +172,9 @@ impl BlockFlow {
(width_Au, left_margin_Au, right_margin_Au) (width_Au, left_margin_Au, right_margin_Au)
} }
fn compute_block_margins(&self, box: &Box, remaining_width: Au, available_width: Au) fn compute_block_margins(&self, box_: &Box, remaining_width: Au, available_width: Au)
-> (Au, Au, Au) { -> (Au, Au, Au) {
let style = box.style(); let style = box_.style();
let (width, maybe_margin_left, maybe_margin_right) = let (width, maybe_margin_left, maybe_margin_right) =
(MaybeAuto::from_style(style.Box.width, remaining_width), (MaybeAuto::from_style(style.Box.width, remaining_width),
@ -215,8 +215,8 @@ impl BlockFlow {
return (width, margin_left, margin_right); return (width, margin_left, margin_right);
} }
fn compute_float_margins(&self, box: &Box, remaining_width: Au) -> (Au, Au, Au) { fn compute_float_margins(&self, box_: &Box, remaining_width: Au) -> (Au, Au, Au) {
let style = box.style(); let style = box_.style();
let margin_left = MaybeAuto::from_style(style.Margin.margin_left, let margin_left = MaybeAuto::from_style(style.Margin.margin_left,
remaining_width).specified_or_zero(); remaining_width).specified_or_zero();
let margin_right = MaybeAuto::from_style(style.Margin.margin_right, let margin_right = MaybeAuto::from_style(style.Margin.margin_right,
@ -240,20 +240,20 @@ impl BlockFlow {
let mut left_offset = Au::new(0); let mut left_offset = Au::new(0);
let mut float_ctx = Invalid; let mut float_ctx = Invalid;
for box in self.box.iter() { for box_ in self.box_.iter() {
clearance = match box.clear() { clearance = match box_.clear() {
None => Au::new(0), None => Au::new(0),
Some(clear) => { Some(clear) => {
self.base.floats_in.clearance(clear) self.base.floats_in.clearance(clear)
} }
}; };
top_offset = clearance + box.margin.get().top + box.border.get().top + top_offset = clearance + box_.margin.get().top + box_.border.get().top +
box.padding.get().top; box_.padding.get().top;
cur_y = cur_y + top_offset; cur_y = cur_y + top_offset;
bottom_offset = box.margin.get().bottom + box.border.get().bottom + bottom_offset = box_.margin.get().bottom + box_.border.get().bottom +
box.padding.get().bottom; box_.padding.get().bottom;
left_offset = box.offset(); left_offset = box_.offset();
} }
if inorder { if inorder {
@ -279,17 +279,17 @@ impl BlockFlow {
let mut top_margin_collapsible = false; let mut top_margin_collapsible = false;
let mut bottom_margin_collapsible = false; let mut bottom_margin_collapsible = false;
let mut first_in_flow = true; let mut first_in_flow = true;
for box in self.box.iter() { for box_ in self.box_.iter() {
if !self.is_root && box.border.get().top == Au(0) && box.padding.get().top == Au(0) { if !self.is_root && box_.border.get().top == Au(0) && box_.padding.get().top == Au(0) {
collapsible = box.margin.get().top; collapsible = box_.margin.get().top;
top_margin_collapsible = true; top_margin_collapsible = true;
} }
if !self.is_root && box.border.get().bottom == Au(0) && if !self.is_root && box_.border.get().bottom == Au(0) &&
box.padding.get().bottom == Au(0) { box_.padding.get().bottom == Au(0) {
bottom_margin_collapsible = true; bottom_margin_collapsible = true;
} }
margin_top = box.margin.get().top; margin_top = box_.margin.get().top;
margin_bottom = box.margin.get().bottom; margin_bottom = box_.margin.get().bottom;
} }
for kid in self.base.child_iter() { for kid in self.base.child_iter() {
@ -332,8 +332,8 @@ impl BlockFlow {
cur_y - top_offset - collapsing cur_y - top_offset - collapsing
}; };
for box in self.box.iter() { for box_ in self.box_.iter() {
let style = box.style(); let style = box_.style();
// At this point, `height` is the height of the containing block, so passing `height` // At this point, `height` is the height of the containing block, so passing `height`
// as the second argument here effectively makes percentages relative to the containing // as the second argument here effectively makes percentages relative to the containing
@ -345,9 +345,9 @@ impl BlockFlow {
} }
let mut noncontent_height = Au::new(0); let mut noncontent_height = Au::new(0);
for box in self.box.iter() { for box_ in self.box_.iter() {
let mut position = box.position.get(); let mut position = box_.position.get();
let mut margin = box.margin.get(); let mut margin = box_.margin.get();
// The associated box is the border box of this flow. // The associated box is the border box of this flow.
margin.top = margin_top; margin.top = margin_top;
@ -355,14 +355,14 @@ impl BlockFlow {
position.origin.y = clearance + margin.top; position.origin.y = clearance + margin.top;
noncontent_height = box.padding.get().top + box.padding.get().bottom + noncontent_height = box_.padding.get().top + box_.padding.get().bottom +
box.border.get().top + box.border.get().bottom; box_.border.get().top + box_.border.get().bottom;
position.size.height = height + noncontent_height; position.size.height = height + noncontent_height;
noncontent_height = noncontent_height + clearance + margin.top + margin.bottom; noncontent_height = noncontent_height + clearance + margin.top + margin.bottom;
box.position.set(position); box_.position.set(position);
box.margin.set(margin); box_.margin.set(margin);
} }
self.base.position.size.height = height + noncontent_height; self.base.position.size.height = height + noncontent_height;
@ -384,19 +384,19 @@ impl BlockFlow {
let mut full_noncontent_width = Au(0); let mut full_noncontent_width = Au(0);
let mut margin_height = Au(0); let mut margin_height = Au(0);
for box in self.box.iter() { for box_ in self.box_.iter() {
height = box.position.get().size.height; height = box_.position.get().size.height;
clearance = match box.clear() { clearance = match box_.clear() {
None => Au(0), None => Au(0),
Some(clear) => self.base.floats_in.clearance(clear), Some(clear) => self.base.floats_in.clearance(clear),
}; };
let noncontent_width = box.padding.get().left + box.padding.get().right + let noncontent_width = box_.padding.get().left + box_.padding.get().right +
box.border.get().left + box.border.get().right; box_.border.get().left + box_.border.get().right;
full_noncontent_width = noncontent_width + box.margin.get().left + full_noncontent_width = noncontent_width + box_.margin.get().left +
box.margin.get().right; box_.margin.get().right;
margin_height = box.margin.get().top + box.margin.get().bottom; margin_height = box_.margin.get().top + box_.margin.get().bottom;
} }
let info = PlacementInfo { let info = PlacementInfo {
@ -427,8 +427,8 @@ impl BlockFlow {
let mut cur_y = Au(0); let mut cur_y = Au(0);
let mut top_offset = Au(0); let mut top_offset = Au(0);
for box in self.box.iter() { for box_ in self.box_.iter() {
top_offset = box.margin.get().top + box.border.get().top + box.padding.get().top; top_offset = box_.margin.get().top + box_.border.get().top + box_.padding.get().top;
cur_y = cur_y + top_offset; cur_y = cur_y + top_offset;
} }
@ -441,31 +441,31 @@ impl BlockFlow {
let mut height = cur_y - top_offset; let mut height = cur_y - top_offset;
let mut noncontent_height; let mut noncontent_height;
let box = self.box.as_ref().unwrap(); let box_ = self.box_.as_ref().unwrap();
let mut position = box.position.get(); let mut position = box_.position.get();
// The associated box is the border box of this flow. // The associated box is the border box of this flow.
position.origin.y = box.margin.get().top; position.origin.y = box_.margin.get().top;
noncontent_height = box.padding.get().top + box.padding.get().bottom + noncontent_height = box_.padding.get().top + box_.padding.get().bottom +
box.border.get().top + box.border.get().bottom; box_.border.get().top + box_.border.get().bottom;
//TODO(eatkinson): compute heights properly using the 'height' property. //TODO(eatkinson): compute heights properly using the 'height' property.
let height_prop = MaybeAuto::from_style(box.style().Box.height, let height_prop = MaybeAuto::from_style(box_.style().Box.height,
Au::new(0)).specified_or_zero(); Au::new(0)).specified_or_zero();
height = geometry::max(height, height_prop) + noncontent_height; height = geometry::max(height, height_prop) + noncontent_height;
debug!("assign_height_float -- height: {}", height); debug!("assign_height_float -- height: {}", height);
position.size.height = height; position.size.height = height;
box.position.set(position); box_.position.set(position);
} }
pub fn build_display_list_block<E:ExtraDisplayListData>( pub fn build_display_list_block<E:ExtraDisplayListData>(
&mut self, &mut self,
builder: &DisplayListBuilder, builder: &DisplayListBuilder,
dirty: &Rect<Au>, dirty: &Rect<Au>,
list: &Cell<DisplayList<E>>) list: &RefCell<DisplayList<E>>)
-> bool { -> bool {
if self.is_float() { if self.is_float() {
return self.build_display_list_float(builder, dirty, list); return self.build_display_list_float(builder, dirty, list);
@ -479,8 +479,8 @@ impl BlockFlow {
debug!("build_display_list_block: adding display element"); debug!("build_display_list_block: adding display element");
// add box that starts block context // add box that starts block context
for box in self.box.iter() { for box_ in self.box_.iter() {
box.build_display_list(builder, dirty, self.base.abs_position, (&*self) as &Flow, list) box_.build_display_list(builder, dirty, self.base.abs_position, (&*self) as &Flow, list)
} }
// TODO: handle any out-of-flow elements // TODO: handle any out-of-flow elements
@ -497,7 +497,7 @@ impl BlockFlow {
&mut self, &mut self,
builder: &DisplayListBuilder, builder: &DisplayListBuilder,
dirty: &Rect<Au>, dirty: &Rect<Au>,
list: &Cell<DisplayList<E>>) list: &RefCell<DisplayList<E>>)
-> bool { -> bool {
let abs_rect = Rect(self.base.abs_position, self.base.position.size); let abs_rect = Rect(self.base.abs_position, self.base.position.size);
if !abs_rect.intersects(dirty) { if !abs_rect.intersects(dirty) {
@ -506,8 +506,8 @@ impl BlockFlow {
let offset = self.base.abs_position + self.float.get_ref().rel_pos; let offset = self.base.abs_position + self.float.get_ref().rel_pos;
// add box that starts block context // add box that starts block context
for box in self.box.iter() { for box_ in self.box_.iter() {
box.build_display_list(builder, dirty, offset, (&*self) as &Flow, list) box_.build_display_list(builder, dirty, offset, (&*self) as &Flow, list)
} }
@ -564,13 +564,13 @@ impl Flow for BlockFlow {
/* if not an anonymous block context, add in block box's widths. /* if not an anonymous block context, add in block box's widths.
these widths will not include child elements, just padding etc. */ these widths will not include child elements, just padding etc. */
for box in self.box.iter() { for box_ in self.box_.iter() {
{ {
// Can compute border width here since it doesn't depend on anything. // Can compute border width here since it doesn't depend on anything.
box.compute_borders(box.style()) box_.compute_borders(box_.style())
} }
let (this_minimum_width, this_preferred_width) = box.minimum_and_preferred_widths(); let (this_minimum_width, this_preferred_width) = box_.minimum_and_preferred_widths();
min_width = min_width + this_minimum_width; min_width = min_width + this_minimum_width;
pref_width = pref_width + this_preferred_width; pref_width = pref_width + this_preferred_width;
} }
@ -612,17 +612,17 @@ impl Flow for BlockFlow {
self.base.flags.set_inorder(false); self.base.flags.set_inorder(false);
} }
for box in self.box.iter() { for box_ in self.box_.iter() {
let style = box.style(); let style = box_.style();
// The text alignment of a block flow is the text alignment of its box's style. // The text alignment of a block flow is the text alignment of its box's style.
self.base.flags.set_text_align(style.Text.text_align); self.base.flags.set_text_align(style.Text.text_align);
// Can compute padding here since we know containing block width. // Can compute padding here since we know containing block width.
box.compute_padding(style, remaining_width); box_.compute_padding(style, remaining_width);
// Margins are 0 right now so base.noncontent_width() is just borders + padding. // Margins are 0 right now so base.noncontent_width() is just borders + padding.
let available_width = remaining_width - box.noncontent_width(); let available_width = remaining_width - box_.noncontent_width();
// Top and bottom margins for blocks are 0 if auto. // Top and bottom margins for blocks are 0 if auto.
let margin_top = MaybeAuto::from_style(style.Margin.margin_top, let margin_top = MaybeAuto::from_style(style.Margin.margin_top,
@ -631,25 +631,25 @@ impl Flow for BlockFlow {
remaining_width).specified_or_zero(); remaining_width).specified_or_zero();
let (width, margin_left, margin_right) = if self.is_float() { let (width, margin_left, margin_right) = if self.is_float() {
self.compute_float_margins(box, remaining_width) self.compute_float_margins(box_, remaining_width)
} else { } else {
self.compute_block_margins(box, remaining_width, available_width) self.compute_block_margins(box_, remaining_width, available_width)
}; };
box.margin.set(SideOffsets2D::new(margin_top, box_.margin.set(SideOffsets2D::new(margin_top,
margin_right, margin_right,
margin_bottom, margin_bottom,
margin_left)); margin_left));
x_offset = box.offset(); x_offset = box_.offset();
remaining_width = width; remaining_width = width;
// The associated box is the border box of this flow. // The associated box is the border box of this flow.
let position_ref = box.position.mutate(); let mut position_ref = box_.position.borrow_mut();
position_ref.ptr.origin.x = box.margin.get().left; position_ref.get().origin.x = box_.margin.get().left;
let padding_and_borders = box.padding.get().left + box.padding.get().right + let padding_and_borders = box_.padding.get().left + box_.padding.get().right +
box.border.get().left + box.border.get().right; box_.border.get().left + box_.border.get().right;
position_ref.ptr.size.width = remaining_width + padding_and_borders; position_ref.get().size.width = remaining_width + padding_and_borders;
} }
if self.is_float() { if self.is_float() {
@ -722,24 +722,24 @@ impl Flow for BlockFlow {
return; return;
} }
for box in self.box.iter() { for box_ in self.box_.iter() {
// The top margin collapses with its first in-flow block-level child's // The top margin collapses with its first in-flow block-level child's
// top margin if the parent has no top border, no top padding. // top margin if the parent has no top border, no top padding.
if *first_in_flow && top_margin_collapsible { if *first_in_flow && top_margin_collapsible {
// If top-margin of parent is less than top-margin of its first child, // If top-margin of parent is less than top-margin of its first child,
// the parent box goes down until its top is aligned with the child. // the parent box goes down until its top is aligned with the child.
if *margin_top < box.margin.get().top { if *margin_top < box_.margin.get().top {
// TODO: The position of child floats should be updated and this // TODO: The position of child floats should be updated and this
// would influence clearance as well. See #725 // would influence clearance as well. See #725
let extra_margin = box.margin.get().top - *margin_top; let extra_margin = box_.margin.get().top - *margin_top;
*top_offset = *top_offset + extra_margin; *top_offset = *top_offset + extra_margin;
*margin_top = box.margin.get().top; *margin_top = box_.margin.get().top;
} }
} }
// The bottom margin of an in-flow block-level element collapses // The bottom margin of an in-flow block-level element collapses
// with the top margin of its next in-flow block-level sibling. // with the top margin of its next in-flow block-level sibling.
*collapsing = geometry::min(box.margin.get().top, *collapsible); *collapsing = geometry::min(box_.margin.get().top, *collapsible);
*collapsible = box.margin.get().bottom; *collapsible = box_.margin.get().bottom;
} }
*first_in_flow = false; *first_in_flow = false;
@ -757,7 +757,7 @@ impl Flow for BlockFlow {
} else { } else {
~"BlockFlow: " ~"BlockFlow: "
}; };
txt.append(match self.box { txt.append(match self.box_ {
Some(ref rb) => rb.debug_str(), Some(ref rb) => rb.debug_str(),
None => ~"", None => ~"",
}) })

View file

@ -22,9 +22,8 @@ use servo_net::local_image_cache::LocalImageCache;
use servo_util::geometry::Au; use servo_util::geometry::Au;
use servo_util::geometry; use servo_util::geometry;
use servo_util::range::*; use servo_util::range::*;
use servo_util::slot::Slot;
use std::cast; use std::cast;
use std::cell::Cell; use std::cell::RefCell;
use std::cmp::ApproxEq; use std::cmp::ApproxEq;
use std::num::Zero; use std::num::Zero;
use style::{ComputedValues, TElement, TNode, cascade}; use style::{ComputedValues, TElement, TNode, cascade};
@ -71,24 +70,24 @@ pub struct Box {
style: Arc<ComputedValues>, style: Arc<ComputedValues>,
/// The position of this box relative to its owning flow. /// The position of this box relative to its owning flow.
position: Slot<Rect<Au>>, position: RefCell<Rect<Au>>,
/// The border of the content box. /// The border of the content box.
/// ///
/// FIXME(pcwalton): This need not be stored in the box. /// FIXME(pcwalton): This need not be stored in the box.
border: Slot<SideOffsets2D<Au>>, border: RefCell<SideOffsets2D<Au>>,
/// The padding of the content box. /// The padding of the content box.
padding: Slot<SideOffsets2D<Au>>, padding: RefCell<SideOffsets2D<Au>>,
/// The margin of the content box. /// The margin of the content box.
margin: Slot<SideOffsets2D<Au>>, margin: RefCell<SideOffsets2D<Au>>,
/// Info specific to the kind of box. Keep this enum small. /// Info specific to the kind of box. Keep this enum small.
specific: SpecificBoxInfo, specific: SpecificBoxInfo,
/// positioned box offsets /// positioned box offsets
position_offsets: Slot<SideOffsets2D<Au>>, position_offsets: RefCell<SideOffsets2D<Au>>,
} }
/// Info specific to the kind of box. Keep this enum small. /// Info specific to the kind of box. Keep this enum small.
@ -105,7 +104,7 @@ pub enum SpecificBoxInfo {
#[deriving(Clone)] #[deriving(Clone)]
pub struct ImageBoxInfo { pub struct ImageBoxInfo {
/// The image held within this box. /// The image held within this box.
image: Slot<ImageHolder>, image: RefCell<ImageHolder>,
/// The width attribute supplied by the DOM, if any. /// The width attribute supplied by the DOM, if any.
dom_width: Option<Au>, dom_width: Option<Au>,
/// The height attribute supplied by the DOM, if any. /// The height attribute supplied by the DOM, if any.
@ -129,7 +128,7 @@ impl ImageBoxInfo {
} }
ImageBoxInfo { ImageBoxInfo {
image: Slot::init(ImageHolder::new(image_url, local_image_cache)), image: RefCell::new(ImageHolder::new(image_url, local_image_cache)),
dom_width: convert_length(node, "width"), dom_width: convert_length(node, "width"),
dom_height: convert_length(node, "height"), dom_height: convert_length(node, "height"),
} }
@ -139,7 +138,8 @@ impl ImageBoxInfo {
fn image_width(&self) -> Au { fn image_width(&self) -> Au {
// TODO(brson): Consult margins and borders? // TODO(brson): Consult margins and borders?
self.dom_width.unwrap_or_else(|| { self.dom_width.unwrap_or_else(|| {
Au::from_px(self.image.mutate().ptr.get_size().unwrap_or(Size2D(0, 0)).width) let mut image_ref = self.image.borrow_mut();
Au::from_px(image_ref.get().get_size().unwrap_or(Size2D(0, 0)).width)
}) })
} }
@ -147,7 +147,8 @@ impl ImageBoxInfo {
pub fn image_height(&self) -> Au { pub fn image_height(&self) -> Au {
// TODO(brson): Consult margins and borders? // TODO(brson): Consult margins and borders?
self.dom_height.unwrap_or_else(|| { self.dom_height.unwrap_or_else(|| {
Au::from_px(self.image.mutate().ptr.get_size().unwrap_or(Size2D(0, 0)).height) let mut image_ref = self.image.borrow_mut();
Au::from_px(image_ref.get().get_size().unwrap_or(Size2D(0, 0)).height)
}) })
} }
} }
@ -256,12 +257,12 @@ impl Box {
Box { Box {
node: OpaqueNode::from_layout_node(&node), node: OpaqueNode::from_layout_node(&node),
style: node_style, style: node_style,
position: Slot::init(Au::zero_rect()), position: RefCell::new(Au::zero_rect()),
border: Slot::init(Zero::zero()), border: RefCell::new(Zero::zero()),
padding: Slot::init(Zero::zero()), padding: RefCell::new(Zero::zero()),
margin: Slot::init(Zero::zero()), margin: RefCell::new(Zero::zero()),
specific: specific, specific: specific,
position_offsets: Slot::init(Zero::zero()), position_offsets: RefCell::new(Zero::zero()),
} }
} }
@ -279,12 +280,12 @@ impl Box {
Box { Box {
node: self.node, node: self.node,
style: self.style.clone(), style: self.style.clone(),
position: Slot::init(Rect(self.position.get().origin, size)), position: RefCell::new(Rect(self.position.get().origin, size)),
border: Slot::init(self.border.get()), border: RefCell::new(self.border.get()),
padding: Slot::init(self.padding.get()), padding: RefCell::new(self.padding.get()),
margin: Slot::init(self.margin.get()), margin: RefCell::new(self.margin.get()),
specific: specific, specific: specific,
position_offsets: Slot::init(Zero::zero()) position_offsets: RefCell::new(Zero::zero())
} }
} }
@ -310,11 +311,6 @@ impl Box {
self.border.get().left + self.border.get().right self.border.get().left + self.border.get().right
} }
/// Sets the size of this box.
fn set_size(&self, new_size: Size2D<Au>) {
self.position.set(Rect(self.position.get().origin, new_size))
}
pub fn calculate_line_height(&self, font_size: Au) -> Au { pub fn calculate_line_height(&self, font_size: Au) -> Au {
match self.line_height() { match self.line_height() {
line_height::Normal => font_size.scale_by(1.14), line_height::Normal => font_size.scale_by(1.14),
@ -408,11 +404,11 @@ impl Box {
debug!("(font style) start"); debug!("(font style) start");
// FIXME: Too much allocation here. // FIXME: Too much allocation here.
let font_families = do my_style.Font.font_family.map |family| { let font_families = my_style.Font.font_family.map(|family| {
match *family { match *family {
font_family::FamilyName(ref name) => (*name).clone(), font_family::FamilyName(ref name) => (*name).clone(),
} }
}; });
debug!("(font style) font families: `{:?}`", font_families); debug!("(font style) font families: `{:?}`", font_families);
let font_size = my_style.Font.font_size.to_f64().unwrap() / 60.0; let font_size = my_style.Font.font_size.to_f64().unwrap() / 60.0;
@ -465,7 +461,7 @@ impl Box {
/// and so on. /// and so on.
pub fn is_replaced(&self) -> bool { pub fn is_replaced(&self) -> bool {
match self.specific { match self.specific {
ImageBox(*) => true, ImageBox(..) => true,
_ => false, _ => false,
} }
} }
@ -473,7 +469,7 @@ impl Box {
/// Returns true if this element can be split. This is true for text boxes. /// Returns true if this element can be split. This is true for text boxes.
pub fn can_split(&self) -> bool { pub fn can_split(&self) -> bool {
match self.specific { match self.specific {
ScannedTextBox(*) => true, ScannedTextBox(..) => true,
_ => false, _ => false,
} }
} }
@ -496,7 +492,7 @@ impl Box {
/// necessary. /// necessary.
pub fn paint_background_if_applicable<E:ExtraDisplayListData>( pub fn paint_background_if_applicable<E:ExtraDisplayListData>(
&self, &self,
list: &Cell<DisplayList<E>>, list: &RefCell<DisplayList<E>>,
absolute_bounds: &Rect<Au>) { absolute_bounds: &Rect<Au>) {
// FIXME: This causes a lot of background colors to be displayed when they are clearly not // FIXME: This causes a lot of background colors to be displayed when they are clearly not
// needed. We could use display list optimization to clean this up, but it still seems // needed. We could use display list optimization to clean this up, but it still seems
@ -505,7 +501,7 @@ impl Box {
let style = self.style(); let style = self.style();
let background_color = style.resolve_color(style.Background.background_color); let background_color = style.resolve_color(style.Background.background_color);
if !background_color.alpha.approx_eq(&0.0) { if !background_color.alpha.approx_eq(&0.0) {
list.with_mut_ref(|list| { list.with_mut(|list| {
let solid_color_display_item = ~SolidColorDisplayItem { let solid_color_display_item = ~SolidColorDisplayItem {
base: BaseDisplayItem { base: BaseDisplayItem {
bounds: *absolute_bounds, bounds: *absolute_bounds,
@ -523,7 +519,7 @@ impl Box {
/// necessary. /// necessary.
pub fn paint_borders_if_applicable<E:ExtraDisplayListData>( pub fn paint_borders_if_applicable<E:ExtraDisplayListData>(
&self, &self,
list: &Cell<DisplayList<E>>, list: &RefCell<DisplayList<E>>,
abs_bounds: &Rect<Au>) { abs_bounds: &Rect<Au>) {
// Fast path. // Fast path.
let border = self.border.get(); let border = self.border.get();
@ -542,7 +538,7 @@ impl Box {
let left_style = style.Border.border_left_style; let left_style = style.Border.border_left_style;
// Append the border to the display list. // Append the border to the display list.
do list.with_mut_ref |list| { list.with_mut(|list| {
let border_display_item = ~BorderDisplayItem { let border_display_item = ~BorderDisplayItem {
base: BaseDisplayItem { base: BaseDisplayItem {
bounds: *abs_bounds, bounds: *abs_bounds,
@ -560,7 +556,7 @@ impl Box {
}; };
list.append_item(BorderDisplayItemClass(border_display_item)) list.append_item(BorderDisplayItemClass(border_display_item))
} });
} }
/// Adds the display items for this box to the given display list. /// Adds the display items for this box to the given display list.
@ -583,7 +579,7 @@ impl Box {
dirty: &Rect<Au>, dirty: &Rect<Au>,
offset: Point2D<Au>, offset: Point2D<Au>,
flow: &Flow, flow: &Flow,
list: &Cell<DisplayList<E>>) { list: &RefCell<DisplayList<E>>) {
let box_bounds = self.position.get(); let box_bounds = self.position.get();
let absolute_box_bounds = box_bounds.translate(&offset); let absolute_box_bounds = box_bounds.translate(&offset);
debug!("Box::build_display_list at rel={}, abs={}: {:s}", debug!("Box::build_display_list at rel={}, abs={}: {:s}",
@ -607,7 +603,7 @@ impl Box {
match self.specific { match self.specific {
UnscannedTextBox(_) => fail!("Shouldn't see unscanned boxes here."), UnscannedTextBox(_) => fail!("Shouldn't see unscanned boxes here."),
ScannedTextBox(ref text_box) => { ScannedTextBox(ref text_box) => {
do list.with_mut_ref |list| { list.with_mut(|list| {
let item = ~ClipDisplayItem { let item = ~ClipDisplayItem {
base: BaseDisplayItem { base: BaseDisplayItem {
bounds: absolute_box_bounds, bounds: absolute_box_bounds,
@ -617,7 +613,7 @@ impl Box {
need_clip: false need_clip: false
}; };
list.append_item(ClipDisplayItemClass(item)); list.append_item(ClipDisplayItemClass(item));
} });
let color = self.style().Color.color.to_gfx_color(); let color = self.style().Color.color.to_gfx_color();
@ -629,7 +625,7 @@ impl Box {
text_flags.set_override_line_through(flow_flags.override_line_through()); text_flags.set_override_line_through(flow_flags.override_line_through());
// Create the text box. // Create the text box.
do list.with_mut_ref |list| { list.with_mut(|list| {
let text_display_item = ~TextDisplayItem { let text_display_item = ~TextDisplayItem {
base: BaseDisplayItem { base: BaseDisplayItem {
bounds: absolute_box_bounds, bounds: absolute_box_bounds,
@ -642,7 +638,7 @@ impl Box {
}; };
list.append_item(TextDisplayItemClass(text_display_item)) list.append_item(TextDisplayItemClass(text_display_item))
} });
// Draw debug frames for text bounds. // Draw debug frames for text bounds.
// //
@ -652,7 +648,7 @@ impl Box {
// Compute the text box bounds and draw a border surrounding them. // Compute the text box bounds and draw a border surrounding them.
let debug_border = SideOffsets2D::new_all_same(Au::from_px(1)); let debug_border = SideOffsets2D::new_all_same(Au::from_px(1));
do list.with_mut_ref |list| { list.with_mut(|list| {
let border_display_item = ~BorderDisplayItem { let border_display_item = ~BorderDisplayItem {
base: BaseDisplayItem { base: BaseDisplayItem {
bounds: absolute_box_bounds, bounds: absolute_box_bounds,
@ -664,7 +660,7 @@ impl Box {
}; };
list.append_item(BorderDisplayItemClass(border_display_item)) list.append_item(BorderDisplayItemClass(border_display_item))
} });
// Draw a rectangle representing the baselines. // Draw a rectangle representing the baselines.
// //
@ -674,7 +670,7 @@ impl Box {
let baseline = Rect(absolute_box_bounds.origin + Point2D(Au(0), ascent), let baseline = Rect(absolute_box_bounds.origin + Point2D(Au(0), ascent),
Size2D(absolute_box_bounds.size.width, Au(0))); Size2D(absolute_box_bounds.size.width, Au(0)));
do list.with_mut_ref |list| { list.with_mut(|list| {
let border_display_item = ~BorderDisplayItem { let border_display_item = ~BorderDisplayItem {
base: BaseDisplayItem { base: BaseDisplayItem {
bounds: baseline, bounds: baseline,
@ -686,13 +682,11 @@ impl Box {
}; };
list.append_item(BorderDisplayItemClass(border_display_item)) list.append_item(BorderDisplayItemClass(border_display_item))
} });
()
}); });
}, },
GenericBox | IframeBox(_) => { GenericBox | IframeBox(..) => {
do list.with_mut_ref |list| { list.with_mut(|list| {
let item = ~ClipDisplayItem { let item = ~ClipDisplayItem {
base: BaseDisplayItem { base: BaseDisplayItem {
bounds: absolute_box_bounds, bounds: absolute_box_bounds,
@ -702,14 +696,14 @@ impl Box {
need_clip: self.needs_clip() need_clip: self.needs_clip()
}; };
list.append_item(ClipDisplayItemClass(item)); list.append_item(ClipDisplayItemClass(item));
} });
// FIXME(pcwalton): This is a bit of an abuse of the logging infrastructure. We // FIXME(pcwalton): This is a bit of an abuse of the logging infrastructure. We
// should have a real `SERVO_DEBUG` system. // should have a real `SERVO_DEBUG` system.
debug!("{:?}", { debug!("{:?}", {
let debug_border = SideOffsets2D::new_all_same(Au::from_px(1)); let debug_border = SideOffsets2D::new_all_same(Au::from_px(1));
do list.with_mut_ref |list| { list.with_mut(|list| {
let border_display_item = ~BorderDisplayItem { let border_display_item = ~BorderDisplayItem {
base: BaseDisplayItem { base: BaseDisplayItem {
bounds: absolute_box_bounds, bounds: absolute_box_bounds,
@ -721,13 +715,11 @@ impl Box {
}; };
list.append_item(BorderDisplayItemClass(border_display_item)) list.append_item(BorderDisplayItemClass(border_display_item))
} });
()
}); });
}, },
ImageBox(ref image_box) => { ImageBox(ref image_box) => {
do list.with_mut_ref |list| { list.with_mut(|list| {
let item = ~ClipDisplayItem { let item = ~ClipDisplayItem {
base: BaseDisplayItem { base: BaseDisplayItem {
bounds: absolute_box_bounds, bounds: absolute_box_bounds,
@ -737,14 +729,15 @@ impl Box {
need_clip: false need_clip: false
}; };
list.append_item(ClipDisplayItemClass(item)); list.append_item(ClipDisplayItemClass(item));
} });
match image_box.image.mutate().ptr.get_image() { let mut image_ref = image_box.image.borrow_mut();
match image_ref.get().get_image() {
Some(image) => { Some(image) => {
debug!("(building display list) building image box"); debug!("(building display list) building image box");
// Place the image into the display list. // Place the image into the display list.
do list.with_mut_ref |list| { list.with_mut(|list| {
let image_display_item = ~ImageDisplayItem { let image_display_item = ~ImageDisplayItem {
base: BaseDisplayItem { base: BaseDisplayItem {
bounds: absolute_box_bounds, bounds: absolute_box_bounds,
@ -752,8 +745,8 @@ impl Box {
}, },
image: image.clone(), image: image.clone(),
}; };
list.append_item(ImageDisplayItemClass(image_display_item)) list.append_item(ImageDisplayItemClass(image_display_item));
} });
} }
None => { None => {
// No image data at all? Do nothing. // No image data at all? Do nothing.
@ -809,7 +802,7 @@ impl Box {
(min_line_width, max_line_width) (min_line_width, max_line_width)
} }
UnscannedTextBox(*) => fail!("Unscanned text boxes should have been scanned by now!"), UnscannedTextBox(..) => fail!("Unscanned text boxes should have been scanned by now!"),
}; };
(guessed_width + additional_minimum, guessed_width + additional_preferred) (guessed_width + additional_minimum, guessed_width + additional_preferred)
} }
@ -822,11 +815,12 @@ impl Box {
match self.specific { match self.specific {
GenericBox | IframeBox(_) => Au(0), GenericBox | IframeBox(_) => Au(0),
ImageBox(ref image_box_info) => { ImageBox(ref image_box_info) => {
let size = image_box_info.image.mutate().ptr.get_size(); let mut image_ref = image_box_info.image.borrow_mut();
let size = image_ref.get().get_size();
let height = Au::from_px(size.unwrap_or(Size2D(0, 0)).height); let height = Au::from_px(size.unwrap_or(Size2D(0, 0)).height);
// Eww. Refactor this. // Eww. Refactor this.
self.position.mutate().ptr.size.height = height; self.position.borrow_mut().get().size.height = height;
debug!("box_height: found image height: {}", height); debug!("box_height: found image height: {}", height);
height height
@ -955,11 +949,11 @@ impl Box {
match self.specific { match self.specific {
GenericBox | IframeBox(_) => { GenericBox | IframeBox(_) => {
// FIXME(pcwalton): This seems clownshoes; can we remove? // FIXME(pcwalton): This seems clownshoes; can we remove?
self.position.mutate().ptr.size.width = Au::from_px(45) self.position.borrow_mut().get().size.width = Au::from_px(45)
} }
ImageBox(ref image_box_info) => { ImageBox(ref image_box_info) => {
let image_width = image_box_info.image_width(); let image_width = image_box_info.image_width();
self.position.mutate().ptr.size.width = image_width self.position.borrow_mut().get().size.width = image_width
} }
ScannedTextBox(_) => { ScannedTextBox(_) => {
// Scanned text boxes will have already had their widths assigned by this point. // Scanned text boxes will have already had their widths assigned by this point.

View file

@ -22,8 +22,8 @@
use css::node_style::StyledNode; use css::node_style::StyledNode;
use layout::block::BlockFlow; use layout::block::BlockFlow;
use layout::box::{Box, GenericBox, IframeBox, IframeBoxInfo, ImageBox, ImageBoxInfo}; use layout::box_::{Box, GenericBox, IframeBox, IframeBoxInfo, ImageBox, ImageBoxInfo};
use layout::box::{UnscannedTextBox, UnscannedTextBoxInfo}; use layout::box_::{UnscannedTextBox, UnscannedTextBoxInfo};
use layout::context::LayoutContext; use layout::context::LayoutContext;
use layout::float_context::FloatType; use layout::float_context::FloatType;
use layout::flow::{Flow, FlowData, MutableFlowUtils}; use layout::flow::{Flow, FlowData, MutableFlowUtils};
@ -35,10 +35,11 @@ use layout::wrapper::{LayoutNode, PostorderNodeMutTraversal};
use script::dom::element::{HTMLIframeElementTypeId, HTMLImageElementTypeId}; use script::dom::element::{HTMLIframeElementTypeId, HTMLImageElementTypeId};
use script::dom::node::{CommentNodeTypeId, DoctypeNodeTypeId, DocumentFragmentNodeTypeId}; use script::dom::node::{CommentNodeTypeId, DoctypeNodeTypeId, DocumentFragmentNodeTypeId};
use script::dom::node::{DocumentNodeTypeId, ElementNodeTypeId, TextNodeTypeId}; use script::dom::node::{DocumentNodeTypeId, ElementNodeTypeId, TextNodeTypeId};
use servo_util::slot::Slot;
use std::util;
use style::computed_values::{display, float}; use style::computed_values::{display, float};
use std::cell::RefCell;
use std::util;
/// The results of flow construction for a DOM node. /// The results of flow construction for a DOM node.
pub enum ConstructionResult { pub enum ConstructionResult {
/// This node contributes nothing at all (`display: none`). Alternately, this is what newly /// This node contributes nothing at all (`display: none`). Alternately, this is what newly
@ -47,7 +48,7 @@ pub enum ConstructionResult {
/// This node contributed a flow at the proper position in the tree. Nothing more needs to be /// This node contributed a flow at the proper position in the tree. Nothing more needs to be
/// done for this node. /// done for this node.
FlowConstructionResult(~Flow:), FlowConstructionResult(~Flow),
/// This node contributed some object or objects that will be needed to construct a proper flow /// This node contributed some object or objects that will be needed to construct a proper flow
/// later up the tree, but these objects have not yet found their home. /// later up the tree, but these objects have not yet found their home.
@ -102,7 +103,7 @@ struct InlineBlockSplit {
predecessor_boxes: ~[Box], predecessor_boxes: ~[Box],
/// The flow that caused this {ib} split. /// The flow that caused this {ib} split.
flow: ~Flow:, flow: ~Flow,
} }
/// Methods on optional vectors. /// Methods on optional vectors.
@ -169,24 +170,24 @@ impl<T> OptVector<T> for Option<~[T]> {
} }
/// An object that knows how to create flows. /// An object that knows how to create flows.
pub struct FlowConstructor<'self> { pub struct FlowConstructor<'a> {
/// The layout context. /// The layout context.
/// ///
/// FIXME(pcwalton): Why does this contain `@`??? That destroys parallelism!!! /// FIXME(pcwalton): Why does this contain `@`??? That destroys parallelism!!!
layout_context: &'self mut LayoutContext, layout_context: &'a mut LayoutContext,
/// The next flow ID to assign. /// The next flow ID to assign.
/// ///
/// FIXME(pcwalton): This is going to have to be atomic; can't we do something better? /// FIXME(pcwalton): This is going to have to be atomic; can't we do something better?
next_flow_id: Slot<int>, next_flow_id: RefCell<int>,
} }
impl<'self> FlowConstructor<'self> { impl<'fc> FlowConstructor<'fc> {
/// Creates a new flow constructor. /// Creates a new flow constructor.
pub fn init<'a>(layout_context: &'a mut LayoutContext) -> FlowConstructor<'a> { pub fn init<'a>(layout_context: &'a mut LayoutContext) -> FlowConstructor<'a> {
FlowConstructor { FlowConstructor {
layout_context: layout_context, layout_context: layout_context,
next_flow_id: Slot::init(0), next_flow_id: RefCell::new(0),
} }
} }
@ -231,10 +232,10 @@ impl<'self> FlowConstructor<'self> {
/// `#[inline(always)]` because this is performance critical and LLVM will not inline it /// `#[inline(always)]` because this is performance critical and LLVM will not inline it
/// otherwise. /// otherwise.
#[inline(always)] #[inline(always)]
fn flush_inline_boxes_to_flow(&mut self, boxes: ~[Box], flow: &mut ~Flow:, node: LayoutNode) { fn flush_inline_boxes_to_flow(&mut self, boxes: ~[Box], flow: &mut ~Flow, node: LayoutNode) {
if boxes.len() > 0 { if boxes.len() > 0 {
let inline_base = FlowData::new(self.next_flow_id(), node); let inline_base = FlowData::new(self.next_flow_id(), node);
let mut inline_flow = ~InlineFlow::from_boxes(inline_base, boxes) as ~Flow:; let mut inline_flow = ~InlineFlow::from_boxes(inline_base, boxes) as ~Flow;
TextRunScanner::new().scan_for_runs(self.layout_context, inline_flow); TextRunScanner::new().scan_for_runs(self.layout_context, inline_flow);
flow.add_new_child(inline_flow) flow.add_new_child(inline_flow)
} }
@ -244,7 +245,7 @@ impl<'self> FlowConstructor<'self> {
/// the given flow. /// the given flow.
fn flush_inline_boxes_to_flow_if_necessary(&mut self, fn flush_inline_boxes_to_flow_if_necessary(&mut self,
opt_boxes: &mut Option<~[Box]>, opt_boxes: &mut Option<~[Box]>,
flow: &mut ~Flow:, flow: &mut ~Flow,
node: LayoutNode) { node: LayoutNode) {
let opt_boxes = util::replace(opt_boxes, None); let opt_boxes = util::replace(opt_boxes, None);
if opt_boxes.len() > 0 { if opt_boxes.len() > 0 {
@ -256,7 +257,7 @@ impl<'self> FlowConstructor<'self> {
/// other `BlockFlow`s or `InlineFlow`s will be populated underneath this node, depending on /// other `BlockFlow`s or `InlineFlow`s will be populated underneath this node, depending on
/// whether {ib} splits needed to happen. /// whether {ib} splits needed to happen.
fn build_children_of_block_flow(&mut self, fn build_children_of_block_flow(&mut self,
flow: &mut ~Flow:, flow: &mut ~Flow,
node: LayoutNode) { node: LayoutNode) {
// Gather up boxes for the inline flows we might need to create. // Gather up boxes for the inline flows we might need to create.
let mut opt_boxes_for_inline_flow = None; let mut opt_boxes_for_inline_flow = None;
@ -342,10 +343,10 @@ impl<'self> FlowConstructor<'self> {
/// Builds a flow for a node with `display: block`. This yields a `BlockFlow` with possibly /// Builds a flow for a node with `display: block`. This yields a `BlockFlow` with possibly
/// other `BlockFlow`s or `InlineFlow`s underneath it, depending on whether {ib} splits needed /// other `BlockFlow`s or `InlineFlow`s underneath it, depending on whether {ib} splits needed
/// to happen. /// to happen.
fn build_flow_for_block(&mut self, node: LayoutNode) -> ~Flow: { fn build_flow_for_block(&mut self, node: LayoutNode) -> ~Flow {
let base = FlowData::new(self.next_flow_id(), node); let base = FlowData::new(self.next_flow_id(), node);
let box = self.build_box_for_node(node); let box_ = self.build_box_for_node(node);
let mut flow = ~BlockFlow::from_box(base, box) as ~Flow:; let mut flow = ~BlockFlow::from_box(base, box_) as ~Flow;
self.build_children_of_block_flow(&mut flow, node); self.build_children_of_block_flow(&mut flow, node);
flow flow
} }
@ -353,10 +354,10 @@ impl<'self> FlowConstructor<'self> {
/// Builds the flow for a node with `float: {left|right}`. This yields a float `BlockFlow` with /// Builds the flow for a node with `float: {left|right}`. This yields a float `BlockFlow` with
/// a `BlockFlow` underneath it. /// a `BlockFlow` underneath it.
fn build_flow_for_floated_block(&mut self, node: LayoutNode, float_type: FloatType) fn build_flow_for_floated_block(&mut self, node: LayoutNode, float_type: FloatType)
-> ~Flow: { -> ~Flow {
let base = FlowData::new(self.next_flow_id(), node); let base = FlowData::new(self.next_flow_id(), node);
let box = self.build_box_for_node(node); let box_ = self.build_box_for_node(node);
let mut flow = ~BlockFlow::float_from_box(base, float_type, box) as ~Flow:; let mut flow = ~BlockFlow::float_from_box(base, float_type, box_) as ~Flow;
self.build_children_of_block_flow(&mut flow, node); self.build_children_of_block_flow(&mut flow, node);
flow flow
} }
@ -458,7 +459,7 @@ impl<'self> FlowConstructor<'self> {
} }
} }
impl<'self> PostorderNodeMutTraversal for FlowConstructor<'self> { impl<'a> PostorderNodeMutTraversal for FlowConstructor<'a> {
// `#[inline(always)]` because this is always called from the traversal function and for some // `#[inline(always)]` because this is always called from the traversal function and for some
// reason LLVM's inlining heuristics go awry here. // reason LLVM's inlining heuristics go awry here.
#[inline(always)] #[inline(always)]
@ -528,7 +529,7 @@ trait NodeUtils {
fn swap_out_construction_result(self) -> ConstructionResult; fn swap_out_construction_result(self) -> ConstructionResult;
} }
impl<'self> NodeUtils for LayoutNode<'self> { impl<'ln> NodeUtils for LayoutNode<'ln> {
fn is_replaced_content(self) -> bool { fn is_replaced_content(self) -> bool {
match self.type_id() { match self.type_id() {
TextNodeTypeId | TextNodeTypeId |
@ -543,17 +544,19 @@ impl<'self> NodeUtils for LayoutNode<'self> {
#[inline(always)] #[inline(always)]
fn set_flow_construction_result(self, result: ConstructionResult) { fn set_flow_construction_result(self, result: ConstructionResult) {
match *self.mutate_layout_data().ptr { let mut layout_data_ref = self.mutate_layout_data();
Some(ref mut layout_data) => layout_data.flow_construction_result = result, match *layout_data_ref.get() {
Some(ref mut layout_data) => layout_data.data.flow_construction_result = result,
None => fail!("no layout data"), None => fail!("no layout data"),
} }
} }
#[inline(always)] #[inline(always)]
fn swap_out_construction_result(self) -> ConstructionResult { fn swap_out_construction_result(self) -> ConstructionResult {
match *self.mutate_layout_data().ptr { let mut layout_data_ref = self.mutate_layout_data();
match *layout_data_ref.get() {
Some(ref mut layout_data) => { Some(ref mut layout_data) => {
util::replace(&mut layout_data.flow_construction_result, NoConstructionResult) util::replace(&mut layout_data.data.flow_construction_result, NoConstructionResult)
} }
None => fail!("no layout data"), None => fail!("no layout data"),
} }
@ -568,14 +571,14 @@ fn strip_ignorable_whitespace_from_start(opt_boxes: &mut Option<~[Box]>) {
// FIXME(pcwalton): This is slow because vector shift is broken. :( // FIXME(pcwalton): This is slow because vector shift is broken. :(
let mut found_nonwhitespace = false; let mut found_nonwhitespace = false;
let mut result = ~[]; let mut result = ~[];
for box in boxes.move_iter() { for box_ in boxes.move_iter() {
if !found_nonwhitespace && box.is_whitespace_only() { if !found_nonwhitespace && box_.is_whitespace_only() {
debug!("stripping ignorable whitespace from start"); debug!("stripping ignorable whitespace from start");
continue continue
} }
found_nonwhitespace = true; found_nonwhitespace = true;
result.push(box) result.push(box_)
} }
*opt_boxes = Some(result) *opt_boxes = Some(result)

View file

@ -4,7 +4,7 @@
//! Constructs display lists from boxes. //! Constructs display lists from boxes.
use layout::box::Box; use layout::box_::Box;
use layout::context::LayoutContext; use layout::context::LayoutContext;
use layout::util::OpaqueNode; use layout::util::OpaqueNode;
@ -12,14 +12,14 @@ use gfx;
use style; use style;
pub trait ExtraDisplayListData { pub trait ExtraDisplayListData {
fn new(box: &Box) -> Self; fn new(box_: &Box) -> Self;
} }
pub type Nothing = (); pub type Nothing = ();
impl ExtraDisplayListData for OpaqueNode { impl ExtraDisplayListData for OpaqueNode {
fn new(box: &Box) -> OpaqueNode { fn new(box_: &Box) -> OpaqueNode {
box.node box_.node
} }
} }
@ -35,8 +35,8 @@ impl ExtraDisplayListData for Nothing {
/// ///
/// Right now, the builder isn't used for much, but it establishes the pattern we'll need once we /// Right now, the builder isn't used for much, but it establishes the pattern we'll need once we
/// support display-list-based hit testing and so forth. /// support display-list-based hit testing and so forth.
pub struct DisplayListBuilder<'self> { pub struct DisplayListBuilder<'a> {
ctx: &'self LayoutContext, ctx: &'a LayoutContext,
} }
// //

View file

@ -4,33 +4,39 @@
//! Code for managing the layout data in the DOM. //! Code for managing the layout data in the DOM.
use layout::util::{LayoutData, LayoutDataAccess}; use layout::util::{PrivateLayoutData, LayoutDataAccess, LayoutDataWrapper};
use layout::wrapper::LayoutNode; use layout::wrapper::LayoutNode;
use script::layout_interface::LayoutChan;
/// Functionality useful for querying the layout-specific data on DOM nodes. /// Functionality useful for querying the layout-specific data on DOM nodes.
pub trait LayoutAuxMethods { pub trait LayoutAuxMethods {
fn initialize_layout_data(self); fn initialize_layout_data(self, chan: LayoutChan);
fn initialize_style_for_subtree(self); fn initialize_style_for_subtree(self, chan: LayoutChan);
} }
impl<'self> LayoutAuxMethods for LayoutNode<'self> { impl<'ln> LayoutAuxMethods for LayoutNode<'ln> {
/// Resets layout data and styles for the node. /// Resets layout data and styles for the node.
/// ///
/// FIXME(pcwalton): Do this as part of box building instead of in a traversal. /// FIXME(pcwalton): Do this as part of box building instead of in a traversal.
fn initialize_layout_data(self) { fn initialize_layout_data(self, chan: LayoutChan) {
let layout_data_handle = self.mutate_layout_data(); let mut layout_data_ref = self.mutate_layout_data();
match *layout_data_handle.ptr { match *layout_data_ref.get() {
None => *layout_data_handle.ptr = Some(~LayoutData::new()), None => {
*layout_data_ref.get() = Some(LayoutDataWrapper {
chan: Some(chan),
data: ~PrivateLayoutData::new(),
});
}
Some(_) => {} Some(_) => {}
} }
} }
/// Resets layout data and styles for a Node tree. /// Resets layout data and styles for a Node tree.
/// ///
/// FIXME(pcwalton): Do this as part of box building instead of in a traversal. /// FIXME(pcwalton): Do this as part of box building instead of in a traversal.
fn initialize_style_for_subtree(self) { fn initialize_style_for_subtree(self, chan: LayoutChan) {
for n in self.traverse_preorder() { for n in self.traverse_preorder() {
n.initialize_layout_data(); n.initialize_layout_data(chan.clone());
} }
} }
} }

View file

@ -77,7 +77,7 @@ impl FloatContext {
} }
#[inline(always)] #[inline(always)]
fn with_mut_base<R>(&mut self, callback: &fn(&mut FloatContextBase) -> R) -> R { fn with_mut_base<R>(&mut self, callback: |&mut FloatContextBase| -> R) -> R {
match *self { match *self {
Invalid => fail!("Float context no longer available"), Invalid => fail!("Float context no longer available"),
Valid(ref mut base) => callback(&mut *base) Valid(ref mut base) => callback(&mut *base)
@ -85,7 +85,7 @@ impl FloatContext {
} }
#[inline(always)] #[inline(always)]
pub fn with_base<R>(&self, callback: &fn(&FloatContextBase) -> R) -> R { pub fn with_base<R>(&self, callback: |&FloatContextBase| -> R) -> R {
match *self { match *self {
Invalid => fail!("Float context no longer available"), Invalid => fail!("Float context no longer available"),
Valid(ref base) => callback(&*base) Valid(ref base) => callback(&*base)
@ -94,46 +94,46 @@ impl FloatContext {
#[inline(always)] #[inline(always)]
pub fn translate(&mut self, trans: Point2D<Au>) -> FloatContext { pub fn translate(&mut self, trans: Point2D<Au>) -> FloatContext {
do self.with_mut_base |base| { self.with_mut_base(|base| {
base.translate(trans); base.translate(trans);
} });
replace(self, Invalid) replace(self, Invalid)
} }
#[inline(always)] #[inline(always)]
pub fn available_rect(&mut self, top: Au, height: Au, max_x: Au) -> Option<Rect<Au>> { pub fn available_rect(&mut self, top: Au, height: Au, max_x: Au) -> Option<Rect<Au>> {
do self.with_base |base| { self.with_base(|base| {
base.available_rect(top, height, max_x) base.available_rect(top, height, max_x)
} })
} }
#[inline(always)] #[inline(always)]
pub fn add_float(&mut self, info: &PlacementInfo) -> FloatContext{ pub fn add_float(&mut self, info: &PlacementInfo) -> FloatContext{
do self.with_mut_base |base| { self.with_mut_base(|base| {
base.add_float(info); base.add_float(info);
} });
replace(self, Invalid) replace(self, Invalid)
} }
#[inline(always)] #[inline(always)]
pub fn place_between_floats(&self, info: &PlacementInfo) -> Rect<Au> { pub fn place_between_floats(&self, info: &PlacementInfo) -> Rect<Au> {
do self.with_base |base| { self.with_base(|base| {
base.place_between_floats(info) base.place_between_floats(info)
} })
} }
#[inline(always)] #[inline(always)]
pub fn last_float_pos(&mut self) -> Point2D<Au> { pub fn last_float_pos(&mut self) -> Point2D<Au> {
do self.with_base |base| { self.with_base(|base| {
base.last_float_pos() base.last_float_pos()
} })
} }
#[inline(always)] #[inline(always)]
pub fn clearance(&self, clear: ClearType) -> Au { pub fn clearance(&self, clear: ClearType) -> Au {
do self.with_base |base| { self.with_base(|base| {
base.clearance(clear) base.clearance(clear)
} })
} }
} }
@ -288,24 +288,6 @@ impl FloatContextBase {
self.floats_used += 1; self.floats_used += 1;
} }
/// Returns true if the given rect overlaps with any floats.
fn collides_with_float(&self, bounds: &Rect<Au>) -> bool {
for floats in self.float_data.iter() {
for float in floats.iter() {
match *float {
None => (),
Some(data) => {
if data.bounds.translate(&self.offset).intersects(bounds) {
return true;
}
}
};
}
}
return false;
}
/// Given the top 3 sides of the rectange, finds the largest height that /// Given the top 3 sides of the rectange, finds the largest height that
/// will result in the rectange not colliding with any floats. Returns /// will result in the rectange not colliding with any floats. Returns
/// None if that height is infinite. /// None if that height is infinite.

View file

@ -27,7 +27,7 @@
use css::node_style::StyledNode; use css::node_style::StyledNode;
use layout::block::BlockFlow; use layout::block::BlockFlow;
use layout::box::Box; use layout::box_::Box;
use layout::context::LayoutContext; use layout::context::LayoutContext;
use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData}; use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData};
use layout::float_context::{FloatContext, Invalid}; use layout::float_context::{FloatContext, Invalid};
@ -42,7 +42,7 @@ use geom::rect::Rect;
use gfx::display_list::{ClipDisplayItemClass, DisplayList}; use gfx::display_list::{ClipDisplayItemClass, DisplayList};
use servo_util::geometry::Au; use servo_util::geometry::Au;
use std::cast; use std::cast;
use std::cell::Cell; use std::cell::RefCell;
use style::ComputedValues; use style::ComputedValues;
use style::computed_values::text_align; use style::computed_values::text_align;
@ -127,7 +127,7 @@ pub fn base<'a>(this: &'a Flow) -> &'a FlowData {
} }
/// Iterates over the children of this immutable flow. /// Iterates over the children of this immutable flow.
pub fn imm_child_iter<'a>(flow: &'a Flow) -> DListIterator<'a,~Flow:> { pub fn imm_child_iter<'a>(flow: &'a Flow) -> DListIterator<'a,~Flow> {
base(flow).children.iter() base(flow).children.iter()
} }
@ -140,12 +140,12 @@ pub fn mut_base<'a>(this: &'a mut Flow) -> &'a mut FlowData {
} }
/// Returns the last child of this flow. /// Returns the last child of this flow.
pub fn last_child<'a>(flow: &'a mut Flow) -> Option<&'a mut ~Flow:> { pub fn last_child<'a>(flow: &'a mut Flow) -> Option<&'a mut ~Flow> {
mut_base(flow).children.back_mut() mut_base(flow).children.back_mut()
} }
/// Iterates over the children of this flow. /// Iterates over the children of this flow.
pub fn child_iter<'a>(flow: &'a mut Flow) -> MutDListIterator<'a,~Flow:> { pub fn child_iter<'a>(flow: &'a mut Flow) -> MutDListIterator<'a,~Flow> {
mut_base(flow).children.mut_iter() mut_base(flow).children.mut_iter()
} }
@ -183,13 +183,13 @@ pub trait MutableFlowUtils {
// Mutators // Mutators
/// Adds a new flow as a child of this flow. /// Adds a new flow as a child of this flow.
fn add_new_child(self, new_child: ~Flow:); fn add_new_child(self, new_child: ~Flow);
/// Invokes a closure with the first child of this flow. /// Invokes a closure with the first child of this flow.
fn with_first_child<R>(self, f: &fn(Option<&mut ~Flow:>) -> R) -> R; fn with_first_child<R>(self, f: |Option<&mut ~Flow>| -> R) -> R;
/// Invokes a closure with the last child of this flow. /// Invokes a closure with the last child of this flow.
fn with_last_child<R>(self, f: &fn(Option<&mut ~Flow:>) -> R) -> R; fn with_last_child<R>(self, f: |Option<&mut ~Flow>| -> R) -> R;
/// Removes the first child of this flow and destroys it. /// Removes the first child of this flow and destroys it.
fn remove_first(self); fn remove_first(self);
@ -205,7 +205,7 @@ pub trait MutableFlowUtils {
self, self,
builder: &DisplayListBuilder, builder: &DisplayListBuilder,
dirty: &Rect<Au>, dirty: &Rect<Au>,
list: &Cell<DisplayList<E>>) list: &RefCell<DisplayList<E>>)
-> bool; -> bool;
} }
@ -385,7 +385,7 @@ pub struct FlowData {
restyle_damage: RestyleDamage, restyle_damage: RestyleDamage,
/// The children of this flow. /// The children of this flow.
children: DList<~Flow:>, children: DList<~Flow>,
/* TODO (Issue #87): debug only */ /* TODO (Issue #87): debug only */
id: int, id: int,
@ -454,12 +454,12 @@ impl FlowData {
} }
} }
pub fn child_iter<'a>(&'a mut self) -> MutDListIterator<'a,~Flow:> { pub fn child_iter<'a>(&'a mut self) -> MutDListIterator<'a,~Flow> {
self.children.mut_iter() self.children.mut_iter()
} }
} }
impl<'self> ImmutableFlowUtils for &'self Flow { impl<'a> ImmutableFlowUtils for &'a Flow {
/// Returns true if this flow is a block or a float flow. /// Returns true if this flow is a block or a float flow.
fn is_block_like(self) -> bool { fn is_block_like(self) -> bool {
match self.class() { match self.class() {
@ -508,7 +508,7 @@ impl<'self> ImmutableFlowUtils for &'self Flow {
} }
} }
impl<'self> MutableFlowUtils for &'self mut Flow { impl<'a> MutableFlowUtils for &'a mut Flow {
/// Traverses the tree in preorder. /// Traverses the tree in preorder.
fn traverse_preorder<T:PreorderFlowTraversal>(self, traversal: &mut T) -> bool { fn traverse_preorder<T:PreorderFlowTraversal>(self, traversal: &mut T) -> bool {
if traversal.should_prune(self) { if traversal.should_prune(self) {
@ -548,17 +548,17 @@ impl<'self> MutableFlowUtils for &'self mut Flow {
} }
/// Adds a new flow as a child of this flow. /// Adds a new flow as a child of this flow.
fn add_new_child(self, new_child: ~Flow:) { fn add_new_child(self, new_child: ~Flow) {
mut_base(self).children.push_back(new_child) mut_base(self).children.push_back(new_child)
} }
/// Invokes a closure with the first child of this flow. /// Invokes a closure with the first child of this flow.
fn with_first_child<R>(self, f: &fn(Option<&mut ~Flow:>) -> R) -> R { fn with_first_child<R>(self, f: |Option<&mut ~Flow>| -> R) -> R {
f(mut_base(self).children.front_mut()) f(mut_base(self).children.front_mut())
} }
/// Invokes a closure with the last child of this flow. /// Invokes a closure with the last child of this flow.
fn with_last_child<R>(self, f: &fn(Option<&mut ~Flow:>) -> R) -> R { fn with_last_child<R>(self, f: |Option<&mut ~Flow>| -> R) -> R {
f(mut_base(self).children.back_mut()) f(mut_base(self).children.back_mut())
} }
@ -587,7 +587,7 @@ impl<'self> MutableFlowUtils for &'self mut Flow {
self, self,
builder: &DisplayListBuilder, builder: &DisplayListBuilder,
dirty: &Rect<Au>, dirty: &Rect<Au>,
list: &Cell<DisplayList<E>>) list: &RefCell<DisplayList<E>>)
-> bool { -> bool {
debug!("Flow: building display list for f{}", base(self).id); debug!("Flow: building display list for f{}", base(self).id);
match self.class() { match self.class() {
@ -596,20 +596,21 @@ impl<'self> MutableFlowUtils for &'self mut Flow {
_ => fail!("Tried to build_display_list_recurse of flow: {:?}", self), _ => fail!("Tried to build_display_list_recurse of flow: {:?}", self),
}; };
if list.with_mut_ref(|list| list.list.len() == 0) { if list.with_mut(|list| list.list.len() == 0) {
return true; return true;
} }
let child_list = ~Cell::new(DisplayList::new()); let child_list = ~RefCell::new(DisplayList::new());
for kid in child_iter(self) { for kid in child_iter(self) {
kid.build_display_list(builder,dirty,child_list); kid.build_display_list(builder,dirty,child_list);
} }
do list.with_mut_ref |list| { let mut child_list = Some(child_list.unwrap());
list.with_mut(|list| {
let result = list.list.mut_rev_iter().position(|item| { let result = list.list.mut_rev_iter().position(|item| {
match *item { match *item {
ClipDisplayItemClass(ref mut item) => { ClipDisplayItemClass(ref mut item) => {
item.child_list.push_all_move(child_list.take().list); item.child_list.push_all_move(child_list.take_unwrap().list);
true true
}, },
_ => false, _ => false,
@ -620,7 +621,7 @@ impl<'self> MutableFlowUtils for &'self mut Flow {
fail!("fail to find parent item"); fail!("fail to find parent item");
} }
} });
true true
} }
} }

View file

@ -3,14 +3,14 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use css::node_style::StyledNode; use css::node_style::StyledNode;
use layout::box::{Box, CannotSplit, GenericBox, IframeBox, ImageBox, ScannedTextBox, SplitDidFit}; use layout::box_::{Box, CannotSplit, GenericBox, IframeBox, ImageBox, ScannedTextBox, SplitDidFit};
use layout::box::{SplitDidNotFit, UnscannedTextBox}; use layout::box_::{SplitDidNotFit, UnscannedTextBox};
use layout::context::LayoutContext; use layout::context::LayoutContext;
use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData}; use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData};
use layout::flow::{FlowClass, Flow, FlowData, InlineFlowClass}; use layout::flow::{FlowClass, Flow, FlowData, InlineFlowClass};
use layout::flow; use layout::flow;
use layout::float_context::FloatContext; use layout::float_context::FloatContext;
use layout::util::{ElementMapping}; use layout::util::ElementMapping;
use layout::float_context::{PlacementInfo, FloatLeft}; use layout::float_context::{PlacementInfo, FloatLeft};
use extra::container::Deque; use extra::container::Deque;
@ -19,7 +19,7 @@ use geom::{Point2D, Rect, Size2D};
use gfx::display_list::DisplayList; use gfx::display_list::DisplayList;
use servo_util::geometry::Au; use servo_util::geometry::Au;
use servo_util::range::Range; use servo_util::range::Range;
use std::cell::Cell; use std::cell::RefCell;
use std::u16; use std::u16;
use std::util; use std::util;
use style::computed_values::{text_align, vertical_align}; use style::computed_values::{text_align, vertical_align};
@ -80,18 +80,6 @@ impl LineboxScanner {
} }
} }
fn reinitialize(&mut self, float_ctx: FloatContext) {
self.floats = float_ctx;
self.new_boxes.truncate(0);
self.work_list.clear();
self.pending_line.range = Range::empty();
self.pending_line.bounds = Rect(Point2D(Au::new(0), Au::new(0)),
Size2D(Au::new(0), Au::new(0)));
self.pending_line.green_zone = Size2D(Au::new(0), Au::new(0));
self.lines.truncate(0);
self.cur_y = Au::new(0);
}
pub fn floats_out(&mut self) -> FloatContext { pub fn floats_out(&mut self) -> FloatContext {
self.floats.clone() self.floats.clone()
} }
@ -119,13 +107,13 @@ impl LineboxScanner {
if flow.boxes.is_empty() { if flow.boxes.is_empty() {
break; break;
} }
let box = flow.boxes.remove(0); // FIXME: use a linkedlist let box_ = flow.boxes.remove(0); // FIXME: use a linkedlist
debug!("LineboxScanner: Working with box from box list: b{}", box.debug_id()); debug!("LineboxScanner: Working with box from box list: b{}", box_.debug_id());
box box_
} else { } else {
let box = self.work_list.pop_front().unwrap(); let box_ = self.work_list.pop_front().unwrap();
debug!("LineboxScanner: Working with box from work list: b{}", box.debug_id()); debug!("LineboxScanner: Working with box from work list: b{}", box_.debug_id());
box box_
}; };
let box_was_appended = self.try_append_to_line(cur_box, flow); let box_was_appended = self.try_append_to_line(cur_box, flow);
@ -413,8 +401,8 @@ impl LineboxScanner {
} }
// An unconditional push // An unconditional push
fn push_box_to_line(&mut self, box: Box) { fn push_box_to_line(&mut self, box_: Box) {
debug!("LineboxScanner: Pushing box {} to line {:u}", box.debug_id(), self.lines.len()); debug!("LineboxScanner: Pushing box {} to line {:u}", box_.debug_id(), self.lines.len());
if self.pending_line.range.length() == 0 { if self.pending_line.range.length() == 0 {
assert!(self.new_boxes.len() <= (u16::max_value as uint)); assert!(self.new_boxes.len() <= (u16::max_value as uint));
@ -422,10 +410,10 @@ impl LineboxScanner {
} }
self.pending_line.range.extend_by(1); self.pending_line.range.extend_by(1);
self.pending_line.bounds.size.width = self.pending_line.bounds.size.width + self.pending_line.bounds.size.width = self.pending_line.bounds.size.width +
box.position.get().size.width; box_.position.get().size.width;
self.pending_line.bounds.size.height = Au::max(self.pending_line.bounds.size.height, self.pending_line.bounds.size.height = Au::max(self.pending_line.bounds.size.height,
box.position.get().size.height); box_.position.get().size.height);
self.new_boxes.push(box); self.new_boxes.push(box_);
} }
} }
@ -467,8 +455,8 @@ impl InlineFlow {
} }
pub fn teardown(&mut self) { pub fn teardown(&mut self) {
for box in self.boxes.iter() { for box_ in self.boxes.iter() {
box.teardown(); box_.teardown();
} }
self.boxes = ~[]; self.boxes = ~[];
} }
@ -477,7 +465,7 @@ impl InlineFlow {
&self, &self,
builder: &DisplayListBuilder, builder: &DisplayListBuilder,
dirty: &Rect<Au>, dirty: &Rect<Au>,
list: &Cell<DisplayList<E>>) list: &RefCell<DisplayList<E>>)
-> bool { -> bool {
let abs_rect = Rect(self.base.abs_position, self.base.position.size); let abs_rect = Rect(self.base.abs_position, self.base.position.size);
if !abs_rect.intersects(dirty) { if !abs_rect.intersects(dirty) {
@ -490,8 +478,8 @@ impl InlineFlow {
self.base.id, self.base.id,
self.boxes.len()); self.boxes.len());
for box in self.boxes.iter() { for box_ in self.boxes.iter() {
box.build_display_list(builder, dirty, self.base.abs_position, (&*self) as &Flow, list) box_.build_display_list(builder, dirty, self.base.abs_position, (&*self) as &Flow, list)
} }
// TODO(#225): Should `inline-block` elements have flows as children of the inline flow or // TODO(#225): Should `inline-block` elements have flows as children of the inline flow or
@ -590,9 +578,9 @@ impl InlineFlow {
}; };
for i in line.range.eachi() { for i in line.range.eachi() {
let box = &boxes[i]; let box_ = &boxes[i];
let size = box.position.get().size; let size = box_.position.get().size;
box.position.set(Rect(Point2D(offset_x, box.position.get().origin.y), size)); box_.position.set(Rect(Point2D(offset_x, box_.position.get().origin.y), size));
offset_x = offset_x + size.width; offset_x = offset_x + size.width;
} }
} }
@ -623,10 +611,10 @@ impl Flow for InlineFlow {
let mut min_width = Au::new(0); let mut min_width = Au::new(0);
let mut pref_width = Au::new(0); let mut pref_width = Au::new(0);
for box in self.boxes.iter() { for box_ in self.boxes.iter() {
debug!("Flow[{:d}]: measuring {:s}", self.base.id, box.debug_str()); debug!("Flow[{:d}]: measuring {:s}", self.base.id, box_.debug_str());
let (this_minimum_width, this_preferred_width) = let (this_minimum_width, this_preferred_width) =
box.minimum_and_preferred_widths(); box_.minimum_and_preferred_widths();
min_width = Au::max(min_width, this_minimum_width); min_width = Au::max(min_width, this_minimum_width);
pref_width = Au::max(pref_width, this_preferred_width); pref_width = Au::max(pref_width, this_preferred_width);
} }
@ -647,8 +635,8 @@ impl Flow for InlineFlow {
{ {
let this = &mut *self; let this = &mut *self;
for box in this.boxes.iter() { for box_ in this.boxes.iter() {
box.assign_width(); box_.assign_width();
} }
} }
@ -736,9 +724,9 @@ impl Flow for InlineFlow {
let noncontent_height = top + bottom; let noncontent_height = top + bottom;
height = height + noncontent_height; height = height + noncontent_height;
let position_ref = cur_box.position.mutate(); let mut position_ref = cur_box.position.borrow_mut();
position_ref.ptr.size.height = height; position_ref.get().size.height = height;
position_ref.ptr.translate(&Point2D(Au::new(0), -height)); position_ref.get().translate(&Point2D(Au::new(0), -height));
let ascent = height + bottom; let ascent = height + bottom;
(height, Au::new(0), ascent) (height, Au::new(0), ascent)
@ -818,7 +806,7 @@ impl Flow for InlineFlow {
bottommost = bottom_from_base; bottommost = bottom_from_base;
} }
cur_box.position.mutate().ptr.origin.y = line.bounds.origin.y + offset; cur_box.position.borrow_mut().get().origin.y = line.bounds.origin.y + offset;
} }
// Calculate the distance from baseline to the top of the biggest box with 'bottom' // Calculate the distance from baseline to the top of the biggest box with 'bottom'
@ -847,7 +835,7 @@ impl Flow for InlineFlow {
_ => baseline_offset, _ => baseline_offset,
}; };
cur_box.position.mutate().ptr.origin.y = cur_box.position.get().origin.y + cur_box.position.borrow_mut().get().origin.y = cur_box.position.get().origin.y +
adjust_offset; adjust_offset;
} }

View file

@ -16,7 +16,7 @@ use layout::flow::{Flow, ImmutableFlowUtils, MutableFlowUtils, PreorderFlowTrave
use layout::flow::{PostorderFlowTraversal}; use layout::flow::{PostorderFlowTraversal};
use layout::flow; use layout::flow;
use layout::incremental::{RestyleDamage}; use layout::incremental::{RestyleDamage};
use layout::util::{LayoutData, LayoutDataAccess, OpaqueNode}; use layout::util::{LayoutDataAccess, OpaqueNode, LayoutDataWrapper};
use layout::wrapper::LayoutNode; use layout::wrapper::LayoutNode;
use extra::arc::{Arc, RWArc, MutexArc}; use extra::arc::{Arc, RWArc, MutexArc};
@ -34,7 +34,7 @@ use script::dom::element::{HTMLBodyElementTypeId, HTMLHtmlElementTypeId};
use script::layout_interface::{AddStylesheetMsg, ContentBoxQuery}; use script::layout_interface::{AddStylesheetMsg, ContentBoxQuery};
use script::layout_interface::{ContentBoxesQuery, ContentBoxesResponse, ExitNowMsg, LayoutQuery}; use script::layout_interface::{ContentBoxesQuery, ContentBoxesResponse, ExitNowMsg, LayoutQuery};
use script::layout_interface::{HitTestQuery, ContentBoxResponse, HitTestResponse}; use script::layout_interface::{HitTestQuery, ContentBoxResponse, HitTestResponse};
use script::layout_interface::{ContentChangedDocumentDamage, Msg, PrepareToExitMsg}; use script::layout_interface::{ContentChangedDocumentDamage, LayoutChan, Msg, PrepareToExitMsg};
use script::layout_interface::{QueryMsg, ReapLayoutDataMsg, Reflow, ReflowDocumentDamage}; use script::layout_interface::{QueryMsg, ReapLayoutDataMsg, Reflow, ReflowDocumentDamage};
use script::layout_interface::{ReflowForDisplay, ReflowMsg}; use script::layout_interface::{ReflowForDisplay, ReflowMsg};
use script::script_task::{ReflowCompleteMsg, ScriptChan, SendEventMsg}; use script::script_task::{ReflowCompleteMsg, ScriptChan, SendEventMsg};
@ -46,20 +46,22 @@ use servo_util::time::{ProfilerChan, profile};
use servo_util::time; use servo_util::time;
use std::cast::transmute; use std::cast::transmute;
use std::cast; use std::cast;
use std::cell::Cell; use std::cell::RefCell;
use std::comm::Port; use std::comm::Port;
use std::task;
use std::util; use std::util;
use style::{AuthorOrigin, Stylesheet, Stylist}; use style::{AuthorOrigin, Stylesheet, Stylist};
/// Information needed by the layout task. /// Information needed by the layout task.
struct LayoutTask { pub struct LayoutTask {
/// The ID of the pipeline that we belong to. /// The ID of the pipeline that we belong to.
id: PipelineId, id: PipelineId,
/// The port on which we receive messages. /// The port on which we receive messages.
port: Port<Msg>, port: Port<Msg>,
//// The channel to send messages to ourself.
chan: LayoutChan,
/// The channel on which messages can be sent to the constellation. /// The channel on which messages can be sent to the constellation.
constellation_chan: ConstellationChan, constellation_chan: ConstellationChan,
@ -132,9 +134,9 @@ impl PreorderFlowTraversal for PropagateDamageTraversal {
/// The bubble-widths traversal, the first part of layout computation. This computes preferred /// The bubble-widths traversal, the first part of layout computation. This computes preferred
/// and intrinsic widths and bubbles them up the tree. /// and intrinsic widths and bubbles them up the tree.
struct BubbleWidthsTraversal<'self>(&'self mut LayoutContext); struct BubbleWidthsTraversal<'a>(&'a mut LayoutContext);
impl<'self> PostorderFlowTraversal for BubbleWidthsTraversal<'self> { impl<'a> PostorderFlowTraversal for BubbleWidthsTraversal<'a> {
#[inline] #[inline]
fn process(&mut self, flow: &mut Flow) -> bool { fn process(&mut self, flow: &mut Flow) -> bool {
flow.bubble_widths(**self); flow.bubble_widths(**self);
@ -151,9 +153,9 @@ impl<'self> PostorderFlowTraversal for BubbleWidthsTraversal<'self> {
} }
/// The assign-widths traversal. In Gecko this corresponds to `Reflow`. /// The assign-widths traversal. In Gecko this corresponds to `Reflow`.
struct AssignWidthsTraversal<'self>(&'self mut LayoutContext); struct AssignWidthsTraversal<'a>(&'a mut LayoutContext);
impl<'self> PreorderFlowTraversal for AssignWidthsTraversal<'self> { impl<'a> PreorderFlowTraversal for AssignWidthsTraversal<'a> {
#[inline] #[inline]
fn process(&mut self, flow: &mut Flow) -> bool { fn process(&mut self, flow: &mut Flow) -> bool {
flow.assign_widths(**self); flow.assign_widths(**self);
@ -164,9 +166,9 @@ impl<'self> PreorderFlowTraversal for AssignWidthsTraversal<'self> {
/// The assign-heights-and-store-overflow traversal, the last (and most expensive) part of layout /// The assign-heights-and-store-overflow traversal, the last (and most expensive) part of layout
/// computation. Determines the final heights for all layout objects, computes positions, and /// computation. Determines the final heights for all layout objects, computes positions, and
/// computes overflow regions. In Gecko this corresponds to `FinishAndStoreOverflow`. /// computes overflow regions. In Gecko this corresponds to `FinishAndStoreOverflow`.
struct AssignHeightsAndStoreOverflowTraversal<'self>(&'self mut LayoutContext); struct AssignHeightsAndStoreOverflowTraversal<'a>(&'a mut LayoutContext);
impl<'self> PostorderFlowTraversal for AssignHeightsAndStoreOverflowTraversal<'self> { impl<'a> PostorderFlowTraversal for AssignHeightsAndStoreOverflowTraversal<'a> {
#[inline] #[inline]
fn process(&mut self, flow: &mut Flow) -> bool { fn process(&mut self, flow: &mut Flow) -> bool {
flow.assign_height(**self); flow.assign_height(**self);
@ -186,10 +188,10 @@ struct LayoutImageResponder {
} }
impl ImageResponder for LayoutImageResponder { impl ImageResponder for LayoutImageResponder {
fn respond(&self) -> ~fn(ImageResponseMsg) { fn respond(&self) -> proc(ImageResponseMsg) {
let id = self.id.clone(); let id = self.id.clone();
let script_chan = self.script_chan.clone(); let script_chan = self.script_chan.clone();
let f: ~fn(ImageResponseMsg) = |_| { let f: proc(ImageResponseMsg) = proc(_) {
script_chan.send(SendEventMsg(id.clone(), ReflowEvent)) script_chan.send(SendEventMsg(id.clone(), ReflowEvent))
}; };
f f
@ -200,6 +202,7 @@ impl LayoutTask {
/// Spawns a new layout task. /// Spawns a new layout task.
pub fn create(id: PipelineId, pub fn create(id: PipelineId,
port: Port<Msg>, port: Port<Msg>,
chan: LayoutChan,
constellation_chan: ConstellationChan, constellation_chan: ConstellationChan,
script_chan: ScriptChan, script_chan: ScriptChan,
render_chan: RenderChan<OpaqueNode>, render_chan: RenderChan<OpaqueNode>,
@ -207,11 +210,11 @@ impl LayoutTask {
opts: Opts, opts: Opts,
profiler_chan: ProfilerChan, profiler_chan: ProfilerChan,
shutdown_chan: Chan<()>) { shutdown_chan: Chan<()>) {
spawn_with!(task::task(), [port, constellation_chan, script_chan, spawn(proc() {
render_chan, img_cache_task, profiler_chan, shutdown_chan], { { // Ensures layout task is destroyed before we send shutdown message
{ // Ensures LayoutTask gets destroyed before we send the shutdown message
let mut layout = LayoutTask::new(id, let mut layout = LayoutTask::new(id,
port, port,
chan,
constellation_chan, constellation_chan,
script_chan, script_chan,
render_chan, render_chan,
@ -220,7 +223,6 @@ impl LayoutTask {
profiler_chan); profiler_chan);
layout.start(); layout.start();
} }
shutdown_chan.send(()); shutdown_chan.send(());
}); });
} }
@ -228,6 +230,7 @@ impl LayoutTask {
/// Creates a new `LayoutTask` structure. /// Creates a new `LayoutTask` structure.
fn new(id: PipelineId, fn new(id: PipelineId,
port: Port<Msg>, port: Port<Msg>,
chan: LayoutChan,
constellation_chan: ConstellationChan, constellation_chan: ConstellationChan,
script_chan: ScriptChan, script_chan: ScriptChan,
render_chan: RenderChan<OpaqueNode>, render_chan: RenderChan<OpaqueNode>,
@ -239,6 +242,7 @@ impl LayoutTask {
LayoutTask { LayoutTask {
id: id, id: id,
port: port, port: port,
chan: chan,
constellation_chan: constellation_chan, constellation_chan: constellation_chan,
script_chan: script_chan, script_chan: script_chan,
render_chan: render_chan, render_chan: render_chan,
@ -281,17 +285,15 @@ impl LayoutTask {
match self.port.recv() { match self.port.recv() {
AddStylesheetMsg(sheet) => self.handle_add_stylesheet(sheet), AddStylesheetMsg(sheet) => self.handle_add_stylesheet(sheet),
ReflowMsg(data) => { ReflowMsg(data) => {
let data = Cell::new(data); profile(time::LayoutPerformCategory, self.profiler_chan.clone(), || {
self.handle_reflow(data);
do profile(time::LayoutPerformCategory, self.profiler_chan.clone()) { });
self.handle_reflow(data.take());
}
} }
QueryMsg(query) => { QueryMsg(query) => {
let query = Cell::new(query); let mut query = Some(query);
do profile(time::LayoutQueryCategory, self.profiler_chan.clone()) { profile(time::LayoutQueryCategory, self.profiler_chan.clone(), || {
self.handle_query(query.take()); self.handle_query(query.take_unwrap());
} });
} }
ReapLayoutDataMsg(dead_layout_data) => { ReapLayoutDataMsg(dead_layout_data) => {
unsafe { unsafe {
@ -340,16 +342,16 @@ impl LayoutTask {
/// Shuts down the layout task now. If there are any DOM nodes left, layout will now (safely) /// Shuts down the layout task now. If there are any DOM nodes left, layout will now (safely)
/// crash. /// crash.
fn exit_now(&mut self) { fn exit_now(&mut self) {
let (response_port, response_chan) = stream(); let (response_port, response_chan) = Chan::new();
self.render_chan.send(render_task::ExitMsg(response_chan)); self.render_chan.send(render_task::ExitMsg(response_chan));
response_port.recv() response_port.recv()
} }
fn handle_add_stylesheet(&mut self, sheet: Stylesheet) { fn handle_add_stylesheet(&mut self, sheet: Stylesheet) {
let sheet = Cell::new(sheet); let mut sheet = Some(sheet);
do self.stylist.write |stylist| { self.stylist.write(|stylist| {
stylist.add_stylesheet(sheet.take(), AuthorOrigin); stylist.add_stylesheet(sheet.take_unwrap(), AuthorOrigin);
} });
} }
/// Builds the flow tree. /// Builds the flow tree.
@ -359,12 +361,13 @@ impl LayoutTask {
/// is intertwined with selector matching, making it difficult to compare directly. It is /// is intertwined with selector matching, making it difficult to compare directly. It is
/// marked `#[inline(never)]` to aid benchmarking in sampling profilers. /// marked `#[inline(never)]` to aid benchmarking in sampling profilers.
#[inline(never)] #[inline(never)]
fn construct_flow_tree(&self, layout_context: &mut LayoutContext, node: LayoutNode) -> ~Flow: { fn construct_flow_tree(&self, layout_context: &mut LayoutContext, node: LayoutNode) -> ~Flow {
node.traverse_postorder_mut(&mut FlowConstructor::init(layout_context)); node.traverse_postorder_mut(&mut FlowConstructor::init(layout_context));
let result = match *node.mutate_layout_data().ptr { let mut layout_data_ref = node.mutate_layout_data();
let result = match *layout_data_ref.get() {
Some(ref mut layout_data) => { Some(ref mut layout_data) => {
util::replace(&mut layout_data.flow_construction_result, NoConstructionResult) util::replace(&mut layout_data.data.flow_construction_result, NoConstructionResult)
} }
None => fail!("no layout data for root node"), None => fail!("no layout data for root node"),
}; };
@ -436,18 +439,18 @@ impl LayoutTask {
// Initialize layout data for each node. // Initialize layout data for each node.
// //
// FIXME: This is inefficient. We don't need an entire traversal to do this! // FIXME: This is inefficient. We don't need an entire traversal to do this!
do profile(time::LayoutAuxInitCategory, self.profiler_chan.clone()) { profile(time::LayoutAuxInitCategory, self.profiler_chan.clone(), || {
node.initialize_style_for_subtree(); node.initialize_style_for_subtree(self.chan.clone());
} });
// Perform CSS selector matching if necessary. // Perform CSS selector matching if necessary.
match data.damage.level { match data.damage.level {
ReflowDocumentDamage => {} ReflowDocumentDamage => {}
_ => { _ => {
do profile(time::LayoutSelectorMatchCategory, self.profiler_chan.clone()) { profile(time::LayoutSelectorMatchCategory, self.profiler_chan.clone(), || {
node.match_subtree(self.stylist.clone()); node.match_subtree(self.stylist.clone());
node.cascade_subtree(None); node.cascade_subtree(None);
} });
} }
} }
@ -464,25 +467,25 @@ impl LayoutTask {
// Perform the primary layout passes over the flow tree to compute the locations of all // Perform the primary layout passes over the flow tree to compute the locations of all
// the boxes. // the boxes.
do profile(time::LayoutMainCategory, self.profiler_chan.clone()) { profile(time::LayoutMainCategory, self.profiler_chan.clone(), || {
self.solve_constraints(layout_root, &mut layout_ctx) self.solve_constraints(layout_root, &mut layout_ctx)
} });
debug!("layout: constraint solving done:"); debug!("layout: constraint solving done:");
debug!("{:?}", layout_root.dump()); debug!("{:?}", layout_root.dump());
// Build the display list if necessary, and send it to the renderer. // Build the display list if necessary, and send it to the renderer.
if data.goal == ReflowForDisplay { if data.goal == ReflowForDisplay {
do profile(time::LayoutDispListBuildCategory, self.profiler_chan.clone()) { profile(time::LayoutDispListBuildCategory, self.profiler_chan.clone(), || {
let root_size = flow::base(layout_root).position.size; let root_size = flow::base(layout_root).position.size;
let display_list = ~Cell::new(DisplayList::<OpaqueNode>::new()); let display_list = ~RefCell::new(DisplayList::<OpaqueNode>::new());
let dirty = flow::base(layout_root).position.clone(); let dirty = flow::base(layout_root).position.clone();
let display_list_builder = DisplayListBuilder { let display_list_builder = DisplayListBuilder {
ctx: &layout_ctx, ctx: &layout_ctx,
}; };
layout_root.build_display_list(&display_list_builder, &dirty, display_list); layout_root.build_display_list(&display_list_builder, &dirty, display_list);
let display_list = Arc::new(display_list.take()); let display_list = Arc::new(display_list.unwrap());
let mut color = color::rgba(255.0, 255.0, 255.0, 255.0); let mut color = color::rgba(255.0, 255.0, 255.0, 255.0);
@ -516,7 +519,7 @@ impl LayoutTask {
self.display_list = Some(display_list.clone()); self.display_list = Some(display_list.clone());
self.render_chan.send(RenderMsg(render_layer)); self.render_chan.send(RenderMsg(render_layer));
} // time(layout: display list building) });
} }
// Tell script that we're done. // Tell script that we're done.
@ -663,8 +666,9 @@ impl LayoutTask {
/// Handles a message to destroy layout data. Layout data must be destroyed on *this* task /// Handles a message to destroy layout data. Layout data must be destroyed on *this* task
/// because it contains local managed pointers. /// because it contains local managed pointers.
unsafe fn handle_reap_layout_data(&self, layout_data: LayoutDataRef) { unsafe fn handle_reap_layout_data(&self, layout_data: LayoutDataRef) {
let ptr: &mut Option<~LayoutData> = cast::transmute(layout_data.borrow_unchecked()); let mut layout_data_ref = layout_data.borrow_mut();
*ptr = None let _: Option<LayoutDataWrapper> = cast::transmute(
util::replace(layout_data_ref.get(), None));
} }
} }

View file

@ -4,7 +4,7 @@
//! Text layout. //! Text layout.
use layout::box::{Box, ScannedTextBox, ScannedTextBoxInfo, UnscannedTextBox}; use layout::box_::{Box, ScannedTextBox, ScannedTextBoxInfo, UnscannedTextBox};
use layout::context::LayoutContext; use layout::context::LayoutContext;
use layout::flow::Flow; use layout::flow::Flow;
@ -15,7 +15,7 @@ use servo_util::range::Range;
use std::vec; use std::vec;
/// A stack-allocated object for scanning an inline flow into `TextRun`-containing `TextBox`es. /// A stack-allocated object for scanning an inline flow into `TextRun`-containing `TextBox`es.
struct TextRunScanner { pub struct TextRunScanner {
clump: Range, clump: Range,
} }
@ -123,7 +123,7 @@ impl TextRunScanner {
// font group fonts. This is probably achieved by creating the font group above // font group fonts. This is probably achieved by creating the font group above
// and then letting `FontGroup` decide which `Font` to stick into the text run. // and then letting `FontGroup` decide which `Font` to stick into the text run.
let fontgroup = ctx.font_ctx.get_resolved_font_for_style(&font_style); let fontgroup = ctx.font_ctx.get_resolved_font_for_style(&font_style);
let run = ~fontgroup.with_borrow(|fg| fg.create_textrun(transformed_text.clone(), decoration)); let run = ~fontgroup.borrow().with(|fg| fg.create_textrun(transformed_text.clone(), decoration));
debug!("TextRunScanner: pushing single text box in range: {} ({})", debug!("TextRunScanner: pushing single text box in range: {} ({})",
self.clump, self.clump,
@ -142,7 +142,7 @@ impl TextRunScanner {
// First, transform/compress text of all the nodes. // First, transform/compress text of all the nodes.
let mut last_whitespace_in_clump = new_whitespace; let mut last_whitespace_in_clump = new_whitespace;
let transformed_strs: ~[~str] = do vec::from_fn(self.clump.length()) |i| { let transformed_strs: ~[~str] = vec::from_fn(self.clump.length(), |i| {
// TODO(#113): We should be passing the compression context between calls to // TODO(#113): We should be passing the compression context between calls to
// `transform_text`, so that boxes starting and/or ending with whitespace can // `transform_text`, so that boxes starting and/or ending with whitespace can
// be compressed correctly with respect to the text run. // be compressed correctly with respect to the text run.
@ -157,7 +157,7 @@ impl TextRunScanner {
last_whitespace_in_clump); last_whitespace_in_clump);
last_whitespace_in_clump = new_whitespace; last_whitespace_in_clump = new_whitespace;
new_str new_str
}; });
new_whitespace = last_whitespace_in_clump; new_whitespace = last_whitespace_in_clump;
// Next, concatenate all of the transformed strings together, saving the new // Next, concatenate all of the transformed strings together, saving the new
@ -186,8 +186,8 @@ impl TextRunScanner {
// sequence. If no clump takes ownership, however, it will leak. // sequence. If no clump takes ownership, however, it will leak.
let clump = self.clump; let clump = self.clump;
let run = if clump.length() != 0 && run_str.len() > 0 { let run = if clump.length() != 0 && run_str.len() > 0 {
fontgroup.with_borrow( |fg| { fontgroup.borrow().with(|fg| {
fg.fonts[0].with_mut_borrow( |font| { fg.fonts[0].borrow().with_mut(|font| {
Some(Arc::new(~TextRun::new(font, run_str.clone(), decoration))) Some(Arc::new(~TextRun::new(font, run_str.clone(), decoration)))
}) })
}) })
@ -216,14 +216,14 @@ impl TextRunScanner {
} // End of match. } // End of match.
debug!("--- In boxes: ---"); debug!("--- In boxes: ---");
for (i, box) in in_boxes.iter().enumerate() { for (i, box_) in in_boxes.iter().enumerate() {
debug!("{:u} --> {:s}", i, box.debug_str()); debug!("{:u} --> {:s}", i, box_.debug_str());
} }
debug!("------------------"); debug!("------------------");
debug!("--- Out boxes: ---"); debug!("--- Out boxes: ---");
for (i, box) in out_boxes.iter().enumerate() { for (i, box_) in out_boxes.iter().enumerate() {
debug!("{:u} --> {:s}", i, box.debug_str()); debug!("{:u} --> {:s}", i, box_.debug_str());
} }
debug!("------------------"); debug!("------------------");

View file

@ -2,15 +2,16 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use layout::box::Box; use layout::box_::Box;
use layout::construct::{ConstructionResult, NoConstructionResult}; use layout::construct::{ConstructionResult, NoConstructionResult};
use layout::wrapper::LayoutNode; use layout::wrapper::LayoutNode;
use extra::arc::Arc; use extra::arc::Arc;
use script::dom::node::AbstractNode; use script::dom::node::AbstractNode;
use script::layout_interface::LayoutChan;
use servo_util::range::Range; use servo_util::range::Range;
use servo_util::slot::{MutSlotRef, SlotRef};
use std::cast; use std::cast;
use std::cell::{Ref, RefMut};
use std::iter::Enumerate; use std::iter::Enumerate;
use std::libc::uintptr_t; use std::libc::uintptr_t;
use std::vec::VecIterator; use std::vec::VecIterator;
@ -31,7 +32,7 @@ impl NodeRange {
} }
} }
struct ElementMapping { pub struct ElementMapping {
priv entries: ~[NodeRange], priv entries: ~[NodeRange],
} }
@ -46,7 +47,7 @@ impl ElementMapping {
self.entries.push(NodeRange::new(node, range)) self.entries.push(NodeRange::new(node, range))
} }
pub fn each(&self, callback: &fn(nr: &NodeRange) -> bool) -> bool { pub fn each(&self, callback: |nr: &NodeRange| -> bool) -> bool {
for nr in self.entries.iter() { for nr in self.entries.iter() {
if !callback(nr) { if !callback(nr) {
break break
@ -63,14 +64,14 @@ impl ElementMapping {
let entries = &mut self.entries; let entries = &mut self.entries;
debug!("--- Old boxes: ---"); debug!("--- Old boxes: ---");
for (i, box) in old_boxes.iter().enumerate() { for (i, box_) in old_boxes.iter().enumerate() {
debug!("{:u} --> {:s}", i, box.debug_str()); debug!("{:u} --> {:s}", i, box_.debug_str());
} }
debug!("------------------"); debug!("------------------");
debug!("--- New boxes: ---"); debug!("--- New boxes: ---");
for (i, box) in new_boxes.iter().enumerate() { for (i, box_) in new_boxes.iter().enumerate() {
debug!("{:u} --> {:s}", i, box.debug_str()); debug!("{:u} --> {:s}", i, box_.debug_str());
} }
debug!("------------------"); debug!("------------------");
@ -125,7 +126,7 @@ impl ElementMapping {
} }
/// Data that layout associates with a node. /// Data that layout associates with a node.
pub struct LayoutData { pub struct PrivateLayoutData {
/// The results of CSS matching for this node. /// The results of CSS matching for this node.
before_applicable_declarations: ~[Arc<~[PropertyDeclaration]>], before_applicable_declarations: ~[Arc<~[PropertyDeclaration]>],
@ -148,10 +149,10 @@ pub struct LayoutData {
flow_construction_result: ConstructionResult, flow_construction_result: ConstructionResult,
} }
impl LayoutData { impl PrivateLayoutData {
/// Creates new layout data. /// Creates new layout data.
pub fn new() -> LayoutData { pub fn new() -> PrivateLayoutData {
LayoutData { PrivateLayoutData {
applicable_declarations: ~[], applicable_declarations: ~[],
before_applicable_declarations: ~[], before_applicable_declarations: ~[],
after_applicable_declarations: ~[], after_applicable_declarations: ~[],
@ -164,35 +165,35 @@ impl LayoutData {
} }
} }
pub struct LayoutDataWrapper {
chan: Option<LayoutChan>,
data: ~PrivateLayoutData,
}
/// A trait that allows access to the layout data of a DOM node. /// A trait that allows access to the layout data of a DOM node.
pub trait LayoutDataAccess { pub trait LayoutDataAccess {
/// Borrows the layout data without checks. /// Borrows the layout data without checks.
/// ///
/// FIXME(pcwalton): Make safe. /// FIXME(pcwalton): Make safe.
unsafe fn borrow_layout_data_unchecked<'a>(&'a self) -> &'a Option<~LayoutData>; // unsafe fn borrow_layout_data_unchecked<'a>(&'a self) -> &'a Option<~LayoutData>;
/// Borrows the layout data immutably. Fails on a conflicting borrow. /// Borrows the layout data immutably. Fails on a conflicting borrow.
fn borrow_layout_data<'a>(&'a self) -> SlotRef<'a,Option<~LayoutData>>; fn borrow_layout_data<'a>(&'a self) -> Ref<'a,Option<LayoutDataWrapper>>;
/// Borrows the layout data mutably. Fails on a conflicting borrow. /// Borrows the layout data mutably. Fails on a conflicting borrow.
fn mutate_layout_data<'a>(&'a self) -> MutSlotRef<'a,Option<~LayoutData>>; fn mutate_layout_data<'a>(&'a self) -> RefMut<'a,Option<LayoutDataWrapper>>;
} }
impl<'self> LayoutDataAccess for LayoutNode<'self> { impl<'ln> LayoutDataAccess for LayoutNode<'ln> {
#[inline(always)] #[inline(always)]
unsafe fn borrow_layout_data_unchecked<'a>(&'a self) -> &'a Option<~LayoutData> { fn borrow_layout_data<'a>(&'a self) -> Ref<'a,Option<LayoutDataWrapper>> {
cast::transmute(self.get().layout_data.borrow_unchecked())
}
#[inline(always)]
fn borrow_layout_data<'a>(&'a self) -> SlotRef<'a,Option<~LayoutData>> {
unsafe { unsafe {
cast::transmute(self.get().layout_data.borrow()) cast::transmute(self.get().layout_data.borrow())
} }
} }
#[inline(always)] #[inline(always)]
fn mutate_layout_data<'a>(&'a self) -> MutSlotRef<'a,Option<~LayoutData>> { fn mutate_layout_data<'a>(&'a self) -> RefMut<'a,Option<LayoutDataWrapper>> {
unsafe { unsafe {
cast::transmute(self.get().layout_data.mutate()) cast::transmute(self.get().layout_data.borrow_mut())
} }
} }
} }

View file

@ -29,17 +29,17 @@ use style::{PropertyDeclarationBlock, TElement, TNode};
/// A wrapper so that layout can access only the methods that it should have access to. Layout must /// A wrapper so that layout can access only the methods that it should have access to. Layout must
/// only ever see these and must never see instances of `AbstractNode`. /// only ever see these and must never see instances of `AbstractNode`.
#[deriving(Clone, Eq)] #[deriving(Clone, Eq)]
pub struct LayoutNode<'self> { pub struct LayoutNode<'a> {
/// The wrapped node. /// The wrapped node.
priv node: AbstractNode, priv node: AbstractNode,
/// Being chained to a value prevents `LayoutNode`s from escaping. /// Being chained to a value prevents `LayoutNode`s from escaping.
priv chain: &'self (), priv chain: &'a (),
} }
impl<'self> LayoutNode<'self> { impl<'ln> LayoutNode<'ln> {
/// Creates a new layout node, scoped to the given closure. /// Creates a new layout node, scoped to the given closure.
pub unsafe fn with_layout_node<R>(node: AbstractNode, f: &fn<'a>(LayoutNode<'a>) -> R) -> R { pub unsafe fn with_layout_node<R>(node: AbstractNode, f: <'a> |LayoutNode<'a>| -> R) -> R {
let heavy_iron_ball = (); let heavy_iron_ball = ();
f(LayoutNode { f(LayoutNode {
node: node, node: node,
@ -48,7 +48,7 @@ impl<'self> LayoutNode<'self> {
} }
/// Creates a new layout node with the same lifetime as this layout node. /// Creates a new layout node with the same lifetime as this layout node.
unsafe fn new_with_this_lifetime(&self, node: AbstractNode) -> LayoutNode<'self> { unsafe fn new_with_this_lifetime(&self, node: AbstractNode) -> LayoutNode<'ln> {
LayoutNode { LayoutNode {
node: node, node: node,
chain: self.chain, chain: self.chain,
@ -62,14 +62,14 @@ impl<'self> LayoutNode<'self> {
} }
/// Returns the first child of this node. /// Returns the first child of this node.
pub fn first_child(&self) -> Option<LayoutNode<'self>> { pub fn first_child(&self) -> Option<LayoutNode<'ln>> {
unsafe { unsafe {
self.node.first_child().map(|node| self.new_with_this_lifetime(node)) self.node.first_child().map(|node| self.new_with_this_lifetime(node))
} }
} }
/// Returns the first child of this node. /// Returns the first child of this node.
pub fn last_child(&self) -> Option<LayoutNode<'self>> { pub fn last_child(&self) -> Option<LayoutNode<'ln>> {
unsafe { unsafe {
self.node.last_child().map(|node| self.new_with_this_lifetime(node)) self.node.last_child().map(|node| self.new_with_this_lifetime(node))
} }
@ -78,14 +78,14 @@ impl<'self> LayoutNode<'self> {
/// Iterates over this node and all its descendants, in preorder. /// Iterates over this node and all its descendants, in preorder.
/// ///
/// FIXME(pcwalton): Terribly inefficient. We should use parallelism. /// FIXME(pcwalton): Terribly inefficient. We should use parallelism.
pub fn traverse_preorder(&self) -> LayoutTreeIterator<'self> { pub fn traverse_preorder(&self) -> LayoutTreeIterator<'ln> {
let mut nodes = ~[]; let mut nodes = ~[];
gather_layout_nodes(self, &mut nodes, false); gather_layout_nodes(self, &mut nodes, false);
LayoutTreeIterator::new(nodes) LayoutTreeIterator::new(nodes)
} }
/// Returns an iterator over this node's children. /// Returns an iterator over this node's children.
pub fn children(&self) -> LayoutNodeChildrenIterator<'self> { pub fn children(&self) -> LayoutNodeChildrenIterator<'ln> {
LayoutNodeChildrenIterator { LayoutNodeChildrenIterator {
current_node: self.first_child(), current_node: self.first_child(),
} }
@ -110,7 +110,7 @@ impl<'self> LayoutNode<'self> {
/// Downcasts this node to an image element and calls the given closure. /// Downcasts this node to an image element and calls the given closure.
/// ///
/// FIXME(pcwalton): RAII. /// FIXME(pcwalton): RAII.
unsafe fn with_image_element<R>(self, f: &fn(&HTMLImageElement) -> R) -> R { unsafe fn with_image_element<R>(self, f: |&HTMLImageElement| -> R) -> R {
if !self.node.is_image_element() { if !self.node.is_image_element() {
fail!(~"node is not an image element"); fail!(~"node is not an image element");
} }
@ -131,7 +131,7 @@ impl<'self> LayoutNode<'self> {
/// Downcasts this node to an iframe element and calls the given closure. /// Downcasts this node to an iframe element and calls the given closure.
/// ///
/// FIXME(pcwalton): RAII. /// FIXME(pcwalton): RAII.
unsafe fn with_iframe_element<R>(self, f: &fn(&HTMLIFrameElement) -> R) -> R { unsafe fn with_iframe_element<R>(self, f: |&HTMLIFrameElement| -> R) -> R {
if !self.node.is_iframe_element() { if !self.node.is_iframe_element() {
fail!(~"node is not an iframe element"); fail!(~"node is not an iframe element");
} }
@ -164,7 +164,7 @@ impl<'self> LayoutNode<'self> {
/// Downcasts this node to a text node and calls the given closure. /// Downcasts this node to a text node and calls the given closure.
/// ///
/// FIXME(pcwalton): RAII. /// FIXME(pcwalton): RAII.
unsafe fn with_text<R>(self, f: &fn(&Text) -> R) -> R { unsafe fn with_text<R>(self, f: |&Text| -> R) -> R {
self.node.with_imm_text(f) self.node.with_imm_text(f)
} }
@ -228,20 +228,20 @@ impl<'self> LayoutNode<'self> {
} }
} }
impl<'self> TNode<LayoutElement<'self>> for LayoutNode<'self> { impl<'ln> TNode<LayoutElement<'ln>> for LayoutNode<'ln> {
fn parent_node(&self) -> Option<LayoutNode<'self>> { fn parent_node(&self) -> Option<LayoutNode<'ln>> {
unsafe { unsafe {
self.node.node().parent_node.map(|node| self.new_with_this_lifetime(node)) self.node.node().parent_node.map(|node| self.new_with_this_lifetime(node))
} }
} }
fn prev_sibling(&self) -> Option<LayoutNode<'self>> { fn prev_sibling(&self) -> Option<LayoutNode<'ln>> {
unsafe { unsafe {
self.node.node().prev_sibling.map(|node| self.new_with_this_lifetime(node)) self.node.node().prev_sibling.map(|node| self.new_with_this_lifetime(node))
} }
} }
fn next_sibling(&self) -> Option<LayoutNode<'self>> { fn next_sibling(&self) -> Option<LayoutNode<'ln>> {
unsafe { unsafe {
self.node.node().next_sibling.map(|node| self.new_with_this_lifetime(node)) self.node.node().next_sibling.map(|node| self.new_with_this_lifetime(node))
} }
@ -249,21 +249,21 @@ impl<'self> TNode<LayoutElement<'self>> for LayoutNode<'self> {
fn is_element(&self) -> bool { fn is_element(&self) -> bool {
match self.node.type_id() { match self.node.type_id() {
ElementNodeTypeId(*) => true, ElementNodeTypeId(..) => true,
_ => false _ => false
} }
} }
fn is_document(&self) -> bool { fn is_document(&self) -> bool {
match self.node.type_id() { match self.node.type_id() {
DocumentNodeTypeId(*) => true, DocumentNodeTypeId(..) => true,
_ => false _ => false
} }
} }
/// If this is an element, accesses the element data. Fails if this is not an element node. /// If this is an element, accesses the element data. Fails if this is not an element node.
#[inline] #[inline]
fn with_element<R>(&self, f: &fn(&LayoutElement<'self>) -> R) -> R { fn with_element<R>(&self, f: |&LayoutElement<'ln>| -> R) -> R {
self.node.with_imm_element(|element| { self.node.with_imm_element(|element| {
// FIXME(pcwalton): Workaround until Rust gets multiple lifetime parameters on // FIXME(pcwalton): Workaround until Rust gets multiple lifetime parameters on
// implementations. // implementations.
@ -276,16 +276,16 @@ impl<'self> TNode<LayoutElement<'self>> for LayoutNode<'self> {
} }
} }
pub struct LayoutNodeChildrenIterator<'self> { pub struct LayoutNodeChildrenIterator<'a> {
priv current_node: Option<LayoutNode<'self>>, priv current_node: Option<LayoutNode<'a>>,
} }
impl<'self> Iterator<LayoutNode<'self>> for LayoutNodeChildrenIterator<'self> { impl<'a> Iterator<LayoutNode<'a>> for LayoutNodeChildrenIterator<'a> {
fn next(&mut self) -> Option<LayoutNode<'self>> { fn next(&mut self) -> Option<LayoutNode<'a>> {
let node = self.current_node; let node = self.current_node;
self.current_node = do self.current_node.and_then |node| { self.current_node = self.current_node.and_then(|node| {
node.next_sibling() node.next_sibling()
}; });
node node
} }
} }
@ -294,13 +294,13 @@ impl<'self> Iterator<LayoutNode<'self>> for LayoutNodeChildrenIterator<'self> {
// Easy for preorder; harder for postorder. // Easy for preorder; harder for postorder.
// //
// FIXME(pcwalton): Parallelism! Eventually this should just be nuked. // FIXME(pcwalton): Parallelism! Eventually this should just be nuked.
pub struct LayoutTreeIterator<'self> { pub struct LayoutTreeIterator<'a> {
priv nodes: ~[LayoutNode<'self>], priv nodes: ~[LayoutNode<'a>],
priv index: uint, priv index: uint,
} }
impl<'self> LayoutTreeIterator<'self> { impl<'a> LayoutTreeIterator<'a> {
fn new(nodes: ~[LayoutNode<'self>]) -> LayoutTreeIterator<'self> { fn new(nodes: ~[LayoutNode<'a>]) -> LayoutTreeIterator<'a> {
LayoutTreeIterator { LayoutTreeIterator {
nodes: nodes, nodes: nodes,
index: 0, index: 0,
@ -308,8 +308,8 @@ impl<'self> LayoutTreeIterator<'self> {
} }
} }
impl<'self> Iterator<LayoutNode<'self>> for LayoutTreeIterator<'self> { impl<'a> Iterator<LayoutNode<'a>> for LayoutTreeIterator<'a> {
fn next(&mut self) -> Option<LayoutNode<'self>> { fn next(&mut self) -> Option<LayoutNode<'a>> {
if self.index >= self.nodes.len() { if self.index >= self.nodes.len() {
None None
} else { } else {
@ -360,17 +360,17 @@ pub trait PostorderNodeMutTraversal {
} }
/// A wrapper around elements that ensures layout can only ever access safe properties. /// A wrapper around elements that ensures layout can only ever access safe properties.
pub struct LayoutElement<'self> { pub struct LayoutElement<'le> {
priv element: &'self Element, priv element: &'le Element,
} }
impl<'self> LayoutElement<'self> { impl<'le> LayoutElement<'le> {
pub fn style_attribute(&self) -> &'self Option<PropertyDeclarationBlock> { pub fn style_attribute(&self) -> &'le Option<PropertyDeclarationBlock> {
&self.element.style_attribute &self.element.style_attribute
} }
} }
impl<'self> TElement for LayoutElement<'self> { impl<'le> TElement for LayoutElement<'le> {
fn get_local_name<'a>(&'a self) -> &'a str { fn get_local_name<'a>(&'a self) -> &'a str {
self.element.tag_name.as_slice() self.element.tag_name.as_slice()
} }

View file

@ -2,26 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#[macro_escape]; #[macro_escape];
macro_rules! special_stream(
($Chan:ident) => (
{
let (port, chan) = stream::();
(port, $Chan::new(chan))
}
);
)
// Spawn a task, capturing the listed variables in a way that avoids the // Spawn a task, capturing the listed variables in a way that avoids the
// move-from-closure error. This is sugar around the function spawn_with, // move-from-closure error. This is sugar around the function spawn_with,
// taking care of building a tuple and a lambda. // taking care of building a tuple and a lambda.
//
// FIXME: Once cross-crate macros work, there are a few places outside of
// the main crate which could benefit from this macro.
macro_rules! spawn_with(
($task:expr, [ $($var:ident),+ ], $body:block) => (
do ($task).spawn_with(( $($var),+ , () )) |( $($var),+ , () )| $body
)
)
macro_rules! bitfield( macro_rules! bitfield(
($bitfieldname:ident, $getter:ident, $setter:ident, $value:expr) => ( ($bitfieldname:ident, $getter:ident, $setter:ident, $value:expr) => (

View file

@ -15,12 +15,10 @@ use script::layout_interface::LayoutChan;
use script::script_task::LoadMsg; use script::script_task::LoadMsg;
use script::script_task::{AttachLayoutMsg, NewLayoutInfo, ScriptTask, ScriptChan}; use script::script_task::{AttachLayoutMsg, NewLayoutInfo, ScriptTask, ScriptChan};
use script::script_task; use script::script_task;
use servo_msg::constellation_msg::{ConstellationChan, FailureMsg, PipelineId, SubpageId}; use servo_msg::constellation_msg::{ConstellationChan, PipelineId, SubpageId};
use servo_net::image_cache_task::ImageCacheTask; use servo_net::image_cache_task::ImageCacheTask;
use servo_net::resource_task::ResourceTask; use servo_net::resource_task::ResourceTask;
use servo_util::time::ProfilerChan; use servo_util::time::ProfilerChan;
use std::task;
use std::comm;
/// A uniquely-identifiable pipeline of script task, layout task, and render task. /// A uniquely-identifiable pipeline of script task, layout task, and render task.
pub struct Pipeline { pub struct Pipeline {
@ -55,10 +53,10 @@ impl Pipeline {
opts: Opts, opts: Opts,
script_pipeline: &Pipeline) script_pipeline: &Pipeline)
-> Pipeline { -> Pipeline {
let (layout_port, layout_chan) = special_stream!(LayoutChan); let (layout_port, layout_chan) = LayoutChan::new();
let (render_port, render_chan) = special_stream!(RenderChan); let (render_port, render_chan) = RenderChan::new();
let (render_shutdown_port, render_shutdown_chan) = comm::stream(); let (render_shutdown_port, render_shutdown_chan) = Chan::new();
let (layout_shutdown_port, layout_shutdown_chan) = comm::stream(); let (layout_shutdown_port, layout_shutdown_chan) = Chan::new();
RenderTask::create(id, RenderTask::create(id,
render_port, render_port,
@ -70,6 +68,7 @@ impl Pipeline {
LayoutTask::create(id, LayoutTask::create(id,
layout_port, layout_port,
layout_chan.clone(),
constellation_chan, constellation_chan,
script_pipeline.script_chan.clone(), script_pipeline.script_chan.clone(),
render_chan.clone(), render_chan.clone(),
@ -105,11 +104,11 @@ impl Pipeline {
window_size: Size2D<uint>, window_size: Size2D<uint>,
opts: Opts) opts: Opts)
-> Pipeline { -> Pipeline {
let (script_port, script_chan) = special_stream!(ScriptChan); let (script_port, script_chan) = ScriptChan::new();
let (layout_port, layout_chan) = special_stream!(LayoutChan); let (layout_port, layout_chan) = LayoutChan::new();
let (render_port, render_chan) = special_stream!(RenderChan); let (render_port, render_chan) = RenderChan::new();
let (render_shutdown_port, render_shutdown_chan) = comm::stream(); let (render_shutdown_port, render_shutdown_chan) = Chan::new();
let (layout_shutdown_port, layout_shutdown_chan) = comm::stream(); let (layout_shutdown_port, layout_shutdown_chan) = Chan::new();
let pipeline = Pipeline::new(id, let pipeline = Pipeline::new(id,
subpage_id, subpage_id,
script_chan.clone(), script_chan.clone(),
@ -118,65 +117,36 @@ impl Pipeline {
layout_shutdown_port, layout_shutdown_port,
render_shutdown_port); render_shutdown_port);
// Wrap task creation within a supervised task so that failure will // FIXME(#1434): add back failure supervision
// only tear down those tasks instead of ours.
let hard_fail = opts.hard_fail;
let failure_chan = constellation_chan.clone();
let mut supervised_task = task::task();
let task_port = supervised_task.future_result();
supervised_task.supervised();
spawn_with!(supervised_task, [ ScriptTask::create(id,
script_port, compositor_chan.clone(),
resource_task, layout_chan.clone(),
render_port, script_port,
layout_port, script_chan.clone(),
constellation_chan, constellation_chan.clone(),
image_cache_task, resource_task,
profiler_chan, image_cache_task.clone(),
layout_shutdown_chan, window_size);
render_shutdown_chan
], {
ScriptTask::create(id,
compositor_chan.clone(),
layout_chan.clone(),
script_port,
script_chan.clone(),
constellation_chan.clone(),
resource_task,
image_cache_task.clone(),
window_size);
RenderTask::create(id, RenderTask::create(id,
render_port, render_port,
compositor_chan.clone(), compositor_chan.clone(),
constellation_chan.clone(), constellation_chan.clone(),
opts.clone(), opts.clone(),
profiler_chan.clone(), profiler_chan.clone(),
render_shutdown_chan); render_shutdown_chan);
LayoutTask::create(id, LayoutTask::create(id,
layout_port, layout_port,
constellation_chan, layout_chan.clone(),
script_chan.clone(), constellation_chan,
render_chan.clone(), script_chan.clone(),
image_cache_task, render_chan.clone(),
opts.clone(), image_cache_task,
profiler_chan, opts.clone(),
layout_shutdown_chan); profiler_chan,
}); layout_shutdown_chan);
spawn_with!(task::task(), [failure_chan], {
match task_port.recv() {
Ok(*) => (),
Err(*) => {
if hard_fail {
fail!("Pipeline failed in hard-fail mode");
}
failure_chan.send(FailureMsg(id, subpage_id));
}
}
});
pipeline pipeline
} }
@ -215,9 +185,9 @@ impl Pipeline {
} }
pub fn reload(&mut self) { pub fn reload(&mut self) {
do self.url.clone().map() |url| { self.url.clone().map(|url| {
self.load(url); self.load(url);
}; });
} }
pub fn exit(&self) { pub fn exit(&self) {
@ -226,8 +196,8 @@ impl Pipeline {
// Wait until all slave tasks have terminated and run destructors // Wait until all slave tasks have terminated and run destructors
// NOTE: We don't wait for script task as we don't always own it // NOTE: We don't wait for script task as we don't always own it
self.render_shutdown_port.try_recv(); self.render_shutdown_port.recv_opt();
self.layout_shutdown_port.try_recv(); self.layout_shutdown_port.recv_opt();
} }
pub fn to_sendable(&self) -> CompositionPipeline { pub fn to_sendable(&self) -> CompositionPipeline {

View file

@ -30,9 +30,7 @@ impl ApplicationMethods for Application {
fn new() -> Application { fn new() -> Application {
// Per GLFW docs it's safe to set the error callback before calling // Per GLFW docs it's safe to set the error callback before calling
// glfwInit(), and this way we notice errors from init too. // glfwInit(), and this way we notice errors from init too.
do glfw::set_error_callback |_error_code, description| { glfw::set_error_callback(~glfw::LogErrorHandler);
error!("GLFW error: {:s}", description);
};
glfw::init(); glfw::init();
Application Application
} }
@ -45,6 +43,38 @@ impl Drop for Application {
} }
} }
macro_rules! glfw_callback(
(
$callback:path ($($arg:ident: $arg_ty:ty),*) $block:expr
) => ({
struct GlfwCallback;
impl $callback for GlfwCallback {
fn call(&self $(, $arg: $arg_ty)*) {
$block
}
}
~GlfwCallback
});
(
[$($state:ident: $state_ty:ty),*],
$callback:path ($($arg:ident: $arg_ty:ty),*) $block:expr
) => ({
struct GlfwCallback {
$($state: $state_ty,)*
}
impl $callback for GlfwCallback {
fn call(&self $(, $arg: $arg_ty)*) {
$block
}
}
~GlfwCallback {
$($state: $state,)*
}
});
)
/// The type of a window. /// The type of a window.
pub struct Window { pub struct Window {
glfw_window: glfw::Window, glfw_window: glfw::Window,
@ -90,43 +120,50 @@ impl WindowMethods<Application> for Window {
install_local_window(window); install_local_window(window);
// Register event handlers. // Register event handlers.
do window.glfw_window.set_framebuffer_size_callback |_win, width, height| { window.glfw_window.set_framebuffer_size_callback(
local_window().event_queue.push(ResizeWindowEvent(width as uint, height as uint)) glfw_callback!(glfw::FramebufferSizeCallback(_win: &glfw::Window, width: i32, height: i32) {
} local_window().event_queue.push(ResizeWindowEvent(width as uint, height as uint));
do window.glfw_window.set_refresh_callback |_win| { }));
local_window().event_queue.push(RefreshWindowEvent) window.glfw_window.set_refresh_callback(
} glfw_callback!(glfw::WindowRefreshCallback(_win: &glfw::Window) {
do window.glfw_window.set_key_callback |_win, key, _scancode, action, mods| { local_window().event_queue.push(RefreshWindowEvent);
if action == glfw::Press { }));
local_window().handle_key(key, mods) window.glfw_window.set_key_callback(
} glfw_callback!(glfw::KeyCallback(_win: &glfw::Window, key: glfw::Key, _scancode: c_int,
} action: glfw::Action, mods: glfw::Modifiers) {
do window.glfw_window.set_mouse_button_callback |win, button, action, _mods| { if action == glfw::Press {
let (x, y) = win.get_cursor_pos(); local_window().handle_key(key, mods)
//handle hidpi displays, since GLFW returns non-hi-def coordinates. }
let (backing_size, _) = win.get_framebuffer_size(); }));
let (window_size, _) = win.get_size(); window.glfw_window.set_mouse_button_callback(
let hidpi = (backing_size as f32) / (window_size as f32); glfw_callback!(glfw::MouseButtonCallback(win: &glfw::Window, button: glfw::MouseButton,
let x = x as f32 * hidpi; action: glfw::Action, _mods: glfw::Modifiers) {
let y = y as f32 * hidpi; let (x, y) = win.get_cursor_pos();
if button == glfw::MouseButtonLeft || button == glfw::MouseButtonRight { //handle hidpi displays, since GLFW returns non-hi-def coordinates.
local_window().handle_mouse(button, action, x as i32, y as i32); let (backing_size, _) = win.get_framebuffer_size();
} let (window_size, _) = win.get_size();
} let hidpi = (backing_size as f32) / (window_size as f32);
do window.glfw_window.set_scroll_callback |win, x_offset, y_offset| { let x = x as f32 * hidpi;
let dx = (x_offset as f32) * 30.0; let y = y as f32 * hidpi;
let dy = (y_offset as f32) * 30.0; if button == glfw::MouseButtonLeft || button == glfw::MouseButtonRight {
local_window().handle_mouse(button, action, x as i32, y as i32);
}
}));
window.glfw_window.set_scroll_callback(
glfw_callback!(glfw::ScrollCallback(win: &glfw::Window, xpos: f64, ypos: f64) {
let dx = (xpos as f32) * 30.0;
let dy = (ypos as f32) * 30.0;
let (x, y) = win.get_cursor_pos(); let (x, y) = win.get_cursor_pos();
//handle hidpi displays, since GLFW returns non-hi-def coordinates. //handle hidpi displays, since GLFW returns non-hi-def coordinates.
let (backing_size, _) = win.get_framebuffer_size(); let (backing_size, _) = win.get_framebuffer_size();
let (window_size, _) = win.get_size(); let (window_size, _) = win.get_size();
let hidpi = (backing_size as f32) / (window_size as f32); let hidpi = (backing_size as f32) / (window_size as f32);
let x = x as f32 * hidpi; let x = x as f32 * hidpi;
let y = y as f32 * hidpi; let y = y as f32 * hidpi;
local_window().event_queue.push(ScrollWindowEvent(Point2D(dx, dy), Point2D(x as i32, y as i32))); local_window().event_queue.push(ScrollWindowEvent(Point2D(dx, dy), Point2D(x as i32, y as i32)));
} }));
window window
} }

View file

@ -7,22 +7,22 @@
use windowing::{ApplicationMethods, WindowEvent, WindowMethods}; use windowing::{ApplicationMethods, WindowEvent, WindowMethods};
use windowing::{IdleWindowEvent, ResizeWindowEvent, LoadUrlWindowEvent, MouseWindowEventClass}; use windowing::{IdleWindowEvent, ResizeWindowEvent, LoadUrlWindowEvent, MouseWindowEventClass};
use windowing::{ScrollWindowEvent, ZoomWindowEvent, NavigationWindowEvent, FinishedWindowEvent}; use windowing::{ScrollWindowEvent, ZoomWindowEvent, NavigationWindowEvent, FinishedWindowEvent};
use windowing::{QuitWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEvent, MouseWindowMouseUpEvent}; use windowing::{MouseWindowClickEvent, MouseWindowMouseDownEvent, MouseWindowMouseUpEvent};
use windowing::{Forward, Back}; use windowing::{Forward, Back};
use alert::{Alert, AlertMethods}; use alert::{Alert, AlertMethods};
use std::libc::c_int; use std::libc::{c_int, c_uchar};
use std::local_data; use std::local_data;
use geom::point::Point2D; use geom::point::Point2D;
use geom::size::Size2D; use geom::size::Size2D;
use servo_msg::compositor_msg::{IdleRenderState, RenderState, RenderingRenderState}; use servo_msg::compositor_msg::{IdleRenderState, RenderState, RenderingRenderState};
use servo_msg::compositor_msg::{FinishedLoading, Blank, Loading, PerformingLayout, ReadyState}; use servo_msg::compositor_msg::{FinishedLoading, Blank, ReadyState};
use glut::glut::{ACTIVE_CTRL, ACTIVE_SHIFT, DOUBLE, HAVE_PRECISE_MOUSE_WHEEL, WindowHeight}; use glut::glut::{ACTIVE_SHIFT, DOUBLE, WindowHeight};
use glut::glut::WindowWidth; use glut::glut::WindowWidth;
use glut::glut; use glut::glut;
static THROBBER: [char, ..8] = [ '⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷' ]; // static THROBBER: [char, ..8] = [ '⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷' ];
/// A structure responsible for setting up and tearing down the entire windowing system. /// A structure responsible for setting up and tearing down the entire windowing system.
pub struct Application; pub struct Application;
@ -85,31 +85,47 @@ impl WindowMethods<Application> for Window {
// Register event handlers. // Register event handlers.
//Added dummy display callback to freeglut. According to freeglut ref, we should register some kind of display callback after freeglut 3.0. //Added dummy display callback to freeglut. According to freeglut ref, we should register some kind of display callback after freeglut 3.0.
do glut::display_func || {
debug!("GLUT display func registered"); struct DisplayCallbackState;
} impl glut::DisplayCallback for DisplayCallbackState {
do glut::reshape_func(window.glut_window) |width, height| { fn call(&self) {
local_window().event_queue.push(ResizeWindowEvent(width as uint, height as uint)) debug!("GLUT display func registgered");
}
do glut::keyboard_func |key, _, _| {
local_window().handle_key(key)
}
do glut::mouse_func |button, state, x, y| {
if button < 3 {
local_window().handle_mouse(button, state, x, y);
} }
else { }
match button { glut::display_func(~DisplayCallbackState);
3 => { struct ReshapeCallbackState;
local_window().event_queue.push(ScrollWindowEvent(Point2D(0.0, 5.0 as f32), Point2D(0.0 as i32, 5.0 as i32))); impl glut::ReshapeCallback for ReshapeCallbackState {
}, fn call(&self, width: c_int, height: c_int) {
4 => { local_window().event_queue.push(ResizeWindowEvent(width as uint, height as uint))
local_window().event_queue.push(ScrollWindowEvent(Point2D(0.0, -5.0 as f32), Point2D(0.0 as i32, -5.0 as i32))); }
}, }
_ => {} glut::reshape_func(glut_window, ~ReshapeCallbackState);
struct KeyboardCallbackState;
impl glut::KeyboardCallback for KeyboardCallbackState {
fn call(&self, key: c_uchar, _x: c_int, _y: c_int) {
local_window().handle_key(key)
}
}
glut::keyboard_func(~KeyboardCallbackState);
struct MouseCallbackState;
impl glut::MouseCallback for MouseCallbackState {
fn call(&self, button: c_int, state: c_int, x: c_int, y: c_int) {
if button < 3 {
local_window().handle_mouse(button, state, x, y);
} else {
match button {
3 => {
local_window().event_queue.push(ScrollWindowEvent(Point2D(0.0, 5.0 as f32), Point2D(0.0 as i32, 5.0 as i32)));
},
4 => {
local_window().event_queue.push(ScrollWindowEvent(Point2D(0.0, -5.0 as f32), Point2D(0.0 as i32, -5.0 as i32)));
},
_ => {}
}
} }
} }
} }
glut::mouse_func(~MouseCallbackState);
window window
} }
@ -165,28 +181,28 @@ impl WindowMethods<Application> for Window {
impl Window { impl Window {
/// Helper function to set the window title in accordance with the ready state. /// Helper function to set the window title in accordance with the ready state.
fn update_window_title(&self) { // fn update_window_title(&self) {
let throbber = THROBBER[self.throbber_frame]; // let throbber = THROBBER[self.throbber_frame];
match self.ready_state { // match self.ready_state {
Blank => { // Blank => {
glut::set_window_title(self.glut_window, "Blank") // glut::set_window_title(self.glut_window, "Blank")
} // }
Loading => { // Loading => {
glut::set_window_title(self.glut_window, format!("{:c} Loading . Servo", throbber)) // glut::set_window_title(self.glut_window, format!("{:c} Loading . Servo", throbber))
} // }
PerformingLayout => { // PerformingLayout => {
glut::set_window_title(self.glut_window, format!("{:c} Performing Layout . Servo", throbber)) // glut::set_window_title(self.glut_window, format!("{:c} Performing Layout . Servo", throbber))
} // }
FinishedLoading => { // FinishedLoading => {
match self.render_state { // match self.render_state {
RenderingRenderState => { // RenderingRenderState => {
glut::set_window_title(self.glut_window, format!("{:c} Rendering . Servo", throbber)) // glut::set_window_title(self.glut_window, format!("{:c} Rendering . Servo", throbber))
} // }
IdleRenderState => glut::set_window_title(self.glut_window, "Servo"), // IdleRenderState => glut::set_window_title(self.glut_window, "Servo"),
} // }
} // }
} // }
} // }
/// Helper function to handle keyboard events. /// Helper function to handle keyboard events.
fn handle_key(&self, key: u8) { fn handle_key(&self, key: u8) {

View file

@ -2,21 +2,16 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#[link(name = "servo", #[crate_id = "github.com/mozilla/servo"];
vers = "0.1",
uuid = "637ffc98-9058-471d-9de7-abfc49ef0549",
url = "http://servo.org/")];
#[comment = "The Servo Parallel Browser Project"]; #[comment = "The Servo Parallel Browser Project"];
#[license = "MPL"]; #[license = "MPL"];
#[crate_type = "lib"];
#[feature(globs, macro_rules, managed_boxes)]; #[feature(globs, macro_rules, managed_boxes)];
extern mod alert; extern mod alert;
extern mod azure; extern mod azure;
extern mod geom; extern mod geom;
extern mod gfx (name = "gfx"); extern mod gfx;
#[cfg(not(target_os="android"))] #[cfg(not(target_os="android"))]
extern mod glfw; extern mod glfw;
#[cfg(target_os="android")] #[cfg(target_os="android")]
@ -26,39 +21,50 @@ extern mod layers;
extern mod opengles; extern mod opengles;
extern mod png; extern mod png;
extern mod script; extern mod script;
extern mod servo_net (name = "net"); extern mod servo_net = "net";
extern mod servo_msg (name = "msg"); extern mod servo_msg = "msg";
extern mod servo_util (name = "util"); extern mod servo_util = "util";
extern mod style; extern mod style;
extern mod sharegl; extern mod sharegl;
extern mod stb_image; extern mod stb_image;
extern mod extra; extern mod extra;
extern mod green;
extern mod native;
#[cfg(target_os="macos")] #[cfg(target_os="macos")]
extern mod core_graphics; extern mod core_graphics;
#[cfg(target_os="macos")] #[cfg(target_os="macos")]
extern mod core_text; extern mod core_text;
#[cfg(not(test))]
use compositing::{CompositorChan, CompositorTask}; use compositing::{CompositorChan, CompositorTask};
#[cfg(not(test))]
use constellation::Constellation; use constellation::Constellation;
use servo_msg::constellation_msg::{ConstellationChan, InitLoadUrlMsg}; #[cfg(not(test))]
use servo_msg::constellation_msg::InitLoadUrlMsg;
#[cfg(not(test))] #[cfg(not(test))]
use gfx::opts; use gfx::opts;
#[cfg(not(test))]
use servo_net::image_cache_task::ImageCacheTask; use servo_net::image_cache_task::ImageCacheTask;
#[cfg(not(test))]
use servo_net::resource_task::ResourceTask; use servo_net::resource_task::ResourceTask;
use servo_util::time::{Profiler, ProfilerChan}; #[cfg(not(test))]
use servo_util::time::Profiler;
pub use gfx::opts::Opts; pub use gfx::opts::Opts;
pub use gfx::text; pub use gfx::text;
pub use servo_util::url::make_url; pub use servo_util::url::make_url;
use std::comm;
#[cfg(not(test))] #[cfg(not(test))]
use std::os; use std::os;
#[cfg(not(test), target_os="android")] #[cfg(not(test), target_os="android")]
use std::str; use std::str;
use std::task::spawn_with; #[cfg(not(test))]
use std::task::TaskOpts;
#[path="compositing/compositor_task.rs"] #[path="compositing/compositor_task.rs"]
pub mod compositing; pub mod compositing;
@ -78,7 +84,7 @@ pub mod pipeline;
pub mod layout { pub mod layout {
pub mod block; pub mod block;
pub mod box; pub mod box_;
pub mod construct; pub mod construct;
pub mod context; pub mod context;
pub mod display_list_builder; pub mod display_list_builder;
@ -106,15 +112,15 @@ pub mod util;
#[cfg(not(test), target_os="macos")] #[cfg(not(test), target_os="macos")]
#[start] #[start]
fn start(argc: int, argv: **u8) -> int { fn start(argc: int, argv: **u8) -> int {
do std::rt::start_on_main_thread(argc, argv) { native::start(argc, argv, proc() {
run(opts::from_cmdline_args(os::args())) run(opts::from_cmdline_args(os::args()))
} })
} }
#[cfg(not(test), target_os="android")] #[cfg(not(test), target_os="android")]
#[no_mangle] #[no_mangle]
pub extern "C" fn android_start(argc: int, argv: **u8) -> int { pub extern "C" fn android_start(argc: int, argv: **u8) -> int {
do std::rt::start_on_main_thread(argc, argv) { native::start(argc, argv, proc() {
let mut args:~[~str] = ~[]; let mut args:~[~str] = ~[];
for i in range(0u, argc as uint) { for i in range(0u, argc as uint) {
unsafe { unsafe {
@ -122,53 +128,51 @@ pub extern "C" fn android_start(argc: int, argv: **u8) -> int {
} }
} }
run(opts::from_cmdline_args(args)) run(opts::from_cmdline_args(args))
} })
} }
#[cfg(not(test))]
fn run(opts: Opts) { fn run(opts: Opts) {
let (exit_response_from_constellation, exit_chan) = comm::stream(); let mut pool = green::SchedPool::new(green::PoolConfig::new());
let (profiler_port, profiler_chan) = special_stream!(ProfilerChan);
let (compositor_port, compositor_chan) = special_stream!(CompositorChan);
let (constellation_port, constellation_chan) = special_stream!(ConstellationChan);
Profiler::create(profiler_port, profiler_chan.clone(), opts.profiler_period); let (exit_response_from_constellation, exit_chan) = Chan::new();
let (compositor_port, compositor_chan) = CompositorChan::new();
let profiler_chan = Profiler::create(opts.profiler_period);
do spawn_with((constellation_port, let opts_clone = opts.clone();
constellation_chan.clone(), let profiler_chan_clone = profiler_chan.clone();
profiler_chan.clone(),
compositor_chan,
opts.clone()))
|(constellation_port,
constellation_chan,
profiler_chan,
compositor_chan,
opts)| {
let opts = &opts;
let (result_port, result_chan) = Chan::new();
pool.spawn(TaskOpts::new(), proc() {
let opts = &opts_clone;
// Create a Servo instance. // Create a Servo instance.
let resource_task = ResourceTask(); let resource_task = ResourceTask();
let image_cache_task = ImageCacheTask(resource_task.clone()); let image_cache_task = ImageCacheTask(resource_task.clone());
Constellation::start(constellation_port, let constellation_chan = Constellation::start(compositor_chan,
constellation_chan.clone(), opts,
compositor_chan, resource_task,
opts, image_cache_task,
resource_task, profiler_chan_clone);
image_cache_task,
profiler_chan.clone()); // Send the constallation Chan as the result
result_chan.send(constellation_chan.clone());
// Send the URL command to the constellation. // Send the URL command to the constellation.
for filename in opts.urls.iter() { for filename in opts.urls.iter() {
constellation_chan.send(InitLoadUrlMsg(make_url(filename.clone(), None))) constellation_chan.send(InitLoadUrlMsg(make_url(filename.clone(), None)))
} }
} });
let constellation_chan = result_port.recv();
debug!("preparing to enter main loop"); debug!("preparing to enter main loop");
CompositorTask::create(opts, CompositorTask::create(opts,
compositor_port, compositor_port,
constellation_chan.clone(), constellation_chan,
profiler_chan, profiler_chan,
exit_chan, exit_chan,
exit_response_from_constellation); exit_response_from_constellation);
pool.shutdown();
} }

View file

@ -2,26 +2,20 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use std::cell::Cell; pub fn spawn_listener<A: Send>(f: proc(Port<A>)) -> Chan<A> {
use std::comm; let (setup_po, setup_ch) = Chan::new();
use std::comm::{Chan, Port}; spawn(proc() {
use std::task; let (po, ch) = Chan::new();
pub fn spawn_listener<A: Send>(f: ~fn(Port<A>)) -> Chan<A> {
let (setup_po, setup_ch) = comm::stream();
do task::spawn {
let (po, ch) = comm::stream();
setup_ch.send(ch); setup_ch.send(ch);
f(po); f(po);
} });
setup_po.recv() setup_po.recv()
} }
pub fn spawn_conversation<A: Send, B: Send>(f: ~fn(Port<A>, Chan<B>)) -> (Port<B>, Chan<A>) { pub fn spawn_conversation<A: Send, B: Send>(f: proc(Port<A>, Chan<B>)) -> (Port<B>, Chan<A>) {
let (from_child, to_parent) = comm::stream(); let (from_child, to_parent) = Chan::new();
let to_parent = Cell::new(to_parent);
let to_child = do spawn_listener |from_parent| { let to_child = do spawn_listener |from_parent| {
f(from_parent, to_parent.take()) f(from_parent, to_parent)
}; };
(from_child, to_child) (from_child, to_child)
} }

View file

@ -14,8 +14,9 @@ use std::comm::{Chan, SharedChan};
pub struct ConstellationChan(SharedChan<Msg>); pub struct ConstellationChan(SharedChan<Msg>);
impl ConstellationChan { impl ConstellationChan {
pub fn new(chan: Chan<Msg>) -> ConstellationChan { pub fn new() -> (Port<Msg>, ConstellationChan) {
ConstellationChan(SharedChan::new(chan)) let (port, chan) = SharedChan::new();
(port, ConstellationChan(chan))
} }
} }
@ -53,5 +54,6 @@ pub enum NavigationDirection {
#[deriving(Clone, Eq, IterBytes)] #[deriving(Clone, Eq, IterBytes)]
pub struct PipelineId(uint); pub struct PipelineId(uint);
#[deriving(Clone, Eq, IterBytes)] #[deriving(Clone, Eq, IterBytes)]
pub struct SubpageId(uint); pub struct SubpageId(uint);

View file

@ -2,10 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#[link(name = "msg", #[crate_id = "github.com/mozilla/servo#msg:0.1"];
vers = "0.1",
uuid = "4c6054e4-2a7b-4fae-b0c8-6d04416b2bf2",
url = "http://servo.org/")];
#[crate_type = "lib"]; #[crate_type = "lib"];
extern mod azure; extern mod azure;

View file

@ -11,7 +11,7 @@ use http::headers::test_utils::from_stream_with_str;
use http::headers::content_type::MediaType; use http::headers::content_type::MediaType;
pub fn factory() -> LoaderTask { pub fn factory() -> LoaderTask {
|url, start_chan| { proc(url, start_chan) {
// NB: we don't spawn a new task. // NB: we don't spawn a new task.
// Hypothesis: data URLs are too small for parallel base64 etc. to be worth it. // Hypothesis: data URLs are too small for parallel base64 etc. to be worth it.
// Should be tested at some point. // Should be tested at some point.
@ -25,7 +25,7 @@ fn load(url: Url, start_chan: Chan<LoadResponse>) {
let mut metadata = Metadata::default(url.clone()); let mut metadata = Metadata::default(url.clone());
// Split out content type and data. // Split out content type and data.
let parts: ~[&str] = url.path.splitn_iter(',', 1).to_owned_vec(); let parts: ~[&str] = url.path.splitn(',', 1).to_owned_vec();
if parts.len() != 2 { if parts.len() != 2 {
start_sending(start_chan, metadata).send(Done(Err(()))); start_sending(start_chan, metadata).send(Done(Err(())));
return; return;
@ -49,7 +49,7 @@ fn load(url: Url, start_chan: Chan<LoadResponse>) {
if is_base64 { if is_base64 {
match parts[1].from_base64() { match parts[1].from_base64() {
Err(*) => { Err(..) => {
progress_chan.send(Done(Err(()))); progress_chan.send(Done(Err(())));
} }
Ok(data) => { Ok(data) => {
@ -71,9 +71,8 @@ fn assert_parse(url: &'static str,
charset: Option<~str>, charset: Option<~str>,
data: Option<~[u8]>) { data: Option<~[u8]>) {
use std::from_str::FromStr; use std::from_str::FromStr;
use std::comm;
let (start_port, start_chan) = comm::stream(); let (start_port, start_chan) = Chan::new();
load(FromStr::from_str(url).unwrap(), start_chan); load(FromStr::from_str(url).unwrap(), start_chan);
let response = start_port.recv(); let response = start_port.recv();

View file

@ -5,45 +5,44 @@
use resource_task::{ProgressMsg, Metadata, Payload, Done, LoaderTask, start_sending}; use resource_task::{ProgressMsg, Metadata, Payload, Done, LoaderTask, start_sending};
use servo_util::io::result; use servo_util::io::result;
use std::comm::Chan; use std::io;
use std::rt::io::file; use std::io::File;
use std::rt::io::{FileStream, Reader, EndOfFile, Open, Read, ignore_io_error};
use std::task;
static READ_SIZE: uint = 1024; static READ_SIZE: uint = 1024;
fn read_all(reader: &mut FileStream, progress_chan: &Chan<ProgressMsg>) fn read_all(reader: &mut io::Stream, progress_chan: &SharedChan<ProgressMsg>)
-> Result<(), ()> { -> Result<(), ()> {
loop { loop {
match (do result { match (result(|| {
let data = reader.read_bytes(READ_SIZE); let data = reader.read_bytes(READ_SIZE);
progress_chan.send(Payload(data)); progress_chan.send(Payload(data));
}) { })) {
Ok(()) => (), Ok(()) => (),
Err(e) => match e.kind { Err(e) => match e.kind {
EndOfFile => return Ok(()), io::EndOfFile => return Ok(()),
_ => return Err(()), _ => return Err(()),
} }
} }
} }
} }
pub fn factory() -> LoaderTask { pub fn factory() -> LoaderTask {
let f: LoaderTask = |url, start_chan| { let f: LoaderTask = proc(url, start_chan) {
assert!("file" == url.scheme); assert!("file" == url.scheme);
let progress_chan = start_sending(start_chan, Metadata::default(url.clone())); let progress_chan = start_sending(start_chan, Metadata::default(url.clone()));
do task::spawn { spawn(proc() {
// ignore_io_error causes us to get None instead of a task failure. // ignore_io_error causes us to get None instead of a task failure.
match ignore_io_error(|| file::open(&url.path.as_slice(), Open, Read)) { let _guard = io::ignore_io_error();
match File::open_mode(&Path::new(url.path), io::Open, io::Read) {
Some(ref mut reader) => { Some(ref mut reader) => {
let res = read_all(reader, &progress_chan); let res = read_all(reader as &mut io::Stream, &progress_chan);
progress_chan.send(Done(res)); progress_chan.send(Done(res));
} }
None => { None => {
progress_chan.send(Done(Err(()))); progress_chan.send(Done(Err(())));
} }
} };
} });
}; };
f f
} }

View file

@ -4,19 +4,16 @@
use resource_task::{Metadata, Payload, Done, LoadResponse, LoaderTask, start_sending}; use resource_task::{Metadata, Payload, Done, LoadResponse, LoaderTask, start_sending};
use std::cell::Cell;
use std::vec; use std::vec;
use extra::url::Url; use extra::url::Url;
use http::client::RequestWriter; use http::client::RequestWriter;
use http::method::Get; use http::method::Get;
use http::headers::HeaderEnum; use http::headers::HeaderEnum;
use std::rt::io::Reader; use std::io::Reader;
pub fn factory() -> LoaderTask { pub fn factory() -> LoaderTask {
let f: LoaderTask = |url, start_chan| { let f: LoaderTask = proc(url, start_chan) {
let url = Cell::new(url); spawn(proc() load(url, start_chan))
let start_chan = Cell::new(start_chan);
spawn(|| load(url.take(), start_chan.take()))
}; };
f f
} }
@ -63,10 +60,10 @@ fn load(mut url: Url, start_chan: Chan<LoadResponse>) {
loop { loop {
let mut buf = vec::with_capacity(1024); let mut buf = vec::with_capacity(1024);
unsafe { vec::raw::set_len(&mut buf, 1024) }; unsafe { buf.set_len(1024); }
match response.read(buf) { match response.read(buf) {
Some(len) => { Some(len) => {
unsafe { vec::raw::set_len(&mut buf, len) }; unsafe { buf.set_len(len); }
progress_chan.send(Payload(buf)); progress_chan.send(Payload(buf));
} }
None => { None => {

View file

@ -64,12 +64,12 @@ impl ImageHolder {
/// Query and update the current image size. /// Query and update the current image size.
pub fn get_size(&mut self) -> Option<Size2D<int>> { pub fn get_size(&mut self) -> Option<Size2D<int>> {
debug!("get_size() {}", self.url.to_str()); debug!("get_size() {}", self.url.to_str());
do self.get_image().map |img| { self.get_image().map(|img| {
let img_ref = img.get(); let img_ref = img.get();
self.cached_size = Size2D(img_ref.width as int, self.cached_size = Size2D(img_ref.width as int,
img_ref.height as int); img_ref.height as int);
self.cached_size.clone() self.cached_size.clone()
} })
} }
pub fn get_image(&mut self) -> Option<Arc<~Image>> { pub fn get_image(&mut self) -> Option<Arc<~Image>> {

View file

@ -7,8 +7,7 @@ use resource_task;
use resource_task::ResourceTask; use resource_task::ResourceTask;
use servo_util::url::{UrlMap, url_map}; use servo_util::url::{UrlMap, url_map};
use std::cell::Cell; use std::comm::{Chan, Port, SharedChan};
use std::comm::{Chan, Port, SharedChan, stream};
use std::task::spawn; use std::task::spawn;
use std::to_str::ToStr; use std::to_str::ToStr;
use std::util::replace; use std::util::replace;
@ -24,7 +23,7 @@ pub enum Msg {
// FIXME: We can probably get rid of this Cell now // FIXME: We can probably get rid of this Cell now
// FIXME: make this priv after visibility rules change // FIXME: make this priv after visibility rules change
/// Used be the prefetch tasks to post back image binaries /// Used be the prefetch tasks to post back image binaries
StorePrefetchedImageData(Url, Result<Cell<~[u8]>, ()>), StorePrefetchedImageData(Url, Result<~[u8], ()>),
/// Tell the cache to decode an image. Must be posted before GetImage/WaitForImage /// Tell the cache to decode an image. Must be posted before GetImage/WaitForImage
Decode(Url), Decode(Url),
@ -40,12 +39,16 @@ pub enum Msg {
/// Wait for an image to become available (or fail to load). /// Wait for an image to become available (or fail to load).
WaitForImage(Url, Chan<ImageResponseMsg>), WaitForImage(Url, Chan<ImageResponseMsg>),
/// For testing
// FIXME: make this priv after visibility rules change
OnMsg(~fn(msg: &Msg)),
/// Clients must wait for a response before shutting down the ResourceTask /// Clients must wait for a response before shutting down the ResourceTask
Exit(Chan<()>), Exit(Chan<()>),
/// For testing
// FIXME: make this priv after visibility rules change
WaitForStore(Chan<()>),
/// For testing
// FIXME: make this priv after visibility rules change
WaitForStorePrefetched(Chan<()>),
} }
#[deriving(Clone)] #[deriving(Clone)]
@ -59,11 +62,11 @@ impl Eq for ImageResponseMsg {
fn eq(&self, other: &ImageResponseMsg) -> bool { fn eq(&self, other: &ImageResponseMsg) -> bool {
// FIXME: Bad copies // FIXME: Bad copies
match (self.clone(), other.clone()) { match (self.clone(), other.clone()) {
(ImageReady(*), ImageReady(*)) => fail!(~"unimplemented comparison"), (ImageReady(..), ImageReady(..)) => fail!(~"unimplemented comparison"),
(ImageNotReady, ImageNotReady) => true, (ImageNotReady, ImageNotReady) => true,
(ImageFailed, ImageFailed) => true, (ImageFailed, ImageFailed) => true,
(ImageReady(*), _) | (ImageNotReady, _) | (ImageFailed, _) => false (ImageReady(..), _) | (ImageNotReady, _) | (ImageFailed, _) => false
} }
} }
@ -72,49 +75,39 @@ impl Eq for ImageResponseMsg {
} }
} }
pub type ImageCacheTask = SharedChan<Msg>; #[deriving(Clone)]
pub struct ImageCacheTask {
type DecoderFactory = ~fn() -> ~fn(&[u8]) -> Option<Image>; chan: SharedChan<Msg>,
pub fn ImageCacheTask(resource_task: ResourceTask) -> ImageCacheTask {
ImageCacheTask_(resource_task, default_decoder_factory)
} }
pub fn ImageCacheTask_(resource_task: ResourceTask, decoder_factory: DecoderFactory) type DecoderFactory = fn() -> proc(&[u8]) -> Option<Image>;
-> ImageCacheTask {
// FIXME: Doing some dancing to avoid copying decoder_factory, our test
// version of which contains an uncopyable type which rust will currently
// copy unsoundly
let decoder_factory_cell = Cell::new(decoder_factory);
let (port, chan) = stream(); pub fn ImageCacheTask(resource_task: ResourceTask) -> ImageCacheTask {
let chan = SharedChan::new(chan); let (port, chan) = SharedChan::new();
let port_cell = Cell::new(port); let chan_clone = chan.clone();
let chan_cell = Cell::new(chan.clone());
do spawn { spawn(proc() {
let mut cache = ImageCache { let mut cache = ImageCache {
resource_task: resource_task.clone(), resource_task: resource_task.clone(),
decoder_factory: decoder_factory_cell.take(), port: port,
port: port_cell.take(), chan: chan_clone,
chan: chan_cell.take(),
state_map: url_map(), state_map: url_map(),
wait_map: url_map(), wait_map: url_map(),
need_exit: None need_exit: None
}; };
cache.run(); cache.run();
} });
chan ImageCacheTask {
chan: chan,
}
} }
// FIXME: make this priv after visibility rules change // FIXME: make this priv after visibility rules change
pub fn SyncImageCacheTask(resource_task: ResourceTask) -> ImageCacheTask { pub fn SyncImageCacheTask(resource_task: ResourceTask) -> ImageCacheTask {
let (port, chan) = stream(); let (port, chan) = SharedChan::new();
let port_cell = Cell::new(port);
do spawn { spawn(proc() {
let port = port_cell.take();
let inner_cache = ImageCacheTask(resource_task.clone()); let inner_cache = ImageCacheTask(resource_task.clone());
loop { loop {
@ -131,16 +124,16 @@ pub fn SyncImageCacheTask(resource_task: ResourceTask) -> ImageCacheTask {
msg => inner_cache.send(msg) msg => inner_cache.send(msg)
} }
} }
} });
SharedChan::new(chan) ImageCacheTask {
chan: chan,
}
} }
struct ImageCache { struct ImageCache {
/// A handle to the resource task for fetching the image binaries /// A handle to the resource task for fetching the image binaries
resource_task: ResourceTask, resource_task: ResourceTask,
/// Creates image decoders
decoder_factory: DecoderFactory,
/// The port on which we'll receive client requests /// The port on which we'll receive client requests
port: Port<Msg>, port: Port<Msg>,
/// A copy of the shared chan to give to child tasks /// A copy of the shared chan to give to child tasks
@ -156,7 +149,7 @@ struct ImageCache {
enum ImageState { enum ImageState {
Init, Init,
Prefetching(AfterPrefetch), Prefetching(AfterPrefetch),
Prefetched(Cell<~[u8]>), Prefetched(~[u8]),
Decoding, Decoding,
Decoded(Arc<~Image>), Decoded(Arc<~Image>),
Failed Failed
@ -170,29 +163,39 @@ enum AfterPrefetch {
impl ImageCache { impl ImageCache {
pub fn run(&mut self) { pub fn run(&mut self) {
let mut msg_handlers: ~[~fn(msg: &Msg)] = ~[]; let mut store_chan: Option<Chan<()>> = None;
let mut store_prefetched_chan: Option<Chan<()>> = None;
loop { loop {
let msg = self.port.recv(); let msg = self.port.recv();
for handler in msg_handlers.iter() {
(*handler)(&msg)
}
debug!("image_cache_task: received: {:?}", msg); debug!("image_cache_task: received: {:?}", msg);
match msg { match msg {
Prefetch(url) => self.prefetch(url), Prefetch(url) => self.prefetch(url),
StorePrefetchedImageData(url, data) => { StorePrefetchedImageData(url, data) => {
store_prefetched_chan.map(|chan| {
chan.send(());
});
store_prefetched_chan = None;
self.store_prefetched_image_data(url, data); self.store_prefetched_image_data(url, data);
} }
Decode(url) => self.decode(url), Decode(url) => self.decode(url),
StoreImage(url, image) => self.store_image(url, image), StoreImage(url, image) => {
store_chan.map(|chan| {
chan.send(());
});
store_chan = None;
self.store_image(url, image)
}
GetImage(url, response) => self.get_image(url, response), GetImage(url, response) => self.get_image(url, response),
WaitForImage(url, response) => { WaitForImage(url, response) => {
self.wait_for_image(url, response) self.wait_for_image(url, response)
} }
OnMsg(handler) => msg_handlers.push(handler), WaitForStore(chan) => store_chan = Some(chan),
WaitForStorePrefetched(chan) => store_prefetched_chan = Some(chan),
Exit(response) => { Exit(response) => {
assert!(self.need_exit.is_none()); assert!(self.need_exit.is_none());
self.need_exit = Some(response); self.need_exit = Some(response);
@ -208,10 +211,10 @@ impl ImageCache {
let mut can_exit = true; let mut can_exit = true;
for (_, state) in self.state_map.iter() { for (_, state) in self.state_map.iter() {
match *state { match *state {
Prefetching(*) => can_exit = false, Prefetching(..) => can_exit = false,
Decoding => can_exit = false, Decoding => can_exit = false,
Init | Prefetched(*) | Decoded(*) | Failed => () Init | Prefetched(..) | Decoded(..) | Failed => ()
} }
} }
@ -243,45 +246,44 @@ impl ImageCache {
Init => { Init => {
let to_cache = self.chan.clone(); let to_cache = self.chan.clone();
let resource_task = self.resource_task.clone(); let resource_task = self.resource_task.clone();
let url_cell = Cell::new(url.clone()); let url_clone = url.clone();
do spawn { spawn(proc() {
let url = url_cell.take(); let url = url_clone;
debug!("image_cache_task: started fetch for {:s}", url.to_str()); debug!("image_cache_task: started fetch for {:s}", url.to_str());
let image = load_image_data(url.clone(), resource_task.clone()); let image = load_image_data(url.clone(), resource_task.clone());
let result = if image.is_ok() { let result = if image.is_ok() {
Ok(Cell::new(image.unwrap())) Ok(image.unwrap())
} else { } else {
Err(()) Err(())
}; };
to_cache.send(StorePrefetchedImageData(url.clone(), result)); to_cache.send(StorePrefetchedImageData(url.clone(), result));
debug!("image_cache_task: ended fetch for {:s}", (url.clone()).to_str()); debug!("image_cache_task: ended fetch for {:s}", (url.clone()).to_str());
} });
self.set_state(url, Prefetching(DoNotDecode)); self.set_state(url, Prefetching(DoNotDecode));
} }
Prefetching(*) | Prefetched(*) | Decoding | Decoded(*) | Failed => { Prefetching(..) | Prefetched(..) | Decoding | Decoded(..) | Failed => {
// We've already begun working on this image // We've already begun working on this image
} }
} }
} }
fn store_prefetched_image_data(&mut self, url: Url, data: Result<Cell<~[u8]>, ()>) { fn store_prefetched_image_data(&mut self, url: Url, data: Result<~[u8], ()>) {
match self.get_state(url.clone()) { match self.get_state(url.clone()) {
Prefetching(next_step) => { Prefetching(next_step) => {
match data { match data {
Ok(data_cell) => { Ok(data) => {
let data = data_cell.take(); self.set_state(url.clone(), Prefetched(data));
self.set_state(url.clone(), Prefetched(Cell::new(data)));
match next_step { match next_step {
DoDecode => self.decode(url), DoDecode => self.decode(url),
_ => () _ => ()
} }
} }
Err(*) => { Err(..) => {
self.set_state(url.clone(), Failed); self.set_state(url.clone(), Failed);
self.purge_waiters(url, || ImageFailed); self.purge_waiters(url, || ImageFailed);
} }
@ -289,9 +291,9 @@ impl ImageCache {
} }
Init Init
| Prefetched(*) | Prefetched(..)
| Decoding | Decoding
| Decoded(*) | Decoded(..)
| Failed => { | Failed => {
fail!(~"wrong state for storing prefetched image") fail!(~"wrong state for storing prefetched image")
} }
@ -311,18 +313,14 @@ impl ImageCache {
// We don't have the data yet, but the decode request is queued up // We don't have the data yet, but the decode request is queued up
} }
Prefetched(data_cell) => { Prefetched(data) => {
assert!(!data_cell.is_empty());
let data = data_cell.take();
let to_cache = self.chan.clone(); let to_cache = self.chan.clone();
let url_cell = Cell::new(url.clone()); let url_clone = url.clone();
let decode = (self.decoder_factory)();
do spawn { spawn(proc() {
let url = url_cell.take(); let url = url_clone;
debug!("image_cache_task: started image decode for {:s}", url.to_str()); debug!("image_cache_task: started image decode for {:s}", url.to_str());
let image = decode(data); let image = load_from_memory(data);
let image = if image.is_some() { let image = if image.is_some() {
Some(Arc::new(~image.unwrap())) Some(Arc::new(~image.unwrap()))
} else { } else {
@ -330,12 +328,12 @@ impl ImageCache {
}; };
to_cache.send(StoreImage(url.clone(), image)); to_cache.send(StoreImage(url.clone(), image));
debug!("image_cache_task: ended image decode for {:s}", url.to_str()); debug!("image_cache_task: ended image decode for {:s}", url.to_str());
} });
self.set_state(url, Decoding); self.set_state(url, Decoding);
} }
Decoding | Decoded(*) | Failed => { Decoding | Decoded(..) | Failed => {
// We've already begun decoding // We've already begun decoding
} }
} }
@ -358,9 +356,9 @@ impl ImageCache {
} }
Init Init
| Prefetching(*) | Prefetching(..)
| Prefetched(*) | Prefetched(..)
| Decoded(*) | Decoded(..)
| Failed => { | Failed => {
fail!(~"incorrect state in store_image") fail!(~"incorrect state in store_image")
} }
@ -368,7 +366,7 @@ impl ImageCache {
} }
fn purge_waiters(&mut self, url: Url, f: &fn() -> ImageResponseMsg) { fn purge_waiters(&mut self, url: Url, f: || -> ImageResponseMsg) {
match self.wait_map.pop(&url) { match self.wait_map.pop(&url) {
Some(waiters) => { Some(waiters) => {
unsafe { unsafe {
@ -387,7 +385,7 @@ impl ImageCache {
match self.get_state(url.clone()) { match self.get_state(url.clone()) {
Init => fail!(~"request for image before prefetch"), Init => fail!(~"request for image before prefetch"),
Prefetching(DoDecode) => response.send(ImageNotReady), Prefetching(DoDecode) => response.send(ImageNotReady),
Prefetching(DoNotDecode) | Prefetched(*) => fail!(~"request for image before decode"), Prefetching(DoNotDecode) | Prefetched(..) => fail!(~"request for image before decode"),
Decoding => response.send(ImageNotReady), Decoding => response.send(ImageNotReady),
Decoded(image) => response.send(ImageReady(image.clone())), Decoded(image) => response.send(ImageReady(image.clone())),
Failed => response.send(ImageFailed), Failed => response.send(ImageFailed),
@ -398,16 +396,16 @@ impl ImageCache {
match self.get_state(url.clone()) { match self.get_state(url.clone()) {
Init => fail!(~"request for image before prefetch"), Init => fail!(~"request for image before prefetch"),
Prefetching(DoNotDecode) | Prefetched(*) => fail!(~"request for image before decode"), Prefetching(DoNotDecode) | Prefetched(..) => fail!(~"request for image before decode"),
Prefetching(DoDecode) | Decoding => { Prefetching(DoDecode) | Decoding => {
// We don't have this image yet // We don't have this image yet
if self.wait_map.contains_key(&url) { if self.wait_map.contains_key(&url) {
let waiters = self.wait_map.find_mut(&url).unwrap(); let waiters = self.wait_map.find_mut(&url).unwrap();
let mut response = Some(response);
unsafe { unsafe {
let res = Cell::new(response); waiters.unsafe_access(|waiters| {
waiters.unsafe_access( |waiters| { waiters.push(response.take().unwrap());
waiters.push(res.take());
}); });
} }
} else { } else {
@ -434,14 +432,34 @@ trait ImageCacheTaskClient {
impl ImageCacheTaskClient for ImageCacheTask { impl ImageCacheTaskClient for ImageCacheTask {
fn exit(&self) { fn exit(&self) {
let (response_port, response_chan) = stream(); let (response_port, response_chan) = Chan::new();
self.send(Exit(response_chan)); self.send(Exit(response_chan));
response_port.recv(); response_port.recv();
} }
} }
impl ImageCacheTask {
pub fn send(&self, msg: Msg) {
self.chan.send(msg);
}
#[cfg(test)]
fn wait_for_store(&self) -> Port<()> {
let (port, chan) = Chan::new();
self.send(WaitForStore(chan));
port
}
#[cfg(test)]
fn wait_for_store_prefetched(&self) -> Port<()> {
let (port, chan) = Chan::new();
self.send(WaitForStorePrefetched(chan));
port
}
}
fn load_image_data(url: Url, resource_task: ResourceTask) -> Result<~[u8], ()> { fn load_image_data(url: Url, resource_task: ResourceTask) -> Result<~[u8], ()> {
let (response_port, response_chan) = stream(); let (response_port, response_chan) = Chan::new();
resource_task.send(resource_task::Load(url, response_chan)); resource_task.send(resource_task::Load(url, response_chan));
let mut image_data = ~[]; let mut image_data = ~[];
@ -452,38 +470,29 @@ fn load_image_data(url: Url, resource_task: ResourceTask) -> Result<~[u8], ()> {
resource_task::Payload(data) => { resource_task::Payload(data) => {
image_data.push_all(data); image_data.push_all(data);
} }
resource_task::Done(result::Ok(*)) => { resource_task::Done(result::Ok(..)) => {
return Ok(image_data); return Ok(image_data);
} }
resource_task::Done(result::Err(*)) => { resource_task::Done(result::Err(..)) => {
return Err(()); return Err(());
} }
} }
} }
} }
fn default_decoder_factory() -> ~fn(&[u8]) -> Option<Image> {
let foo: ~fn(&[u8]) -> Option<Image> = |data: &[u8]| { load_from_memory(data) };
foo
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use std::comm;
use std::comm::{Port, SharedChan};
use std::result;
use std::cell::Cell;
use resource_task; use resource_task;
use resource_task::{ResourceTask, Metadata, start_sending}; use resource_task::{ResourceTask, Metadata, start_sending};
use image::base::{Image, test_image_bin, load_from_memory}; use image::base::test_image_bin;
use util::spawn_listener; use util::spawn_listener;
use servo_util::url::make_url; use servo_util::url::make_url;
fn mock_resource_task(on_load: ~fn(resource: Chan<resource_task::ProgressMsg>)) -> ResourceTask { fn mock_resource_task(on_load: proc(resource: SharedChan<resource_task::ProgressMsg>)) -> ResourceTask {
let chan = do spawn_listener |port: Port<resource_task::ControlMsg>| { spawn_listener(proc(port: Port<resource_task::ControlMsg>) {
loop { loop {
match port.recv() { match port.recv() {
resource_task::Load(_, response) => { resource_task::Load(_, response) => {
@ -493,13 +502,12 @@ mod tests {
resource_task::Exit => break resource_task::Exit => break
} }
} }
}; })
SharedChan::new(chan)
} }
#[test] #[test]
fn should_exit_on_request() { fn should_exit_on_request() {
let mock_resource_task = mock_resource_task(|_response| () ); let mock_resource_task = mock_resource_task(proc(_response) {});
let image_cache_task = ImageCacheTask(mock_resource_task.clone()); let image_cache_task = ImageCacheTask(mock_resource_task.clone());
let _url = make_url(~"file", None); let _url = make_url(~"file", None);
@ -511,24 +519,24 @@ mod tests {
#[test] #[test]
#[should_fail] #[should_fail]
fn should_fail_if_unprefetched_image_is_requested() { fn should_fail_if_unprefetched_image_is_requested() {
let mock_resource_task = mock_resource_task(|_response| () ); let mock_resource_task = mock_resource_task(proc(_response) {});
let image_cache_task = ImageCacheTask(mock_resource_task.clone()); let image_cache_task = ImageCacheTask(mock_resource_task.clone());
let url = make_url(~"file", None); let url = make_url(~"file", None);
let (port, chan) = stream(); let (port, chan) = Chan::new();
image_cache_task.send(GetImage(url, chan)); image_cache_task.send(GetImage(url, chan));
port.recv(); port.recv();
} }
#[test] #[test]
fn should_request_url_from_resource_task_on_prefetch() { fn should_request_url_from_resource_task_on_prefetch() {
let (url_requested, url_requested_chan) = comm::stream(); let (url_requested, url_requested_chan) = Chan::new();
let mock_resource_task = do mock_resource_task |response| { let mock_resource_task = mock_resource_task(proc(response) {
url_requested_chan.send(()); url_requested_chan.send(());
response.send(resource_task::Done(result::Ok(()))); response.send(resource_task::Done(Ok(())));
}; });
let image_cache_task = ImageCacheTask(mock_resource_task.clone()); let image_cache_task = ImageCacheTask(mock_resource_task.clone());
let url = make_url(~"file", None); let url = make_url(~"file", None);
@ -539,47 +547,14 @@ mod tests {
mock_resource_task.send(resource_task::Exit); mock_resource_task.send(resource_task::Exit);
} }
#[test]
#[should_fail]
fn should_fail_if_requesting_decode_of_an_unprefetched_image() {
let mock_resource_task = mock_resource_task(|_response| () );
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
let url = make_url(~"file", None);
image_cache_task.send(Decode(url));
image_cache_task.exit();
}
#[test]
#[should_fail]
fn should_fail_if_requesting_image_before_requesting_decode() {
let mock_resource_task = do mock_resource_task |response| {
response.send(resource_task::Done(result::Ok(())));
};
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
let url = make_url(~"file", None);
image_cache_task.send(Prefetch(url.clone()));
// no decode message
let (_port, chan) = stream();
image_cache_task.send(GetImage(url, chan));
image_cache_task.exit();
mock_resource_task.send(resource_task::Exit);
}
#[test] #[test]
fn should_not_request_url_from_resource_task_on_multiple_prefetches() { fn should_not_request_url_from_resource_task_on_multiple_prefetches() {
let (url_requested, url_requested_chan) = comm::stream(); let (url_requested, url_requested_chan) = Chan::new();
let mock_resource_task = do mock_resource_task |response| { let mock_resource_task = mock_resource_task(proc(response) {
url_requested_chan.send(()); url_requested_chan.send(());
response.send(resource_task::Done(result::Ok(()))); response.send(resource_task::Done(Ok(())));
}; });
let image_cache_task = ImageCacheTask(mock_resource_task.clone()); let image_cache_task = ImageCacheTask(mock_resource_task.clone());
let url = make_url(~"file", None); let url = make_url(~"file", None);
@ -589,27 +564,27 @@ mod tests {
url_requested.recv(); url_requested.recv();
image_cache_task.exit(); image_cache_task.exit();
mock_resource_task.send(resource_task::Exit); mock_resource_task.send(resource_task::Exit);
assert!(!url_requested.peek()) assert!(url_requested.try_recv().is_none())
} }
#[test] #[test]
fn should_return_image_not_ready_if_data_has_not_arrived() { fn should_return_image_not_ready_if_data_has_not_arrived() {
let (wait_port, wait_chan) = comm::stream(); let (wait_port, wait_chan) = Chan::new();
let mock_resource_task = do mock_resource_task |response| { let mock_resource_task = mock_resource_task(proc(response) {
// Don't send the data until after the client requests // Don't send the data until after the client requests
// the image // the image
wait_port.recv(); wait_port.recv();
response.send(resource_task::Payload(test_image_bin())); response.send(resource_task::Payload(test_image_bin()));
response.send(resource_task::Done(result::Ok(()))); response.send(resource_task::Done(Ok(())));
}; });
let image_cache_task = ImageCacheTask(mock_resource_task.clone()); let image_cache_task = ImageCacheTask(mock_resource_task.clone());
let url = make_url(~"file", None); let url = make_url(~"file", None);
image_cache_task.send(Prefetch(url.clone())); image_cache_task.send(Prefetch(url.clone()));
image_cache_task.send(Decode(url.clone())); image_cache_task.send(Decode(url.clone()));
let (response_port, response_chan) = stream(); let (response_port, response_chan) = Chan::new();
image_cache_task.send(GetImage(url, response_chan)); image_cache_task.send(GetImage(url, response_chan));
assert!(response_port.recv() == ImageNotReady); assert!(response_port.recv() == ImageNotReady);
wait_chan.send(()); wait_chan.send(());
@ -619,30 +594,23 @@ mod tests {
#[test] #[test]
fn should_return_decoded_image_data_if_data_has_arrived() { fn should_return_decoded_image_data_if_data_has_arrived() {
let mock_resource_task = do mock_resource_task |response| { let mock_resource_task = mock_resource_task(proc(response) {
response.send(resource_task::Payload(test_image_bin())); response.send(resource_task::Payload(test_image_bin()));
response.send(resource_task::Done(result::Ok(()))); response.send(resource_task::Done(Ok(())));
}; });
let image_cache_task = ImageCacheTask(mock_resource_task.clone()); let image_cache_task = ImageCacheTask(mock_resource_task.clone());
let url = make_url(~"file", None); let url = make_url(~"file", None);
let (wait_for_image, wait_for_image_chan) = comm::stream(); let join_port = image_cache_task.wait_for_store();
image_cache_task.send(OnMsg(|msg| {
match *msg {
StoreImage(*) => wait_for_image_chan.send(()),
_ => ()
}
}));
image_cache_task.send(Prefetch(url.clone())); image_cache_task.send(Prefetch(url.clone()));
image_cache_task.send(Decode(url.clone())); image_cache_task.send(Decode(url.clone()));
// Wait until our mock resource task has sent the image to the image cache // Wait until our mock resource task has sent the image to the image cache
wait_for_image.recv(); join_port.recv();
let (response_port, response_chan) = stream(); let (response_port, response_chan) = Chan::new();
image_cache_task.send(GetImage(url, response_chan)); image_cache_task.send(GetImage(url, response_chan));
match response_port.recv() { match response_port.recv() {
ImageReady(_) => (), ImageReady(_) => (),
@ -655,31 +623,24 @@ mod tests {
#[test] #[test]
fn should_return_decoded_image_data_for_multiple_requests() { fn should_return_decoded_image_data_for_multiple_requests() {
let mock_resource_task = do mock_resource_task |response| { let mock_resource_task = mock_resource_task(proc(response) {
response.send(resource_task::Payload(test_image_bin())); response.send(resource_task::Payload(test_image_bin()));
response.send(resource_task::Done(result::Ok(()))); response.send(resource_task::Done(Ok(())));
}; });
let image_cache_task = ImageCacheTask(mock_resource_task.clone()); let image_cache_task = ImageCacheTask(mock_resource_task.clone());
let url = make_url(~"file", None); let url = make_url(~"file", None);
let (wait_for_image, wait_for_image_chan) = comm::stream(); let join_port = image_cache_task.wait_for_store();
image_cache_task.send(OnMsg(|msg| {
match *msg {
StoreImage(*) => wait_for_image_chan.send(()),
_ => ()
}
}));
image_cache_task.send(Prefetch(url.clone())); image_cache_task.send(Prefetch(url.clone()));
image_cache_task.send(Decode(url.clone())); image_cache_task.send(Decode(url.clone()));
// Wait until our mock resource task has sent the image to the image cache // Wait until our mock resource task has sent the image to the image cache
wait_for_image.recv(); join_port.recv();
for _ in range(0,2) { for _ in range(0,2) {
let (response_port, response_chan) = stream(); let (response_port, response_chan) = Chan::new();
image_cache_task.send(GetImage(url.clone(), response_chan)); image_cache_task.send(GetImage(url.clone(), response_chan));
match response_port.recv() { match response_port.recv() {
ImageReady(_) => (), ImageReady(_) => (),
@ -693,17 +654,17 @@ mod tests {
#[test] #[test]
fn should_not_request_image_from_resource_task_if_image_is_already_available() { fn should_not_request_image_from_resource_task_if_image_is_already_available() {
let (image_bin_sent, image_bin_sent_chan) = comm::stream(); let (image_bin_sent, image_bin_sent_chan) = Chan::new();
let (resource_task_exited, resource_task_exited_chan) = comm::stream(); let (resource_task_exited, resource_task_exited_chan) = Chan::new();
let mock_resource_task = do spawn_listener |port: comm::Port<resource_task::ControlMsg>| { let mock_resource_task = spawn_listener(proc(port: Port<resource_task::ControlMsg>) {
loop { loop {
match port.recv() { match port.recv() {
resource_task::Load(_, response) => { resource_task::Load(_, response) => {
let chan = start_sending(response, Metadata::default(make_url(~"file:///fake", None))); let chan = start_sending(response, Metadata::default(make_url(~"file:///fake", None)));
chan.send(resource_task::Payload(test_image_bin())); chan.send(resource_task::Payload(test_image_bin()));
chan.send(resource_task::Done(result::Ok(()))); chan.send(resource_task::Done(Ok(())));
image_bin_sent_chan.send(()); image_bin_sent_chan.send(());
} }
resource_task::Exit => { resource_task::Exit => {
@ -712,8 +673,7 @@ mod tests {
} }
} }
} }
}; });
let mock_resource_task = SharedChan::new(mock_resource_task);
let image_cache_task = ImageCacheTask(mock_resource_task.clone()); let image_cache_task = ImageCacheTask(mock_resource_task.clone());
let url = make_url(~"file", None); let url = make_url(~"file", None);
@ -732,22 +692,22 @@ mod tests {
// Our resource task should not have received another request for the image // Our resource task should not have received another request for the image
// because it's already cached // because it's already cached
assert!(!image_bin_sent.peek()); assert!(image_bin_sent.try_recv().is_none());
} }
#[test] #[test]
fn should_not_request_image_from_resource_task_if_image_fetch_already_failed() { fn should_not_request_image_from_resource_task_if_image_fetch_already_failed() {
let (image_bin_sent, image_bin_sent_chan) = comm::stream(); let (image_bin_sent, image_bin_sent_chan) = Chan::new();
let (resource_task_exited, resource_task_exited_chan) = comm::stream(); let (resource_task_exited, resource_task_exited_chan) = Chan::new();
let mock_resource_task = do spawn_listener |port: comm::Port<resource_task::ControlMsg>| { let mock_resource_task = spawn_listener(proc(port: Port<resource_task::ControlMsg>) {
loop { loop {
match port.recv() { match port.recv() {
resource_task::Load(_, response) => { resource_task::Load(_, response) => {
let chan = start_sending(response, Metadata::default(make_url(~"file:///fake", None))); let chan = start_sending(response, Metadata::default(make_url(~"file:///fake", None)));
chan.send(resource_task::Payload(test_image_bin())); chan.send(resource_task::Payload(test_image_bin()));
chan.send(resource_task::Done(result::Err(()))); chan.send(resource_task::Done(Err(())));
image_bin_sent_chan.send(()); image_bin_sent_chan.send(());
} }
resource_task::Exit => { resource_task::Exit => {
@ -756,8 +716,7 @@ mod tests {
} }
} }
} }
}; });
let mock_resource_task = SharedChan::new(mock_resource_task);
let image_cache_task = ImageCacheTask(mock_resource_task.clone()); let image_cache_task = ImageCacheTask(mock_resource_task.clone());
let url = make_url(~"file", None); let url = make_url(~"file", None);
@ -778,36 +737,29 @@ mod tests {
// Our resource task should not have received another request for the image // Our resource task should not have received another request for the image
// because it's already cached // because it's already cached
assert!(!image_bin_sent.peek()); assert!(image_bin_sent.try_recv().is_none());
} }
#[test] #[test]
fn should_return_failed_if_image_bin_cannot_be_fetched() { fn should_return_failed_if_image_bin_cannot_be_fetched() {
let mock_resource_task = do mock_resource_task |response| { let mock_resource_task = mock_resource_task(proc(response) {
response.send(resource_task::Payload(test_image_bin())); response.send(resource_task::Payload(test_image_bin()));
// ERROR fetching image // ERROR fetching image
response.send(resource_task::Done(result::Err(()))); response.send(resource_task::Done(Err(())));
}; });
let image_cache_task = ImageCacheTask(mock_resource_task.clone()); let image_cache_task = ImageCacheTask(mock_resource_task.clone());
let url = make_url(~"file", None); let url = make_url(~"file", None);
let (wait_for_prefetech, wait_for_prefetech_chan) = comm::stream(); let join_port = image_cache_task.wait_for_store_prefetched();
image_cache_task.send(OnMsg(|msg| {
match *msg {
StorePrefetchedImageData(*) => wait_for_prefetech_chan.send(()),
_ => ()
}
}));
image_cache_task.send(Prefetch(url.clone())); image_cache_task.send(Prefetch(url.clone()));
image_cache_task.send(Decode(url.clone())); image_cache_task.send(Decode(url.clone()));
// Wait until our mock resource task has sent the image to the image cache // Wait until our mock resource task has sent the image to the image cache
wait_for_prefetech.recv(); join_port.recv();
let (response_port, response_chan) = stream(); let (response_port, response_chan) = Chan::new();
image_cache_task.send(GetImage(url, response_chan)); image_cache_task.send(GetImage(url, response_chan));
match response_port.recv() { match response_port.recv() {
ImageFailed => (), ImageFailed => (),
@ -820,31 +772,24 @@ mod tests {
#[test] #[test]
fn should_return_failed_for_multiple_get_image_requests_if_image_bin_cannot_be_fetched() { fn should_return_failed_for_multiple_get_image_requests_if_image_bin_cannot_be_fetched() {
let mock_resource_task = do mock_resource_task |response | { let mock_resource_task = mock_resource_task(proc(response) {
response.send(resource_task::Payload(test_image_bin())); response.send(resource_task::Payload(test_image_bin()));
// ERROR fetching image // ERROR fetching image
response.send(resource_task::Done(result::Err(()))); response.send(resource_task::Done(Err(())));
}; });
let image_cache_task = ImageCacheTask(mock_resource_task.clone()); let image_cache_task = ImageCacheTask(mock_resource_task.clone());
let url = make_url(~"file", None); let url = make_url(~"file", None);
let (wait_for_prefetech, wait_for_prefetech_chan) = comm::stream(); let join_port = image_cache_task.wait_for_store_prefetched();
image_cache_task.send(OnMsg(|msg| {
match *msg {
StorePrefetchedImageData(*) => wait_for_prefetech_chan.send(()),
_ => ()
}
}));
image_cache_task.send(Prefetch(url.clone())); image_cache_task.send(Prefetch(url.clone()));
image_cache_task.send(Decode(url.clone())); image_cache_task.send(Decode(url.clone()));
// Wait until our mock resource task has sent the image to the image cache // Wait until our mock resource task has sent the image to the image cache
wait_for_prefetech.recv(); join_port.recv();
let (response_port, response_chan) = stream(); let (response_port, response_chan) = Chan::new();
image_cache_task.send(GetImage(url.clone(), response_chan)); image_cache_task.send(GetImage(url.clone(), response_chan));
match response_port.recv() { match response_port.recv() {
ImageFailed => (), ImageFailed => (),
@ -852,7 +797,7 @@ mod tests {
} }
// And ask again, we should get the same response // And ask again, we should get the same response
let (response_port, response_chan) = stream(); let (response_port, response_chan) = Chan::new();
image_cache_task.send(GetImage(url, response_chan)); image_cache_task.send(GetImage(url, response_chan));
match response_port.recv() { match response_port.recv() {
ImageFailed => (), ImageFailed => (),
@ -863,87 +808,27 @@ mod tests {
mock_resource_task.send(resource_task::Exit); mock_resource_task.send(resource_task::Exit);
} }
#[test]
fn should_return_not_ready_if_image_is_still_decoding() {
let (wait_to_decode_port, wait_to_decode_chan) = comm::stream();
let mock_resource_task = do mock_resource_task |response| {
response.send(resource_task::Payload(test_image_bin()));
response.send(resource_task::Done(result::Ok(())));
};
let wait_to_decode_port_cell = Cell::new(wait_to_decode_port);
let decoder_factory: ~fn:Send() -> ~fn:Send(&[u8]) -> Option<Image> = || {
let wait_to_decode_port = wait_to_decode_port_cell.take();
|data: &[u8]| {
// Don't decode until after the client requests the image
wait_to_decode_port.recv();
load_from_memory(data)
}
};
let image_cache_task = ImageCacheTask_(mock_resource_task.clone(), decoder_factory);
let url = make_url(~"file", None);
let (wait_for_prefetech, wait_for_prefetech_chan) = comm::stream();
image_cache_task.send(OnMsg(|msg| {
match *msg {
StorePrefetchedImageData(*) => wait_for_prefetech_chan.send(()),
_ => ()
}
}));
image_cache_task.send(Prefetch(url.clone()));
image_cache_task.send(Decode(url.clone()));
// Wait until our mock resource task has sent the image to the image cache
wait_for_prefetech.recv();
// Make the request
let (response_port, response_chan) = stream();
image_cache_task.send(GetImage(url, response_chan));
match response_port.recv() {
ImageNotReady => (),
_ => fail!("bleh")
}
// Now decode
wait_to_decode_chan.send(());
image_cache_task.exit();
mock_resource_task.send(resource_task::Exit);
}
#[test] #[test]
fn should_return_failed_if_image_decode_fails() { fn should_return_failed_if_image_decode_fails() {
let mock_resource_task = do mock_resource_task |response| { let mock_resource_task = mock_resource_task(proc(response) {
// Bogus data // Bogus data
response.send(resource_task::Payload(~[])); response.send(resource_task::Payload(~[]));
response.send(resource_task::Done(result::Ok(()))); response.send(resource_task::Done(Ok(())));
}; });
let image_cache_task = ImageCacheTask(mock_resource_task.clone()); let image_cache_task = ImageCacheTask(mock_resource_task.clone());
let url = make_url(~"file", None); let url = make_url(~"file", None);
let (wait_for_decode, wait_for_decode_chan) = comm::stream(); let join_port = image_cache_task.wait_for_store();
image_cache_task.send(OnMsg(|msg| {
match *msg {
StoreImage(*) => wait_for_decode_chan.send(()),
_ => ()
}
}));
image_cache_task.send(Prefetch(url.clone())); image_cache_task.send(Prefetch(url.clone()));
image_cache_task.send(Decode(url.clone())); image_cache_task.send(Decode(url.clone()));
// Wait until our mock resource task has sent the image to the image cache // Wait until our mock resource task has sent the image to the image cache
wait_for_decode.recv(); join_port.recv();
// Make the request // Make the request
let (response_port, response_chan) = stream(); let (response_port, response_chan) = Chan::new();
image_cache_task.send(GetImage(url, response_chan)); image_cache_task.send(GetImage(url, response_chan));
match response_port.recv() { match response_port.recv() {
@ -957,33 +842,26 @@ mod tests {
#[test] #[test]
fn should_return_image_on_wait_if_image_is_already_loaded() { fn should_return_image_on_wait_if_image_is_already_loaded() {
let mock_resource_task = do mock_resource_task |response| { let mock_resource_task = mock_resource_task(proc(response) {
response.send(resource_task::Payload(test_image_bin())); response.send(resource_task::Payload(test_image_bin()));
response.send(resource_task::Done(result::Ok(()))); response.send(resource_task::Done(Ok(())));
}; });
let image_cache_task = ImageCacheTask(mock_resource_task.clone()); let image_cache_task = ImageCacheTask(mock_resource_task.clone());
let url = make_url(~"file", None); let url = make_url(~"file", None);
let (wait_for_decode, wait_for_decode_chan) = comm::stream(); let join_port = image_cache_task.wait_for_store();
image_cache_task.send(OnMsg(|msg| {
match *msg {
StoreImage(*) => wait_for_decode_chan.send(()),
_ => ()
}
}));
image_cache_task.send(Prefetch(url.clone())); image_cache_task.send(Prefetch(url.clone()));
image_cache_task.send(Decode(url.clone())); image_cache_task.send(Decode(url.clone()));
// Wait until our mock resource task has sent the image to the image cache // Wait until our mock resource task has sent the image to the image cache
wait_for_decode.recv(); join_port.recv();
let (response_port, response_chan) = stream(); let (response_port, response_chan) = Chan::new();
image_cache_task.send(WaitForImage(url, response_chan)); image_cache_task.send(WaitForImage(url, response_chan));
match response_port.recv() { match response_port.recv() {
ImageReady(*) => (), ImageReady(..) => (),
_ => fail!("bleh") _ => fail!("bleh")
} }
@ -993,13 +871,13 @@ mod tests {
#[test] #[test]
fn should_return_image_on_wait_if_image_is_not_yet_loaded() { fn should_return_image_on_wait_if_image_is_not_yet_loaded() {
let (wait_port, wait_chan) = comm::stream(); let (wait_port, wait_chan) = Chan::new();
let mock_resource_task = do mock_resource_task |response| { let mock_resource_task = mock_resource_task(proc(response) {
wait_port.recv(); wait_port.recv();
response.send(resource_task::Payload(test_image_bin())); response.send(resource_task::Payload(test_image_bin()));
response.send(resource_task::Done(result::Ok(()))); response.send(resource_task::Done(Ok(())));
}; });
let image_cache_task = ImageCacheTask(mock_resource_task.clone()); let image_cache_task = ImageCacheTask(mock_resource_task.clone());
let url = make_url(~"file", None); let url = make_url(~"file", None);
@ -1007,13 +885,13 @@ mod tests {
image_cache_task.send(Prefetch(url.clone())); image_cache_task.send(Prefetch(url.clone()));
image_cache_task.send(Decode(url.clone())); image_cache_task.send(Decode(url.clone()));
let (response_port, response_chan) = stream(); let (response_port, response_chan) = Chan::new();
image_cache_task.send(WaitForImage(url, response_chan)); image_cache_task.send(WaitForImage(url, response_chan));
wait_chan.send(()); wait_chan.send(());
match response_port.recv() { match response_port.recv() {
ImageReady(*) => (), ImageReady(..) => (),
_ => fail!("bleh") _ => fail!("bleh")
} }
@ -1023,13 +901,13 @@ mod tests {
#[test] #[test]
fn should_return_image_failed_on_wait_if_image_fails_to_load() { fn should_return_image_failed_on_wait_if_image_fails_to_load() {
let (wait_port, wait_chan) = comm::stream(); let (wait_port, wait_chan) = Chan::new();
let mock_resource_task = do mock_resource_task |response| { let mock_resource_task = mock_resource_task(proc(response) {
wait_port.recv(); wait_port.recv();
response.send(resource_task::Payload(test_image_bin())); response.send(resource_task::Payload(test_image_bin()));
response.send(resource_task::Done(result::Err(()))); response.send(resource_task::Done(Err(())));
}; });
let image_cache_task = ImageCacheTask(mock_resource_task.clone()); let image_cache_task = ImageCacheTask(mock_resource_task.clone());
let url = make_url(~"file", None); let url = make_url(~"file", None);
@ -1037,7 +915,7 @@ mod tests {
image_cache_task.send(Prefetch(url.clone())); image_cache_task.send(Prefetch(url.clone()));
image_cache_task.send(Decode(url.clone())); image_cache_task.send(Decode(url.clone()));
let (response_port, response_chan) = stream(); let (response_port, response_chan) = Chan::new();
image_cache_task.send(WaitForImage(url, response_chan)); image_cache_task.send(WaitForImage(url, response_chan));
wait_chan.send(()); wait_chan.send(());
@ -1053,10 +931,10 @@ mod tests {
#[test] #[test]
fn sync_cache_should_wait_for_images() { fn sync_cache_should_wait_for_images() {
let mock_resource_task = do mock_resource_task |response| { let mock_resource_task = mock_resource_task(proc(response) {
response.send(resource_task::Payload(test_image_bin())); response.send(resource_task::Payload(test_image_bin()));
response.send(resource_task::Done(result::Ok(()))); response.send(resource_task::Done(Ok(())));
}; });
let image_cache_task = SyncImageCacheTask(mock_resource_task.clone()); let image_cache_task = SyncImageCacheTask(mock_resource_task.clone());
let url = make_url(~"file", None); let url = make_url(~"file", None);
@ -1064,7 +942,7 @@ mod tests {
image_cache_task.send(Prefetch(url.clone())); image_cache_task.send(Prefetch(url.clone()));
image_cache_task.send(Decode(url.clone())); image_cache_task.send(Decode(url.clone()));
let (response_port, response_chan) = stream(); let (response_port, response_chan) = Chan::new();
image_cache_task.send(GetImage(url, response_chan)); image_cache_task.send(GetImage(url, response_chan));
match response_port.recv() { match response_port.recv() {
ImageReady(_) => (), ImageReady(_) => (),

View file

@ -11,14 +11,13 @@ multiple times and thus triggering reflows multiple times.
use image_cache_task::{Decode, GetImage, ImageCacheTask, ImageFailed, ImageNotReady, ImageReady}; use image_cache_task::{Decode, GetImage, ImageCacheTask, ImageFailed, ImageNotReady, ImageReady};
use image_cache_task::{ImageResponseMsg, Prefetch, WaitForImage}; use image_cache_task::{ImageResponseMsg, Prefetch, WaitForImage};
use std::comm;
use std::comm::Port; use std::comm::Port;
use std::task; use std::task;
use servo_util::url::{UrlMap, url_map}; use servo_util::url::{UrlMap, url_map};
use extra::url::Url; use extra::url::Url;
pub trait ImageResponder { pub trait ImageResponder {
fn respond(&self) -> ~fn(ImageResponseMsg); fn respond(&self) -> proc(ImageResponseMsg);
} }
pub fn LocalImageCache(image_cache_task: ImageCacheTask) -> LocalImageCache { pub fn LocalImageCache(image_cache_task: ImageCacheTask) -> LocalImageCache {
@ -90,13 +89,13 @@ impl LocalImageCache {
match state.last_response { match state.last_response {
ImageReady(ref image) => { ImageReady(ref image) => {
let (port, chan) = comm::stream(); let (port, chan) = Chan::new();
chan.send(ImageReady(image.clone())); chan.send(ImageReady(image.clone()));
return port; return port;
} }
ImageNotReady => { ImageNotReady => {
if last_round == self.round_number { if last_round == self.round_number {
let (port, chan) = comm::stream(); let (port, chan) = Chan::new();
chan.send(ImageNotReady); chan.send(ImageNotReady);
return port; return port;
} else { } else {
@ -105,14 +104,14 @@ impl LocalImageCache {
} }
} }
ImageFailed => { ImageFailed => {
let (port, chan) = comm::stream(); let (port, chan) = Chan::new();
chan.send(ImageFailed); chan.send(ImageFailed);
return port; return port;
} }
} }
} }
let (response_port, response_chan) = comm::stream(); let (response_port, response_chan) = Chan::new();
self.image_cache_task.send(GetImage((*url).clone(), response_chan)); self.image_cache_task.send(GetImage((*url).clone(), response_chan));
let response = response_port.recv(); let response = response_port.recv();
@ -128,7 +127,7 @@ impl LocalImageCache {
let on_image_available = self.on_image_available.as_ref().unwrap().respond(); let on_image_available = self.on_image_available.as_ref().unwrap().respond();
let url = (*url).clone(); let url = (*url).clone();
do task::spawn { do task::spawn {
let (response_port, response_chan) = comm::stream(); let (response_port, response_chan) = Chan::new();
image_cache_task.send(WaitForImage(url.clone(), response_chan)); image_cache_task.send(WaitForImage(url.clone(), response_chan));
on_image_available(response_port.recv()); on_image_available(response_port.recv());
} }
@ -144,7 +143,7 @@ impl LocalImageCache {
}; };
self.get_state(url).last_response = response_copy; self.get_state(url).last_response = response_copy;
let (port, chan) = comm::stream(); let (port, chan) = Chan::new();
chan.send(response); chan.send(response);
return port; return port;
} }

View file

@ -2,17 +2,14 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#[link(name = "net", #[crate_id = "github.com/mozilla/servo#net:0.1"];
vers = "0.1",
uuid = "69c2b7b7-0d7d-4514-a48a-0eed61476039",
url = "http://servo.org/")];
#[crate_type = "lib"]; #[crate_type = "lib"];
#[feature(globs, managed_boxes)]; #[feature(globs, managed_boxes)];
extern mod geom; extern mod geom;
extern mod http; extern mod http;
extern mod servo_util (name = "util"); extern mod servo_util = "util";
extern mod stb_image; extern mod stb_image;
extern mod extra; extern mod extra;
extern mod png; extern mod png;

View file

@ -8,9 +8,7 @@ use file_loader;
use http_loader; use http_loader;
use data_loader; use data_loader;
use std::cell::Cell;
use std::comm::{Chan, Port, SharedChan}; use std::comm::{Chan, Port, SharedChan};
use std::comm;
use extra::url::Url; use extra::url::Url;
use util::spawn_listener; use util::spawn_listener;
use http::headers::content_type::MediaType; use http::headers::content_type::MediaType;
@ -87,8 +85,8 @@ pub enum ProgressMsg {
/// For use by loaders in responding to a Load message. /// For use by loaders in responding to a Load message.
pub fn start_sending(start_chan: Chan<LoadResponse>, pub fn start_sending(start_chan: Chan<LoadResponse>,
metadata: Metadata) -> Chan<ProgressMsg> { metadata: Metadata) -> SharedChan<ProgressMsg> {
let (progress_port, progress_chan) = comm::stream(); let (progress_port, progress_chan) = SharedChan::new();
start_chan.send(LoadResponse { start_chan.send(LoadResponse {
metadata: metadata, metadata: metadata,
progress_port: progress_port, progress_port: progress_port,
@ -99,7 +97,7 @@ pub fn start_sending(start_chan: Chan<LoadResponse>,
/// Convenience function for synchronously loading a whole resource. /// Convenience function for synchronously loading a whole resource.
pub fn load_whole_resource(resource_task: &ResourceTask, url: Url) pub fn load_whole_resource(resource_task: &ResourceTask, url: Url)
-> Result<(Metadata, ~[u8]), ()> { -> Result<(Metadata, ~[u8]), ()> {
let (start_port, start_chan) = comm::stream(); let (start_port, start_chan) = Chan::new();
resource_task.send(Load(url, start_chan)); resource_task.send(Load(url, start_chan));
let response = start_port.recv(); let response = start_port.recv();
@ -116,7 +114,7 @@ pub fn load_whole_resource(resource_task: &ResourceTask, url: Url)
/// Handle to a resource task /// Handle to a resource task
pub type ResourceTask = SharedChan<ControlMsg>; pub type ResourceTask = SharedChan<ControlMsg>;
pub type LoaderTask = ~fn(url: Url, Chan<LoadResponse>); pub type LoaderTask = proc(url: Url, Chan<LoadResponse>);
/** /**
Creates a task to load a specific resource Creates a task to load a specific resource
@ -137,12 +135,11 @@ pub fn ResourceTask() -> ResourceTask {
} }
fn create_resource_task_with_loaders(loaders: ~[(~str, LoaderTaskFactory)]) -> ResourceTask { fn create_resource_task_with_loaders(loaders: ~[(~str, LoaderTaskFactory)]) -> ResourceTask {
let loaders_cell = Cell::new(loaders); let chan = spawn_listener(proc(from_client) {
let chan = do spawn_listener |from_client| {
// TODO: change copy to move once we can move out of closures // TODO: change copy to move once we can move out of closures
ResourceManager(from_client, loaders_cell.take()).start() ResourceManager(from_client, loaders).start()
}; });
SharedChan::new(chan) chan
} }
pub struct ResourceManager { pub struct ResourceManager {
@ -211,7 +208,7 @@ fn test_exit() {
#[test] #[test]
fn test_bad_scheme() { fn test_bad_scheme() {
let resource_task = ResourceTask(); let resource_task = ResourceTask();
let (start, start_chan) = comm::stream(); let (start, start_chan) = Chan::new();
resource_task.send(Load(FromStr::from_str("bogus://whatever").unwrap(), start_chan)); resource_task.send(Load(FromStr::from_str("bogus://whatever").unwrap(), start_chan));
let response = start.recv(); let response = start.recv();
match response.progress_port.recv() { match response.progress_port.recv() {
@ -226,7 +223,7 @@ static snicklefritz_payload: [u8, ..3] = [1, 2, 3];
#[cfg(test)] #[cfg(test)]
fn snicklefritz_loader_factory() -> LoaderTask { fn snicklefritz_loader_factory() -> LoaderTask {
let f: LoaderTask = |url: Url, start_chan: Chan<LoadResponse>| { let f: LoaderTask = proc(url: Url, start_chan: Chan<LoadResponse>) {
let progress_chan = start_sending(start_chan, Metadata::default(url)); let progress_chan = start_sending(start_chan, Metadata::default(url));
progress_chan.send(Payload(snicklefritz_payload.into_owned())); progress_chan.send(Payload(snicklefritz_payload.into_owned()));
progress_chan.send(Done(Ok(()))); progress_chan.send(Done(Ok(())));
@ -238,7 +235,7 @@ fn snicklefritz_loader_factory() -> LoaderTask {
fn should_delegate_to_scheme_loader() { fn should_delegate_to_scheme_loader() {
let loader_factories = ~[(~"snicklefritz", snicklefritz_loader_factory)]; let loader_factories = ~[(~"snicklefritz", snicklefritz_loader_factory)];
let resource_task = create_resource_task_with_loaders(loader_factories); let resource_task = create_resource_task_with_loaders(loader_factories);
let (start, start_chan) = comm::stream(); let (start, start_chan) = Chan::new();
resource_task.send(Load(FromStr::from_str("snicklefritz://heya").unwrap(), start_chan)); resource_task.send(Load(FromStr::from_str("snicklefritz://heya").unwrap(), start_chan));
let response = start.recv(); let response = start.recv();

View file

@ -2,14 +2,13 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use std::comm;
use std::comm::{Chan, Port}; use std::comm::{Chan, Port};
use std::task; use std::task;
pub fn spawn_listener<A: Send>(f: ~fn(Port<A>)) -> Chan<A> { pub fn spawn_listener<A: Send>(f: proc(Port<A>)) -> SharedChan<A> {
let (setup_port, setup_chan) = comm::stream(); let (setup_port, setup_chan) = Chan::new();
do task::spawn { do task::spawn {
let (port, chan) = comm::stream(); let (port, chan) = SharedChan::new();
setup_chan.send(chan); setup_chan.send(chan);
f(port); f(port);
} }

View file

@ -43,7 +43,6 @@ impl CallbackInterface {
} }
} }
#[fixed_stack_segment]
pub fn GetCallableProperty(&self, cx: *JSContext, name: *libc::c_char, callable: &mut JSVal) -> bool { pub fn GetCallableProperty(&self, cx: *JSContext, name: *libc::c_char, callable: &mut JSVal) -> bool {
unsafe { unsafe {
if JS_GetProperty(cx, self.callback, name, &*callable) == 0 { if JS_GetProperty(cx, self.callback, name, &*callable) == 0 {
@ -65,7 +64,6 @@ pub fn GetJSObjectFromCallback<T: CallbackContainer>(callback: &T) -> *JSObject
callback.callback() callback.callback()
} }
#[fixed_stack_segment]
pub fn WrapCallThisObject<T: 'static + CallbackContainer + Reflectable>(cx: *JSContext, pub fn WrapCallThisObject<T: 'static + CallbackContainer + Reflectable>(cx: *JSContext,
_scope: *JSObject, _scope: *JSObject,
p: @mut T) -> *JSObject { p: @mut T) -> *JSObject {

View file

@ -1091,7 +1091,7 @@ for (uint32_t i = 0; i < length; ++i) {
return handleDefault( return handleDefault(
conversionCode, conversionCode,
("static data: [u8, ..%s] = [ %s ];\n" ("static data: [u8, ..%s] = [ %s ];\n"
"%s = str::from_utf8(data)" % "%s = str::from_utf8(data).to_owned()" %
(len(defaultValue.value) + 1, (len(defaultValue.value) + 1,
", ".join(["'" + char + "' as u8" for char in defaultValue.value] + ["0"]), ", ".join(["'" + char + "' as u8" for char in defaultValue.value] + ["0"]),
varName))) varName)))
@ -2173,7 +2173,7 @@ class CGImports(CGWrapper):
# Allow unreachable_code because we use 'break' in a way that sometimes produces # Allow unreachable_code because we use 'break' in a way that sometimes produces
# two 'break's in a row. See for example CallbackMember.getArgConversions. # two 'break's in a row. See for example CallbackMember.getArgConversions.
return '\n'.join([ return '\n'.join([
'#[allow(unreachable_code,non_uppercase_statics,unused_imports,unused_variable,unused_unsafe,unused_mut,dead_assignment)];', '#[allow(unreachable_code,non_uppercase_statics,unused_imports,unused_variable,unused_unsafe,unused_mut,dead_assignment,dead_code)];',
''.join('use %s;\n' % i for i in imports), ''.join('use %s;\n' % i for i in imports),
'']) ''])
CGWrapper.__init__(self, child, CGWrapper.__init__(self, child,
@ -2454,16 +2454,14 @@ class CGAbstractMethod(CGThing):
def _decorators(self): def _decorators(self):
decorators = [] decorators = []
if self.alwaysInline: if self.alwaysInline:
# FIXME Rust #8801 #[inline(always)] and #[fixed_stack_segment] not compatible decorators.append('#[inline(always)]')
# decorators.append('#[inline(always)]')
pass
elif self.inline: elif self.inline:
#decorators.append('inline') #decorators.append('inline')
pass pass
if self.extern: if self.extern:
decorators.append('extern') decorators.append('extern')
if not self.extern: if not self.extern:
decorators.append('#[fixed_stack_segment]') pass
if self.static: if self.static:
#decorators.append('static') #decorators.append('static')
pass pass
@ -3522,6 +3520,7 @@ class CGEnum(CGThing):
def define(self): def define(self):
return """ return """
#[repr(uint)]
pub enum valuelist { pub enum valuelist {
%s %s
} }
@ -3576,7 +3575,7 @@ class ClassMethod(ClassItem):
ClassItem.__init__(self, name, visibility) ClassItem.__init__(self, name, visibility)
def getDecorators(self, declaring): def getDecorators(self, declaring):
decorators = ['#[fixed_stack_segment]'] decorators = []
if self.inline: if self.inline:
decorators.append('inline') decorators.append('inline')
if declaring: if declaring:
@ -4150,8 +4149,8 @@ class CGProxyUnwrap(CGAbstractMethod):
obj = js::UnwrapObject(obj); obj = js::UnwrapObject(obj);
}*/ }*/
//MOZ_ASSERT(IsProxy(obj)); //MOZ_ASSERT(IsProxy(obj));
let box: *Box<%s> = cast::transmute(RUST_JSVAL_TO_PRIVATE(GetProxyPrivate(obj))); let box_: *Box<%s> = cast::transmute(RUST_JSVAL_TO_PRIVATE(GetProxyPrivate(obj)));
return ptr::to_unsafe_ptr(&(*box).data);""" % (self.descriptor.concreteType) return ptr::to_unsafe_ptr(&(*box_).data);""" % (self.descriptor.concreteType)
class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod): class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod):
def __init__(self, descriptor): def __init__(self, descriptor):
@ -4443,9 +4442,9 @@ class CGDOMJSProxyHandler_obj_toString(CGAbstractExternMethod):
JSString* jsresult; JSString* jsresult;
return xpc_qsStringToJsstring(cx, result, &jsresult) ? jsresult : NULL;""" return xpc_qsStringToJsstring(cx, result, &jsresult) ? jsresult : NULL;"""
return """ do "%s".to_c_str().with_ref |s| { return """ "%s".to_c_str().with_ref(|s| {
_obj_toString(cx, s) _obj_toString(cx, s)
}""" % self.descriptor.name })""" % self.descriptor.name
def definition_body(self): def definition_body(self):
return self.getBody() return self.getBody()
@ -4907,7 +4906,6 @@ class CGDictionary(CGThing):
" return true;\n" " return true;\n"
" }\n" " }\n"
"\n" if not self.workers else "") + "\n" if not self.workers else "") +
" #[fixed_stack_segment]\n" +
" pub fn Init(&mut self, cx: *JSContext, val: JSVal) -> JSBool {\n" " pub fn Init(&mut self, cx: *JSContext, val: JSVal) -> JSBool {\n"
" unsafe {\n" + " unsafe {\n" +
# NOTE: jsids are per-runtime, so don't use them in workers # NOTE: jsids are per-runtime, so don't use them in workers

View file

@ -13,14 +13,12 @@ pub trait JSValConvertible {
impl JSValConvertible for i64 { impl JSValConvertible for i64 {
#[fixed_stack_segment]
fn to_jsval(&self) -> JSVal { fn to_jsval(&self) -> JSVal {
unsafe { unsafe {
RUST_DOUBLE_TO_JSVAL(*self as f64) RUST_DOUBLE_TO_JSVAL(*self as f64)
} }
} }
#[fixed_stack_segment]
fn from_jsval(val: JSVal) -> Option<i64> { fn from_jsval(val: JSVal) -> Option<i64> {
unsafe { unsafe {
Some(RUST_JSVAL_TO_DOUBLE(val) as i64) Some(RUST_JSVAL_TO_DOUBLE(val) as i64)
@ -29,14 +27,12 @@ impl JSValConvertible for i64 {
} }
impl JSValConvertible for u32 { impl JSValConvertible for u32 {
#[fixed_stack_segment]
fn to_jsval(&self) -> JSVal { fn to_jsval(&self) -> JSVal {
unsafe { unsafe {
RUST_UINT_TO_JSVAL(*self) RUST_UINT_TO_JSVAL(*self)
} }
} }
#[fixed_stack_segment]
fn from_jsval(val: JSVal) -> Option<u32> { fn from_jsval(val: JSVal) -> Option<u32> {
unsafe { unsafe {
Some(RUST_JSVAL_TO_INT(val) as u32) Some(RUST_JSVAL_TO_INT(val) as u32)
@ -45,14 +41,12 @@ impl JSValConvertible for u32 {
} }
impl JSValConvertible for i32 { impl JSValConvertible for i32 {
#[fixed_stack_segment]
fn to_jsval(&self) -> JSVal { fn to_jsval(&self) -> JSVal {
unsafe { unsafe {
RUST_UINT_TO_JSVAL(*self as u32) RUST_UINT_TO_JSVAL(*self as u32)
} }
} }
#[fixed_stack_segment]
fn from_jsval(val: JSVal) -> Option<i32> { fn from_jsval(val: JSVal) -> Option<i32> {
unsafe { unsafe {
Some(RUST_JSVAL_TO_INT(val) as i32) Some(RUST_JSVAL_TO_INT(val) as i32)
@ -61,14 +55,12 @@ impl JSValConvertible for i32 {
} }
impl JSValConvertible for u16 { impl JSValConvertible for u16 {
#[fixed_stack_segment]
fn to_jsval(&self) -> JSVal { fn to_jsval(&self) -> JSVal {
unsafe { unsafe {
RUST_UINT_TO_JSVAL(*self as u32) RUST_UINT_TO_JSVAL(*self as u32)
} }
} }
#[fixed_stack_segment]
fn from_jsval(val: JSVal) -> Option<u16> { fn from_jsval(val: JSVal) -> Option<u16> {
unsafe { unsafe {
Some(RUST_JSVAL_TO_INT(val) as u16) Some(RUST_JSVAL_TO_INT(val) as u16)
@ -97,14 +89,12 @@ impl JSValConvertible for bool {
} }
impl JSValConvertible for f32 { impl JSValConvertible for f32 {
#[fixed_stack_segment]
fn to_jsval(&self) -> JSVal { fn to_jsval(&self) -> JSVal {
unsafe { unsafe {
RUST_DOUBLE_TO_JSVAL(*self as f64) RUST_DOUBLE_TO_JSVAL(*self as f64)
} }
} }
#[fixed_stack_segment]
fn from_jsval(val: JSVal) -> Option<f32> { fn from_jsval(val: JSVal) -> Option<f32> {
unsafe { unsafe {
Some(RUST_JSVAL_TO_DOUBLE(val) as f32) Some(RUST_JSVAL_TO_DOUBLE(val) as f32)
@ -113,14 +103,12 @@ impl JSValConvertible for f32 {
} }
impl JSValConvertible for f64 { impl JSValConvertible for f64 {
#[fixed_stack_segment]
fn to_jsval(&self) -> JSVal { fn to_jsval(&self) -> JSVal {
unsafe { unsafe {
RUST_DOUBLE_TO_JSVAL(*self as f64) RUST_DOUBLE_TO_JSVAL(*self as f64)
} }
} }
#[fixed_stack_segment]
fn from_jsval(val: JSVal) -> Option<f64> { fn from_jsval(val: JSVal) -> Option<f64> {
unsafe { unsafe {
Some(RUST_JSVAL_TO_DOUBLE(val) as f64) Some(RUST_JSVAL_TO_DOUBLE(val) as f64)

View file

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::bindings::utils::{Reflectable, Reflector, Traceable}; use dom::bindings::utils::{Reflectable, Reflector, Traceable, trace_reflector};
use dom::types::*; use dom::types::*;
use dom::node::AbstractNode; use dom::node::AbstractNode;
@ -23,7 +23,6 @@ impl Reflectable for AbstractNode {
impl Traceable for Node { impl Traceable for Node {
fn trace(&self, tracer: *mut JSTracer) { fn trace(&self, tracer: *mut JSTracer) {
#[fixed_stack_segment]
fn trace_node(tracer: *mut JSTracer, node: Option<AbstractNode>, name: &str) { fn trace_node(tracer: *mut JSTracer, node: Option<AbstractNode>, name: &str) {
if node.is_none() { if node.is_none() {
return; return;
@ -35,10 +34,10 @@ impl Traceable for Node {
unsafe { unsafe {
(*tracer).debugPrinter = ptr::null(); (*tracer).debugPrinter = ptr::null();
(*tracer).debugPrintIndex = -1; (*tracer).debugPrintIndex = -1;
do name.to_c_str().with_ref |name| { name.to_c_str().with_ref(|name| {
(*tracer).debugPrintArg = name as *libc::c_void; (*tracer).debugPrintArg = name as *libc::c_void;
JS_CallTracer(cast::transmute(tracer), obj, JSTRACE_OBJECT as u32); JS_CallTracer(cast::transmute(tracer), obj, JSTRACE_OBJECT as u32);
} });
} }
} }
debug!("tracing {:p}?:", self.reflector().get_jsobject()); debug!("tracing {:p}?:", self.reflector().get_jsobject());
@ -47,5 +46,7 @@ impl Traceable for Node {
trace_node(tracer, self.last_child, "last child"); trace_node(tracer, self.last_child, "last child");
trace_node(tracer, self.next_sibling, "next sibling"); trace_node(tracer, self.next_sibling, "next sibling");
trace_node(tracer, self.prev_sibling, "prev sibling"); trace_node(tracer, self.prev_sibling, "prev sibling");
let owner_doc = self.owner_doc();
trace_reflector(tracer, "document", owner_doc.reflector());
} }
} }

View file

@ -44,7 +44,6 @@ pub extern fn getPropertyDescriptor(cx: *JSContext, proxy: *JSObject, id: jsid,
} }
} }
#[fixed_stack_segment]
pub fn defineProperty_(cx: *JSContext, proxy: *JSObject, id: jsid, pub fn defineProperty_(cx: *JSContext, proxy: *JSObject, id: jsid,
desc: *JSPropertyDescriptor) -> JSBool { desc: *JSPropertyDescriptor) -> JSBool {
unsafe { unsafe {
@ -72,7 +71,6 @@ pub extern fn defineProperty(cx: *JSContext, proxy: *JSObject, id: jsid,
defineProperty_(cx, proxy, id, desc) defineProperty_(cx, proxy, id, desc)
} }
#[fixed_stack_segment]
pub fn _obj_toString(cx: *JSContext, className: *libc::c_char) -> *JSString { pub fn _obj_toString(cx: *JSContext, className: *libc::c_char) -> *JSString {
unsafe { unsafe {
let name = str::raw::from_c_str(className); let name = str::raw::from_c_str(className);
@ -83,7 +81,7 @@ pub fn _obj_toString(cx: *JSContext, className: *libc::c_char) -> *JSString {
} }
let result = ~"[object " + name + "]"; let result = ~"[object " + name + "]";
for (i, c) in result.iter().enumerate() { for (i, c) in result.chars().enumerate() {
*chars.offset(i as int) = c as jschar; *chars.offset(i as int) = c as jschar;
} }
*chars.offset(nchars as int) = 0; *chars.offset(nchars as int) = 0;
@ -95,7 +93,6 @@ pub fn _obj_toString(cx: *JSContext, className: *libc::c_char) -> *JSString {
} }
} }
#[fixed_stack_segment]
pub fn GetExpandoObject(obj: *JSObject) -> *JSObject { pub fn GetExpandoObject(obj: *JSObject) -> *JSObject {
unsafe { unsafe {
assert!(is_dom_proxy(obj)); assert!(is_dom_proxy(obj));
@ -108,7 +105,6 @@ pub fn GetExpandoObject(obj: *JSObject) -> *JSObject {
} }
} }
#[fixed_stack_segment]
pub fn EnsureExpandoObject(cx: *JSContext, obj: *JSObject) -> *JSObject { pub fn EnsureExpandoObject(cx: *JSContext, obj: *JSObject) -> *JSObject {
unsafe { unsafe {
assert!(is_dom_proxy(obj)); assert!(is_dom_proxy(obj));

View file

@ -29,7 +29,7 @@ use js::jsapi::{JS_NewUCStringCopyN, JS_DefineFunctions, JS_DefineProperty};
use js::jsapi::{JS_ValueToString, JS_GetReservedSlot, JS_SetReservedSlot}; use js::jsapi::{JS_ValueToString, JS_GetReservedSlot, JS_SetReservedSlot};
use js::jsapi::{JSContext, JSObject, JSBool, jsid, JSClass, JSNative, JSTracer}; use js::jsapi::{JSContext, JSObject, JSBool, jsid, JSClass, JSNative, JSTracer};
use js::jsapi::{JSFunctionSpec, JSPropertySpec, JSVal, JSPropertyDescriptor}; use js::jsapi::{JSFunctionSpec, JSPropertySpec, JSVal, JSPropertyDescriptor};
use js::jsapi::{JSPropertyOp, JSStrictPropertyOp, JS_NewGlobalObject, JS_InitStandardClasses}; use js::jsapi::{JS_NewGlobalObject, JS_InitStandardClasses};
use js::jsapi::{JSString, JS_CallTracer, JSTRACE_OBJECT}; use js::jsapi::{JSString, JS_CallTracer, JSTRACE_OBJECT};
use js::jsapi::{JS_IsExceptionPending}; use js::jsapi::{JS_IsExceptionPending};
use js::jsfriendapi::bindgen::JS_NewObjectWithUniqueType; use js::jsfriendapi::bindgen::JS_NewObjectWithUniqueType;
@ -47,22 +47,18 @@ mod jsval {
use js::glue::{RUST_JSVAL_IS_STRING, RUST_JSVAL_TO_STRING}; use js::glue::{RUST_JSVAL_IS_STRING, RUST_JSVAL_TO_STRING};
use js::jsapi::{JSVal, JSString}; use js::jsapi::{JSVal, JSString};
#[fixed_stack_segment]
pub fn is_null(v: JSVal) -> bool { pub fn is_null(v: JSVal) -> bool {
unsafe { RUST_JSVAL_IS_NULL(v) == 1 } unsafe { RUST_JSVAL_IS_NULL(v) == 1 }
} }
#[fixed_stack_segment]
pub fn is_undefined(v: JSVal) -> bool { pub fn is_undefined(v: JSVal) -> bool {
unsafe { RUST_JSVAL_IS_VOID(v) == 1 } unsafe { RUST_JSVAL_IS_VOID(v) == 1 }
} }
#[fixed_stack_segment]
pub fn is_string(v: JSVal) -> bool { pub fn is_string(v: JSVal) -> bool {
unsafe { RUST_JSVAL_IS_STRING(v) == 1 } unsafe { RUST_JSVAL_IS_STRING(v) == 1 }
} }
#[fixed_stack_segment]
pub unsafe fn to_string(v: JSVal) -> *JSString { pub unsafe fn to_string(v: JSVal) -> *JSString {
RUST_JSVAL_TO_STRING(v) RUST_JSVAL_TO_STRING(v)
} }
@ -149,7 +145,6 @@ fn is_dom_class(clasp: *JSClass) -> bool {
} }
} }
#[fixed_stack_segment]
pub fn is_dom_proxy(obj: *JSObject) -> bool { pub fn is_dom_proxy(obj: *JSObject) -> bool {
unsafe { unsafe {
(js_IsObjectProxyClass(obj) || js_IsFunctionProxyClass(obj)) && (js_IsObjectProxyClass(obj) || js_IsFunctionProxyClass(obj)) &&
@ -157,7 +152,6 @@ pub fn is_dom_proxy(obj: *JSObject) -> bool {
} }
} }
#[fixed_stack_segment]
pub unsafe fn dom_object_slot(obj: *JSObject) -> u32 { pub unsafe fn dom_object_slot(obj: *JSObject) -> u32 {
let clasp = JS_GetClass(obj); let clasp = JS_GetClass(obj);
if is_dom_class(clasp) { if is_dom_class(clasp) {
@ -168,14 +162,12 @@ pub unsafe fn dom_object_slot(obj: *JSObject) -> u32 {
} }
} }
#[fixed_stack_segment]
pub unsafe fn unwrap<T>(obj: *JSObject) -> T { pub unsafe fn unwrap<T>(obj: *JSObject) -> T {
let slot = dom_object_slot(obj); let slot = dom_object_slot(obj);
let val = JS_GetReservedSlot(obj, slot); let val = JS_GetReservedSlot(obj, slot);
cast::transmute(RUST_JSVAL_TO_PRIVATE(val)) cast::transmute(RUST_JSVAL_TO_PRIVATE(val))
} }
#[fixed_stack_segment]
pub unsafe fn get_dom_class(obj: *JSObject) -> Result<DOMClass, ()> { pub unsafe fn get_dom_class(obj: *JSObject) -> Result<DOMClass, ()> {
let clasp = JS_GetClass(obj); let clasp = JS_GetClass(obj);
if is_dom_class(clasp) { if is_dom_class(clasp) {
@ -194,7 +186,7 @@ pub unsafe fn get_dom_class(obj: *JSObject) -> Result<DOMClass, ()> {
pub fn unwrap_object<T>(obj: *JSObject, proto_id: PrototypeList::id::ID, proto_depth: uint) -> Result<T, ()> { pub fn unwrap_object<T>(obj: *JSObject, proto_id: PrototypeList::id::ID, proto_depth: uint) -> Result<T, ()> {
unsafe { unsafe {
do get_dom_class(obj).and_then |dom_class| { get_dom_class(obj).and_then(|dom_class| {
if dom_class.interface_chain[proto_depth] == proto_id { if dom_class.interface_chain[proto_depth] == proto_id {
debug!("good prototype"); debug!("good prototype");
Ok(unwrap(obj)) Ok(unwrap(obj))
@ -202,11 +194,10 @@ pub fn unwrap_object<T>(obj: *JSObject, proto_id: PrototypeList::id::ID, proto_d
debug!("bad prototype"); debug!("bad prototype");
Err(()) Err(())
} }
} })
} }
} }
#[fixed_stack_segment]
pub fn unwrap_value<T>(val: *JSVal, proto_id: PrototypeList::id::ID, proto_depth: uint) -> Result<T, ()> { pub fn unwrap_value<T>(val: *JSVal, proto_id: PrototypeList::id::ID, proto_depth: uint) -> Result<T, ()> {
unsafe { unsafe {
let obj = RUST_JSVAL_TO_OBJECT(*val); let obj = RUST_JSVAL_TO_OBJECT(*val);
@ -216,22 +207,19 @@ pub fn unwrap_value<T>(val: *JSVal, proto_id: PrototypeList::id::ID, proto_depth
pub unsafe fn squirrel_away<T>(x: @mut T) -> *Box<T> { pub unsafe fn squirrel_away<T>(x: @mut T) -> *Box<T> {
let y: *Box<T> = cast::transmute(x); let y: *Box<T> = cast::transmute(x);
cast::forget(x);
y y
} }
#[fixed_stack_segment]
pub fn jsstring_to_str(cx: *JSContext, s: *JSString) -> ~str { pub fn jsstring_to_str(cx: *JSContext, s: *JSString) -> ~str {
unsafe { unsafe {
let length = 0; let length = 0;
let chars = JS_GetStringCharsAndLength(cx, s, &length); let chars = JS_GetStringCharsAndLength(cx, s, &length);
do vec::raw::buf_as_slice(chars, length as uint) |char_vec| { vec::raw::buf_as_slice(chars, length as uint, |char_vec| {
str::from_utf16(char_vec) str::from_utf16(char_vec)
} })
} }
} }
#[fixed_stack_segment]
pub fn jsid_to_str(cx: *JSContext, id: jsid) -> ~str { pub fn jsid_to_str(cx: *JSContext, id: jsid) -> ~str {
unsafe { unsafe {
assert!(RUST_JSID_IS_STRING(id) != 0); assert!(RUST_JSID_IS_STRING(id) != 0);
@ -245,7 +233,6 @@ pub enum StringificationBehavior {
Empty, Empty,
} }
#[fixed_stack_segment]
pub fn jsval_to_str(cx: *JSContext, v: JSVal, pub fn jsval_to_str(cx: *JSContext, v: JSVal,
nullBehavior: StringificationBehavior) -> Result<~str, ()> { nullBehavior: StringificationBehavior) -> Result<~str, ()> {
if jsval::is_null(v) && nullBehavior == Empty { if jsval::is_null(v) && nullBehavior == Empty {
@ -261,7 +248,6 @@ pub fn jsval_to_str(cx: *JSContext, v: JSVal,
} }
} }
#[fixed_stack_segment]
pub fn jsval_to_domstring(cx: *JSContext, v: JSVal) -> Result<Option<DOMString>, ()> { pub fn jsval_to_domstring(cx: *JSContext, v: JSVal) -> Result<Option<DOMString>, ()> {
if jsval::is_null(v) || jsval::is_undefined(v) { if jsval::is_null(v) || jsval::is_undefined(v) {
Ok(None) Ok(None)
@ -276,20 +262,17 @@ pub fn jsval_to_domstring(cx: *JSContext, v: JSVal) -> Result<Option<DOMString>,
} }
} }
#[fixed_stack_segment]
pub unsafe fn str_to_jsval(cx: *JSContext, string: DOMString) -> JSVal { pub unsafe fn str_to_jsval(cx: *JSContext, string: DOMString) -> JSVal {
do string.to_utf16().as_imm_buf |buf, len| { let string_utf16 = string.to_utf16();
let jsstr = JS_NewUCStringCopyN(cx, buf, len as libc::size_t); let jsstr = JS_NewUCStringCopyN(cx, string_utf16.as_ptr(), string_utf16.len() as libc::size_t);
if jsstr.is_null() { if jsstr.is_null() {
// FIXME: is there something else we should do on failure? // FIXME: is there something else we should do on failure?
JSVAL_NULL JSVAL_NULL
} else { } else {
RUST_STRING_TO_JSVAL(jsstr) RUST_STRING_TO_JSVAL(jsstr)
}
} }
} }
#[fixed_stack_segment]
pub unsafe fn domstring_to_jsval(cx: *JSContext, string: Option<DOMString>) -> JSVal { pub unsafe fn domstring_to_jsval(cx: *JSContext, string: Option<DOMString>) -> JSVal {
match string { match string {
None => JSVAL_NULL, None => JSVAL_NULL,
@ -313,7 +296,7 @@ pub static DOM_PROTOTYPE_SLOT: u32 = js::JSCLASS_GLOBAL_SLOT_COUNT;
// NOTE: This is baked into the Ion JIT as 0 in codegen for LGetDOMProperty and // NOTE: This is baked into the Ion JIT as 0 in codegen for LGetDOMProperty and
// LSetDOMProperty. Those constants need to be changed accordingly if this value // LSetDOMProperty. Those constants need to be changed accordingly if this value
// changes. // changes.
static JSCLASS_DOM_GLOBAL: u32 = js::JSCLASS_USERBIT1; pub static JSCLASS_DOM_GLOBAL: u32 = js::JSCLASS_USERBIT1;
pub struct NativeProperties { pub struct NativeProperties {
staticMethods: *JSFunctionSpec, staticMethods: *JSFunctionSpec,
@ -379,7 +362,6 @@ pub struct DOMJSClass {
dom_class: DOMClass dom_class: DOMClass
} }
#[fixed_stack_segment]
pub fn GetProtoOrIfaceArray(global: *JSObject) -> **JSObject { pub fn GetProtoOrIfaceArray(global: *JSObject) -> **JSObject {
unsafe { unsafe {
/*assert ((*JS_GetClass(global)).flags & JSCLASS_DOM_GLOBAL) != 0;*/ /*assert ((*JS_GetClass(global)).flags & JSCLASS_DOM_GLOBAL) != 0;*/
@ -387,7 +369,6 @@ pub fn GetProtoOrIfaceArray(global: *JSObject) -> **JSObject {
} }
} }
#[fixed_stack_segment]
pub fn CreateInterfaceObjects2(cx: *JSContext, global: *JSObject, receiver: *JSObject, pub fn CreateInterfaceObjects2(cx: *JSContext, global: *JSObject, receiver: *JSObject,
protoProto: *JSObject, protoClass: *JSClass, protoProto: *JSObject, protoClass: *JSClass,
constructorClass: *JSClass, constructor: Option<JSNative>, constructorClass: *JSClass, constructor: Option<JSNative>,
@ -415,11 +396,11 @@ pub fn CreateInterfaceObjects2(cx: *JSContext, global: *JSObject, receiver: *JSO
let mut interface = ptr::null(); let mut interface = ptr::null();
if constructorClass.is_not_null() || constructor.is_some() { if constructorClass.is_not_null() || constructor.is_some() {
interface = do name.to_c_str().with_ref |s| { interface = name.to_c_str().with_ref(|s| {
CreateInterfaceObject(cx, global, receiver, constructorClass, CreateInterfaceObject(cx, global, receiver, constructorClass,
constructor, ctorNargs, proto, constructor, ctorNargs, proto,
staticMethods, constants, s) staticMethods, constants, s)
}; });
if interface.is_null() { if interface.is_null() {
return ptr::null(); return ptr::null();
} }
@ -432,7 +413,6 @@ pub fn CreateInterfaceObjects2(cx: *JSContext, global: *JSObject, receiver: *JSO
} }
} }
#[fixed_stack_segment]
fn CreateInterfaceObject(cx: *JSContext, global: *JSObject, receiver: *JSObject, fn CreateInterfaceObject(cx: *JSContext, global: *JSObject, receiver: *JSObject,
constructorClass: *JSClass, constructorNative: Option<JSNative>, constructorClass: *JSClass, constructorNative: Option<JSNative>,
ctorNargs: u32, proto: *JSObject, ctorNargs: u32, proto: *JSObject,
@ -467,11 +447,11 @@ fn CreateInterfaceObject(cx: *JSContext, global: *JSObject, receiver: *JSObject,
} }
if constructorClass.is_not_null() { if constructorClass.is_not_null() {
let toString = do "toString".to_c_str().with_ref |s| { let toString = "toString".to_c_str().with_ref(|s| {
DefineFunctionWithReserved(cx, constructor, s, DefineFunctionWithReserved(cx, constructor, s,
InterfaceObjectToString, InterfaceObjectToString,
0, 0) 0, 0)
}; });
if toString.is_null() { if toString.is_null() {
return ptr::null(); return ptr::null();
} }
@ -511,7 +491,6 @@ fn CreateInterfaceObject(cx: *JSContext, global: *JSObject, receiver: *JSObject,
} }
} }
#[fixed_stack_segment]
fn DefineConstants(cx: *JSContext, obj: *JSObject, constants: *ConstantSpec) -> bool { fn DefineConstants(cx: *JSContext, obj: *JSObject, constants: *ConstantSpec) -> bool {
let mut i = 0; let mut i = 0;
loop { loop {
@ -541,21 +520,18 @@ fn DefineConstants(cx: *JSContext, obj: *JSObject, constants: *ConstantSpec) ->
} }
} }
#[fixed_stack_segment]
fn DefineMethods(cx: *JSContext, obj: *JSObject, methods: *JSFunctionSpec) -> bool { fn DefineMethods(cx: *JSContext, obj: *JSObject, methods: *JSFunctionSpec) -> bool {
unsafe { unsafe {
JS_DefineFunctions(cx, obj, methods) != 0 JS_DefineFunctions(cx, obj, methods) != 0
} }
} }
#[fixed_stack_segment]
fn DefineProperties(cx: *JSContext, obj: *JSObject, properties: *JSPropertySpec) -> bool { fn DefineProperties(cx: *JSContext, obj: *JSObject, properties: *JSPropertySpec) -> bool {
unsafe { unsafe {
JS_DefineProperties(cx, obj, properties) != 0 JS_DefineProperties(cx, obj, properties) != 0
} }
} }
#[fixed_stack_segment]
fn CreateInterfacePrototypeObject(cx: *JSContext, global: *JSObject, fn CreateInterfacePrototypeObject(cx: *JSContext, global: *JSObject,
parentProto: *JSObject, protoClass: *JSClass, parentProto: *JSObject, protoClass: *JSClass,
methods: *JSFunctionSpec, methods: *JSFunctionSpec,
@ -592,17 +568,16 @@ pub trait Traceable {
fn trace(&self, trc: *mut JSTracer); fn trace(&self, trc: *mut JSTracer);
} }
#[fixed_stack_segment]
pub fn trace_reflector(tracer: *mut JSTracer, description: &str, reflector: &Reflector) { pub fn trace_reflector(tracer: *mut JSTracer, description: &str, reflector: &Reflector) {
unsafe { unsafe {
do description.to_c_str().with_ref |name| { description.to_c_str().with_ref(|name| {
(*tracer).debugPrinter = ptr::null(); (*tracer).debugPrinter = ptr::null();
(*tracer).debugPrintIndex = -1; (*tracer).debugPrintIndex = -1;
(*tracer).debugPrintArg = name as *libc::c_void; (*tracer).debugPrintArg = name as *libc::c_void;
debug!("tracing {:s}", description); debug!("tracing {:s}", description);
JS_CallTracer(tracer as *JSTracer, reflector.get_jsobject(), JS_CallTracer(tracer as *JSTracer, reflector.get_jsobject(),
JSTRACE_OBJECT as u32); JSTRACE_OBJECT as u32);
} });
} }
} }
@ -610,13 +585,12 @@ pub fn trace_option<T: Reflectable>(tracer: *mut JSTracer, description: &str, op
option.map(|some| trace_reflector(tracer, description, some.reflector())); option.map(|some| trace_reflector(tracer, description, some.reflector()));
} }
#[fixed_stack_segment]
pub fn initialize_global(global: *JSObject) { pub fn initialize_global(global: *JSObject) {
let protoArray = @mut ([0 as *JSObject, ..PrototypeList::id::_ID_Count as uint]); let protoArray = @mut ([0 as *JSObject, ..PrototypeList::id::_ID_Count as uint]);
unsafe { unsafe {
//XXXjdm we should be storing the box pointer instead of the inner //XXXjdm we should be storing the box pointer instead of the inner
let box = squirrel_away(protoArray); let box_ = squirrel_away(protoArray);
let inner = ptr::to_unsafe_ptr(&(*box).data); let inner = ptr::to_unsafe_ptr(&(*box_).data);
JS_SetReservedSlot(global, JS_SetReservedSlot(global,
DOM_PROTOTYPE_SLOT, DOM_PROTOTYPE_SLOT,
RUST_PRIVATE_TO_JSVAL(inner as *libc::c_void)); RUST_PRIVATE_TO_JSVAL(inner as *libc::c_void));
@ -668,7 +642,6 @@ impl Reflector {
} }
} }
#[fixed_stack_segment]
pub fn GetReflector(cx: *JSContext, reflector: &Reflector, pub fn GetReflector(cx: *JSContext, reflector: &Reflector,
vp: *mut JSVal) -> JSBool { vp: *mut JSVal) -> JSBool {
let obj = reflector.get_jsobject(); let obj = reflector.get_jsobject();
@ -679,7 +652,6 @@ pub fn GetReflector(cx: *JSContext, reflector: &Reflector,
} }
} }
#[fixed_stack_segment]
pub fn GetPropertyOnPrototype(cx: *JSContext, proxy: *JSObject, id: jsid, found: *mut bool, pub fn GetPropertyOnPrototype(cx: *JSContext, proxy: *JSObject, id: jsid, found: *mut bool,
vp: *JSVal) -> bool { vp: *JSVal) -> bool {
unsafe { unsafe {
@ -703,7 +675,6 @@ pub fn GetPropertyOnPrototype(cx: *JSContext, proxy: *JSObject, id: jsid, found:
} }
} }
#[fixed_stack_segment]
pub fn GetArrayIndexFromId(_cx: *JSContext, id: jsid) -> Option<u32> { pub fn GetArrayIndexFromId(_cx: *JSContext, id: jsid) -> Option<u32> {
unsafe { unsafe {
if RUST_JSID_IS_INT(id) != 0 { if RUST_JSID_IS_INT(id) != 0 {
@ -727,7 +698,6 @@ pub fn GetArrayIndexFromId(_cx: *JSContext, id: jsid) -> Option<u32> {
}*/ }*/
} }
#[fixed_stack_segment]
pub fn XrayResolveProperty(cx: *JSContext, pub fn XrayResolveProperty(cx: *JSContext,
wrapper: *JSObject, wrapper: *JSObject,
id: jsid, id: jsid,
@ -754,7 +724,7 @@ pub fn XrayResolveProperty(cx: *JSContext,
RUST_SET_JITINFO(fun, attr.getter.info); RUST_SET_JITINFO(fun, attr.getter.info);
let funobj = JS_GetFunctionObject(fun); let funobj = JS_GetFunctionObject(fun);
(*desc).getter = Some(funobj as JSPropertyOp); (*desc).getter = Some(cast::transmute(funobj));
(*desc).attrs |= JSPROP_GETTER; (*desc).attrs |= JSPROP_GETTER;
if attr.setter.op.is_some() { if attr.setter.op.is_some() {
let fun = JS_NewFunction(cx, attr.setter.op, 1, 0, global, ptr::null()); let fun = JS_NewFunction(cx, attr.setter.op, 1, 0, global, ptr::null());
@ -764,7 +734,7 @@ pub fn XrayResolveProperty(cx: *JSContext,
RUST_SET_JITINFO(fun, attr.setter.info); RUST_SET_JITINFO(fun, attr.setter.info);
let funobj = JS_GetFunctionObject(fun); let funobj = JS_GetFunctionObject(fun);
(*desc).setter = Some(funobj as JSStrictPropertyOp); (*desc).setter = Some(cast::transmute(funobj));
(*desc).attrs |= JSPROP_SETTER; (*desc).attrs |= JSPROP_SETTER;
} else { } else {
(*desc).setter = None; (*desc).setter = None;
@ -777,7 +747,6 @@ pub fn XrayResolveProperty(cx: *JSContext,
} }
} }
#[fixed_stack_segment]
fn InternJSString(cx: *JSContext, chars: *libc::c_char) -> Option<jsid> { fn InternJSString(cx: *JSContext, chars: *libc::c_char) -> Option<jsid> {
unsafe { unsafe {
let s = JS_InternString(cx, chars); let s = JS_InternString(cx, chars);
@ -824,7 +793,6 @@ pub struct EnumEntry {
length: uint length: uint
} }
#[fixed_stack_segment]
pub fn FindEnumStringIndex(cx: *JSContext, pub fn FindEnumStringIndex(cx: *JSContext,
v: JSVal, v: JSVal,
values: &[EnumEntry]) -> Result<uint, ()> { values: &[EnumEntry]) -> Result<uint, ()> {
@ -865,14 +833,12 @@ pub fn HasPropertyOnPrototype(cx: *JSContext, proxy: *JSObject, id: jsid) -> boo
return !GetPropertyOnPrototype(cx, proxy, id, &mut found, ptr::null()) || found; return !GetPropertyOnPrototype(cx, proxy, id, &mut found, ptr::null()) || found;
} }
#[fixed_stack_segment]
pub fn IsConvertibleToCallbackInterface(cx: *JSContext, obj: *JSObject) -> bool { pub fn IsConvertibleToCallbackInterface(cx: *JSContext, obj: *JSObject) -> bool {
unsafe { unsafe {
JS_ObjectIsDate(cx, obj) == 0 && JS_ObjectIsRegExp(cx, obj) == 0 JS_ObjectIsDate(cx, obj) == 0 && JS_ObjectIsRegExp(cx, obj) == 0
} }
} }
#[fixed_stack_segment]
pub fn CreateDOMGlobal(cx: *JSContext, class: *JSClass) -> *JSObject { pub fn CreateDOMGlobal(cx: *JSContext, class: *JSClass) -> *JSObject {
unsafe { unsafe {
let obj = JS_NewGlobalObject(cx, class, ptr::null()); let obj = JS_NewGlobalObject(cx, class, ptr::null());
@ -886,7 +852,6 @@ pub fn CreateDOMGlobal(cx: *JSContext, class: *JSClass) -> *JSObject {
} }
/// Returns the global object of the realm that the given JS object was created in. /// Returns the global object of the realm that the given JS object was created in.
#[fixed_stack_segment]
fn global_object_for_js_object(obj: *JSObject) -> *Box<window::Window> { fn global_object_for_js_object(obj: *JSObject) -> *Box<window::Window> {
unsafe { unsafe {
let global = GetGlobalForObjectCrossCompartment(obj); let global = GetGlobalForObjectCrossCompartment(obj);
@ -900,7 +865,6 @@ fn global_object_for_js_object(obj: *JSObject) -> *Box<window::Window> {
} }
} }
#[fixed_stack_segment]
fn cx_for_dom_reflector(obj: *JSObject) -> *JSContext { fn cx_for_dom_reflector(obj: *JSObject) -> *JSContext {
unsafe { unsafe {
let win = global_object_for_js_object(obj); let win = global_object_for_js_object(obj);
@ -912,7 +876,6 @@ fn cx_for_dom_reflector(obj: *JSObject) -> *JSContext {
} }
/// Returns the global object of the realm that the given DOM object was created in. /// Returns the global object of the realm that the given DOM object was created in.
#[fixed_stack_segment]
pub fn global_object_for_dom_object<T: Reflectable>(obj: &mut T) -> *Box<window::Window> { pub fn global_object_for_dom_object<T: Reflectable>(obj: &mut T) -> *Box<window::Window> {
global_object_for_js_object(obj.reflector().get_jsobject()) global_object_for_js_object(obj.reflector().get_jsobject())
} }
@ -921,7 +884,6 @@ pub fn cx_for_dom_object<T: Reflectable>(obj: &mut T) -> *JSContext {
cx_for_dom_reflector(obj.reflector().get_jsobject()) cx_for_dom_reflector(obj.reflector().get_jsobject())
} }
#[fixed_stack_segment]
pub fn throw_method_failed_with_details<T>(cx: *JSContext, pub fn throw_method_failed_with_details<T>(cx: *JSContext,
result: Result<T, Error>, result: Result<T, Error>,
interface: &'static str, interface: &'static str,
@ -929,9 +891,9 @@ pub fn throw_method_failed_with_details<T>(cx: *JSContext,
assert!(result.is_err()); assert!(result.is_err());
assert!(unsafe { JS_IsExceptionPending(cx) } == 0); assert!(unsafe { JS_IsExceptionPending(cx) } == 0);
let message = format!("Method failed: {}.{}", interface, member); let message = format!("Method failed: {}.{}", interface, member);
do message.with_c_str |string| { message.with_c_str(|string| {
unsafe { ReportError(cx, string) }; unsafe { ReportError(cx, string) };
} });
return 0; return 0;
} }
@ -979,7 +941,7 @@ pub fn xml_name_type(name: &str) -> XMLName {
} }
} }
let mut iter = name.iter(); let mut iter = name.chars();
let mut non_qname_colons = false; let mut non_qname_colons = false;
let mut seen_colon = false; let mut seen_colon = false;
match iter.next() { match iter.next() {
@ -994,7 +956,7 @@ pub fn xml_name_type(name: &str) -> XMLName {
} }
} }
for c in name.iter() { for c in name.chars() {
if !is_valid_continuation(c) { if !is_valid_continuation(c) {
return InvalidXMLName; return InvalidXMLName;
} }

View file

@ -55,17 +55,12 @@ impl AbstractDocument {
} }
} }
unsafe fn transmute<T, R>(&self, f: &fn(&T) -> R) -> R { unsafe fn transmute<T, R>(&self, f: |&T| -> R) -> R {
let box: *Box<T> = cast::transmute(self.document); let box_: *Box<T> = cast::transmute(self.document);
f(&(*box).data) f(&(*box_).data)
} }
unsafe fn transmute_mut<T, R>(&self, f: &fn(&mut T) -> R) -> R { pub fn with_html<R>(&self, callback: |&HTMLDocument| -> R) -> R {
let box: *mut Box<T> = cast::transmute(self.document);
f(&mut (*box).data)
}
pub fn with_html<R>(&self, callback: &fn(&HTMLDocument) -> R) -> R {
match self.document().doctype { match self.document().doctype {
HTML => unsafe { self.transmute(callback) }, HTML => unsafe { self.transmute(callback) },
_ => fail!("attempt to downcast a non-HTMLDocument to HTMLDocument") _ => fail!("attempt to downcast a non-HTMLDocument to HTMLDocument")
@ -105,9 +100,9 @@ impl Document {
let document = reflect_dom_object(document, window, wrap_fn); let document = reflect_dom_object(document, window, wrap_fn);
assert!(document.reflector().get_jsobject().is_not_null()); assert!(document.reflector().get_jsobject().is_not_null());
// This surrenders memory management of the document! // JS object now owns the Document, so transmute_copy is needed
let abstract = AbstractDocument { let abstract = AbstractDocument {
document: unsafe { cast::transmute(document) } document: unsafe { cast::transmute_copy(&document) }
}; };
abstract.mut_document().node.set_owner_doc(abstract); abstract.mut_document().node.set_owner_doc(abstract);
abstract abstract
@ -165,10 +160,6 @@ impl Document {
self.node.child_elements().next() self.node.child_elements().next()
} }
fn get_cx(&self) -> *JSContext {
self.window.get_cx()
}
pub fn GetElementsByTagName(&self, tag: DOMString) -> @mut HTMLCollection { pub fn GetElementsByTagName(&self, tag: DOMString) -> @mut HTMLCollection {
self.createHTMLCollection(|elem| eq_slice(elem.tag_name, tag)) self.createHTMLCollection(|elem| eq_slice(elem.tag_name, tag))
} }
@ -238,9 +229,9 @@ impl Document {
} }
for child in node.children() { for child in node.children() {
if child.is_text() { if child.is_text() {
do child.with_imm_text() |text| { child.with_imm_text(|text| {
title = title + text.element.Data(); title = title + text.element.Data();
} });
} }
} }
break; break;
@ -249,7 +240,7 @@ impl Document {
} }
} }
} }
let v: ~[&str] = title.word_iter().collect(); let v: ~[&str] = title.words().collect();
title = v.connect(" "); title = v.connect(" ");
title = title.trim().to_owned(); title = title.trim().to_owned();
title title
@ -295,12 +286,12 @@ impl Document {
} }
fn get_html_element(&self) -> Option<AbstractNode> { fn get_html_element(&self) -> Option<AbstractNode> {
do self.GetDocumentElement().filtered |root| { self.GetDocumentElement().filtered(|root| {
match root.type_id() { match root.type_id() {
ElementNodeTypeId(HTMLHtmlElementTypeId) => true, ElementNodeTypeId(HTMLHtmlElementTypeId) => true,
_ => false _ => false
} }
} })
} }
// http://www.whatwg.org/specs/web-apps/current-work/#dom-document-head // http://www.whatwg.org/specs/web-apps/current-work/#dom-document-head
@ -316,13 +307,13 @@ impl Document {
match self.get_html_element() { match self.get_html_element() {
None => None, None => None,
Some(root) => { Some(root) => {
do root.children().find |child| { root.children().find(|child| {
match child.type_id() { match child.type_id() {
ElementNodeTypeId(HTMLBodyElementTypeId) | ElementNodeTypeId(HTMLBodyElementTypeId) |
ElementNodeTypeId(HTMLFrameSetElementTypeId) => true, ElementNodeTypeId(HTMLFrameSetElementTypeId) => true,
_ => false _ => false
} }
} })
} }
} }
} }
@ -365,18 +356,18 @@ impl Document {
elem.get_attr(Null, "name").is_some() && eq_slice(elem.get_attr(Null, "name").unwrap(), name)) elem.get_attr(Null, "name").is_some() && eq_slice(elem.get_attr(Null, "name").unwrap(), name))
} }
pub fn createHTMLCollection(&self, callback: &fn(elem: &Element) -> bool) -> @mut HTMLCollection { pub fn createHTMLCollection(&self, callback: |elem: &Element| -> bool) -> @mut HTMLCollection {
let mut elements = ~[]; let mut elements = ~[];
match self.GetDocumentElement() { match self.GetDocumentElement() {
None => {}, None => {},
Some(root) => { Some(root) => {
for child in root.traverse_preorder() { for child in root.traverse_preorder() {
if child.is_element() { if child.is_element() {
do child.with_imm_element |elem| { child.with_imm_element(|elem| {
if callback(elem) { if callback(elem) {
elements.push(child); elements.push(child);
} }
} });
} }
} }
} }
@ -435,25 +426,24 @@ impl Document {
} }
#[inline(always)] #[inline(always)]
fn foreach_ided_elements(root: &AbstractNode, callback: &fn(&DOMString, &AbstractNode)) { fn foreach_ided_elements(root: &AbstractNode, callback: |&DOMString, &AbstractNode|) {
for node in root.traverse_preorder() { for node in root.traverse_preorder() {
if !node.is_element() { if !node.is_element() {
continue; continue;
} }
do node.with_imm_element |element| { node.with_imm_element(|element| {
match element.get_attr(Null, "id") { match element.get_attr(Null, "id") {
Some(id) => { Some(id) => {
callback(&id.to_str(), &node); callback(&id.to_str(), &node);
} }
None => () None => ()
} }
} });
} }
} }
impl Traceable for Document { impl Traceable for Document {
#[fixed_stack_segment]
fn trace(&self, tracer: *mut JSTracer) { fn trace(&self, tracer: *mut JSTracer) {
self.node.trace(tracer); self.node.trace(tracer);
} }

View file

@ -22,7 +22,6 @@ use layout_interface::{ContentBoxesResponse, ContentChangedDocumentDamage};
use layout_interface::{MatchSelectorsDocumentDamage}; use layout_interface::{MatchSelectorsDocumentDamage};
use style; use style;
use std::comm;
use std::str::eq; use std::str::eq;
use std::ascii::StrAsciiExt; use std::ascii::StrAsciiExt;
@ -123,7 +122,7 @@ pub enum ElementTypeId {
// //
impl<'self> Element { impl Element {
pub fn new_inherited(type_id: ElementTypeId, tag_name: ~str, namespace: Namespace, document: AbstractDocument) -> Element { pub fn new_inherited(type_id: ElementTypeId, tag_name: ~str, namespace: Namespace, document: AbstractDocument) -> Element {
Element { Element {
node: Node::new_inherited(ElementNodeTypeId(type_id), document), node: Node::new_inherited(ElementNodeTypeId(type_id), document),
@ -175,7 +174,7 @@ impl<'self> Element {
//FIXME: Throw for XML-invalid names //FIXME: Throw for XML-invalid names
//FIXME: Throw for XMLNS-invalid names //FIXME: Throw for XMLNS-invalid names
let (prefix, local_name) = if name.contains(":") { let (prefix, local_name) = if name.contains(":") {
let parts: ~[&str] = name.splitn_iter(':', 1).collect(); let parts: ~[&str] = name.splitn(':', 1).collect();
(Some(parts[0].to_owned()), parts[1].to_owned()) (Some(parts[0].to_owned()), parts[1].to_owned())
} else { } else {
(None, name.clone()) (None, name.clone())
@ -238,14 +237,14 @@ impl<'self> Element {
// This hardcoding is awful. // This hardcoding is awful.
match abstract_self.type_id() { match abstract_self.type_id() {
ElementNodeTypeId(HTMLImageElementTypeId) => { ElementNodeTypeId(HTMLImageElementTypeId) => {
do abstract_self.with_mut_image_element |image| { abstract_self.with_mut_image_element(|image| {
image.AfterSetAttr(local_name.clone(), value.clone()); image.AfterSetAttr(local_name.clone(), value.clone());
} });
} }
ElementNodeTypeId(HTMLIframeElementTypeId) => { ElementNodeTypeId(HTMLIframeElementTypeId) => {
do abstract_self.with_mut_iframe_element |iframe| { abstract_self.with_mut_iframe_element(|iframe| {
iframe.AfterSetAttr(local_name.clone(), value.clone()); iframe.AfterSetAttr(local_name.clone(), value.clone());
} });
} }
_ => () _ => ()
} }
@ -390,18 +389,18 @@ impl Element {
let win = self.node.owner_doc().document().window; let win = self.node.owner_doc().document().window;
let node = abstract_self; let node = abstract_self;
assert!(node.is_element()); assert!(node.is_element());
let (port, chan) = comm::stream(); let (port, chan) = Chan::new();
let rects = let rects =
match win.page.query_layout(ContentBoxesQuery(node, chan), port) { match win.page.query_layout(ContentBoxesQuery(node, chan), port) {
ContentBoxesResponse(rects) => { ContentBoxesResponse(rects) => {
do rects.map |r| { rects.map(|r| {
ClientRect::new( ClientRect::new(
win, win,
r.origin.y, r.origin.y,
r.origin.y + r.size.height, r.origin.y + r.size.height,
r.origin.x, r.origin.x,
r.origin.x + r.size.width) r.origin.x + r.size.width)
} })
}, },
}; };
@ -412,7 +411,7 @@ impl Element {
let win = self.node.owner_doc().document().window; let win = self.node.owner_doc().document().window;
let node = abstract_self; let node = abstract_self;
assert!(node.is_element()); assert!(node.is_element());
let (port, chan) = comm::stream(); let (port, chan) = Chan::new();
match win.page.query_layout(ContentBoxQuery(node, chan), port) { match win.page.query_layout(ContentBoxQuery(node, chan), port) {
ContentBoxResponse(rect) => { ContentBoxResponse(rect) => {
ClientRect::new( ClientRect::new(

View file

@ -35,9 +35,9 @@ pub enum EventPhase {
} }
impl AbstractEvent { impl AbstractEvent {
pub fn from_box(box: *mut Box<Event>) -> AbstractEvent { pub fn from_box(box_: *mut Box<Event>) -> AbstractEvent {
AbstractEvent { AbstractEvent {
event: box event: box_
} }
} }
@ -47,15 +47,15 @@ impl AbstractEvent {
fn transmute<'a, T>(&'a self) -> &'a T { fn transmute<'a, T>(&'a self) -> &'a T {
unsafe { unsafe {
let box: *Box<T> = self.event as *Box<T>; let box_: *Box<T> = self.event as *Box<T>;
&(*box).data &(*box_).data
} }
} }
fn transmute_mut<'a, T>(&'a self) -> &'a mut T { fn transmute_mut<'a, T>(&'a self) -> &'a mut T {
unsafe { unsafe {
let box: *mut Box<T> = self.event as *mut Box<T>; let box_: *mut Box<T> = self.event as *mut Box<T>;
&mut (*box).data &mut (*box_).data
} }
} }

View file

@ -44,9 +44,9 @@ pub struct AbstractEventTarget {
} }
impl AbstractEventTarget { impl AbstractEventTarget {
pub fn from_box<T>(box: *mut Box<T>) -> AbstractEventTarget { pub fn from_box<T>(box_: *mut Box<T>) -> AbstractEventTarget {
AbstractEventTarget { AbstractEventTarget {
eventtarget: box as *mut Box<EventTarget> eventtarget: box_ as *mut Box<EventTarget>
} }
} }
@ -86,15 +86,15 @@ impl AbstractEventTarget {
fn transmute<'a, T>(&'a self) -> &'a T { fn transmute<'a, T>(&'a self) -> &'a T {
unsafe { unsafe {
let box: *Box<T> = self.eventtarget as *Box<T>; let box_: *Box<T> = self.eventtarget as *Box<T>;
&(*box).data &(*box_).data
} }
} }
fn transmute_mut<'a, T>(&'a mut self) -> &'a mut T { fn transmute_mut<'a, T>(&'a mut self) -> &'a mut T {
unsafe { unsafe {
let box: *mut Box<T> = self.eventtarget as *mut Box<T>; let box_: *mut Box<T> = self.eventtarget as *mut Box<T>;
&mut (*box).data &mut (*box_).data
} }
} }
@ -127,17 +127,17 @@ impl EventTarget {
} }
pub fn get_listeners(&self, type_: &str) -> Option<~[EventListener]> { pub fn get_listeners(&self, type_: &str) -> Option<~[EventListener]> {
do self.handlers.find_equiv(&type_).map |listeners| { self.handlers.find_equiv(&type_).map(|listeners| {
listeners.iter().map(|entry| entry.listener).collect() listeners.iter().map(|entry| entry.listener).collect()
} })
} }
pub fn get_listeners_for(&self, type_: &str, desired_phase: ListenerPhase) pub fn get_listeners_for(&self, type_: &str, desired_phase: ListenerPhase)
-> Option<~[EventListener]> { -> Option<~[EventListener]> {
do self.handlers.find_equiv(&type_).map |listeners| { self.handlers.find_equiv(&type_).map(|listeners| {
let filtered = listeners.iter().filter(|entry| entry.phase == desired_phase); let filtered = listeners.iter().filter(|entry| entry.phase == desired_phase);
filtered.map(|entry| entry.listener).collect() filtered.map(|entry| entry.listener).collect()
} })
} }
pub fn AddEventListener(&mut self, pub fn AddEventListener(&mut self,

View file

@ -95,7 +95,7 @@ impl HTMLIFrameElement {
pub fn AfterSetAttr(&mut self, name: DOMString, value: DOMString) { pub fn AfterSetAttr(&mut self, name: DOMString, value: DOMString) {
if "sandbox" == name { if "sandbox" == name {
let mut modes = AllowNothing as u8; let mut modes = AllowNothing as u8;
for word in value.split_iter(' ') { for word in value.split(' ') {
// FIXME: Workaround for https://github.com/mozilla/rust/issues/10683 // FIXME: Workaround for https://github.com/mozilla/rust/issues/10683
let word_lower = word.to_ascii_lower(); let word_lower = word.to_ascii_lower();
modes |= match word_lower.as_slice() { modes |= match word_lower.as_slice() {

View file

@ -112,7 +112,7 @@ impl HTMLImageElement {
pub fn Width(&self, abstract_self: AbstractNode) -> u32 { pub fn Width(&self, abstract_self: AbstractNode) -> u32 {
let node = &self.htmlelement.element.node; let node = &self.htmlelement.element.node;
let page = node.owner_doc().document().window.page; let page = node.owner_doc().document().window.page;
let (port, chan) = stream(); let (port, chan) = Chan::new();
match page.query_layout(ContentBoxQuery(abstract_self, chan), port) { match page.query_layout(ContentBoxQuery(abstract_self, chan), port) {
ContentBoxResponse(rect) => { ContentBoxResponse(rect) => {
to_px(rect.size.width) as u32 to_px(rect.size.width) as u32
@ -129,7 +129,7 @@ impl HTMLImageElement {
pub fn Height(&self, abstract_self: AbstractNode) -> u32 { pub fn Height(&self, abstract_self: AbstractNode) -> u32 {
let node = &self.htmlelement.element.node; let node = &self.htmlelement.element.node;
let page = node.owner_doc().document().window.page; let page = node.owner_doc().document().window.page;
let (port, chan) = stream(); let (port, chan) = Chan::new();
match page.query_layout(ContentBoxQuery(abstract_self, chan), port) { match page.query_layout(ContentBoxQuery(abstract_self, chan), port) {
ContentBoxResponse(rect) => { ContentBoxResponse(rect) => {
to_px(rect.size.height) as u32 to_px(rect.size.height) as u32

View file

@ -7,7 +7,6 @@
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object}; use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::bindings::utils::{DOMString, null_str_as_empty}; use dom::bindings::utils::{DOMString, null_str_as_empty};
use dom::bindings::utils::{ErrorResult, Fallible, NotFound, HierarchyRequest}; use dom::bindings::utils::{ErrorResult, Fallible, NotFound, HierarchyRequest};
use dom::bindings::utils;
use dom::characterdata::CharacterData; use dom::characterdata::CharacterData;
use dom::document::{AbstractDocument, DocumentTypeId}; use dom::document::{AbstractDocument, DocumentTypeId};
use dom::documenttype::DocumentType; use dom::documenttype::DocumentType;
@ -20,12 +19,15 @@ use dom::nodelist::{NodeList};
use dom::text::Text; use dom::text::Text;
use js::jsapi::{JSObject, JSContext}; use js::jsapi::{JSObject, JSContext};
use servo_util::slot::{MutSlotRef, Slot, SlotRef};
use std::cast::transmute; use layout_interface::{LayoutChan, ReapLayoutDataMsg};
use std::cast; use std::cast;
use std::unstable::raw::Box; use std::cast::transmute;
use std::util; use std::cell::{RefCell, Ref, RefMut};
use std::iter::Filter; use std::iter::Filter;
use std::util;
use std::unstable::raw::Box;
// //
// The basic Node structure // The basic Node structure
@ -37,7 +39,7 @@ use std::iter::Filter;
/// FIXME: This should be replaced with a trait once they can inherit from structs. /// FIXME: This should be replaced with a trait once they can inherit from structs.
#[deriving(Eq)] #[deriving(Eq)]
pub struct AbstractNode { pub struct AbstractNode {
priv obj: *mut Box<Node>, priv obj: *mut (),
} }
/// An HTML node. /// An HTML node.
@ -109,30 +111,43 @@ impl Drop for Node {
} }
/// Encapsulates the abstract layout data. /// Encapsulates the abstract layout data.
pub struct LayoutData {
priv chan: Option<LayoutChan>,
priv data: *(),
}
pub struct LayoutDataRef { pub struct LayoutDataRef {
priv data: Slot<Option<*()>>, data_cell: RefCell<Option<LayoutData>>,
} }
impl LayoutDataRef { impl LayoutDataRef {
#[inline] pub fn new() -> LayoutDataRef {
pub fn init() -> LayoutDataRef {
LayoutDataRef { LayoutDataRef {
data: Slot::init(None), data_cell: RefCell::new(None),
} }
} }
/// Creates a new piece of layout data from a value.
#[inline]
pub unsafe fn from_data<T>(data: ~T) -> LayoutDataRef { pub unsafe fn from_data<T>(data: ~T) -> LayoutDataRef {
LayoutDataRef { LayoutDataRef {
data: Slot::init(Some(cast::transmute(data))), data_cell: RefCell::new(Some(cast::transmute(data))),
} }
} }
/// Returns true if this layout data is present or false otherwise. /// Returns true if there is layout data present.
#[inline] #[inline]
pub fn is_present(&self) -> bool { pub fn is_present(&self) -> bool {
self.data.get().is_some() let data_ref = self.data_cell.borrow();
data_ref.get().is_some()
}
/// Take the chan out of the layout data if it is present.
pub fn take_chan(&self) -> Option<LayoutChan> {
let mut data_ref = self.data_cell.borrow_mut();
let layout_data = data_ref.get();
match *layout_data {
None => None,
Some(..) => Some(layout_data.get_mut_ref().chan.take_unwrap()),
}
} }
/// Borrows the layout data immutably, *asserting that there are no mutators*. Bad things will /// Borrows the layout data immutably, *asserting that there are no mutators*. Bad things will
@ -141,17 +156,15 @@ impl LayoutDataRef {
/// ///
/// FIXME(pcwalton): Enforce this invariant via the type system. Will require traversal /// FIXME(pcwalton): Enforce this invariant via the type system. Will require traversal
/// functions to be trusted, but c'est la vie. /// functions to be trusted, but c'est la vie.
#[inline] // #[inline]
pub unsafe fn borrow_unchecked<'a>(&'a self) -> &'a () { // pub unsafe fn borrow_unchecked<'a>(&'a self) -> &'a () {
cast::transmute(self.data.borrow_unchecked()) // self.data.borrow_unchecked()
} // }
/// Borrows the layout data immutably. This function is *not* thread-safe. /// Borrows the layout data immutably. This function is *not* thread-safe.
#[inline] #[inline]
pub fn borrow<'a>(&'a self) -> SlotRef<'a,()> { pub fn borrow<'a>(&'a self) -> Ref<'a,Option<LayoutData>> {
unsafe { self.data_cell.borrow()
cast::transmute(self.data.borrow())
}
} }
/// Borrows the layout data mutably. This function is *not* thread-safe. /// Borrows the layout data mutably. This function is *not* thread-safe.
@ -160,10 +173,8 @@ impl LayoutDataRef {
/// prevent CSS selector matching from mutably accessing nodes it's not supposed to and racing /// prevent CSS selector matching from mutably accessing nodes it's not supposed to and racing
/// on it. This has already resulted in one bug! /// on it. This has already resulted in one bug!
#[inline] #[inline]
pub fn mutate<'a>(&'a self) -> MutSlotRef<'a,()> { pub fn borrow_mut<'a>(&'a self) -> RefMut<'a,Option<LayoutData>> {
unsafe { self.data_cell.borrow_mut()
cast::transmute(self.data.mutate())
}
} }
} }
@ -193,13 +204,15 @@ impl Clone for AbstractNode {
impl AbstractNode { impl AbstractNode {
pub fn node<'a>(&'a self) -> &'a Node { pub fn node<'a>(&'a self) -> &'a Node {
unsafe { unsafe {
&(*self.obj).data let box_: *mut Box<Node> = cast::transmute(self.obj);
&(*box_).data
} }
} }
pub fn mut_node<'a>(&'a self) -> &'a mut Node { pub fn mut_node<'a>(&'a self) -> &'a mut Node {
unsafe { unsafe {
&mut (*self.obj).data let box_: *mut Box<Node> = cast::transmute(self.obj);
&mut (*box_).data
} }
} }
@ -217,20 +230,20 @@ impl AbstractNode {
pub fn is_element(&self) -> bool { pub fn is_element(&self) -> bool {
match self.type_id() { match self.type_id() {
ElementNodeTypeId(*) => true, ElementNodeTypeId(..) => true,
_ => false _ => false
} }
} }
pub fn is_document(&self) -> bool { pub fn is_document(&self) -> bool {
match self.type_id() { match self.type_id() {
DocumentNodeTypeId(*) => true, DocumentNodeTypeId(..) => true,
_ => false _ => false
} }
} }
} }
impl<'self> AbstractNode { impl<'a> AbstractNode {
// Unsafe accessors // Unsafe accessors
pub unsafe fn as_cacheable_wrapper(&self) -> @mut Reflectable { pub unsafe fn as_cacheable_wrapper(&self) -> @mut Reflectable {
@ -252,7 +265,7 @@ impl<'self> AbstractNode {
/// FIXME(pcwalton): Mark unsafe? /// FIXME(pcwalton): Mark unsafe?
pub fn from_box<T>(ptr: *mut Box<T>) -> AbstractNode { pub fn from_box<T>(ptr: *mut Box<T>) -> AbstractNode {
AbstractNode { AbstractNode {
obj: ptr as *mut Box<Node> obj: ptr as *mut ()
} }
} }
@ -291,27 +304,27 @@ impl<'self> AbstractNode {
// Downcasting borrows // Downcasting borrows
// //
pub fn transmute<T, R>(self, f: &fn(&T) -> R) -> R { pub fn transmute<'a, T, R>(self, f: |&'a T| -> R) -> R {
unsafe { unsafe {
let node_box: *mut Box<Node> = transmute(self.obj); let node_box: *mut Box<Node> = transmute(self.obj);
let node = &mut (*node_box).data; let node = &mut (*node_box).data;
let old = node.abstract; let old = node.abstract;
node.abstract = Some(self); node.abstract = Some(self);
let box: *Box<T> = transmute(self.obj); let box_: *Box<T> = transmute(self.obj);
let rv = f(&(*box).data); let rv = f(&(*box_).data);
node.abstract = old; node.abstract = old;
rv rv
} }
} }
pub fn transmute_mut<T, R>(self, f: &fn(&mut T) -> R) -> R { pub fn transmute_mut<T, R>(self, f: |&mut T| -> R) -> R {
unsafe { unsafe {
let node_box: *mut Box<Node> = transmute(self.obj); let node_box: *mut Box<Node> = transmute(self.obj);
let node = &mut (*node_box).data; let node = &mut (*node_box).data;
let old = node.abstract; let old = node.abstract;
node.abstract = Some(self); node.abstract = Some(self);
let box: *Box<T> = transmute(self.obj); let box_: *Box<T> = transmute(self.obj);
let rv = f(cast::transmute(&(*box).data)); let rv = f(cast::transmute(&(*box_).data));
node.abstract = old; node.abstract = old;
rv rv
} }
@ -323,14 +336,14 @@ impl<'self> AbstractNode {
self.is_text() || self.is_comment() self.is_text() || self.is_comment()
} }
pub fn with_imm_characterdata<R>(self, f: &fn(&CharacterData) -> R) -> R { pub fn with_imm_characterdata<R>(self, f: |&CharacterData| -> R) -> R {
if !self.is_characterdata() { if !self.is_characterdata() {
fail!(~"node is not characterdata"); fail!(~"node is not characterdata");
} }
self.transmute(f) self.transmute(f)
} }
pub fn with_mut_characterdata<R>(self, f: &fn(&mut CharacterData) -> R) -> R { pub fn with_mut_characterdata<R>(self, f: |&mut CharacterData| -> R) -> R {
if !self.is_characterdata() { if !self.is_characterdata() {
fail!(~"node is not characterdata"); fail!(~"node is not characterdata");
} }
@ -341,14 +354,14 @@ impl<'self> AbstractNode {
self.type_id() == DoctypeNodeTypeId self.type_id() == DoctypeNodeTypeId
} }
pub fn with_imm_doctype<R>(self, f: &fn(&DocumentType) -> R) -> R { pub fn with_imm_doctype<R>(self, f: |&DocumentType| -> R) -> R {
if !self.is_doctype() { if !self.is_doctype() {
fail!(~"node is not doctype"); fail!(~"node is not doctype");
} }
self.transmute(f) self.transmute(f)
} }
pub fn with_mut_doctype<R>(self, f: &fn(&mut DocumentType) -> R) -> R { pub fn with_mut_doctype<R>(self, f: |&mut DocumentType| -> R) -> R {
if !self.is_doctype() { if !self.is_doctype() {
fail!(~"node is not doctype"); fail!(~"node is not doctype");
} }
@ -375,14 +388,14 @@ impl<'self> AbstractNode {
} }
} }
pub fn with_imm_text<R>(self, f: &fn(&Text) -> R) -> R { pub fn with_imm_text<R>(self, f: |&Text| -> R) -> R {
if !self.is_text() { if !self.is_text() {
fail!(~"node is not text"); fail!(~"node is not text");
} }
self.transmute(f) self.transmute(f)
} }
pub fn with_mut_text<R>(self, f: &fn(&mut Text) -> R) -> R { pub fn with_mut_text<R>(self, f: |&mut Text| -> R) -> R {
if !self.is_text() { if !self.is_text() {
fail!(~"node is not text"); fail!(~"node is not text");
} }
@ -390,7 +403,7 @@ impl<'self> AbstractNode {
} }
// FIXME: This should be doing dynamic borrow checking for safety. // FIXME: This should be doing dynamic borrow checking for safety.
pub fn with_imm_element<R>(self, f: &fn(&Element) -> R) -> R { pub fn with_imm_element<R>(self, f: |&Element| -> R) -> R {
if !self.is_element() { if !self.is_element() {
fail!(~"node is not an element"); fail!(~"node is not an element");
} }
@ -398,7 +411,7 @@ impl<'self> AbstractNode {
} }
// FIXME: This should be doing dynamic borrow checking for safety. // FIXME: This should be doing dynamic borrow checking for safety.
pub fn as_mut_element<R>(self, f: &fn(&mut Element) -> R) -> R { pub fn as_mut_element<R>(self, f: |&mut Element| -> R) -> R {
if !self.is_element() { if !self.is_element() {
fail!(~"node is not an element"); fail!(~"node is not an element");
} }
@ -413,7 +426,7 @@ impl<'self> AbstractNode {
} }
} }
pub fn with_mut_image_element<R>(self, f: &fn(&mut HTMLImageElement) -> R) -> R { pub fn with_mut_image_element<R>(self, f: |&mut HTMLImageElement| -> R) -> R {
if !self.is_image_element() { if !self.is_image_element() {
fail!(~"node is not an image element"); fail!(~"node is not an image element");
} }
@ -424,7 +437,7 @@ impl<'self> AbstractNode {
self.type_id() == ElementNodeTypeId(HTMLIframeElementTypeId) self.type_id() == ElementNodeTypeId(HTMLIframeElementTypeId)
} }
pub fn with_mut_iframe_element<R>(self, f: &fn(&mut HTMLIFrameElement) -> R) -> R { pub fn with_mut_iframe_element<R>(self, f: |&mut HTMLIFrameElement| -> R) -> R {
if !self.is_iframe_element() { if !self.is_iframe_element() {
fail!(~"node is not an iframe element"); fail!(~"node is not an iframe element");
} }
@ -440,12 +453,12 @@ impl<'self> AbstractNode {
} }
pub unsafe fn raw_object(self) -> *mut Box<Node> { pub unsafe fn raw_object(self) -> *mut Box<Node> {
self.obj cast::transmute(self.obj)
} }
pub fn from_raw(raw: *mut Box<Node>) -> AbstractNode { pub fn from_raw(raw: *mut Box<Node>) -> AbstractNode {
AbstractNode { AbstractNode {
obj: raw obj: raw as *mut ()
} }
} }
@ -479,10 +492,6 @@ impl<'self> AbstractNode {
// Convenience accessors // Convenience accessors
// //
fn is_leaf(&self) -> bool {
self.first_child().is_none()
}
pub fn children(&self) -> AbstractNodeChildrenIterator { pub fn children(&self) -> AbstractNodeChildrenIterator {
self.node().children() self.node().children()
} }
@ -610,35 +619,6 @@ impl AbstractNode {
child_node.set_next_sibling(None); child_node.set_next_sibling(None);
child_node.set_parent_node(None); child_node.set_parent_node(None);
} }
//
// Low-level pointer stitching wrappers
//
fn set_parent_node(&self, new_parent_node: Option<AbstractNode>) {
let node = self.mut_node();
node.set_parent_node(new_parent_node)
}
fn set_first_child(&self, new_first_child: Option<AbstractNode>) {
let node = self.mut_node();
node.set_first_child(new_first_child)
}
fn set_last_child(&self, new_last_child: Option<AbstractNode>) {
let node = self.mut_node();
node.set_last_child(new_last_child)
}
fn set_prev_sibling(&self, new_prev_sibling: Option<AbstractNode>) {
let node = self.mut_node();
node.set_prev_sibling(new_prev_sibling)
}
fn set_next_sibling(&self, new_next_sibling: Option<AbstractNode>) {
let node = self.mut_node();
node.set_next_sibling(new_next_sibling)
}
} }
// //
@ -652,9 +632,9 @@ pub struct AbstractNodeChildrenIterator {
impl Iterator<AbstractNode> for AbstractNodeChildrenIterator { impl Iterator<AbstractNode> for AbstractNodeChildrenIterator {
fn next(&mut self) -> Option<AbstractNode> { fn next(&mut self) -> Option<AbstractNode> {
let node = self.current_node; let node = self.current_node;
self.current_node = do self.current_node.and_then |node| { self.current_node = self.current_node.and_then(|node| {
node.next_sibling() node.next_sibling()
}; });
node node
} }
} }
@ -766,9 +746,9 @@ impl Node {
assert!(node.reflector().get_jsobject().is_null()); assert!(node.reflector().get_jsobject().is_null());
let node = reflect_dom_object(node, document.document().window, wrap_fn); let node = reflect_dom_object(node, document.document().window, wrap_fn);
assert!(node.reflector().get_jsobject().is_not_null()); assert!(node.reflector().get_jsobject().is_not_null());
// This surrenders memory management of the node! // JS owns the node now, so transmute_copy to not increase the refcount
AbstractNode { AbstractNode {
obj: unsafe { transmute(node) }, obj: unsafe { cast::transmute_copy(&node) },
} }
} }
@ -798,16 +778,19 @@ impl Node {
flags: NodeFlags::new(type_id), flags: NodeFlags::new(type_id),
layout_data: LayoutDataRef::init(), layout_data: LayoutDataRef::new(),
} }
} }
/// Sends layout data, if any, back to the script task to be destroyed. /// Sends layout data, if any, back to the script task to be destroyed.
pub unsafe fn reap_layout_data(&mut self) { pub unsafe fn reap_layout_data(&mut self) {
if self.layout_data.is_present() { if self.layout_data.is_present() {
let layout_data = util::replace(&mut self.layout_data, LayoutDataRef::init()); let layout_data = util::replace(&mut self.layout_data, LayoutDataRef::new());
let js_window = utils::global_object_for_dom_object(self); let layout_chan = layout_data.take_chan();
(*js_window).data.page.reap_dead_layout_data(layout_data) match layout_chan {
None => {}
Some(chan) => chan.send(ReapLayoutDataMsg(layout_data)),
}
} }
} }
@ -825,17 +808,17 @@ impl Node {
pub fn NodeName(&self, abstract_self: AbstractNode) -> DOMString { pub fn NodeName(&self, abstract_self: AbstractNode) -> DOMString {
match self.type_id { match self.type_id {
ElementNodeTypeId(*) => { ElementNodeTypeId(..) => {
do abstract_self.with_imm_element |element| { abstract_self.with_imm_element(|element| {
element.TagName() element.TagName()
} })
} }
CommentNodeTypeId => ~"#comment", CommentNodeTypeId => ~"#comment",
TextNodeTypeId => ~"#text", TextNodeTypeId => ~"#text",
DoctypeNodeTypeId => { DoctypeNodeTypeId => {
do abstract_self.with_imm_doctype |doctype| { abstract_self.with_imm_doctype(|doctype| {
doctype.name.clone() doctype.name.clone()
} })
}, },
DocumentFragmentNodeTypeId => ~"#document-fragment", DocumentFragmentNodeTypeId => ~"#document-fragment",
DocumentNodeTypeId(_) => ~"#document" DocumentNodeTypeId(_) => ~"#document"
@ -848,7 +831,7 @@ impl Node {
pub fn GetOwnerDocument(&self) -> Option<AbstractDocument> { pub fn GetOwnerDocument(&self) -> Option<AbstractDocument> {
match self.type_id { match self.type_id {
ElementNodeTypeId(*) | ElementNodeTypeId(..) |
CommentNodeTypeId | CommentNodeTypeId |
TextNodeTypeId | TextNodeTypeId |
DoctypeNodeTypeId | DoctypeNodeTypeId |
@ -889,9 +872,9 @@ impl Node {
match self.type_id { match self.type_id {
// ProcessingInstruction // ProcessingInstruction
CommentNodeTypeId | TextNodeTypeId => { CommentNodeTypeId | TextNodeTypeId => {
do abstract_self.with_imm_characterdata() |characterdata| { abstract_self.with_imm_characterdata(|characterdata| {
Some(characterdata.Data()) Some(characterdata.Data())
} })
} }
_ => { _ => {
None None
@ -906,21 +889,21 @@ impl Node {
pub fn GetTextContent(&self, abstract_self: AbstractNode) -> Option<DOMString> { pub fn GetTextContent(&self, abstract_self: AbstractNode) -> Option<DOMString> {
match self.type_id { match self.type_id {
DocumentFragmentNodeTypeId | ElementNodeTypeId(*) => { DocumentFragmentNodeTypeId | ElementNodeTypeId(..) => {
let mut content = ~""; let mut content = ~"";
for node in abstract_self.traverse_preorder() { for node in abstract_self.traverse_preorder() {
if node.is_text() { if node.is_text() {
do node.with_imm_text() |text| { node.with_imm_text(|text| {
content = content + text.element.Data(); content = content + text.element.Data();
} })
} }
} }
Some(content) Some(content)
} }
CommentNodeTypeId | TextNodeTypeId => { CommentNodeTypeId | TextNodeTypeId => {
do abstract_self.with_imm_characterdata() |characterdata| { abstract_self.with_imm_characterdata(|characterdata| {
Some(characterdata.Data()) Some(characterdata.Data())
} })
} }
DoctypeNodeTypeId | DocumentNodeTypeId(_) => { DoctypeNodeTypeId | DocumentNodeTypeId(_) => {
None None
@ -968,9 +951,9 @@ impl Node {
// Step 1. // Step 1.
match parent.type_id() { match parent.type_id() {
DocumentNodeTypeId(*) | DocumentNodeTypeId(..) |
DocumentFragmentNodeTypeId | DocumentFragmentNodeTypeId |
ElementNodeTypeId(*) => (), ElementNodeTypeId(..) => (),
_ => { _ => {
return Err(HierarchyRequest); return Err(HierarchyRequest);
}, },
@ -999,7 +982,7 @@ impl Node {
TextNodeTypeId | TextNodeTypeId |
// ProcessingInstructionNodeTypeId | // ProcessingInstructionNodeTypeId |
CommentNodeTypeId => (), CommentNodeTypeId => (),
DocumentNodeTypeId(*) => return Err(HierarchyRequest), DocumentNodeTypeId(..) => return Err(HierarchyRequest),
} }
// Step 5. // Step 5.
@ -1241,7 +1224,7 @@ impl Node {
-> ErrorResult { -> ErrorResult {
let value = null_str_as_empty(&value); let value = null_str_as_empty(&value);
match self.type_id { match self.type_id {
DocumentFragmentNodeTypeId | ElementNodeTypeId(*) => { DocumentFragmentNodeTypeId | ElementNodeTypeId(..) => {
// Step 1-2. // Step 1-2.
let node = if value.len() == 0 { let node = if value.len() == 0 {
None None
@ -1255,13 +1238,13 @@ impl Node {
CommentNodeTypeId | TextNodeTypeId => { CommentNodeTypeId | TextNodeTypeId => {
self.wait_until_safe_to_modify_dom(); self.wait_until_safe_to_modify_dom();
do abstract_self.with_mut_characterdata() |characterdata| { abstract_self.with_mut_characterdata(|characterdata| {
characterdata.data = value.clone(); characterdata.data = value.clone();
// Notify the document that the content of this node is different // Notify the document that the content of this node is different
let document = self.owner_doc(); let document = self.owner_doc();
document.document().content_changed(); document.document().content_changed();
} })
} }
DoctypeNodeTypeId | DocumentNodeTypeId(_) => {} DoctypeNodeTypeId | DocumentNodeTypeId(_) => {}
} }

View file

@ -18,19 +18,17 @@ use servo_msg::compositor_msg::ScriptListener;
use servo_net::image_cache_task::ImageCacheTask; use servo_net::image_cache_task::ImageCacheTask;
use js::glue::*; use js::glue::*;
use js::jsapi::{JSObject, JSContext, JS_DefineProperty}; use js::jsapi::{JSObject, JSContext, JS_DefineProperty, JSTracer, JSVal};
use js::jsapi::{JSPropertyOp, JSStrictPropertyOp, JSTracer};
use js::{JSVAL_NULL, JSPROP_ENUMERATE}; use js::{JSVAL_NULL, JSPROP_ENUMERATE};
use std::cell::Cell; use std::cast;
use std::comm;
use std::comm::SharedChan; use std::comm::SharedChan;
use std::comm::Select;
use std::hashmap::HashSet; use std::hashmap::HashSet;
use std::io::timer::Timer;
use std::num;
use std::ptr; use std::ptr;
use std::int; use std::to_bytes::Cb;
use std::rt::io::timer::Timer;
use std::task::spawn_with;
use js::jsapi::JSVal;
pub enum TimerControlMsg { pub enum TimerControlMsg {
TimerMessage_Fire(~TimerData), TimerMessage_Fire(~TimerData),
@ -38,6 +36,29 @@ pub enum TimerControlMsg {
TimerMessage_TriggerExit //XXXjdm this is just a quick hack to talk to the script task TimerMessage_TriggerExit //XXXjdm this is just a quick hack to talk to the script task
} }
pub struct TimerHandle {
handle: i32,
cancel_chan: Option<Chan<()>>,
}
impl IterBytes for TimerHandle {
fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool {
self.handle.iter_bytes(lsb0, f)
}
}
impl Eq for TimerHandle {
fn eq(&self, other: &TimerHandle) -> bool {
self.handle == other.handle
}
}
impl TimerHandle {
fn cancel(&self) {
self.cancel_chan.as_ref().map(|chan| chan.send(()));
}
}
pub struct Window { pub struct Window {
eventtarget: EventTarget, eventtarget: EventTarget,
page: @mut Page, page: @mut Page,
@ -47,7 +68,7 @@ pub struct Window {
location: Option<@mut Location>, location: Option<@mut Location>,
navigator: Option<@mut Navigator>, navigator: Option<@mut Navigator>,
image_cache_task: ImageCacheTask, image_cache_task: ImageCacheTask,
active_timers: ~HashSet<i32>, active_timers: ~HashSet<TimerHandle>,
next_timer_handle: i32, next_timer_handle: i32,
} }
@ -61,6 +82,9 @@ impl Window {
impl Drop for Window { impl Drop for Window {
fn drop(&mut self) { fn drop(&mut self) {
self.timer_chan.send(TimerMessage_Close); self.timer_chan.send(TimerMessage_Close);
for handle in self.active_timers.iter() {
handle.cancel();
}
} }
} }
@ -160,29 +184,40 @@ impl Reflectable for Window {
impl Window { impl Window {
pub fn SetTimeout(&mut self, _cx: *JSContext, callback: JSVal, timeout: i32) -> i32 { pub fn SetTimeout(&mut self, _cx: *JSContext, callback: JSVal, timeout: i32) -> i32 {
let timeout = int::max(0, timeout) as u64; let timeout = num::max(0, timeout) as u64;
let handle = self.next_timer_handle; let handle = self.next_timer_handle;
self.next_timer_handle += 1; self.next_timer_handle += 1;
// Post a delayed message to the per-window timer task; it will dispatch it // Post a delayed message to the per-window timer task; it will dispatch it
// to the relevant script handler that will deal with it. // to the relevant script handler that will deal with it.
let tm = Cell::new(Timer::new().unwrap()); let tm = Timer::new().unwrap();
let (cancel_port, cancel_chan) = Chan::new();
let chan = self.timer_chan.clone(); let chan = self.timer_chan.clone();
do spawn { spawn(proc() {
let mut tm = tm.take(); let mut tm = tm;
tm.sleep(timeout); let mut timeout_port = tm.oneshot(timeout);
chan.send(TimerMessage_Fire(~TimerData { let mut cancel_port = cancel_port;
handle: handle,
funval: callback, let select = Select::new();
args: ~[] let timeout_handle = select.add(&mut timeout_port);
})); let _cancel_handle = select.add(&mut cancel_port);
} let id = select.wait();
self.active_timers.insert(handle); if id == timeout_handle.id {
chan.send(TimerMessage_Fire(~TimerData {
handle: handle,
funval: callback,
args: ~[],
}));
}
});
self.active_timers.insert(TimerHandle { handle: handle, cancel_chan: Some(cancel_chan) });
handle handle
} }
pub fn ClearTimeout(&mut self, handle: i32) { pub fn ClearTimeout(&mut self, handle: i32) {
self.active_timers.remove(&handle); // FIXME(#1477): active_timers should be a HashMap and this should
// cancel the removed timer.
self.active_timers.remove(&TimerHandle { handle: handle, cancel_chan: None });
} }
pub fn damage_and_reflow(&self, damage: DocumentDamageLevel) { pub fn damage_and_reflow(&self, damage: DocumentDamageLevel) {
@ -199,7 +234,6 @@ impl Window {
self.page.join_layout(); self.page.join_layout();
} }
#[fixed_stack_segment]
pub fn new(cx: *JSContext, pub fn new(cx: *JSContext,
page: @mut Page, page: @mut Page,
script_chan: ScriptChan, script_chan: ScriptChan,
@ -212,9 +246,9 @@ impl Window {
script_chan: script_chan.clone(), script_chan: script_chan.clone(),
compositor: compositor, compositor: compositor,
timer_chan: { timer_chan: {
let (timer_port, timer_chan) = comm::stream::<TimerControlMsg>(); let (timer_port, timer_chan): (Port<TimerControlMsg>, SharedChan<TimerControlMsg>) = SharedChan::new();
let id = page.id.clone(); let id = page.id.clone();
do spawn_with(script_chan) |script_chan| { spawn(proc() {
loop { loop {
match timer_port.recv() { match timer_port.recv() {
TimerMessage_Close => break, TimerMessage_Close => break,
@ -222,8 +256,8 @@ impl Window {
TimerMessage_TriggerExit => script_chan.send(ExitWindowMsg(id)), TimerMessage_TriggerExit => script_chan.send(ExitWindowMsg(id)),
} }
} }
} });
SharedChan::new(timer_chan) timer_chan
}, },
location: None, location: None,
navigator: None, navigator: None,
@ -236,13 +270,13 @@ impl Window {
unsafe { unsafe {
let fn_names = ["window","self"]; let fn_names = ["window","self"];
for str in fn_names.iter() { for str in fn_names.iter() {
do (*str).to_c_str().with_ref |name| { (*str).to_c_str().with_ref(|name| {
JS_DefineProperty(cx, global, name, JS_DefineProperty(cx, global, name,
RUST_OBJECT_TO_JSVAL(global), RUST_OBJECT_TO_JSVAL(global),
Some(GetJSClassHookStubPointer(PROPERTY_STUB) as JSPropertyOp), Some(cast::transmute(GetJSClassHookStubPointer(PROPERTY_STUB))),
Some(GetJSClassHookStubPointer(STRICT_PROPERTY_STUB) as JSStrictPropertyOp), Some(cast::transmute(GetJSClassHookStubPointer(STRICT_PROPERTY_STUB))),
JSPROP_ENUMERATE); JSPROP_ENUMERATE);
} })
} }

View file

@ -4,10 +4,7 @@
/// Some little helpers for hooking up the HTML parser with the CSS parser. /// Some little helpers for hooking up the HTML parser with the CSS parser.
use std::cell::Cell;
use std::comm;
use std::comm::Port; use std::comm::Port;
use std::task;
use encoding::EncodingRef; use encoding::EncodingRef;
use encoding::all::UTF_8; use encoding::all::UTF_8;
use style::Stylesheet; use style::Stylesheet;
@ -23,25 +20,22 @@ pub enum StylesheetProvenance {
pub fn spawn_css_parser(provenance: StylesheetProvenance, pub fn spawn_css_parser(provenance: StylesheetProvenance,
resource_task: ResourceTask) resource_task: ResourceTask)
-> Port<Stylesheet> { -> Port<Stylesheet> {
let (result_port, result_chan) = comm::stream(); let (result_port, result_chan) = Chan::new();
// TODO: Get the actual value. http://dev.w3.org/csswg/css-syntax/#environment-encoding // TODO: Get the actual value. http://dev.w3.org/csswg/css-syntax/#environment-encoding
let environment_encoding = UTF_8 as EncodingRef; let environment_encoding = UTF_8 as EncodingRef;
let provenance_cell = Cell::new(provenance); spawn(proc() {
do task::spawn {
// TODO: CSS parsing should take a base URL. // TODO: CSS parsing should take a base URL.
let _url = do provenance_cell.with_ref |p| { let _url = match provenance {
match *p { UrlProvenance(ref the_url) => (*the_url).clone(),
UrlProvenance(ref the_url) => (*the_url).clone(), InlineProvenance(ref the_url, _) => (*the_url).clone()
InlineProvenance(ref the_url, _) => (*the_url).clone()
}
}; };
let sheet = match provenance_cell.take() { let sheet = match provenance {
UrlProvenance(url) => { UrlProvenance(url) => {
debug!("cssparse: loading style sheet at {:s}", url.to_str()); debug!("cssparse: loading style sheet at {:s}", url.to_str());
let (input_port, input_chan) = comm::stream(); let (input_port, input_chan) = Chan::new();
resource_task.send(Load(url, input_chan)); resource_task.send(Load(url, input_chan));
let LoadResponse { metadata: metadata, progress_port: progress_port } let LoadResponse { metadata: metadata, progress_port: progress_port }
= input_port.recv(); = input_port.recv();
@ -56,7 +50,7 @@ pub fn spawn_css_parser(provenance: StylesheetProvenance,
} }
}; };
result_chan.send(sheet); result_chan.send(sheet);
} });
return result_port; return result_port;
} }
@ -69,7 +63,7 @@ impl Iterator<~[u8]> for ProgressMsgPortIterator {
fn next(&mut self) -> Option<~[u8]> { fn next(&mut self) -> Option<~[u8]> {
match self.progress_port.recv() { match self.progress_port.recv() {
Payload(data) => Some(data), Payload(data) => Some(data),
Done(*) => None Done(..) => None
} }
} }
} }

View file

@ -22,9 +22,8 @@ use servo_net::image_cache_task::ImageCacheTask;
use servo_net::resource_task::{Load, Payload, Done, ResourceTask, load_whole_resource}; use servo_net::resource_task::{Load, Payload, Done, ResourceTask, load_whole_resource};
use servo_util::url::make_url; use servo_util::url::make_url;
use std::cast; use std::cast;
use std::cell::Cell; use std::cell::RefCell;
use std::comm::{Port, SharedChan}; use std::comm::{Port, SharedChan};
use std::comm;
use std::from_str::FromStr; use std::from_str::FromStr;
use std::str::eq_slice; use std::str::eq_slice;
use std::str; use std::str;
@ -107,11 +106,11 @@ fn css_link_listener(to_parent: SharedChan<HtmlDiscoveryMessage>,
let mut result_vec = ~[]; let mut result_vec = ~[];
loop { loop {
match from_parent.recv() { match from_parent.recv_opt() {
CSSTaskNewFile(provenance) => { Some(CSSTaskNewFile(provenance)) => {
result_vec.push(spawn_css_parser(provenance, resource_task.clone())); result_vec.push(spawn_css_parser(provenance, resource_task.clone()));
} }
CSSTaskExit => { Some(CSSTaskExit) | None => {
break; break;
} }
} }
@ -120,7 +119,7 @@ fn css_link_listener(to_parent: SharedChan<HtmlDiscoveryMessage>,
// Send the sheets back in order // Send the sheets back in order
// FIXME: Shouldn't wait until after we've recieved CSSTaskExit to start sending these // FIXME: Shouldn't wait until after we've recieved CSSTaskExit to start sending these
for port in result_vec.iter() { for port in result_vec.iter() {
to_parent.send(HtmlDiscoveredStyle(port.recv())); to_parent.try_send(HtmlDiscoveredStyle(port.recv()));
} }
} }
@ -130,30 +129,30 @@ fn js_script_listener(to_parent: SharedChan<HtmlDiscoveryMessage>,
let mut result_vec = ~[]; let mut result_vec = ~[];
loop { loop {
match from_parent.recv() { match from_parent.recv_opt() {
JSTaskNewFile(url) => { Some(JSTaskNewFile(url)) => {
match load_whole_resource(&resource_task, url.clone()) { match load_whole_resource(&resource_task, url.clone()) {
Err(_) => { Err(_) => {
error!("error loading script {:s}", url.to_str()); error!("error loading script {:s}", url.to_str());
} }
Ok((metadata, bytes)) => { Ok((metadata, bytes)) => {
result_vec.push(JSFile { result_vec.push(JSFile {
data: str::from_utf8(bytes), data: str::from_utf8(bytes).to_owned(),
url: metadata.final_url, url: metadata.final_url,
}); });
} }
} }
} }
JSTaskNewInlineScript(data, url) => { Some(JSTaskNewInlineScript(data, url)) => {
result_vec.push(JSFile { data: data, url: url }); result_vec.push(JSFile { data: data, url: url });
} }
JSTaskExit => { Some(JSTaskExit) | None => {
break; break;
} }
} }
} }
to_parent.send(HtmlDiscoveredScript(result_vec)); to_parent.try_send(HtmlDiscoveredScript(result_vec));
} }
// Silly macros to handle constructing DOM nodes. This produces bad code and should be optimized // Silly macros to handle constructing DOM nodes. This produces bad code and should be optimized
@ -253,30 +252,23 @@ pub fn parse_html(cx: *JSContext,
// Spawn a CSS parser to receive links to CSS style sheets. // Spawn a CSS parser to receive links to CSS style sheets.
let resource_task2 = resource_task.clone(); let resource_task2 = resource_task.clone();
let (discovery_port, discovery_chan) = comm::stream(); let (discovery_port, discovery_chan) = SharedChan::new();
let discovery_chan = SharedChan::new(discovery_chan); let stylesheet_chan = discovery_chan.clone();
let (css_msg_port, css_chan) = SharedChan::new();
let stylesheet_chan = Cell::new(discovery_chan.clone()); spawn(proc() {
let (css_msg_port, css_msg_chan) = comm::stream(); css_link_listener(stylesheet_chan, css_msg_port, resource_task2.clone());
let css_msg_port = Cell::new(css_msg_port); });
do spawn {
css_link_listener(stylesheet_chan.take(), css_msg_port.take(), resource_task2.clone());
}
let css_chan = SharedChan::new(css_msg_chan);
// Spawn a JS parser to receive JavaScript. // Spawn a JS parser to receive JavaScript.
let resource_task2 = resource_task.clone(); let resource_task2 = resource_task.clone();
let js_result_chan = Cell::new(discovery_chan.clone()); let js_result_chan = discovery_chan.clone();
let (js_msg_port, js_msg_chan) = comm::stream(); let (js_msg_port, js_chan) = SharedChan::new();
let js_msg_port = Cell::new(js_msg_port); spawn(proc() {
do spawn { js_script_listener(js_result_chan, js_msg_port, resource_task2.clone());
js_script_listener(js_result_chan.take(), js_msg_port.take(), resource_task2.clone()); });
}
let js_chan = SharedChan::new(js_msg_chan);
// Wait for the LoadResponse so that the parser knows the final URL. // Wait for the LoadResponse so that the parser knows the final URL.
let (input_port, input_chan) = comm::stream(); let (input_port, input_chan) = Chan::new();
resource_task.send(Load(url.clone(), input_chan)); resource_task.send(Load(url.clone(), input_chan));
let load_response = input_port.recv(); let load_response = input_port.recv();
@ -305,9 +297,10 @@ pub fn parse_html(cx: *JSContext,
parser.enable_styling(true); parser.enable_styling(true);
let (css_chan2, css_chan3, js_chan2) = (css_chan.clone(), css_chan.clone(), js_chan.clone()); let (css_chan2, css_chan3, js_chan2) = (css_chan.clone(), css_chan.clone(), js_chan.clone());
let next_subpage_id = Cell::new(next_subpage_id);
let next_subpage_id = RefCell::new(next_subpage_id);
parser.set_tree_handler(~hubbub::TreeHandler {
let tree_handler = hubbub::TreeHandler {
create_comment: |data: ~str| { create_comment: |data: ~str| {
debug!("create comment"); debug!("create comment");
let comment = Comment::new(data, document); let comment = Comment::new(data, document);
@ -333,19 +326,19 @@ pub fn parse_html(cx: *JSContext,
let node = build_element_from_tag(tag.name.clone(), document); let node = build_element_from_tag(tag.name.clone(), document);
debug!("-- attach attrs"); debug!("-- attach attrs");
do node.as_mut_element |element| { node.as_mut_element(|element| {
for attr in tag.attributes.iter() { for attr in tag.attributes.iter() {
element.set_attr(node, element.set_attr(node,
attr.name.clone(), attr.name.clone(),
attr.value.clone()); attr.value.clone());
} }
} });
// Spawn additional parsing, network loads, etc. from tag and attrs // Spawn additional parsing, network loads, etc. from tag and attrs
match node.type_id() { match node.type_id() {
// Handle CSS style sheets from <link> elements // Handle CSS style sheets from <link> elements
ElementNodeTypeId(HTMLLinkElementTypeId) => { ElementNodeTypeId(HTMLLinkElementTypeId) => {
do node.with_imm_element |element| { node.with_imm_element(|element| {
match (element.get_attr(Null, "rel"), element.get_attr(Null, "href")) { match (element.get_attr(Null, "rel"), element.get_attr(Null, "href")) {
(Some(rel), Some(href)) => { (Some(rel), Some(href)) => {
if "stylesheet" == rel { if "stylesheet" == rel {
@ -356,13 +349,12 @@ pub fn parse_html(cx: *JSContext,
} }
_ => {} _ => {}
} }
} });
} }
ElementNodeTypeId(HTMLIframeElementTypeId) => { ElementNodeTypeId(HTMLIframeElementTypeId) => {
let iframe_chan = Cell::new(discovery_chan.clone()); let iframe_chan = discovery_chan.clone();
do node.with_mut_iframe_element |iframe_element| { node.with_mut_iframe_element(|iframe_element| {
let iframe_chan = iframe_chan.take();
let sandboxed = iframe_element.is_sandboxed(); let sandboxed = iframe_element.is_sandboxed();
let elem = &mut iframe_element.htmlelement.element; let elem = &mut iframe_element.htmlelement.element;
let src_opt = elem.get_attr(Null, "src").map(|x| x.to_str()); let src_opt = elem.get_attr(Null, "src").map(|x| x.to_str());
@ -371,8 +363,8 @@ pub fn parse_html(cx: *JSContext,
iframe_element.frame = Some(iframe_url.clone()); iframe_element.frame = Some(iframe_url.clone());
// Subpage Id // Subpage Id
let subpage_id = next_subpage_id.take(); let subpage_id = next_subpage_id.get();
next_subpage_id.put_back(SubpageId(*subpage_id + 1)); next_subpage_id.set(SubpageId(*subpage_id + 1));
// Pipeline Id // Pipeline Id
let pipeline_id = { let pipeline_id = {
@ -388,15 +380,15 @@ pub fn parse_html(cx: *JSContext,
subpage_id, subpage_id,
sandboxed))); sandboxed)));
} }
} });
} }
//FIXME: This should be taken care of by set_attr, but we don't have //FIXME: This should be taken care of by set_attr, but we don't have
// access to a window so HTMLImageElement::AfterSetAttr bails. // access to a window so HTMLImageElement::AfterSetAttr bails.
ElementNodeTypeId(HTMLImageElementTypeId) => { ElementNodeTypeId(HTMLImageElementTypeId) => {
do node.with_mut_image_element |image_element| { node.with_mut_image_element(|image_element| {
image_element.update_image(image_cache_task.clone(), Some(url2.clone())); image_element.update_image(image_cache_task.clone(), Some(url2.clone()));
} });
} }
_ => {} _ => {}
@ -460,7 +452,7 @@ pub fn parse_html(cx: *JSContext,
complete_script: |script| { complete_script: |script| {
unsafe { unsafe {
let scriptnode: AbstractNode = NodeWrapping::from_hubbub_node(script); let scriptnode: AbstractNode = NodeWrapping::from_hubbub_node(script);
do scriptnode.with_imm_element |script| { scriptnode.with_imm_element(|script| {
match script.get_attr(Null, "src") { match script.get_attr(Null, "src") {
Some(src) => { Some(src) => {
debug!("found script: {:s}", src); debug!("found script: {:s}", src);
@ -472,16 +464,16 @@ pub fn parse_html(cx: *JSContext,
debug!("iterating over children {:?}", scriptnode.first_child()); debug!("iterating over children {:?}", scriptnode.first_child());
for child in scriptnode.children() { for child in scriptnode.children() {
debug!("child = {:?}", child); debug!("child = {:?}", child);
do child.with_imm_text() |text| { child.with_imm_text(|text| {
data.push(text.element.data.to_str()); // FIXME: Bad copy. data.push(text.element.data.to_str()); // FIXME: Bad copy.
} });
} }
debug!("script data = {:?}", data); debug!("script data = {:?}", data);
js_chan2.send(JSTaskNewInlineScript(data.concat(), url3.clone())); js_chan2.send(JSTaskNewInlineScript(data.concat(), url3.clone()));
} }
} }
} });
} }
debug!("complete script"); debug!("complete script");
}, },
@ -490,23 +482,22 @@ pub fn parse_html(cx: *JSContext,
unsafe { unsafe {
let style: AbstractNode = NodeWrapping::from_hubbub_node(style); let style: AbstractNode = NodeWrapping::from_hubbub_node(style);
let url = FromStr::from_str("http://example.com/"); // FIXME let url = FromStr::from_str("http://example.com/"); // FIXME
let url_cell = Cell::new(url);
let mut data = ~[]; let mut data = ~[];
debug!("iterating over children {:?}", style.first_child()); debug!("iterating over children {:?}", style.first_child());
for child in style.children() { for child in style.children() {
debug!("child = {:?}", child); debug!("child = {:?}", child);
do child.with_imm_text() |text| { child.with_imm_text(|text| {
data.push(text.element.data.to_str()); // FIXME: Bad copy. data.push(text.element.data.to_str()); // FIXME: Bad copy.
} });
} }
debug!("style data = {:?}", data); debug!("style data = {:?}", data);
let provenance = InlineProvenance(url_cell.take().unwrap(), data.concat()); let provenance = InlineProvenance(url.unwrap(), data.concat());
css_chan3.send(CSSTaskNewFile(provenance)); css_chan3.send(CSSTaskNewFile(provenance));
} }
}, },
}); };
parser.set_tree_handler(&tree_handler);
debug!("set tree handler"); debug!("set tree handler");
debug!("loaded page"); debug!("loaded page");
@ -516,10 +507,10 @@ pub fn parse_html(cx: *JSContext,
debug!("received data"); debug!("received data");
parser.parse_chunk(data); parser.parse_chunk(data);
} }
Done(Err(*)) => { Done(Err(..)) => {
fail!("Failed to load page URL {:s}", url.to_str()); fail!("Failed to load page URL {:s}", url.to_str());
} }
Done(*) => { Done(..) => {
break; break;
} }
} }

View file

@ -122,9 +122,11 @@ pub struct Reflow {
/// Encapsulates a channel to the layout task. /// Encapsulates a channel to the layout task.
#[deriving(Clone)] #[deriving(Clone)]
pub struct LayoutChan(SharedChan<Msg>); pub struct LayoutChan(SharedChan<Msg>);
impl LayoutChan { impl LayoutChan {
pub fn new(chan: Chan<Msg>) -> LayoutChan { pub fn new() -> (Port<Msg>, LayoutChan) {
LayoutChan(SharedChan::new(chan)) let (port, chan) = SharedChan::new();
(port, LayoutChan(chan))
} }
} }

View file

@ -2,14 +2,11 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#[link(name = "script", #[crate_id = "github.com/mozilla/servo#script:0.1"];
vers = "0.1", #[crate_type = "lib"];
uuid = "536a45e2-b605-4ee0-b54c-466810f1ffc1",
url = "http://servo.org/")];
#[comment = "The Servo Parallel Browser Project"]; #[comment = "The Servo Parallel Browser Project"];
#[license = "MPL"]; #[license = "MPL"];
#[crate_type = "lib"];
#[feature(globs, macro_rules, struct_variant, managed_boxes)]; #[feature(globs, macro_rules, struct_variant, managed_boxes)];
@ -17,11 +14,12 @@ extern mod geom;
extern mod hubbub; extern mod hubbub;
extern mod encoding; extern mod encoding;
extern mod js; extern mod js;
extern mod servo_net (name = "net"); extern mod servo_net = "net";
extern mod servo_util (name = "util"); extern mod servo_util = "util";
extern mod style; extern mod style;
extern mod servo_msg (name = "msg"); extern mod servo_msg = "msg";
extern mod extra; extern mod extra;
extern mod native;
// Macros // Macros
mod macros; mod macros;

View file

@ -14,15 +14,15 @@ use dom::event::Event;
use dom::eventtarget::AbstractEventTarget; use dom::eventtarget::AbstractEventTarget;
use dom::htmldocument::HTMLDocument; use dom::htmldocument::HTMLDocument;
use dom::namespace::Null; use dom::namespace::Null;
use dom::node::{AbstractNode, LayoutDataRef}; use dom::node::AbstractNode;
use dom::window::{TimerData, Window}; use dom::window::{TimerData, TimerHandle, Window};
use html::hubbub_html_parser::HtmlParserResult; use html::hubbub_html_parser::HtmlParserResult;
use html::hubbub_html_parser::{HtmlDiscoveredStyle, HtmlDiscoveredIFrame, HtmlDiscoveredScript}; use html::hubbub_html_parser::{HtmlDiscoveredStyle, HtmlDiscoveredIFrame, HtmlDiscoveredScript};
use html::hubbub_html_parser; use html::hubbub_html_parser;
use layout_interface::{AddStylesheetMsg, DocumentDamage}; use layout_interface::{AddStylesheetMsg, DocumentDamage};
use layout_interface::{ContentBoxQuery, ContentBoxResponse}; use layout_interface::{ContentBoxQuery, ContentBoxResponse};
use layout_interface::{DocumentDamageLevel, HitTestQuery, HitTestResponse, LayoutQuery}; use layout_interface::{DocumentDamageLevel, HitTestQuery, HitTestResponse, LayoutQuery};
use layout_interface::{LayoutChan, MatchSelectorsDocumentDamage, QueryMsg, ReapLayoutDataMsg}; use layout_interface::{LayoutChan, MatchSelectorsDocumentDamage, QueryMsg};
use layout_interface::{Reflow, ReflowDocumentDamage, ReflowForDisplay, ReflowGoal, ReflowMsg}; use layout_interface::{Reflow, ReflowDocumentDamage, ReflowForDisplay, ReflowGoal, ReflowMsg};
use layout_interface::ContentChangedDocumentDamage; use layout_interface::ContentChangedDocumentDamage;
use layout_interface; use layout_interface;
@ -46,12 +46,9 @@ use servo_net::image_cache_task::ImageCacheTask;
use servo_net::resource_task::ResourceTask; use servo_net::resource_task::ResourceTask;
use servo_util::geometry::to_frac_px; use servo_util::geometry::to_frac_px;
use servo_util::url::make_url; use servo_util::url::make_url;
use std::cell::Cell;
use std::comm::{Port, SharedChan}; use std::comm::{Port, SharedChan};
use std::comm;
use std::ptr; use std::ptr;
use std::str::eq_slice; use std::str::eq_slice;
use std::task::{spawn_sched, SingleThreaded};
use std::util::replace; use std::util::replace;
/// Messages used to control the script task. /// Messages used to control the script task.
@ -90,8 +87,9 @@ pub struct ScriptChan(SharedChan<ScriptMsg>);
impl ScriptChan { impl ScriptChan {
/// Creates a new script chan. /// Creates a new script chan.
pub fn new(chan: Chan<ScriptMsg>) -> ScriptChan { pub fn new() -> (Port<ScriptMsg>, ScriptChan) {
ScriptChan(SharedChan::new(chan)) let (port, chan) = SharedChan::new();
(port, ScriptChan(chan))
} }
} }
@ -140,8 +138,8 @@ pub struct PageTree {
inner: ~[PageTree], inner: ~[PageTree],
} }
pub struct PageTreeIterator<'self> { pub struct PageTreeIterator<'a> {
priv stack: ~[&'self mut PageTree], priv stack: ~[&'a mut PageTree],
} }
impl PageTree { impl PageTree {
@ -203,7 +201,7 @@ impl PageTree {
} }
} }
impl<'self> Iterator<@mut Page> for PageTreeIterator<'self> { impl<'a> Iterator<@mut Page> for PageTreeIterator<'a> {
fn next(&mut self) -> Option<@mut Page> { fn next(&mut self) -> Option<@mut Page> {
if !self.stack.is_empty() { if !self.stack.is_empty() {
let next = self.stack.pop(); let next = self.stack.pop();
@ -254,12 +252,14 @@ impl Page {
let join_port = replace(&mut self.layout_join_port, None); let join_port = replace(&mut self.layout_join_port, None);
match join_port { match join_port {
Some(ref join_port) => { Some(ref join_port) => {
if !join_port.peek() { match join_port.try_recv() {
info!("script: waiting on layout"); None => {
info!("script: waiting on layout");
join_port.recv();
}
Some(_) => {}
} }
join_port.recv();
debug!("script: layout joined") debug!("script: layout joined")
} }
None => fail!(~"reader forked but no join port?"), None => fail!(~"reader forked but no join port?"),
@ -307,7 +307,7 @@ impl Page {
compositor.set_ready_state(PerformingLayout); compositor.set_ready_state(PerformingLayout);
// Layout will let us know when it's done. // Layout will let us know when it's done.
let (join_port, join_chan) = comm::stream(); let (join_port, join_chan) = Chan::new();
self.layout_join_port = Some(join_port); self.layout_join_port = Some(join_port);
self.last_reflow_id += 1; self.last_reflow_id += 1;
@ -359,11 +359,6 @@ impl Page {
js_context: js_context, js_context: js_context,
}); });
} }
/// Sends the given layout data back to the layout task to be destroyed.
pub unsafe fn reap_dead_layout_data(&self, layout_data: LayoutDataRef) {
self.layout_chan.send(ReapLayoutDataMsg(layout_data))
}
} }
/// Information for one frame in the browsing context. /// Information for one frame in the browsing context.
@ -412,7 +407,6 @@ pub struct ScriptTask {
} }
/// Returns the relevant page from the associated JS Context. /// Returns the relevant page from the associated JS Context.
#[fixed_stack_segment]
pub fn page_from_context(js_context: *JSContext) -> *mut Page { pub fn page_from_context(js_context: *JSContext) -> *mut Page {
unsafe { unsafe {
JS_GetContextPrivate(js_context) as *mut Page JS_GetContextPrivate(js_context) as *mut Page
@ -468,24 +462,7 @@ impl ScriptTask {
resource_task: ResourceTask, resource_task: ResourceTask,
image_cache_task: ImageCacheTask, image_cache_task: ImageCacheTask,
window_size: Size2D<uint>) { window_size: Size2D<uint>) {
let parms = Cell::new((compositor, spawn(proc() {
layout_chan,
port,
chan,
constellation_chan,
resource_task,
image_cache_task));
// Since SpiderMonkey is blocking it needs to run in its own thread.
// If we don't do this then we'll just end up with a bunch of SpiderMonkeys
// starving all the other tasks.
do spawn_sched(SingleThreaded) {
let (compositor,
layout_chan,
port,
chan,
constellation_chan,
resource_task,
image_cache_task) = parms.take();
let script_task = ScriptTask::new(id, let script_task = ScriptTask::new(id,
@compositor as @ScriptListener, @compositor as @ScriptListener,
layout_chan, layout_chan,
@ -496,7 +473,7 @@ impl ScriptTask {
image_cache_task, image_cache_task,
window_size); window_size);
script_task.start(); script_task.start();
} });
} }
/// Handle incoming control messages. /// Handle incoming control messages.
@ -520,12 +497,13 @@ impl ScriptTask {
// Store new resizes, and gather all other events. // Store new resizes, and gather all other events.
let mut sequential = ~[]; let mut sequential = ~[];
// Receive at least one message so we don't spinloop.
let mut event = self.port.recv();
loop { loop {
// Receive at least one message so we don't spinloop.
let event = self.port.recv();
match event { match event {
ResizeMsg(id, size) => { ResizeMsg(id, size) => {
debug!("script got resize message");
let page = self.page_tree.find(id).expect("resize sent to nonexistent pipeline").page; let page = self.page_tree.find(id).expect("resize sent to nonexistent pipeline").page;
page.resize_event = Some(size); page.resize_event = Some(size);
} }
@ -534,9 +512,9 @@ impl ScriptTask {
} }
} }
// Break if there are no more messages. match self.port.try_recv() {
if !self.port.peek() { None => break,
break; Some(ev) => event = ev,
} }
} }
@ -556,7 +534,7 @@ impl ScriptTask {
self.handle_exit_window_msg(id); self.handle_exit_window_msg(id);
return false return false
}, },
ResizeMsg(*) => fail!("should have handled ResizeMsg already"), ResizeMsg(..) => fail!("should have handled ResizeMsg already"),
} }
} }
@ -579,14 +557,14 @@ impl ScriptTask {
} }
/// Handles a timer that fired. /// Handles a timer that fired.
#[fixed_stack_segment]
fn handle_fire_timer_msg(&mut self, id: PipelineId, timer_data: ~TimerData) { fn handle_fire_timer_msg(&mut self, id: PipelineId, timer_data: ~TimerData) {
let page = self.page_tree.find(id).expect("ScriptTask: received fire timer msg for a let page = self.page_tree.find(id).expect("ScriptTask: received fire timer msg for a
pipeline ID not associated with this script task. This is a bug.").page; pipeline ID not associated with this script task. This is a bug.").page;
let window = page.frame.expect("ScriptTask: Expect a timeout to have a document").window; let window = page.frame.expect("ScriptTask: Expect a timeout to have a document").window;
if !window.active_timers.contains(&timer_data.handle) { if !window.active_timers.contains(&TimerHandle { handle: timer_data.handle, cancel_chan: None }) {
return; return;
} }
window.active_timers.remove(&TimerHandle { handle: timer_data.handle, cancel_chan: None });
unsafe { unsafe {
let this_value = if timer_data.args.len() > 0 { let this_value = if timer_data.args.len() > 0 {
RUST_JSVAL_TO_OBJECT(timer_data.args[0]) RUST_JSVAL_TO_OBJECT(timer_data.args[0])
@ -711,7 +689,6 @@ impl ScriptTask {
// //
// Note: We can parse the next document in parallel with any previous documents. // Note: We can parse the next document in parallel with any previous documents.
let document = HTMLDocument::new(window); let document = HTMLDocument::new(window);
let html_parsing_result = hubbub_html_parser::parse_html(cx.ptr, let html_parsing_result = hubbub_html_parser::parse_html(cx.ptr,
document, document,
url.clone(), url.clone(),
@ -736,7 +713,7 @@ impl ScriptTask {
let mut js_scripts = None; let mut js_scripts = None;
loop { loop {
match discovery_port.try_recv() { match discovery_port.recv_opt() {
Some(HtmlDiscoveredScript(scripts)) => { Some(HtmlDiscoveredScript(scripts)) => {
assert!(js_scripts.is_none()); assert!(js_scripts.is_none());
js_scripts = Some(scripts); js_scripts = Some(scripts);
@ -805,20 +782,20 @@ impl ScriptTask {
None => { None => {
let doc_node = AbstractNode::from_document(document); let doc_node = AbstractNode::from_document(document);
let mut anchors = doc_node.traverse_preorder().filter(|node| node.is_anchor_element()); let mut anchors = doc_node.traverse_preorder().filter(|node| node.is_anchor_element());
do anchors.find |node| { anchors.find(|node| {
do node.with_imm_element |elem| { node.with_imm_element(|elem| {
match elem.get_attr(Null, "name") { match elem.get_attr(Null, "name") {
Some(name) => eq_slice(name, fragid), Some(name) => eq_slice(name, fragid),
None => false None => false
} }
} })
} })
} }
} }
} }
fn scroll_fragment_point(&self, pipeline_id: PipelineId, page: &mut Page, node: AbstractNode) { fn scroll_fragment_point(&self, pipeline_id: PipelineId, page: &mut Page, node: AbstractNode) {
let (port, chan) = comm::stream(); let (port, chan) = Chan::new();
match page.query_layout(ContentBoxQuery(node, chan), port) { match page.query_layout(ContentBoxQuery(node, chan), port) {
ContentBoxResponse(rect) => { ContentBoxResponse(rect) => {
let point = Point2D(to_frac_px(rect.origin.x).to_f32().unwrap(), let point = Point2D(to_frac_px(rect.origin.x).to_f32().unwrap(),
@ -870,7 +847,7 @@ impl ScriptTask {
if root.is_none() { if root.is_none() {
return; return;
} }
let (port, chan) = comm::stream(); let (port, chan) = Chan::new();
match page.query_layout(HitTestQuery(root.unwrap(), point, chan), port) { match page.query_layout(HitTestQuery(root.unwrap(), point, chan), port) {
Ok(node) => match node { Ok(node) => match node {
HitTestResponse(node) => { HitTestResponse(node) => {
@ -886,11 +863,11 @@ impl ScriptTask {
} }
} }
if node.is_element() { if node.is_element() {
do node.with_imm_element |element| { node.with_imm_element(|element| {
if "a" == element.tag_name { if "a" == element.tag_name {
self.load_url_from_element(page, element) self.load_url_from_element(page, element)
} }
} })
} }
} }
}, },
@ -899,8 +876,8 @@ impl ScriptTask {
} }
} }
} }
MouseDownEvent(*) => {} MouseDownEvent(..) => {}
MouseUpEvent(*) => {} MouseUpEvent(..) => {}
} }
} }
@ -910,9 +887,9 @@ impl ScriptTask {
for href in attr.iter() { for href in attr.iter() {
debug!("ScriptTask: clicked on link to {:s}", *href); debug!("ScriptTask: clicked on link to {:s}", *href);
let click_frag = href.starts_with("#"); let click_frag = href.starts_with("#");
let current_url = do page.url.as_ref().map |&(ref url, _)| { let current_url = page.url.as_ref().map(|&(ref url, _)| {
url.clone() url.clone()
}; });
debug!("ScriptTask: current url is {:?}", current_url); debug!("ScriptTask: current url is {:?}", current_url);
let url = make_url(href.to_owned(), current_url); let url = make_url(href.to_owned(), current_url);
@ -933,29 +910,15 @@ fn shut_down_layout(page: @mut Page) {
page.join_layout(); page.join_layout();
// Tell the layout task to begin shutting down. // Tell the layout task to begin shutting down.
let (response_port, response_chan) = comm::stream(); let (response_port, response_chan) = Chan::new();
page.layout_chan.send(layout_interface::PrepareToExitMsg(response_chan)); page.layout_chan.send(layout_interface::PrepareToExitMsg(response_chan));
response_port.recv(); response_port.recv();
// Destroy all nodes. // Destroy all nodes. Setting frame and js_info to None will trigger our
// // compartment to shutdown, run GC, etc.
// If there was a leak, the layout task will soon crash safely when it detects that local data page.frame = None;
// is missing from its heap. page.js_info = None;
//
// FIXME(pcwalton): *But*, for now, because we use `@mut` boxes to hold onto Nodes, if this
// didn't destroy all the nodes there will be an *exploitable* security vulnerability as the
// nodes try to access the destroyed JS context. We need to change this so that the only actor
// who can judge a JS object dead (and thus run its drop glue) is the JS engine itself; thus it
// will be impossible (absent a serious flaw in the JS engine) for the JS context to be dead
// before nodes are.
unsafe {
let document_node = AbstractNode::from_document(page.frame.as_ref().unwrap().document);
for node in document_node.traverse_preorder() {
node.mut_node().reap_layout_data()
}
}
// Destroy the layout task. If there were node leaks, layout will now crash safely. // Destroy the layout task. If there were node leaks, layout will now crash safely.
page.layout_chan.send(layout_interface::ExitNowMsg); page.layout_chan.send(layout_interface::ExitNowMsg);
} }

View file

@ -43,6 +43,7 @@ pub mod specified {
_ => None _ => None
} }
} }
#[allow(dead_code)]
pub fn parse(input: &ComponentValue) -> Option<Length> { pub fn parse(input: &ComponentValue) -> Option<Length> {
Length::parse_internal(input, /* negative_ok = */ true) Length::parse_internal(input, /* negative_ok = */ true)
} }
@ -87,6 +88,7 @@ pub mod specified {
_ => None _ => None
} }
} }
#[allow(dead_code)]
#[inline] #[inline]
pub fn parse(input: &ComponentValue) -> Option<LengthOrPercentage> { pub fn parse(input: &ComponentValue) -> Option<LengthOrPercentage> {
LengthOrPercentage::parse_internal(input, /* negative_ok = */ true) LengthOrPercentage::parse_internal(input, /* negative_ok = */ true)
@ -145,6 +147,7 @@ pub mod specified {
_ => None _ => None
} }
} }
#[allow(dead_code)]
#[inline] #[inline]
pub fn parse(input: &ComponentValue) -> Option<LengthOrPercentageOrNone> { pub fn parse(input: &ComponentValue) -> Option<LengthOrPercentageOrNone> {
LengthOrPercentageOrNone::parse_internal(input, /* negative_ok = */ true) LengthOrPercentageOrNone::parse_internal(input, /* negative_ok = */ true)

View file

@ -31,7 +31,7 @@ pub fn log_css_error(location: SourceLocation, message: &str) {
} }
pub fn with_errors_silenced<T>(f: &fn() -> T) -> T { pub fn with_errors_silenced<T>(f: || -> T) -> T {
local_data::set(silence_errors, ()); local_data::set(silence_errors, ());
let result = f(); let result = f();
local_data::pop(silence_errors); local_data::pop(silence_errors);

View file

@ -121,12 +121,12 @@ pub fn parse_media_query_list(input: &[ComponentValue]) -> MediaQueryList {
impl MediaQueryList { impl MediaQueryList {
pub fn evaluate(&self, device: &Device) -> bool { pub fn evaluate(&self, device: &Device) -> bool {
do self.media_queries.iter().any |mq| { self.media_queries.iter().any(|mq| {
match mq.media_type { match mq.media_type {
MediaType(media_type) => media_type == device.media_type, MediaType(media_type) => media_type == device.media_type,
All => true, All => true,
} }
// TODO: match Level 3 expressions // TODO: match Level 3 expressions
} })
} }
} }

View file

@ -14,7 +14,7 @@ pub trait TNode<E:TElement> : Clone {
fn is_element(&self) -> bool; fn is_element(&self) -> bool;
/// FIXME(pcwalton): This should not use the `with` pattern. /// FIXME(pcwalton): This should not use the `with` pattern.
fn with_element<R>(&self, f: &fn(&E) -> R) -> R; fn with_element<'a, R>(&self, f: |&E| -> R) -> R;
} }
pub trait TElement { pub trait TElement {

View file

@ -74,8 +74,8 @@ pub mod longhands {
pub fn parse_declared(input: &[ComponentValue]) pub fn parse_declared(input: &[ComponentValue])
-> Option<DeclaredValue<SpecifiedValue>> { -> Option<DeclaredValue<SpecifiedValue>> {
match CSSWideKeyword::parse(input) { match CSSWideKeyword::parse(input) {
Some(Left(keyword)) => Some(CSSWideKeyword(keyword)), Some(Some(keyword)) => Some(CSSWideKeyword(keyword)),
Some(Right(Unset)) => Some(CSSWideKeyword(${ Some(None) => Some(CSSWideKeyword(${
"Inherit" if inherited else "Initial"})), "Inherit" if inherited else "Initial"})),
None => parse_specified(input), None => parse_specified(input),
} }
@ -118,14 +118,14 @@ pub mod longhands {
${to_rust_ident(values.split()[0])} ${to_rust_ident(values.split()[0])}
} }
pub fn from_component_value(v: &ComponentValue) -> Option<SpecifiedValue> { pub fn from_component_value(v: &ComponentValue) -> Option<SpecifiedValue> {
do get_ident_lower(v).and_then |keyword| { get_ident_lower(v).and_then(|keyword| {
match keyword.as_slice() { match keyword.as_slice() {
% for value in values.split(): % for value in values.split():
"${value}" => Some(${to_rust_ident(value)}), "${value}" => Some(${to_rust_ident(value)}),
% endfor % endfor
_ => None, _ => None,
} }
} })
} }
</%self:single_component_value> </%self:single_component_value>
</%def> </%def>
@ -648,12 +648,12 @@ pub mod longhands {
/// <length> | <percentage> /// <length> | <percentage>
/// TODO: support <absolute-size> and <relative-size> /// TODO: support <absolute-size> and <relative-size>
pub fn from_component_value(input: &ComponentValue) -> Option<SpecifiedValue> { pub fn from_component_value(input: &ComponentValue) -> Option<SpecifiedValue> {
do specified::LengthOrPercentage::parse_non_negative(input).map |value| { specified::LengthOrPercentage::parse_non_negative(input).map(|value| {
match value { match value {
specified::LP_Length(value) => value, specified::LP_Length(value) => value,
specified::LP_Percentage(value) => specified::Em(value), specified::LP_Percentage(value) => specified::Em(value),
} }
} })
} }
</%self:single_component_value> </%self:single_component_value>
@ -767,9 +767,9 @@ pub mod shorthands {
// TODO: other background-* properties // TODO: other background-* properties
<%self:shorthand name="background" sub_properties="background-color"> <%self:shorthand name="background" sub_properties="background-color">
do one_component_value(input).and_then(specified::CSSColor::parse).map |color| { one_component_value(input).and_then(specified::CSSColor::parse).map(|color| {
Longhands { background_color: Some(color) } Longhands { background_color: Some(color) }
} })
</%self:shorthand> </%self:shorthand>
${four_sides_shorthand("margin", "margin-%s", "margin_top::from_component_value")} ${four_sides_shorthand("margin", "margin-%s", "margin_top::from_component_value")}
@ -818,13 +818,13 @@ pub mod shorthands {
'border-%s-%s' % (side, prop) 'border-%s-%s' % (side, prop)
for prop in ['color', 'style', 'width'] for prop in ['color', 'style', 'width']
)}"> )}">
do parse_border(input).map |(color, style, width)| { parse_border(input).map(|(color, style, width)| {
Longhands { Longhands {
% for prop in ["color", "style", "width"]: % for prop in ["color", "style", "width"]:
${"border_%s_%s: %s," % (side, prop, prop)} ${"border_%s_%s: %s," % (side, prop, prop)}
% endfor % endfor
} }
} })
</%self:shorthand> </%self:shorthand>
% endfor % endfor
@ -833,7 +833,7 @@ pub mod shorthands {
for side in ['top', 'right', 'bottom', 'left'] for side in ['top', 'right', 'bottom', 'left']
for prop in ['color', 'style', 'width'] for prop in ['color', 'style', 'width']
)}"> )}">
do parse_border(input).map |(color, style, width)| { parse_border(input).map(|(color, style, width)| {
Longhands { Longhands {
% for side in ["top", "right", "bottom", "left"]: % for side in ["top", "right", "bottom", "left"]:
% for prop in ["color", "style", "width"]: % for prop in ["color", "style", "width"]:
@ -841,7 +841,7 @@ pub mod shorthands {
% endfor % endfor
% endfor % endfor
} }
} })
</%self:shorthand> </%self:shorthand>
<%self:shorthand name="font" sub_properties="font-style font-variant font-weight <%self:shorthand name="font" sub_properties="font-style font-variant font-weight
@ -966,18 +966,16 @@ pub enum CSSWideKeyword {
Inherit, Inherit,
} }
struct Unset;
impl CSSWideKeyword { impl CSSWideKeyword {
pub fn parse(input: &[ComponentValue]) -> Option<Either<CSSWideKeyword, Unset>> { pub fn parse(input: &[ComponentValue]) -> Option<Option<CSSWideKeyword>> {
do one_component_value(input).and_then(get_ident_lower).and_then |keyword| { one_component_value(input).and_then(get_ident_lower).and_then(|keyword| {
match keyword.as_slice() { match keyword.as_slice() {
"initial" => Some(Left(Initial)), "initial" => Some(Some(Initial)),
"inherit" => Some(Left(Inherit)), "inherit" => Some(Some(Inherit)),
"unset" => Some(Right(Unset)), "unset" => Some(None),
_ => None _ => None
} }
} })
} }
} }
@ -1018,14 +1016,14 @@ impl PropertyDeclaration {
% endfor % endfor
% for shorthand in SHORTHANDS: % for shorthand in SHORTHANDS:
"${shorthand.name}" => match CSSWideKeyword::parse(value) { "${shorthand.name}" => match CSSWideKeyword::parse(value) {
Some(Left(keyword)) => { Some(Some(keyword)) => {
% for sub_property in shorthand.sub_properties: % for sub_property in shorthand.sub_properties:
result_list.push(${sub_property.ident}_declaration( result_list.push(${sub_property.ident}_declaration(
CSSWideKeyword(keyword) CSSWideKeyword(keyword)
)); ));
% endfor % endfor
}, },
Some(Right(Unset)) => { Some(None) => {
% for sub_property in shorthand.sub_properties: % for sub_property in shorthand.sub_properties:
result_list.push(${sub_property.ident}_declaration( result_list.push(${sub_property.ident}_declaration(
CSSWideKeyword(${ CSSWideKeyword(${

View file

@ -3,7 +3,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use extra::arc::Arc; use extra::arc::Arc;
use extra::sort::tim_sort;
use std::ascii::StrAsciiExt; use std::ascii::StrAsciiExt;
use std::hashmap::HashMap; use std::hashmap::HashMap;
use std::str; use std::str;
@ -86,11 +85,9 @@ impl SelectorMap {
match element.get_attr(None, "class") { match element.get_attr(None, "class") {
Some(ref class_attr) => { Some(ref class_attr) => {
for class in class_attr.split_iter(SELECTOR_WHITESPACE) { for class in class_attr.split(SELECTOR_WHITESPACE) {
SelectorMap::get_matching_rules_from_hash(node, SelectorMap::get_matching_rules_from_hash(
&self.class_hash, node, &self.class_hash, class, matching_rules_list);
class,
matching_rules_list)
} }
} }
None => {} None => {}
@ -108,7 +105,13 @@ impl SelectorMap {
}); });
// Sort only the rules we just added. // Sort only the rules we just added.
tim_sort(matching_rules_list.mut_slice_from(init_len)); matching_rules_list.mut_slice_from(init_len).sort_by(|a, b| {
if a < b {
Less
} else {
Greater
}
});
} }
fn get_matching_rules_from_hash<E:TElement, fn get_matching_rules_from_hash<E:TElement,
@ -292,11 +295,11 @@ impl Stylist {
); );
let device = &Device { media_type: Screen }; // TODO, use Print when printing let device = &Device { media_type: Screen }; // TODO, use Print when printing
do iter_style_rules(stylesheet.rules.as_slice(), device) |style_rule| { iter_style_rules(stylesheet.rules.as_slice(), device, |style_rule| {
append!(normal); append!(normal);
append!(important); append!(important);
self.rules_source_order += 1; self.rules_source_order += 1;
} });
} }
/// Returns the applicable CSS declarations for the given element. This corresponds to /// Returns the applicable CSS declarations for the given element. This corresponds to
@ -344,7 +347,7 @@ impl Stylist {
let mut declaration_iter = matching_rules_list.move_iter().map(|rule| { let mut declaration_iter = matching_rules_list.move_iter().map(|rule| {
let Rule { let Rule {
declarations, declarations,
_ ..
} = rule; } = rule;
declarations declarations
}); });
@ -436,9 +439,9 @@ impl Ord for Rule {
fn matches_compound_selector<E:TElement,N:TNode<E>>(selector: &CompoundSelector, element: &N) fn matches_compound_selector<E:TElement,N:TNode<E>>(selector: &CompoundSelector, element: &N)
-> bool { -> bool {
if !do selector.simple_selectors.iter().all |simple_selector| { if !selector.simple_selectors.iter().all(|simple_selector| {
matches_simple_selector(simple_selector, element) matches_simple_selector(simple_selector, element)
} { }) {
return false return false
} }
match selector.next { match selector.next {
@ -479,77 +482,77 @@ fn matches_simple_selector<E:TElement,N:TNode<E>>(selector: &SimpleSelector, ele
// TODO: case-sensitivity depends on the document type // TODO: case-sensitivity depends on the document type
// TODO: intern element names // TODO: intern element names
LocalNameSelector(ref name) => { LocalNameSelector(ref name) => {
do element.with_element |element: &E| { element.with_element(|element: &E| {
element.get_local_name().eq_ignore_ascii_case(name.as_slice()) element.get_local_name().eq_ignore_ascii_case(name.as_slice())
} })
} }
NamespaceSelector(ref url) => { NamespaceSelector(ref url) => {
do element.with_element |element: &E| { element.with_element(|element: &E| {
element.get_namespace_url() == url.as_slice() element.get_namespace_url() == url.as_slice()
} })
} }
// TODO: case-sensitivity depends on the document type and quirks mode // TODO: case-sensitivity depends on the document type and quirks mode
// TODO: cache and intern IDs on elements. // TODO: cache and intern IDs on elements.
IDSelector(ref id) => { IDSelector(ref id) => {
do element.with_element |element: &E| { element.with_element(|element: &E| {
match element.get_attr(None, "id") { match element.get_attr(None, "id") {
Some(attr) => str::eq_slice(attr, *id), Some(attr) => str::eq_slice(attr, *id),
None => false None => false
} }
} })
} }
// TODO: cache and intern classe names on elements. // TODO: cache and intern classe names on elements.
ClassSelector(ref class) => { ClassSelector(ref class) => {
do element.with_element |element: &E| { element.with_element(|element: &E| {
match element.get_attr(None, "class") { match element.get_attr(None, "class") {
None => false, None => false,
// TODO: case-sensitivity depends on the document type and quirks mode // TODO: case-sensitivity depends on the document type and quirks mode
Some(ref class_attr) Some(ref class_attr)
=> class_attr.split_iter(SELECTOR_WHITESPACE).any(|c| c == class.as_slice()), => class_attr.split(SELECTOR_WHITESPACE).any(|c| c == class.as_slice()),
} }
} })
} }
AttrExists(ref attr) => match_attribute(attr, element, |_| true), AttrExists(ref attr) => match_attribute(attr, element, |_| true),
AttrEqual(ref attr, ref value) => match_attribute(attr, element, |v| v == value.as_slice()), AttrEqual(ref attr, ref value) => match_attribute(attr, element, |v| v == value.as_slice()),
AttrIncludes(ref attr, ref value) => do match_attribute(attr, element) |attr_value| { AttrIncludes(ref attr, ref value) => match_attribute(attr, element, |attr_value| {
attr_value.split_iter(SELECTOR_WHITESPACE).any(|v| v == value.as_slice()) attr_value.split(SELECTOR_WHITESPACE).any(|v| v == value.as_slice())
}, }),
AttrDashMatch(ref attr, ref value, ref dashing_value) AttrDashMatch(ref attr, ref value, ref dashing_value)
=> do match_attribute(attr, element) |attr_value| { => match_attribute(attr, element, |attr_value| {
attr_value == value.as_slice() || attr_value.starts_with(dashing_value.as_slice()) attr_value == value.as_slice() || attr_value.starts_with(dashing_value.as_slice())
}, }),
AttrPrefixMatch(ref attr, ref value) => do match_attribute(attr, element) |attr_value| { AttrPrefixMatch(ref attr, ref value) => match_attribute(attr, element, |attr_value| {
attr_value.starts_with(value.as_slice()) attr_value.starts_with(value.as_slice())
}, }),
AttrSubstringMatch(ref attr, ref value) => do match_attribute(attr, element) |attr_value| { AttrSubstringMatch(ref attr, ref value) => match_attribute(attr, element, |attr_value| {
attr_value.contains(value.as_slice()) attr_value.contains(value.as_slice())
}, }),
AttrSuffixMatch(ref attr, ref value) => do match_attribute(attr, element) |attr_value| { AttrSuffixMatch(ref attr, ref value) => match_attribute(attr, element, |attr_value| {
attr_value.ends_with(value.as_slice()) attr_value.ends_with(value.as_slice())
}, }),
AnyLink => { AnyLink => {
do element.with_element |element: &E| { element.with_element(|element: &E| {
element.get_link().is_some() element.get_link().is_some()
} })
} }
Link => { Link => {
do element.with_element |element: &E| { element.with_element(|element: &E| {
match element.get_link() { match element.get_link() {
Some(url) => !url_is_visited(url), Some(url) => !url_is_visited(url),
None => false, None => false,
} }
} })
} }
Visited => { Visited => {
do element.with_element |element: &E| { element.with_element(|element: &E| {
match element.get_link() { match element.get_link() {
Some(url) => url_is_visited(url), Some(url) => url_is_visited(url),
None => false, None => false,
} }
} })
} }
FirstChild => matches_first_child(element), FirstChild => matches_first_child(element),
@ -583,7 +586,8 @@ fn url_is_visited(_url: &str) -> bool {
} }
#[inline] #[inline]
fn matches_generic_nth_child<E:TElement, fn matches_generic_nth_child<'a,
E:TElement,
N:TNode<E>>( N:TNode<E>>(
element: &N, element: &N,
a: i32, a: i32,
@ -601,15 +605,6 @@ fn matches_generic_nth_child<E:TElement,
None => return false None => return false
}; };
let mut element_local_name = "";
let mut element_namespace = "";
if is_of_type {
do element.with_element |element: &E| {
element_local_name = element.get_local_name();
element_namespace = element.get_namespace_url();
}
}
let mut index = 1; let mut index = 1;
loop { loop {
if is_from_end { if is_from_end {
@ -626,12 +621,14 @@ fn matches_generic_nth_child<E:TElement,
if node.is_element() { if node.is_element() {
if is_of_type { if is_of_type {
do node.with_element |node: &E| { element.with_element(|element: &E| {
if element_local_name == node.get_local_name() && node.with_element(|node: &E| {
element_namespace == node.get_namespace_url() { if element.get_local_name() == node.get_local_name() &&
index += 1; element.get_namespace_url() == node.get_namespace_url() {
} index += 1;
} }
})
})
} else { } else {
index += 1; index += 1;
} }
@ -704,18 +701,17 @@ fn match_attribute<E:TElement,
N:TNode<E>>( N:TNode<E>>(
attr: &AttrSelector, attr: &AttrSelector,
element: &N, element: &N,
f: &fn(&str) -> bool) f: |&str| -> bool)
-> bool { -> bool {
do element.with_element |element: &E| { element.with_element(|element: &E| {
// FIXME: avoid .clone() here? See #1367 // FIXME: avoid .clone() here? See #1367
match element.get_attr(attr.namespace.clone(), attr.name) { match element.get_attr(attr.namespace.clone(), attr.name) {
None => false, None => false,
Some(value) => f(value) Some(value) => f(value)
} }
} })
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use extra::arc::Arc; use extra::arc::Arc;

View file

@ -27,9 +27,6 @@ pub struct Selector {
specificity: u32, specificity: u32,
} }
pub static STYLE_ATTRIBUTE_SPECIFICITY: u32 = 1 << 31;
#[deriving(Eq, Clone)] #[deriving(Eq, Clone)]
pub enum PseudoElement { pub enum PseudoElement {
Before, Before,
@ -203,19 +200,19 @@ fn compute_specificity(mut selector: &CompoundSelector,
specificity: &mut Specificity) { specificity: &mut Specificity) {
for simple_selector in simple_selectors.iter() { for simple_selector in simple_selectors.iter() {
match simple_selector { match simple_selector {
&LocalNameSelector(*) => specificity.element_selectors += 1, &LocalNameSelector(..) => specificity.element_selectors += 1,
&IDSelector(*) => specificity.id_selectors += 1, &IDSelector(..) => specificity.id_selectors += 1,
&ClassSelector(*) &ClassSelector(..)
| &AttrExists(*) | &AttrEqual(*) | &AttrIncludes(*) | &AttrDashMatch(*) | &AttrExists(..) | &AttrEqual(..) | &AttrIncludes(..) | &AttrDashMatch(..)
| &AttrPrefixMatch(*) | &AttrSubstringMatch(*) | &AttrSuffixMatch(*) | &AttrPrefixMatch(..) | &AttrSubstringMatch(..) | &AttrSuffixMatch(..)
| &AnyLink | &Link | &Visited | &AnyLink | &Link | &Visited
| &FirstChild | &LastChild | &OnlyChild | &Root | &FirstChild | &LastChild | &OnlyChild | &Root
// | &Empty | &Lang(*) // | &Empty | &Lang(*)
| &NthChild(*) | &NthLastChild(*) | &NthChild(..) | &NthLastChild(..)
| &NthOfType(*) | &NthLastOfType(*) | &NthOfType(..) | &NthLastOfType(..)
| &FirstOfType | &LastOfType | &OnlyOfType | &FirstOfType | &LastOfType | &OnlyOfType
=> specificity.class_like_selectors += 1, => specificity.class_like_selectors += 1,
&NamespaceSelector(*) => (), &NamespaceSelector(..) => (),
&Negation(ref negated) &Negation(ref negated)
=> simple_selectors_specificity(negated.as_slice(), specificity), => simple_selectors_specificity(negated.as_slice(), specificity),
} }

View file

@ -2,21 +2,18 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#[link(name = "style", #[crate_id = "github.com/mozilla/servo#style:0.1"];
vers = "0.1", #[crate_type = "lib"];
uuid = "4a50ca00-3283-11e3-aa6e-0800200c9a66",
url = "http://servo.org/")];
#[comment = "The Servo Parallel Browser Project"]; #[comment = "The Servo Parallel Browser Project"];
#[license = "MPL"]; #[license = "MPL"];
#[crate_type = "lib"];
#[feature(globs, macro_rules, managed_boxes)]; #[feature(globs, macro_rules, managed_boxes)];
extern mod extra; extern mod extra;
extern mod cssparser; extern mod cssparser;
extern mod encoding; extern mod encoding;
extern mod servo_util (name = "util"); extern mod servo_util = "util";
// Public API // Public API

View file

@ -151,7 +151,7 @@ pub fn parse_nested_at_rule(lower_name: &str, rule: AtRule,
pub fn iter_style_rules<'a>(rules: &[CSSRule], device: &media_queries::Device, pub fn iter_style_rules<'a>(rules: &[CSSRule], device: &media_queries::Device,
callback: &fn(&StyleRule)) { callback: |&StyleRule|) {
for rule in rules.iter() { for rule in rules.iter() {
match *rule { match *rule {
CSSStyleRule(ref rule) => callback(rule), CSSStyleRule(ref rule) => callback(rule),

View file

@ -7,7 +7,7 @@ use std::hashmap::HashMap;
pub trait Cache<K: Eq, V: Clone> { pub trait Cache<K: Eq, V: Clone> {
fn insert(&mut self, key: K, value: V); fn insert(&mut self, key: K, value: V);
fn find(&mut self, key: &K) -> Option<V>; fn find(&mut self, key: &K) -> Option<V>;
fn find_or_create(&mut self, key: &K, blk: &fn(&K) -> V) -> V; fn find_or_create(&mut self, key: &K, blk: |&K| -> V) -> V;
fn evict_all(&mut self); fn evict_all(&mut self);
} }
@ -33,7 +33,7 @@ impl<K: Clone + Eq, V: Clone> Cache<K,V> for MonoCache<K,V> {
} }
} }
fn find_or_create(&mut self, key: &K, blk: &fn(&K) -> V) -> V { fn find_or_create(&mut self, key: &K, blk: |&K| -> V) -> V {
match self.find(key) { match self.find(key) {
Some(value) => value, Some(value) => value,
None => { None => {
@ -87,7 +87,7 @@ impl<K: Clone + Eq + Hash, V: Clone> Cache<K,V> for HashCache<K,V> {
} }
} }
fn find_or_create(&mut self, key: &K, blk: &fn(&K) -> V) -> V { fn find_or_create(&mut self, key: &K, blk: |&K| -> V) -> V {
self.entries.find_or_insert_with(key.clone(), blk).clone() self.entries.find_or_insert_with(key.clone(), blk).clone()
} }
@ -149,7 +149,7 @@ impl<K: Clone + Eq, V: Clone> Cache<K,V> for LRUCache<K,V> {
} }
} }
fn find_or_create(&mut self, key: &K, blk: &fn(&K) -> V) -> V { fn find_or_create(&mut self, key: &K, blk: |&K| -> V) -> V {
match self.entries.iter().position(|&(ref k, _)| *k == *key) { match self.entries.iter().position(|&(ref k, _)| *k == *key) {
Some(pos) => self.touch(pos), Some(pos) => self.touch(pos),
None => { None => {
@ -191,7 +191,7 @@ fn test_lru_cache() {
assert!(cache.find(&4).is_some()); // (2, 4) (no change) assert!(cache.find(&4).is_some()); // (2, 4) (no change)
// Test find_or_create. // Test find_or_create.
do cache.find_or_create(&1) |_| { one }; // (4, 1) cache.find_or_create(&1, |_| { one }); // (4, 1)
assert!(cache.find(&1).is_some()); // (4, 1) (no change) assert!(cache.find(&1).is_some()); // (4, 1) (no change)
assert!(cache.find(&2).is_none()); // (4, 1) (no change) assert!(cache.find(&2).is_none()); // (4, 1) (no change)

View file

@ -2,8 +2,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use std::rt::io; use std::io;
use std::rt::io::Writer; use std::io::Writer;
use std::vec::raw::buf_as_slice; use std::vec::raw::buf_as_slice;
use std::cast::transmute; use std::cast::transmute;
use std::mem::size_of; use std::mem::size_of;

View file

@ -124,10 +124,6 @@ impl ToPrimitive for Au {
} }
} }
pub fn box<T:Clone + Ord + Add<T,T> + Sub<T,T>>(x: T, y: T, w: T, h: T) -> Rect<T> {
Rect(Point2D(x, y), Size2D(w, h))
}
impl Au { impl Au {
/// FIXME(pcwalton): Workaround for lack of cross crate inlining of newtype structs! /// FIXME(pcwalton): Workaround for lack of cross crate inlining of newtype structs!
#[inline] #[inline]

View file

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use std::rt::io::{io_error, IoError}; use std::io::{io_error, IoError};
/// Helper for catching an I/O error and wrapping it in a Result object. The /// Helper for catching an I/O error and wrapping it in a Result object. The
/// return result will be the last I/O error that happened or the result of the /// return result will be the last I/O error that happened or the result of the
@ -10,7 +10,7 @@ use std::rt::io::{io_error, IoError};
/// ///
/// FIXME: This is a copy of std::rt::io::result which doesn't exist yet in our /// FIXME: This is a copy of std::rt::io::result which doesn't exist yet in our
/// version of Rust. We should switch after the next Rust upgrade. /// version of Rust. We should switch after the next Rust upgrade.
pub fn result<T>(cb: &fn() -> T) -> Result<T, IoError> { pub fn result<T>(cb: || -> T) -> Result<T, IoError> {
let mut err = None; let mut err = None;
let ret = io_error::cond.trap(|e| err = Some(e)).inside(cb); let ret = io_error::cond.trap(|e| err = Some(e)).inside(cb);
match err { match err {

View file

@ -1,141 +0,0 @@
/* 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/. */
//! An in-place, dynamically borrowable slot. Useful for "mutable fields". Assuming this works out
//! well, this type should be upstreamed to the Rust standard library.
use std::cast;
use std::util;
#[unsafe_no_drop_flag]
#[no_freeze]
pub struct Slot<T> {
// NB: Must be priv, or else someone could borrow it.
priv value: T,
priv immutable_borrow_count: u8,
priv mutably_borrowed: bool,
}
impl<T:Clone> Clone for Slot<T> {
#[inline]
fn clone(&self) -> Slot<T> {
Slot {
value: self.value.clone(),
immutable_borrow_count: 0,
mutably_borrowed: false,
}
}
}
#[unsafe_destructor]
impl<T> Drop for Slot<T> {
fn drop(&mut self) {
// Noncopyable.
}
}
pub struct SlotRef<'self,T> {
ptr: &'self T,
priv immutable_borrow_count: *mut u8,
}
#[unsafe_destructor]
impl<'self,T> Drop for SlotRef<'self,T> {
#[inline]
fn drop(&mut self) {
unsafe {
*self.immutable_borrow_count -= 1
}
}
}
pub struct MutSlotRef<'self,T> {
ptr: &'self mut T,
priv mutably_borrowed: *mut bool,
}
#[unsafe_destructor]
impl<'self,T> Drop for MutSlotRef<'self,T> {
#[inline]
fn drop(&mut self) {
unsafe {
*self.mutably_borrowed = false
}
}
}
impl<T> Slot<T> {
#[inline]
pub fn init(value: T) -> Slot<T> {
Slot {
value: value,
immutable_borrow_count: 0,
mutably_borrowed: false,
}
}
/// Borrows the data immutably. This function is thread-safe, but *bad things will happen if
/// you try to mutate the data while one of these pointers is held*.
#[inline]
pub unsafe fn borrow_unchecked<'a>(&'a self) -> &'a T {
&self.value
}
#[inline]
pub fn borrow<'a>(&'a self) -> SlotRef<'a,T> {
unsafe {
if self.immutable_borrow_count == 255 || self.mutably_borrowed {
self.fail()
}
let immutable_borrow_count = cast::transmute_mut(&self.immutable_borrow_count);
*immutable_borrow_count += 1;
SlotRef {
ptr: &self.value,
immutable_borrow_count: immutable_borrow_count,
}
}
}
#[inline]
pub fn mutate<'a>(&'a self) -> MutSlotRef<'a,T> {
unsafe {
if self.immutable_borrow_count > 0 || self.mutably_borrowed {
self.fail()
}
let mutably_borrowed = cast::transmute_mut(&self.mutably_borrowed);
*mutably_borrowed = true;
MutSlotRef {
ptr: cast::transmute_mut(&self.value),
mutably_borrowed: mutably_borrowed,
}
}
}
#[inline]
pub fn set(&self, value: T) {
*self.mutate().ptr = value
}
/// Replaces the slot's value with the given value and returns the old value.
#[inline]
pub fn replace(&self, value: T) -> T {
util::replace(self.mutate().ptr, value)
}
#[inline(never)]
pub fn fail(&self) -> ! {
fail!("slot is borrowed")
}
}
impl<T:Clone> Slot<T> {
#[inline]
pub fn get(&self) -> T {
self.value.clone()
}
}

View file

@ -4,25 +4,36 @@
//! Timing functions. //! Timing functions.
use extra::sort::tim_sort;
use extra::time::precise_time_ns; use extra::time::precise_time_ns;
use extra::treemap::TreeMap; use extra::treemap::TreeMap;
use std::comm::{Port, SendDeferred, SharedChan}; use std::comm::{Port, SharedChan};
use std::iter::AdditiveIterator; use std::iter::AdditiveIterator;
use std::rt::io::timer::Timer;
use std::task::spawn_with;
// TODO: This code should be changed to use the commented code that uses timers
// directly, once native timers land in Rust.
extern {
pub fn usleep(secs: u64) -> u32;
}
pub struct Timer;
impl Timer {
pub fn sleep(ms: u64) {
//
// let mut timer = Timer::new().unwrap();
// timer.sleep(period);
unsafe { usleep((ms * 1000)); }
}
}
// front-end representation of the profiler used to communicate with the profiler // front-end representation of the profiler used to communicate with the profiler
#[deriving(Clone)] #[deriving(Clone)]
pub struct ProfilerChan(SharedChan<ProfilerMsg>); pub struct ProfilerChan(SharedChan<ProfilerMsg>);
impl ProfilerChan { impl ProfilerChan {
pub fn new(chan: Chan<ProfilerMsg>) -> ProfilerChan { pub fn send(&self, msg: ProfilerMsg) {
ProfilerChan(SharedChan::new(chan)) (**self).send(msg);
}
pub fn send_deferred(&self, msg: ProfilerMsg) {
(**self).send_deferred(msg);
} }
} }
@ -100,32 +111,35 @@ pub struct Profiler {
} }
impl Profiler { impl Profiler {
pub fn create(port: Port<ProfilerMsg>, chan: ProfilerChan, period: Option<f64>) { pub fn create(period: Option<f64>) -> ProfilerChan {
let (port, chan) = SharedChan::new();
match period { match period {
Some(period) => { Some(period) => {
let period = (period * 1000f64) as u64; let period = (period * 1000f64) as u64;
do spawn { let chan = chan.clone();
let mut timer = Timer::new().unwrap(); spawn(proc() {
loop { loop {
timer.sleep(period); Timer::sleep(period);
if !chan.try_send(PrintMsg) { if !chan.try_send(PrintMsg) {
break; break;
} }
} }
} });
// Spawn the profiler // Spawn the profiler
do spawn_with(port) |port| { spawn(proc() {
let mut profiler = Profiler::new(port); let mut profiler = Profiler::new(port);
profiler.start(); profiler.start();
} });
} }
None => { None => {
// no-op to handle profiler messages when the profiler is inactive // no-op to handle profiler messages when the profiler is inactive
do spawn_with(port) |port| { spawn(proc() {
while port.try_recv().is_some() {} while port.recv_opt().is_some() {}
} });
} }
} }
ProfilerChan(chan)
} }
pub fn new(port: Port<ProfilerMsg>) -> Profiler { pub fn new(port: Port<ProfilerMsg>) -> Profiler {
@ -138,7 +152,7 @@ impl Profiler {
pub fn start(&mut self) { pub fn start(&mut self) {
loop { loop {
let msg = self.port.try_recv(); let msg = self.port.recv_opt();
match msg { match msg {
Some (msg) => self.handle_msg(msg), Some (msg) => self.handle_msg(msg),
None => break None => break
@ -151,7 +165,7 @@ impl Profiler {
TimeMsg(category, t) => self.buckets.find_mut(&category).unwrap().push(t), TimeMsg(category, t) => self.buckets.find_mut(&category).unwrap().push(t),
PrintMsg => match self.last_msg { PrintMsg => match self.last_msg {
// only print if more data has arrived since the last printout // only print if more data has arrived since the last printout
Some(TimeMsg(*)) => self.print_buckets(), Some(TimeMsg(..)) => self.print_buckets(),
_ => () _ => ()
}, },
}; };
@ -165,7 +179,13 @@ impl Profiler {
for (category, data) in self.buckets.iter() { for (category, data) in self.buckets.iter() {
// FIXME(XXX): TreeMap currently lacks mut_iter() // FIXME(XXX): TreeMap currently lacks mut_iter()
let mut data = data.clone(); let mut data = data.clone();
tim_sort(data); data.sort_by(|a, b| {
if a < b {
Less
} else {
Greater
}
});
let data_len = data.len(); let data_len = data.len();
if data_len > 0 { if data_len > 0 {
let (mean, median, &min, &max) = let (mean, median, &min, &max) =
@ -184,17 +204,17 @@ impl Profiler {
pub fn profile<T>(category: ProfilerCategory, pub fn profile<T>(category: ProfilerCategory,
profiler_chan: ProfilerChan, profiler_chan: ProfilerChan,
callback: &fn() -> T) callback: || -> T)
-> T { -> T {
let start_time = precise_time_ns(); let start_time = precise_time_ns();
let val = callback(); let val = callback();
let end_time = precise_time_ns(); let end_time = precise_time_ns();
let ms = ((end_time - start_time) as f64 / 1000000f64); let ms = ((end_time - start_time) as f64 / 1000000f64);
profiler_chan.send_deferred(TimeMsg(category, ms)); profiler_chan.send(TimeMsg(category, ms));
return val; return val;
} }
pub fn time<T>(msg: &str, callback: &fn() -> T) -> T{ pub fn time<T>(msg: &str, callback: || -> T) -> T{
let start_time = precise_time_ns(); let start_time = precise_time_ns();
let val = callback(); let val = callback();
let end_time = precise_time_ns(); let end_time = precise_time_ns();

View file

@ -73,7 +73,7 @@ pub fn make_url(str_url: ~str, current_url: Option<Url>) -> Url {
// Drop whitespace within data: URLs, e.g. newlines within a base64 // Drop whitespace within data: URLs, e.g. newlines within a base64
// src="..." block. Whitespace intended as content should be // src="..." block. Whitespace intended as content should be
// %-encoded or base64'd. // %-encoded or base64'd.
str_url.iter().filter(|&c| !c.is_whitespace()).collect() str_url.chars().filter(|&c| !c.is_whitespace()).collect()
}, },
_ => str_url _ => str_url
} }

View file

@ -2,10 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#[link(name = "util", #[crate_id = "github.com/mozilla/servo#util:0.1"];
vers = "0.1",
uuid = "48421f49-17cf-41c5-a68e-ff669ff2ecd5",
url = "http://servo.org/")];
#[crate_type = "lib"]; #[crate_type = "lib"];
#[feature(macro_rules, managed_boxes)]; #[feature(macro_rules, managed_boxes)];
@ -16,7 +13,6 @@ extern mod geom;
pub mod cache; pub mod cache;
pub mod geometry; pub mod geometry;
pub mod range; pub mod range;
pub mod slot;
pub mod time; pub mod time;
pub mod url; pub mod url;
pub mod vec; pub mod vec;

View file

@ -4,13 +4,13 @@
use std::cmp::{Ord, Eq}; use std::cmp::{Ord, Eq};
pub trait BinarySearchMethods<'self, T: Ord + Eq> { pub trait BinarySearchMethods<'a, T: Ord + Eq> {
fn binary_search(&self, key: &T) -> Option<&'self T>; fn binary_search(&self, key: &T) -> Option<&'a T>;
fn binary_search_index(&self, key: &T) -> Option<uint>; fn binary_search_index(&self, key: &T) -> Option<uint>;
} }
impl<'self, T: Ord + Eq> BinarySearchMethods<'self, T> for &'self [T] { impl<'a, T: Ord + Eq> BinarySearchMethods<'a, T> for &'a [T] {
fn binary_search(&self, key: &T) -> Option<&'self T> { fn binary_search(&self, key: &T) -> Option<&'a T> {
self.binary_search_index(key).map(|i| &self[i]) self.binary_search_index(key).map(|i| &self[i])
} }
@ -39,6 +39,7 @@ impl<'self, T: Ord + Eq> BinarySearchMethods<'self, T> for &'self [T] {
} }
} }
#[cfg(test)]
fn test_find_all_elems<T: Eq + Ord>(arr: &[T]) { fn test_find_all_elems<T: Eq + Ord>(arr: &[T]) {
let mut i = 0; let mut i = 0;
while i < arr.len() { while i < arr.len() {
@ -47,6 +48,7 @@ fn test_find_all_elems<T: Eq + Ord>(arr: &[T]) {
} }
} }
#[cfg(test)]
fn test_miss_all_elems<T: Eq + Ord>(arr: &[T], misses: &[T]) { fn test_miss_all_elems<T: Eq + Ord>(arr: &[T], misses: &[T]) {
let mut i = 0; let mut i = 0;
while i < misses.len() { while i < misses.len() {
@ -57,6 +59,7 @@ fn test_miss_all_elems<T: Eq + Ord>(arr: &[T], misses: &[T]) {
} }
} }
#[cfg(test)]
fn test_match<T: Eq>(b: &T, a: Option<&T>) -> bool { fn test_match<T: Eq>(b: &T, a: Option<&T>) -> bool {
match a { match a {
None => false, None => false,
@ -70,9 +73,8 @@ pub fn zip_copies<A: Clone, B: Clone>(avec: &[A], bvec: &[B]) -> ~[(A,B)] {
.collect() .collect()
} }
#[test]
fn should_find_all_elements() { fn should_find_all_elements() {
#[test];
let arr_odd = [1, 2, 4, 6, 7, 8, 9]; let arr_odd = [1, 2, 4, 6, 7, 8, 9];
let arr_even = [1, 2, 5, 6, 7, 8, 9, 42]; let arr_even = [1, 2, 5, 6, 7, 8, 9, 42];
let arr_double = [1, 1, 2, 2, 6, 8, 22]; let arr_double = [1, 1, 2, 2, 6, 8, 22];
@ -88,9 +90,8 @@ fn should_find_all_elements() {
test_find_all_elems(arr_three); test_find_all_elems(arr_three);
} }
#[test]
fn should_not_find_missing_elements() { fn should_not_find_missing_elements() {
#[test];
let arr_odd = [1, 2, 4, 6, 7, 8, 9]; let arr_odd = [1, 2, 4, 6, 7, 8, 9];
let arr_even = [1, 2, 5, 6, 7, 8, 9, 42]; let arr_even = [1, 2, 5, 6, 7, 8, 9, 42];
let arr_double = [1, 1, 2, 2, 6, 8, 22]; let arr_double = [1, 1, 2, 2, 6, 8, 22];

@ -1 +1 @@
Subproject commit d0c6dd720f90e2e8f8d8a103754195096531b531 Subproject commit 3f9c99be6ab7f733ec38e6c566a9cfb441e8f47d

Some files were not shown because too many files have changed in this diff Show more