mirror of
https://github.com/servo/servo.git
synced 2025-06-19 14:48:59 +01:00
Upgrade to latest Rust.
This commit is contained in:
parent
728fb9a7de
commit
a7ef1cd35e
127 changed files with 1892 additions and 2501 deletions
4
.gitmodules
vendored
4
.gitmodules
vendored
|
@ -66,7 +66,7 @@
|
|||
url = https://github.com/mozilla-servo/skia.git
|
||||
[submodule "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"]
|
||||
path = src/support/alert/rust-alert
|
||||
url = https://github.com/mozilla-servo/rust-alert.git
|
||||
|
@ -112,7 +112,7 @@
|
|||
branch = rust-servo
|
||||
[submodule "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"]
|
||||
path = src/platform/android/servo-android-glue
|
||||
url = https://github.com/webconvforge/servo-android-glue.git
|
||||
|
|
2
configure
vendored
2
configure
vendored
|
@ -615,7 +615,7 @@ then
|
|||
cd ${CFG_BUILD_DIR}src/compiler/rust
|
||||
RUST_CONFIGURE_ARGS="--enable-debug"
|
||||
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
|
||||
${CFG_SRC_DIR}src/compiler/rust/configure ${RUST_CONFIGURE_ARGS}
|
||||
cd ${CFG_BUILD_DIR}
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit f6b236b9d2780edc1336ea5f62c2ba0fed6e34c5
|
||||
Subproject commit d3b3c66a3a54a0455b068ede8fe2f48ed99ca908
|
|
@ -1,4 +1,4 @@
|
|||
# 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
|
||||
# build bots then the contents should be changed so git updates the mtime.
|
||||
2014-01-02
|
||||
2014-01-08
|
||||
|
|
|
@ -150,14 +150,14 @@ pub struct ClipDisplayItem<E> {
|
|||
need_clip: bool
|
||||
}
|
||||
|
||||
pub enum DisplayItemIterator<'self,E> {
|
||||
pub enum DisplayItemIterator<'a,E> {
|
||||
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]
|
||||
fn next(&mut self) -> Option<&'self DisplayItem<E>> {
|
||||
fn next(&mut self) -> Option<&'a DisplayItem<E>> {
|
||||
match *self {
|
||||
EmptyDisplayItemIterator => None,
|
||||
ParentDisplayItemIterator(ref mut subiterator) => subiterator.next(),
|
||||
|
@ -192,12 +192,12 @@ impl<E> DisplayItem<E> {
|
|||
let text_run = text.text_run.get();
|
||||
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()
|
||||
});
|
||||
let origin = text.base.bounds.origin;
|
||||
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,
|
||||
text.text_run.get(),
|
||||
&text.range,
|
||||
|
@ -264,10 +264,10 @@ impl<E> DisplayItem<E> {
|
|||
pub fn children<'a>(&'a self) -> DisplayItemIterator<'a,E> {
|
||||
match *self {
|
||||
ClipDisplayItemClass(ref clip) => ParentDisplayItemIterator(clip.child_list.iter()),
|
||||
SolidColorDisplayItemClass(*) |
|
||||
TextDisplayItemClass(*) |
|
||||
ImageDisplayItemClass(*) |
|
||||
BorderDisplayItemClass(*) => EmptyDisplayItemIterator,
|
||||
SolidColorDisplayItemClass(..) |
|
||||
TextDisplayItemClass(..) |
|
||||
ImageDisplayItemClass(..) |
|
||||
BorderDisplayItemClass(..) => EmptyDisplayItemIterator,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,13 +10,11 @@ use geom::{Point2D, Rect, Size2D};
|
|||
use std::cast;
|
||||
use std::ptr;
|
||||
use std::str;
|
||||
use std::vec;
|
||||
use std::rc::RcMut;
|
||||
use std::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
use servo_util::cache::{Cache, HashCache};
|
||||
use servo_util::range::Range;
|
||||
use servo_util::time::ProfilerChan;
|
||||
use style::computed_values::{text_decoration, font_weight, font_style};
|
||||
|
||||
use color::Color;
|
||||
use font_context::FontContext;
|
||||
use servo_util::geometry::Au;
|
||||
|
@ -73,7 +71,7 @@ impl FontTableTagConversions for FontTableTag {
|
|||
}
|
||||
|
||||
pub trait FontTableMethods {
|
||||
fn with_buffer(&self, &fn(*u8, uint));
|
||||
fn with_buffer(&self, |*u8, uint|);
|
||||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
|
@ -108,12 +106,6 @@ pub struct FontStyle {
|
|||
pub type SpecifiedFontStyle = 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
|
||||
// options, such as point size.
|
||||
|
||||
|
@ -153,11 +145,11 @@ pub struct FontGroup {
|
|||
// style of the first western font in group, which is
|
||||
// used for purposes of calculating text run metrics.
|
||||
style: UsedFontStyle,
|
||||
fonts: ~[RcMut<Font>]
|
||||
fonts: ~[Rc<RefCell<Font>>]
|
||||
}
|
||||
|
||||
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 {
|
||||
families: families,
|
||||
style: (*style).clone(),
|
||||
|
@ -173,7 +165,7 @@ impl FontGroup {
|
|||
assert!(self.fonts.len() > 0);
|
||||
|
||||
// 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)
|
||||
})
|
||||
}
|
||||
|
@ -218,18 +210,16 @@ pub struct Font {
|
|||
style: UsedFontStyle,
|
||||
metrics: FontMetrics,
|
||||
backend: BackendType,
|
||||
profiler_chan: ProfilerChan,
|
||||
shape_cache: HashCache<~str, Arc<GlyphStore>>,
|
||||
glyph_advance_cache: HashCache<u32, FractionalPixel>,
|
||||
}
|
||||
|
||||
impl<'self> Font {
|
||||
impl<'a> Font {
|
||||
pub fn new_from_buffer(ctx: &FontContext,
|
||||
buffer: ~[u8],
|
||||
style: &SpecifiedFontStyle,
|
||||
backend: BackendType,
|
||||
profiler_chan: ProfilerChan)
|
||||
-> Result<RcMut<Font>, ()> {
|
||||
backend: BackendType)
|
||||
-> Result<Rc<RefCell<Font>>, ()> {
|
||||
let handle = FontHandleMethods::new_from_buffer(&ctx.handle, buffer, style);
|
||||
let handle: FontHandle = if handle.is_ok() {
|
||||
handle.unwrap()
|
||||
|
@ -240,22 +230,21 @@ impl<'self> Font {
|
|||
let metrics = handle.get_metrics();
|
||||
// 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,
|
||||
azure_font: None,
|
||||
shaper: None,
|
||||
style: (*style).clone(),
|
||||
metrics: metrics,
|
||||
backend: backend,
|
||||
profiler_chan: profiler_chan,
|
||||
shape_cache: HashCache::new(),
|
||||
glyph_advance_cache: HashCache::new(),
|
||||
}));
|
||||
})));
|
||||
}
|
||||
|
||||
pub fn new_from_adopted_handle(_fctx: &FontContext, handle: FontHandle,
|
||||
style: &SpecifiedFontStyle, backend: BackendType,
|
||||
profiler_chan: ProfilerChan) -> Font {
|
||||
style: &SpecifiedFontStyle, backend: BackendType)
|
||||
-> Font {
|
||||
let metrics = handle.get_metrics();
|
||||
|
||||
Font {
|
||||
|
@ -265,15 +254,14 @@ impl<'self> Font {
|
|||
style: (*style).clone(),
|
||||
metrics: metrics,
|
||||
backend: backend,
|
||||
profiler_chan: profiler_chan,
|
||||
shape_cache: HashCache::new(),
|
||||
glyph_advance_cache: HashCache::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_from_existing_handle(fctx: &FontContext, handle: &FontHandle,
|
||||
style: &SpecifiedFontStyle, backend: BackendType,
|
||||
profiler_chan: ProfilerChan) -> Result<RcMut<Font>,()> {
|
||||
style: &SpecifiedFontStyle, backend: BackendType)
|
||||
-> Result<Rc<RefCell<Font>>,()> {
|
||||
|
||||
// TODO(Issue #179): convert between specified and used font style here?
|
||||
let styled_handle = match handle.clone_with_style(&fctx.handle, style) {
|
||||
|
@ -281,14 +269,14 @@ impl<'self> Font {
|
|||
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
|
||||
match self.shaper {
|
||||
Some(ref shaper) => {
|
||||
let s: &'self Shaper = shaper;
|
||||
let s: &'a Shaper = shaper;
|
||||
return s;
|
||||
},
|
||||
None => {}
|
||||
|
@ -349,7 +337,6 @@ impl<'self> Font {
|
|||
|
||||
|
||||
impl Font {
|
||||
#[fixed_stack_segment]
|
||||
pub fn draw_text_into_context(&mut self,
|
||||
rctx: &RenderContext,
|
||||
run: &~TextRun,
|
||||
|
@ -399,7 +386,7 @@ impl Font {
|
|||
if azglyph_buf_len == 0 { return; } // Otherwise the Quartz backend will assert.
|
||||
|
||||
let glyphbuf = struct__AzGlyphBuffer {
|
||||
mGlyphs: vec::raw::to_ptr(azglyphs),
|
||||
mGlyphs: azglyphs.as_ptr(),
|
||||
mNumGlyphs: azglyph_buf_len as uint32_t
|
||||
};
|
||||
|
||||
|
@ -441,11 +428,11 @@ impl Font {
|
|||
|
||||
//FIXME (ksh8281)
|
||||
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);
|
||||
self.shaper.get_ref().shape_text(*txt, &mut glyphs);
|
||||
Arc::new(glyphs)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_descriptor(&self) -> FontDescriptor {
|
||||
|
@ -457,12 +444,12 @@ impl Font {
|
|||
}
|
||||
|
||||
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) {
|
||||
Some(adv) => adv,
|
||||
None => /* FIXME: Need fallback strategy */ 10f64 as FractionalPixel
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,8 @@ use platform::font_context::FontContextHandle;
|
|||
use azure::azure_hl::BackendType;
|
||||
use std::hashmap::HashMap;
|
||||
|
||||
use std::rc::RcMut;
|
||||
use std::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
|
||||
|
||||
pub trait FontContextHandleMethods {
|
||||
|
@ -23,16 +24,16 @@ pub trait FontContextHandleMethods {
|
|||
}
|
||||
|
||||
pub struct FontContext {
|
||||
instance_cache: LRUCache<FontDescriptor, RcMut<Font>>,
|
||||
instance_cache: LRUCache<FontDescriptor, Rc<RefCell<Font>>>,
|
||||
font_list: Option<FontList>, // only needed by layout
|
||||
group_cache: LRUCache<SpecifiedFontStyle, RcMut<FontGroup>>,
|
||||
group_cache: LRUCache<SpecifiedFontStyle, Rc<RefCell<FontGroup>>>,
|
||||
handle: FontContextHandle,
|
||||
backend: BackendType,
|
||||
generic_fonts: HashMap<~str,~str>,
|
||||
profiler_chan: ProfilerChan,
|
||||
}
|
||||
|
||||
impl<'self> FontContext {
|
||||
impl FontContext {
|
||||
pub fn new(backend: BackendType,
|
||||
needs_font_list: bool,
|
||||
profiler_chan: ProfilerChan)
|
||||
|
@ -61,11 +62,8 @@ impl<'self> FontContext {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_font_list(&'self self) -> &'self FontList {
|
||||
self.font_list.get_ref()
|
||||
}
|
||||
|
||||
pub fn get_resolved_font_for_style(&mut self, style: &SpecifiedFontStyle) -> RcMut<FontGroup> {
|
||||
pub fn get_resolved_font_for_style(&mut self, style: &SpecifiedFontStyle)
|
||||
-> Rc<RefCell<FontGroup>> {
|
||||
match self.group_cache.find(style) {
|
||||
Some(fg) => {
|
||||
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) {
|
||||
Some(f) => {
|
||||
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 = ~[];
|
||||
|
||||
debug!("(create font group) --- starting ---");
|
||||
|
@ -140,8 +139,7 @@ impl<'self> FontContext {
|
|||
Some(ref result) => {
|
||||
found = true;
|
||||
let instance = self.get_font_by_descriptor(result);
|
||||
|
||||
for font in instance.iter() { fonts.push(font.clone()); }
|
||||
instance.map(|font| fonts.push(font.clone()));
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
|
@ -179,10 +177,7 @@ impl<'self> FontContext {
|
|||
match font_desc {
|
||||
Some(ref fd) => {
|
||||
let instance = self.get_font_by_descriptor(fd);
|
||||
|
||||
for font in instance.iter() {
|
||||
fonts.push(font.clone());
|
||||
}
|
||||
instance.map(|font| fonts.push(font.clone()));
|
||||
},
|
||||
None => { }
|
||||
};
|
||||
|
@ -194,22 +189,28 @@ impl<'self> FontContext {
|
|||
|
||||
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 {
|
||||
// TODO(Issue #174): implement by-platform-name font selectors.
|
||||
&SelectorPlatformIdentifier(ref identifier) => {
|
||||
let result_handle = self.handle.create_font_from_identifier((*identifier).clone(),
|
||||
desc.style.clone());
|
||||
do result_handle.and_then |handle| {
|
||||
Ok(RcMut::new(Font::new_from_adopted_handle(self,
|
||||
result_handle.and_then(|handle| {
|
||||
Ok(
|
||||
Rc::from_mut(
|
||||
RefCell::new(
|
||||
Font::new_from_adopted_handle(self,
|
||||
handle,
|
||||
&desc.style,
|
||||
self.backend,
|
||||
self.profiler_chan.clone())))
|
||||
}
|
||||
self.backend))))
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ pub struct FontList {
|
|||
prof_chan: ProfilerChan,
|
||||
}
|
||||
|
||||
impl<'self> FontList {
|
||||
impl FontList {
|
||||
pub fn new(fctx: &FontContextHandle,
|
||||
prof_chan: ProfilerChan)
|
||||
-> FontList {
|
||||
|
@ -48,20 +48,20 @@ impl<'self> FontList {
|
|||
// changed. Does OSX have a notification for this event?
|
||||
//
|
||||
// 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();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn find_font_in_family(&'self mut self,
|
||||
pub fn find_font_in_family<'a>(&'a mut self,
|
||||
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
|
||||
// look up canonical name
|
||||
if self.family_map.contains_key(family_name) {
|
||||
//FIXME call twice!(ksh8281)
|
||||
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'.
|
||||
// if such family exists, try to match style to a font
|
||||
let result = s.find_font_for_style(&mut self.handle, style);
|
||||
|
@ -83,12 +83,12 @@ impl<'self> FontList {
|
|||
}
|
||||
|
||||
// Holds a specific font family, and the various
|
||||
pub struct FontFamily<'self> {
|
||||
pub struct FontFamily {
|
||||
family_name: ~str,
|
||||
entries: ~[FontEntry],
|
||||
}
|
||||
|
||||
impl<'self> FontFamily {
|
||||
impl FontFamily {
|
||||
pub fn new(family_name: &str) -> FontFamily {
|
||||
FontFamily {
|
||||
family_name: family_name.to_str(),
|
||||
|
@ -104,8 +104,8 @@ impl<'self> FontFamily {
|
|||
assert!(self.entries.len() > 0)
|
||||
}
|
||||
|
||||
pub fn find_font_for_style(&'self mut self, list: &FontListHandle, style: &SpecifiedFontStyle)
|
||||
-> Option<&'self FontEntry> {
|
||||
pub fn find_font_for_style<'a>(&'a mut self, list: &FontListHandle, style: &SpecifiedFontStyle)
|
||||
-> Option<&'a FontEntry> {
|
||||
self.load_family_variations(list);
|
||||
|
||||
// TODO(Issue #189): optimize lookup for
|
||||
|
|
|
@ -2,10 +2,7 @@
|
|||
* 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/. */
|
||||
|
||||
#[link(name = "gfx",
|
||||
vers = "0.1",
|
||||
uuid = "0106bb54-6ea9-45bf-a39e-a738621f15e5",
|
||||
url = "http://servo.org/")];
|
||||
#[crate_id = "github.com/mozilla/servo#gfx:0.1"];
|
||||
#[crate_type = "lib"];
|
||||
|
||||
#[feature(globs, managed_boxes, macro_rules)];
|
||||
|
@ -16,10 +13,10 @@ extern mod geom;
|
|||
extern mod layers;
|
||||
extern mod stb_image;
|
||||
extern mod png;
|
||||
extern mod servo_net (name = "net");
|
||||
extern mod servo_util (name = "util");
|
||||
extern mod servo_net = "net";
|
||||
extern mod servo_util = "util";
|
||||
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
|
||||
// shapers. For now, however, this is a hard dependency.
|
||||
|
|
|
@ -113,9 +113,9 @@ pub fn from_cmdline_args(args: &[~str]) -> Opts {
|
|||
};
|
||||
|
||||
// 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()
|
||||
};
|
||||
});
|
||||
|
||||
let cpu_painting = opt_match.opt_present("c");
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ pub struct FontTable {
|
|||
}
|
||||
|
||||
impl FontTableMethods for FontTable {
|
||||
fn with_buffer(&self, _blk: &fn(*u8, uint)) {
|
||||
fn with_buffer(&self, _blk: |*u8, uint|) {
|
||||
fail!()
|
||||
}
|
||||
}
|
||||
|
@ -61,7 +61,6 @@ pub struct FontHandle {
|
|||
|
||||
#[unsafe_destructor]
|
||||
impl Drop for FontHandle {
|
||||
#[fixed_stack_segment]
|
||||
fn drop(&mut self) {
|
||||
assert!(self.face.is_not_null());
|
||||
unsafe {
|
||||
|
@ -80,9 +79,7 @@ impl FontHandleMethods for FontHandle {
|
|||
let ft_ctx: FT_Library = fctx.ctx.borrow().ctx;
|
||||
if ft_ctx.is_null() { return Err(()); }
|
||||
|
||||
let face_result = do buf.as_imm_buf |bytes: *u8, len: uint| {
|
||||
create_face_from_buffer(ft_ctx, bytes, len, style.pt_size)
|
||||
};
|
||||
let face_result = create_face_from_buffer(ft_ctx, buf.as_ptr(), buf.len(), style.pt_size);
|
||||
|
||||
// TODO: this could be more simply written as result::chain
|
||||
// and moving buf into the struct ctor, but cant' move out of
|
||||
|
@ -99,7 +96,6 @@ impl FontHandleMethods for FontHandle {
|
|||
Err(()) => Err(())
|
||||
};
|
||||
|
||||
#[fixed_stack_segment]
|
||||
fn create_face_from_buffer(lib: FT_Library, cbuf: *u8, cbuflen: uint, pt_size: f64)
|
||||
-> Result<FT_Face, ()> {
|
||||
unsafe {
|
||||
|
@ -129,14 +125,12 @@ impl FontHandleMethods for FontHandle {
|
|||
fn family_name(&self) -> ~str {
|
||||
unsafe { str::raw::from_c_str((*self.face).family_name) }
|
||||
}
|
||||
#[fixed_stack_segment]
|
||||
fn face_name(&self) -> ~str {
|
||||
unsafe { str::raw::from_c_str(FT_Get_Postscript_Name(self.face)) }
|
||||
}
|
||||
fn is_italic(&self) -> bool {
|
||||
unsafe { (*self.face).style_flags & FT_STYLE_FLAG_ITALIC != 0 }
|
||||
}
|
||||
#[fixed_stack_segment]
|
||||
fn boldness(&self) -> font_weight::T {
|
||||
let default_weight = font_weight::Weight400;
|
||||
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,
|
||||
codepoint: char) -> Option<GlyphIndex> {
|
||||
assert!(self.face.is_not_null());
|
||||
|
@ -194,7 +187,6 @@ impl FontHandleMethods for FontHandle {
|
|||
}
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
fn glyph_h_advance(&self,
|
||||
glyph: GlyphIndex) -> Option<FractionalPixel> {
|
||||
assert!(self.face.is_not_null());
|
||||
|
@ -216,7 +208,6 @@ impl FontHandleMethods for FontHandle {
|
|||
}
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
fn get_metrics(&self) -> FontMetrics {
|
||||
/* TODO(Issue #76): complete me */
|
||||
let face = self.get_face_rec();
|
||||
|
@ -272,8 +263,7 @@ impl FontHandleMethods for FontHandle {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'self> FontHandle {
|
||||
#[fixed_stack_segment]
|
||||
impl<'a> FontHandle {
|
||||
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_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,
|
||||
style: &SpecifiedFontStyle) -> Result<FontHandle, ()> {
|
||||
unsafe {
|
||||
|
@ -295,10 +284,10 @@ impl<'self> FontHandle {
|
|||
|
||||
let mut face: FT_Face = ptr::null();
|
||||
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,
|
||||
face_index, ptr::to_mut_unsafe_ptr(&mut face));
|
||||
}
|
||||
});
|
||||
if face.is_null() {
|
||||
return Err(());
|
||||
}
|
||||
|
@ -314,7 +303,6 @@ impl<'self> FontHandle {
|
|||
}
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
pub fn new_from_file_unstyled(fctx: &FontContextHandle, file: ~str)
|
||||
-> Result<FontHandle, ()> {
|
||||
unsafe {
|
||||
|
@ -323,10 +311,10 @@ impl<'self> FontHandle {
|
|||
|
||||
let mut face: FT_Face = ptr::null();
|
||||
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,
|
||||
face_index, ptr::to_mut_unsafe_ptr(&mut face));
|
||||
}
|
||||
});
|
||||
if face.is_null() {
|
||||
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 {
|
||||
&(*self.face)
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ pub struct FontContextHandle {
|
|||
}
|
||||
|
||||
impl Drop for FreeTypeLibraryHandle {
|
||||
#[fixed_stack_segment]
|
||||
fn drop(&mut self) {
|
||||
assert!(self.ctx.is_not_null());
|
||||
unsafe { FT_Done_FreeType(self.ctx) };
|
||||
|
@ -32,7 +31,6 @@ impl Drop for FreeTypeLibraryHandle {
|
|||
}
|
||||
|
||||
impl FontContextHandle {
|
||||
#[fixed_stack_segment]
|
||||
pub fn new() -> FontContextHandle {
|
||||
unsafe {
|
||||
let ctx: FT_Library = ptr::null();
|
||||
|
@ -49,10 +47,10 @@ impl FontContextHandleMethods for FontContextHandle {
|
|||
fn create_font_from_identifier(&self, name: ~str, style: UsedFontStyle)
|
||||
-> Result<FontHandle, ()> {
|
||||
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);
|
||||
FontHandle::new_from_file(self, file_name.to_owned(), &style)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,6 @@ impl FontListHandle {
|
|||
FontListHandle { fctx: fctx.clone() }
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
pub fn get_available_families(&self) -> FontFamilyMap {
|
||||
let mut family_map : FontFamilyMap = HashMap::new();
|
||||
unsafe {
|
||||
|
@ -50,7 +49,7 @@ impl FontListHandle {
|
|||
let font = (*fontSet).fonts.offset(i);
|
||||
let family: *FcChar8 = ptr::null();
|
||||
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 {
|
||||
let family_name = str::raw::from_c_str(family as *c_char);
|
||||
debug!("Creating new FontFamily for family: {:s}", family_name);
|
||||
|
@ -58,13 +57,12 @@ impl FontListHandle {
|
|||
family_map.insert(family_name, new_family);
|
||||
v += 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return family_map;
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
pub fn load_variations_for_family(&self, family: &mut FontFamily) {
|
||||
debug!("getting variations for {:?}", family);
|
||||
unsafe {
|
||||
|
@ -73,22 +71,22 @@ impl FontListHandle {
|
|||
let font_set_array_ptr = ptr::to_unsafe_ptr(&font_set);
|
||||
let pattern = FcPatternCreate();
|
||||
assert!(pattern.is_not_null());
|
||||
do "family".to_c_str().with_ref |FC_FAMILY| {
|
||||
do family.family_name.to_c_str().with_ref |family_name| {
|
||||
"family".to_c_str().with_ref(|FC_FAMILY| {
|
||||
family.family_name.to_c_str().with_ref(|family_name| {
|
||||
let ok = FcPatternAddString(pattern, FC_FAMILY, family_name as *FcChar8);
|
||||
assert!(ok != 0);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
let object_set = FcObjectSetCreate();
|
||||
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);
|
||||
}
|
||||
do "index".to_c_str().with_ref |FC_INDEX| {
|
||||
});
|
||||
"index".to_c_str().with_ref(|FC_INDEX| {
|
||||
FcObjectSetAdd(object_set, FC_INDEX);
|
||||
}
|
||||
});
|
||||
|
||||
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) {
|
||||
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();
|
||||
if FcPatternGetString(*font, FC_FILE, 0, &file) == FcResultMatch {
|
||||
str::raw::from_c_str(file as *libc::c_char)
|
||||
} else {
|
||||
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;
|
||||
if FcPatternGetInteger(*font, FC_INDEX, 0, &index) == FcResultMatch {
|
||||
index
|
||||
} else {
|
||||
fail!();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
debug!("variation file: {}", file);
|
||||
debug!("variation index: {}", index);
|
||||
|
@ -141,7 +139,6 @@ struct AutoPattern {
|
|||
}
|
||||
|
||||
impl Drop for AutoPattern {
|
||||
#[fixed_stack_segment]
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
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, ()> {
|
||||
unsafe {
|
||||
let config = FcConfigGetCurrent();
|
||||
let wrapper = AutoPattern { pattern: FcPatternCreate() };
|
||||
let pattern = wrapper.pattern;
|
||||
let res = do "family".to_c_str().with_ref |FC_FAMILY| {
|
||||
do name.to_c_str().with_ref |family| {
|
||||
let res = "family".to_c_str().with_ref(|FC_FAMILY| {
|
||||
name.to_c_str().with_ref(|family| {
|
||||
FcPatternAddString(pattern, FC_FAMILY, family as *FcChar8)
|
||||
}
|
||||
};
|
||||
})
|
||||
});
|
||||
if res != 1 {
|
||||
debug!("adding family to pattern failed");
|
||||
return Err(());
|
||||
|
@ -168,18 +164,18 @@ pub fn path_from_identifier(name: ~str, style: &UsedFontStyle) -> Result<~str, (
|
|||
match style.style {
|
||||
font_style::normal => (),
|
||||
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)
|
||||
};
|
||||
});
|
||||
if res != 1 {
|
||||
debug!("adding slant to pattern failed");
|
||||
return Err(());
|
||||
}
|
||||
},
|
||||
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)
|
||||
};
|
||||
});
|
||||
if res != 1 {
|
||||
debug!("adding slant(oblique) to pattern failed");
|
||||
return Err(());
|
||||
|
@ -188,9 +184,9 @@ pub fn path_from_identifier(name: ~str, style: &UsedFontStyle) -> Result<~str, (
|
|||
}
|
||||
|
||||
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)
|
||||
};
|
||||
});
|
||||
if res != 1 {
|
||||
debug!("adding weight to pattern failed");
|
||||
return Err(());
|
||||
|
@ -211,9 +207,9 @@ pub fn path_from_identifier(name: ~str, style: &UsedFontStyle) -> Result<~str, (
|
|||
}
|
||||
|
||||
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)
|
||||
};
|
||||
});
|
||||
if res != FcResultMatch {
|
||||
debug!("getting filename for font failed");
|
||||
return Err(());
|
||||
|
|
|
@ -41,7 +41,7 @@ pub struct FontTable {
|
|||
}
|
||||
|
||||
impl FontTableMethods for FontTable {
|
||||
fn with_buffer(&self, _blk: &fn(*u8, uint)) {
|
||||
fn with_buffer(&self, _blk: |*u8, uint|) {
|
||||
fail!()
|
||||
}
|
||||
}
|
||||
|
@ -61,7 +61,6 @@ pub struct FontHandle {
|
|||
|
||||
#[unsafe_destructor]
|
||||
impl Drop for FontHandle {
|
||||
#[fixed_stack_segment]
|
||||
fn drop(&mut self) {
|
||||
assert!(self.face.is_not_null());
|
||||
unsafe {
|
||||
|
@ -80,9 +79,7 @@ impl FontHandleMethods for FontHandle {
|
|||
let ft_ctx: FT_Library = fctx.ctx.borrow().ctx;
|
||||
if ft_ctx.is_null() { return Err(()); }
|
||||
|
||||
let face_result = do buf.as_imm_buf |bytes: *u8, len: uint| {
|
||||
create_face_from_buffer(ft_ctx, bytes, len, style.pt_size)
|
||||
};
|
||||
let face_result = create_face_from_buffer(ft_ctx, buf.as_ptr(), buf.len(), style.pt_size);
|
||||
|
||||
// TODO: this could be more simply written as result::chain
|
||||
// and moving buf into the struct ctor, but cant' move out of
|
||||
|
@ -99,7 +96,6 @@ impl FontHandleMethods for FontHandle {
|
|||
Err(()) => Err(())
|
||||
};
|
||||
|
||||
#[fixed_stack_segment]
|
||||
fn create_face_from_buffer(lib: FT_Library, cbuf: *u8, cbuflen: uint, pt_size: f64)
|
||||
-> Result<FT_Face, ()> {
|
||||
unsafe {
|
||||
|
@ -129,14 +125,12 @@ impl FontHandleMethods for FontHandle {
|
|||
fn family_name(&self) -> ~str {
|
||||
unsafe { str::raw::from_c_str((*self.face).family_name) }
|
||||
}
|
||||
#[fixed_stack_segment]
|
||||
fn face_name(&self) -> ~str {
|
||||
unsafe { str::raw::from_c_str(FT_Get_Postscript_Name(self.face)) }
|
||||
}
|
||||
fn is_italic(&self) -> bool {
|
||||
unsafe { (*self.face).style_flags & FT_STYLE_FLAG_ITALIC != 0 }
|
||||
}
|
||||
#[fixed_stack_segment]
|
||||
fn boldness(&self) -> font_weight::T {
|
||||
let default_weight = font_weight::Weight400;
|
||||
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,
|
||||
codepoint: char) -> Option<GlyphIndex> {
|
||||
assert!(self.face.is_not_null());
|
||||
|
@ -194,7 +187,6 @@ impl FontHandleMethods for FontHandle {
|
|||
}
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
fn glyph_h_advance(&self,
|
||||
glyph: GlyphIndex) -> Option<FractionalPixel> {
|
||||
assert!(self.face.is_not_null());
|
||||
|
@ -216,7 +208,6 @@ impl FontHandleMethods for FontHandle {
|
|||
}
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
fn get_metrics(&self) -> FontMetrics {
|
||||
/* TODO(Issue #76): complete me */
|
||||
let face = self.get_face_rec();
|
||||
|
@ -272,8 +263,7 @@ impl FontHandleMethods for FontHandle {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'self> FontHandle {
|
||||
#[fixed_stack_segment]
|
||||
impl<'a> FontHandle {
|
||||
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_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,
|
||||
style: &SpecifiedFontStyle) -> Result<FontHandle, ()> {
|
||||
unsafe {
|
||||
|
@ -295,10 +284,10 @@ impl<'self> FontHandle {
|
|||
|
||||
let mut face: FT_Face = ptr::null();
|
||||
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,
|
||||
face_index, ptr::to_mut_unsafe_ptr(&mut face));
|
||||
}
|
||||
});
|
||||
if face.is_null() {
|
||||
return Err(());
|
||||
}
|
||||
|
@ -314,7 +303,6 @@ impl<'self> FontHandle {
|
|||
}
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
pub fn new_from_file_unstyled(fctx: &FontContextHandle, file: ~str)
|
||||
-> Result<FontHandle, ()> {
|
||||
unsafe {
|
||||
|
@ -323,10 +311,10 @@ impl<'self> FontHandle {
|
|||
|
||||
let mut face: FT_Face = ptr::null();
|
||||
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,
|
||||
face_index, ptr::to_mut_unsafe_ptr(&mut face));
|
||||
}
|
||||
});
|
||||
if face.is_null() {
|
||||
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 {
|
||||
&(*self.face)
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ pub struct FontContextHandle {
|
|||
}
|
||||
|
||||
impl Drop for FreeTypeLibraryHandle {
|
||||
#[fixed_stack_segment]
|
||||
fn drop(&mut self) {
|
||||
assert!(self.ctx.is_not_null());
|
||||
unsafe { FT_Done_FreeType(self.ctx) };
|
||||
|
@ -32,7 +31,6 @@ impl Drop for FreeTypeLibraryHandle {
|
|||
}
|
||||
|
||||
impl FontContextHandle {
|
||||
#[fixed_stack_segment]
|
||||
pub fn new() -> FontContextHandle {
|
||||
unsafe {
|
||||
let ctx: FT_Library = ptr::null();
|
||||
|
@ -49,10 +47,10 @@ impl FontContextHandleMethods for FontContextHandle {
|
|||
fn create_font_from_identifier(&self, name: ~str, style: UsedFontStyle)
|
||||
-> Result<FontHandle, ()> {
|
||||
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);
|
||||
FontHandle::new_from_file(self, file_name.to_owned(), &style)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,6 @@ impl FontListHandle {
|
|||
FontListHandle { fctx: fctx.clone() }
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
pub fn get_available_families(&self) -> FontFamilyMap {
|
||||
let mut family_map : FontFamilyMap = HashMap::new();
|
||||
unsafe {
|
||||
|
@ -50,7 +49,7 @@ impl FontListHandle {
|
|||
let font = (*fontSet).fonts.offset(i);
|
||||
let family: *FcChar8 = ptr::null();
|
||||
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 {
|
||||
let family_name = str::raw::from_c_str(family as *c_char);
|
||||
debug!("Creating new FontFamily for family: {:s}", family_name);
|
||||
|
@ -58,13 +57,12 @@ impl FontListHandle {
|
|||
family_map.insert(family_name, new_family);
|
||||
v += 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return family_map;
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
pub fn load_variations_for_family(&self, family: &mut FontFamily) {
|
||||
debug!("getting variations for {:?}", family);
|
||||
unsafe {
|
||||
|
@ -73,22 +71,22 @@ impl FontListHandle {
|
|||
let font_set_array_ptr = ptr::to_unsafe_ptr(&font_set);
|
||||
let pattern = FcPatternCreate();
|
||||
assert!(pattern.is_not_null());
|
||||
do "family".to_c_str().with_ref |FC_FAMILY| {
|
||||
do family.family_name.to_c_str().with_ref |family_name| {
|
||||
"family".to_c_str().with_ref(|FC_FAMILY| {
|
||||
family.family_name.to_c_str().with_ref(|family_name| {
|
||||
let ok = FcPatternAddString(pattern, FC_FAMILY, family_name as *FcChar8);
|
||||
assert!(ok != 0);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
let object_set = FcObjectSetCreate();
|
||||
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);
|
||||
}
|
||||
do "index".to_c_str().with_ref |FC_INDEX| {
|
||||
});
|
||||
"index".to_c_str().with_ref(|FC_INDEX| {
|
||||
FcObjectSetAdd(object_set, FC_INDEX);
|
||||
}
|
||||
});
|
||||
|
||||
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) {
|
||||
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();
|
||||
if FcPatternGetString(*font, FC_FILE, 0, &file) == FcResultMatch {
|
||||
str::raw::from_c_str(file as *libc::c_char)
|
||||
} else {
|
||||
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;
|
||||
if FcPatternGetInteger(*font, FC_INDEX, 0, &index) == FcResultMatch {
|
||||
index
|
||||
} else {
|
||||
fail!();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
debug!("variation file: {}", file);
|
||||
debug!("variation index: {}", index);
|
||||
|
@ -141,7 +139,6 @@ struct AutoPattern {
|
|||
}
|
||||
|
||||
impl Drop for AutoPattern {
|
||||
#[fixed_stack_segment]
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
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, ()> {
|
||||
unsafe {
|
||||
let config = FcConfigGetCurrent();
|
||||
let wrapper = AutoPattern { pattern: FcPatternCreate() };
|
||||
let pattern = wrapper.pattern;
|
||||
let res = do "family".to_c_str().with_ref |FC_FAMILY| {
|
||||
do name.to_c_str().with_ref |family| {
|
||||
let res = "family".to_c_str().with_ref(|FC_FAMILY| {
|
||||
name.to_c_str().with_ref(|family| {
|
||||
FcPatternAddString(pattern, FC_FAMILY, family as *FcChar8)
|
||||
}
|
||||
};
|
||||
})
|
||||
});
|
||||
if res != 1 {
|
||||
debug!("adding family to pattern failed");
|
||||
return Err(());
|
||||
|
@ -168,18 +164,18 @@ pub fn path_from_identifier(name: ~str, style: &UsedFontStyle) -> Result<~str, (
|
|||
match style.style {
|
||||
font_style::normal => (),
|
||||
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)
|
||||
};
|
||||
});
|
||||
if res != 1 {
|
||||
debug!("adding slant to pattern failed");
|
||||
return Err(());
|
||||
}
|
||||
},
|
||||
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)
|
||||
};
|
||||
});
|
||||
if res != 1 {
|
||||
debug!("adding slant(oblique) to pattern failed");
|
||||
return Err(());
|
||||
|
@ -188,9 +184,9 @@ pub fn path_from_identifier(name: ~str, style: &UsedFontStyle) -> Result<~str, (
|
|||
}
|
||||
|
||||
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)
|
||||
};
|
||||
});
|
||||
if res != 1 {
|
||||
debug!("adding weight to pattern failed");
|
||||
return Err(());
|
||||
|
@ -211,9 +207,9 @@ pub fn path_from_identifier(name: ~str, style: &UsedFontStyle) -> Result<~str, (
|
|||
}
|
||||
|
||||
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)
|
||||
};
|
||||
});
|
||||
if res != FcResultMatch {
|
||||
debug!("getting filename for font failed");
|
||||
return Err(());
|
||||
|
|
|
@ -29,7 +29,6 @@ use core_text::font_descriptor::{kCTFontDefaultOrientation};
|
|||
use core_text;
|
||||
|
||||
use std::ptr;
|
||||
use std::vec;
|
||||
|
||||
pub struct FontTable {
|
||||
data: CFData,
|
||||
|
@ -47,8 +46,8 @@ impl FontTable {
|
|||
}
|
||||
|
||||
impl FontTableMethods for FontTable {
|
||||
fn with_buffer(&self, blk: &fn(*u8, uint)) {
|
||||
blk(vec::raw::to_ptr(self.data.bytes()), self.data.len() as uint);
|
||||
fn with_buffer(&self, blk: |*u8, 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> {
|
||||
let result: Option<CFData> = self.ctfont.get_font_table(tag);
|
||||
do result.and_then |data| {
|
||||
result.and_then(|data| {
|
||||
Some(FontTable::wrap(data))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn face_identifier(&self) -> ~str {
|
||||
|
|
|
@ -27,8 +27,8 @@ impl FontContextHandleMethods for FontContextHandle {
|
|||
style: UsedFontStyle)
|
||||
-> Result<FontHandle, ()> {
|
||||
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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,14 +18,13 @@ use geom::side_offsets::SideOffsets2D;
|
|||
use servo_net::image::base::Image;
|
||||
use png::{RGBA8, K8, KA8};
|
||||
use servo_util::geometry::Au;
|
||||
use std::vec;
|
||||
use std::libc::types::common::c99::uint16_t;
|
||||
use std::libc::size_t;
|
||||
|
||||
pub struct RenderContext<'self> {
|
||||
draw_target: &'self DrawTarget,
|
||||
font_ctx: &'self mut ~FontContext,
|
||||
opts: &'self Opts,
|
||||
pub struct RenderContext<'a> {
|
||||
draw_target: &'a DrawTarget,
|
||||
font_ctx: &'a mut ~FontContext,
|
||||
opts: &'a Opts,
|
||||
/// The rectangle that this context encompasses in page coordinates.
|
||||
page_rect: Rect<f32>,
|
||||
/// The rectangle that this context encompasses in screen coordinates (pixels).
|
||||
|
@ -39,8 +38,8 @@ enum Direction {
|
|||
Bottom
|
||||
}
|
||||
|
||||
impl<'self> RenderContext<'self> {
|
||||
pub fn get_draw_target(&self) -> &'self DrawTarget {
|
||||
impl<'a> RenderContext<'a> {
|
||||
pub fn get_draw_target(&self) -> &'a DrawTarget {
|
||||
self.draw_target
|
||||
}
|
||||
|
||||
|
@ -167,7 +166,7 @@ impl<'self> RenderContext<'self> {
|
|||
stroke_opts.line_width = border_width;
|
||||
dash[0] = 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;
|
||||
|
||||
let (start, end) = match direction {
|
||||
|
|
|
@ -20,7 +20,6 @@ use servo_util::time::{ProfilerChan, profile};
|
|||
use servo_util::time;
|
||||
|
||||
use std::comm::{Chan, Port, SharedChan};
|
||||
use std::task::spawn_with;
|
||||
use extra::arc::Arc;
|
||||
|
||||
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
|
||||
// generic newtypes ICE when compiled cross-crate
|
||||
#[deriving(Clone)]
|
||||
pub struct RenderChan<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 {
|
||||
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")
|
||||
}
|
||||
}
|
||||
impl<T: Send> GenericSmartChan<Msg<T>> for RenderChan<T> {
|
||||
fn try_send(&self, msg: Msg<T>) -> bool {
|
||||
|
||||
pub fn try_send(&self, msg: Msg<T>) -> bool {
|
||||
self.chan.try_send(msg)
|
||||
}
|
||||
}
|
||||
|
@ -138,9 +145,7 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
|
|||
opts: Opts,
|
||||
profiler_chan: ProfilerChan,
|
||||
shutdown_chan: Chan<()>) {
|
||||
do spawn_with((port, compositor, constellation_chan, opts, profiler_chan, shutdown_chan))
|
||||
|(port, compositor, constellation_chan, opts, profiler_chan, shutdown_chan)| {
|
||||
|
||||
spawn(proc() {
|
||||
{ // Ensures RenderTask and graphics context are destroyed before shutdown msg
|
||||
let native_graphics_context = compositor.get_graphics_metadata().map(
|
||||
|md| NativePaintingGraphicsContext::from_metadata(&md));
|
||||
|
@ -176,13 +181,12 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
|
|||
render_task.start();
|
||||
|
||||
// Destroy all the buffers.
|
||||
render_task.native_graphics_context.as_ref().map(|ctx|
|
||||
render_task.buffer_map.clear(ctx)
|
||||
);
|
||||
render_task.native_graphics_context.as_ref().map(
|
||||
|ctx| render_task.buffer_map.clear(ctx));
|
||||
}
|
||||
|
||||
shutdown_chan.send(());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn start(&mut self) {
|
||||
|
@ -243,12 +247,12 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
|
|||
}
|
||||
|
||||
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.
|
||||
let mut new_buffers = ~[];
|
||||
|
||||
// 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() {
|
||||
let width = tile.screen_rect.size.width;
|
||||
let height = tile.screen_rect.size.height;
|
||||
|
@ -293,10 +297,10 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
|
|||
ctx.clear();
|
||||
|
||||
// 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);
|
||||
ctx.draw_target.flush();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 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);
|
||||
debug!("RENDERER uploading to native surface {:d}",
|
||||
buffer.native_surface.get_id() as int);
|
||||
}
|
||||
});
|
||||
|
||||
buffer
|
||||
}
|
||||
|
@ -367,7 +371,7 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
|
|||
|
||||
new_buffers.push(buffer);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let layer_buffer_set = ~LayerBufferSet {
|
||||
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.compositor.set_render_state(IdleRenderState);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@ use std::vec;
|
|||
use std::util;
|
||||
use std::iter;
|
||||
use geom::point::Point2D;
|
||||
use extra::sort;
|
||||
|
||||
/// 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_NEWLINE: u32 = 0x00000010;
|
||||
static FLAG_CHAR_IS_LOW_SURROGATE: u32 = 0x00000020;
|
||||
static CHAR_IDENTITY_FLAGS_MASK: u32 = 0x00000038;
|
||||
//static FLAG_CHAR_IS_LOW_SURROGATE: u32 = 0x00000020;
|
||||
//static CHAR_IDENTITY_FLAGS_MASK: u32 = 0x00000038;
|
||||
|
||||
fn is_simple_glyph_id(glyphId: GlyphIndex) -> bool {
|
||||
((glyphId as u32) & GLYPH_ID_MASK) == glyphId
|
||||
|
@ -176,10 +175,6 @@ impl GlyphEntry {
|
|||
self.value & GLYPH_ID_MASK
|
||||
}
|
||||
|
||||
fn offset(&self) -> Point2D<Au> {
|
||||
Point2D(Au(0), Au(0))
|
||||
}
|
||||
|
||||
fn is_ligature_start(&self) -> bool {
|
||||
self.has_flag(!FLAG_NOT_LIGATURE_GROUP_START)
|
||||
}
|
||||
|
@ -312,7 +307,7 @@ struct DetailedGlyphStore {
|
|||
lookup_is_sorted: bool,
|
||||
}
|
||||
|
||||
impl<'self> DetailedGlyphStore {
|
||||
impl<'a> DetailedGlyphStore {
|
||||
fn new() -> DetailedGlyphStore {
|
||||
DetailedGlyphStore {
|
||||
detail_buffer: ~[], // TODO: default size?
|
||||
|
@ -345,8 +340,8 @@ impl<'self> DetailedGlyphStore {
|
|||
self.lookup_is_sorted = false;
|
||||
}
|
||||
|
||||
fn get_detailed_glyphs_for_entry(&'self self, entry_offset: uint, count: u16)
|
||||
-> &'self [DetailedGlyph] {
|
||||
fn get_detailed_glyphs_for_entry(&'a self, entry_offset: uint, count: u16)
|
||||
-> &'a [DetailedGlyph] {
|
||||
debug!("Requesting detailed glyphs[n={:u}] for entry[off={:u}]", count as uint, entry_offset);
|
||||
|
||||
// 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,
|
||||
detail_offset: u16)
|
||||
-> &'self DetailedGlyph {
|
||||
-> &'a DetailedGlyph {
|
||||
assert!((detail_offset as uint) <= self.detail_buffer.len());
|
||||
assert!(self.lookup_is_sorted);
|
||||
|
||||
|
@ -411,7 +406,13 @@ impl<'self> DetailedGlyphStore {
|
|||
let mut unsorted_records: ~[DetailedGlyphRecord] = ~[];
|
||||
util::swap(&mut self.detail_lookup, &mut 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;
|
||||
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).
|
||||
// Rather than eagerly assembling and copying glyph data, it only retrieves
|
||||
// values as they are needed from the GlyphStore, using provided offsets.
|
||||
enum GlyphInfo<'self> {
|
||||
SimpleGlyphInfo(&'self GlyphStore, uint),
|
||||
DetailGlyphInfo(&'self GlyphStore, uint, u16)
|
||||
enum GlyphInfo<'a> {
|
||||
SimpleGlyphInfo(&'a GlyphStore, uint),
|
||||
DetailGlyphInfo(&'a GlyphStore, uint, u16)
|
||||
}
|
||||
|
||||
impl<'self> GlyphInfo<'self> {
|
||||
impl<'a> GlyphInfo<'a> {
|
||||
pub fn index(self) -> GlyphIndex {
|
||||
match self {
|
||||
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
|
||||
|
@ -519,7 +506,7 @@ pub struct GlyphStore {
|
|||
is_whitespace: bool,
|
||||
}
|
||||
|
||||
impl<'self> GlyphStore {
|
||||
impl<'a> GlyphStore {
|
||||
// Initializes the glyph store, but doesn't actually shape anything.
|
||||
// Use the set_glyph, set_glyphs() methods to store glyph data.
|
||||
pub fn new(length: uint, is_whitespace: bool) -> GlyphStore {
|
||||
|
@ -606,12 +593,12 @@ impl<'self> GlyphStore {
|
|||
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))
|
||||
}
|
||||
|
||||
#[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() {
|
||||
fail!("iter_glyphs_for_range: range.begin beyond length!");
|
||||
}
|
||||
|
@ -684,17 +671,17 @@ impl<'self> GlyphStore {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct GlyphIterator<'self> {
|
||||
priv store: &'self GlyphStore,
|
||||
pub struct GlyphIterator<'a> {
|
||||
priv store: &'a GlyphStore,
|
||||
priv char_index: uint,
|
||||
priv char_range: 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.
|
||||
#[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() {
|
||||
Some(j) => Some((self.char_index,
|
||||
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.
|
||||
#[inline(never)]
|
||||
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());
|
||||
self.glyph_range = Some(range(0, glyphs.len()));
|
||||
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
|
||||
// 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
|
||||
// `next_complex_glyph()`.
|
||||
#[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
|
||||
// interferes with mutation.
|
||||
if self.glyph_range.is_some() {
|
||||
|
|
|
@ -10,15 +10,14 @@ use platform::font::FontTable;
|
|||
use text::glyph::{GlyphStore, GlyphIndex, GlyphData};
|
||||
use text::shaping::ShaperMethods;
|
||||
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::char;
|
||||
use std::libc::{c_uint, c_int, c_void, c_char};
|
||||
use std::ptr;
|
||||
use std::ptr::null;
|
||||
use std::uint;
|
||||
use std::util::ignore;
|
||||
use std::num;
|
||||
use std::vec;
|
||||
use geom::Point2D;
|
||||
use harfbuzz::{hb_blob_create, hb_face_create_for_tables};
|
||||
|
@ -63,7 +62,6 @@ pub struct ShapedGlyphEntry {
|
|||
}
|
||||
|
||||
impl ShapedGlyphData {
|
||||
#[fixed_stack_segment]
|
||||
pub fn new(buffer: *hb_buffer_t) -> ShapedGlyphData {
|
||||
unsafe {
|
||||
let glyph_count = 0;
|
||||
|
@ -143,7 +141,6 @@ pub struct Shaper {
|
|||
|
||||
#[unsafe_destructor]
|
||||
impl Drop for Shaper {
|
||||
#[fixed_stack_segment]
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
assert!(self.hb_face.is_not_null());
|
||||
|
@ -159,7 +156,6 @@ impl Drop for Shaper {
|
|||
}
|
||||
|
||||
impl Shaper {
|
||||
#[fixed_stack_segment]
|
||||
pub fn new(font: &mut Font) -> Shaper {
|
||||
unsafe {
|
||||
// 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 {
|
||||
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 {
|
||||
/// Calculate the layout metrics associated with the given text when rendered in a specific
|
||||
/// font.
|
||||
#[fixed_stack_segment]
|
||||
fn shape_text(&self, text: &str, glyphs: &mut GlyphStore) {
|
||||
unsafe {
|
||||
let hb_buffer: *hb_buffer_t = hb_buffer_create();
|
||||
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
|
||||
do text.as_imm_buf |ctext: *u8, _: uint| {
|
||||
hb_buffer_add_utf8(hb_buffer,
|
||||
ctext as *c_char,
|
||||
text.as_ptr() as *c_char,
|
||||
text.len() as c_int,
|
||||
0,
|
||||
text.len() as c_int);
|
||||
}
|
||||
|
||||
hb_shape(self.hb_font, hb_buffer, null(), 0);
|
||||
self.save_glyph_results(text, glyphs, hb_buffer);
|
||||
|
@ -261,7 +250,7 @@ impl Shaper {
|
|||
byteToGlyph = vec::from_elem(byte_max, NO_GLYPH);
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -283,7 +272,7 @@ impl Shaper {
|
|||
|
||||
debug!("text: {:s}", text);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -309,7 +298,7 @@ impl Shaper {
|
|||
// any trailing chars that do not have associated glyphs.
|
||||
while char_byte_span.end() < byte_max {
|
||||
let range = text.char_range_at(char_byte_span.end());
|
||||
ignore(range.ch);
|
||||
drop(range.ch);
|
||||
char_byte_span.extend_to(range.next);
|
||||
|
||||
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 \
|
||||
glyph", 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);
|
||||
}
|
||||
|
||||
|
@ -329,7 +318,7 @@ impl Shaper {
|
|||
let mut max_glyph_idx = glyph_span.end();
|
||||
for i in char_byte_span.eachi() {
|
||||
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
|
||||
&& byteToGlyph[covered_byte_span.end()] == NO_GLYPH {
|
||||
let range = text.char_range_at(covered_byte_span.end());
|
||||
ignore(range.ch);
|
||||
drop(range.ch);
|
||||
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..)
|
||||
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.
|
||||
if glyph_span.length() == 1 {
|
||||
|
@ -443,7 +432,7 @@ impl Shaper {
|
|||
let mut i = covered_byte_span.begin();
|
||||
loop {
|
||||
let range = text.char_range_at(i);
|
||||
ignore(range.ch);
|
||||
drop(range.ch);
|
||||
i = range.next;
|
||||
if i >= covered_byte_span.end() { break; }
|
||||
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 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.
|
||||
blob = hb_blob_create(buf as *c_char,
|
||||
len as c_uint,
|
||||
HB_MEMORY_MODE_READONLY,
|
||||
transmute(skinny_font_table_ptr),
|
||||
destroy_blob_func);
|
||||
}
|
||||
});
|
||||
|
||||
assert!(blob.is_not_null());
|
||||
blob
|
||||
|
|
|
@ -22,16 +22,16 @@ pub struct TextRun {
|
|||
glyphs: Arc<~[Arc<GlyphStore>]>,
|
||||
}
|
||||
|
||||
pub struct SliceIterator<'self> {
|
||||
priv glyph_iter: VecIterator<'self, Arc<GlyphStore>>,
|
||||
pub struct SliceIterator<'a> {
|
||||
priv glyph_iter: VecIterator<'a, Arc<GlyphStore>>,
|
||||
priv range: Range,
|
||||
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)]
|
||||
fn next(&mut self) -> Option<(&'self GlyphStore, uint, Range)> {
|
||||
fn next(&mut self) -> Option<(&'a GlyphStore, uint, Range)> {
|
||||
loop {
|
||||
let slice_glyphs = self.glyph_iter.next();
|
||||
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 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> {
|
||||
// Loop until we hit whitespace and are in a clump.
|
||||
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 {
|
||||
let glyphs = TextRun::break_and_shape(font, text);
|
||||
|
||||
|
@ -170,12 +170,12 @@ impl<'self> TextRun {
|
|||
}
|
||||
|
||||
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()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn glyphs(&'self self) -> &'self ~[Arc<GlyphStore>] {
|
||||
pub fn glyphs(&'a self) -> &'a ~[Arc<GlyphStore>] {
|
||||
self.glyphs.get()
|
||||
}
|
||||
|
||||
|
@ -216,7 +216,7 @@ impl<'self> TextRun {
|
|||
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 {
|
||||
glyph_iter: self.glyphs.get().iter(),
|
||||
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 {
|
||||
range: *range,
|
||||
clump: None,
|
||||
|
|
|
@ -24,7 +24,7 @@ pub fn transform_text(text: &str, mode: CompressionMode, incoming_whitespace: bo
|
|||
let mut out_str: ~str = ~"";
|
||||
let out_whitespace = match mode {
|
||||
CompressNone | DiscardNewline => {
|
||||
for ch in text.iter() {
|
||||
for ch in text.chars() {
|
||||
if is_discardable_char(ch, mode) {
|
||||
// TODO: record skipped char
|
||||
} else {
|
||||
|
@ -40,7 +40,7 @@ pub fn transform_text(text: &str, mode: CompressionMode, incoming_whitespace: bo
|
|||
|
||||
CompressWhitespace | CompressWhitespaceNewline => {
|
||||
let mut in_whitespace: bool = incoming_whitespace;
|
||||
for ch in text.iter() {
|
||||
for ch in text.chars() {
|
||||
// TODO: discard newlines between CJK chars
|
||||
let mut next_in_whitespace: bool = is_in_whitespace(ch, mode);
|
||||
|
||||
|
|
|
@ -34,13 +34,11 @@ use png;
|
|||
use servo_msg::compositor_msg::{Epoch, IdleRenderState, LayerBufferSet, RenderState};
|
||||
use servo_msg::constellation_msg::{ConstellationChan, NavigateMsg, ResizedWindowMsg, LoadUrlMsg, PipelineId};
|
||||
use servo_msg::constellation_msg;
|
||||
use servo_util::time::{profile, ProfilerChan};
|
||||
use servo_util::time::{profile, ProfilerChan, Timer};
|
||||
use servo_util::{time, url};
|
||||
use std::comm::Port;
|
||||
use std::num::Orderable;
|
||||
use std::path::Path;
|
||||
use std::rt::io::timer::Timer;
|
||||
use std::vec;
|
||||
|
||||
|
||||
pub struct IOCompositor {
|
||||
|
@ -157,11 +155,17 @@ impl IOCompositor {
|
|||
self.constellation_chan.send(ResizedWindowMsg(self.window_size));
|
||||
|
||||
// Enter the main event loop.
|
||||
let mut tm = Timer::new().unwrap();
|
||||
while !self.done {
|
||||
// Check for new messages coming from the rendering task.
|
||||
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.
|
||||
self.handle_window_message(self.window.recv());
|
||||
|
||||
|
@ -171,7 +175,7 @@ impl IOCompositor {
|
|||
self.composite();
|
||||
}
|
||||
|
||||
tm.sleep(10);
|
||||
Timer::sleep(10);
|
||||
|
||||
// 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 {
|
||||
|
@ -189,62 +193,65 @@ impl IOCompositor {
|
|||
|
||||
// Drain compositor port, sometimes messages contain channels that are blocking
|
||||
// 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) {
|
||||
while self.port.peek() {
|
||||
match self.port.recv() {
|
||||
Exit => {
|
||||
self.done = true
|
||||
},
|
||||
loop {
|
||||
match self.port.try_recv() {
|
||||
None => break,
|
||||
|
||||
ChangeReadyState(ready_state) => {
|
||||
Some(Exit(chan)) => {
|
||||
self.done = true;
|
||||
chan.send(());
|
||||
}
|
||||
|
||||
Some(ChangeReadyState(ready_state)) => {
|
||||
self.window.set_ready_state(ready_state);
|
||||
}
|
||||
|
||||
ChangeRenderState(render_state) => {
|
||||
Some(ChangeRenderState(render_state)) => {
|
||||
self.change_render_state(render_state);
|
||||
}
|
||||
|
||||
SetUnRenderedColor(_id, color) => {
|
||||
Some(SetUnRenderedColor(_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);
|
||||
}
|
||||
|
||||
GetGraphicsMetadata(chan) => {
|
||||
Some(GetGraphicsMetadata(chan)) => {
|
||||
chan.send(Some(azure_hl::current_graphics_metadata()));
|
||||
}
|
||||
|
||||
NewLayer(_id, new_size) => {
|
||||
Some(NewLayer(_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);
|
||||
}
|
||||
|
||||
SetLayerClipRect(id, new_rect) => {
|
||||
Some(SetLayerClipRect(id, new_rect)) => {
|
||||
self.set_layer_clip_rect(id, new_rect);
|
||||
}
|
||||
|
||||
DeleteLayer(id) => {
|
||||
Some(DeleteLayer(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);
|
||||
}
|
||||
|
||||
InvalidateRect(id, rect) => {
|
||||
Some(InvalidateRect(id, rect)) => {
|
||||
self.invalidate_rect(id, rect);
|
||||
}
|
||||
|
||||
ScrollFragmentPoint(id, point) => {
|
||||
Some(ScrollFragmentPoint(id, point)) => {
|
||||
self.scroll_fragment_to_point(id, point);
|
||||
}
|
||||
}
|
||||
|
@ -601,7 +608,7 @@ impl IOCompositor {
|
|||
}
|
||||
|
||||
fn composite(&mut self) {
|
||||
do profile(time::CompositingCategory, self.profiler_chan.clone()) {
|
||||
profile(time::CompositingCategory, self.profiler_chan.clone(), || {
|
||||
debug!("compositor: compositing");
|
||||
// Adjust the layer dimensions as necessary to correspond to the size of the window.
|
||||
self.scene.size = self.window.size();
|
||||
|
@ -616,7 +623,7 @@ impl IOCompositor {
|
|||
None => {}
|
||||
}
|
||||
rendergl::render_scene(self.context, &self.scene);
|
||||
}
|
||||
});
|
||||
|
||||
// Render to PNG. We must read from the back buffer (ie, before
|
||||
// self.window.present()) as OpenGL ES 2 does not have glReadBuffer().
|
||||
|
@ -634,9 +641,10 @@ impl IOCompositor {
|
|||
for y in range(0, height) {
|
||||
let dst_start = y * stride;
|
||||
let src_start = (height - y - 1) * stride;
|
||||
vec::bytes::copy_memory(pixels.mut_slice(dst_start, dst_start + stride),
|
||||
orig_pixels.slice(src_start, src_start + stride),
|
||||
stride);
|
||||
unsafe {
|
||||
pixels.mut_slice(dst_start, dst_start + stride)
|
||||
.copy_memory(orig_pixels.slice(src_start, src_start + stride).slice_to(stride));
|
||||
}
|
||||
}
|
||||
let img = png::Image {
|
||||
width: width as u32,
|
||||
|
|
|
@ -22,7 +22,6 @@ use script::dom::event::{ClickEvent, MouseDownEvent, MouseUpEvent};
|
|||
use script::script_task::SendEventMsg;
|
||||
use servo_msg::compositor_msg::{LayerBuffer, LayerBufferSet, Epoch, Tile};
|
||||
use servo_msg::constellation_msg::PipelineId;
|
||||
use std::cell::Cell;
|
||||
use windowing::{MouseWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEvent};
|
||||
use windowing::{MouseWindowMouseUpEvent};
|
||||
use azure::azure_hl::Color;
|
||||
|
@ -141,7 +140,7 @@ impl CompositorLayer {
|
|||
-> CompositorLayer {
|
||||
let SendableFrameTree { pipeline, children } = frame_tree;
|
||||
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 container = @mut ContainerLayer();
|
||||
match rect {
|
||||
|
@ -165,7 +164,7 @@ impl CompositorLayer {
|
|||
child: child_layer,
|
||||
container: container,
|
||||
}
|
||||
}).collect();
|
||||
})).collect();
|
||||
layer.set_occlusions();
|
||||
layer
|
||||
}
|
||||
|
@ -267,7 +266,7 @@ impl CompositorLayer {
|
|||
let mut redisplay: bool;
|
||||
{ // block here to prevent double mutable borrow of self
|
||||
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),
|
||||
Tree(ref mut quadtree) => quadtree,
|
||||
};
|
||||
|
@ -327,7 +326,7 @@ impl CompositorLayer {
|
|||
let old_rect = con.scissor;
|
||||
con.scissor = Some(new_rect);
|
||||
match self.quadtree {
|
||||
NoTree(*) => {} // Nothing to do
|
||||
NoTree(..) => {} // Nothing to do
|
||||
Tree(ref mut quadtree) => {
|
||||
match old_rect {
|
||||
Some(old_rect) => {
|
||||
|
@ -494,15 +493,15 @@ impl CompositorLayer {
|
|||
// Delete old layer.
|
||||
while current_layer_child.is_some() {
|
||||
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;
|
||||
}
|
||||
});
|
||||
self.root_layer.remove_child(trash);
|
||||
}
|
||||
|
||||
// Add new tiles.
|
||||
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),
|
||||
Tree(ref mut quadtree) => quadtree,
|
||||
};
|
||||
|
@ -544,9 +543,9 @@ impl CompositorLayer {
|
|||
buffer.native_surface.bind_to_texture(graphics_context, texture, size);
|
||||
|
||||
// Move on to the next sibling.
|
||||
do current_layer_child.unwrap().with_common |common| {
|
||||
current_layer_child.unwrap().with_common(|common| {
|
||||
common.next_sibling
|
||||
}
|
||||
})
|
||||
}
|
||||
Some(_) => fail!(~"found unexpected layer kind"),
|
||||
};
|
||||
|
@ -584,29 +583,29 @@ impl CompositorLayer {
|
|||
pub fn add_buffers(&mut self,
|
||||
graphics_context: &NativeCompositingGraphicsContext,
|
||||
pipeline_id: PipelineId,
|
||||
new_buffers: ~LayerBufferSet,
|
||||
mut new_buffers: ~LayerBufferSet,
|
||||
epoch: Epoch)
|
||||
-> Option<~LayerBufferSet> {
|
||||
let cell = Cell::new(new_buffers);
|
||||
if self.pipeline.id == pipeline_id {
|
||||
if self.epoch != epoch {
|
||||
debug!("compositor epoch mismatch: {:?} != {:?}, id: {:?}",
|
||||
self.epoch,
|
||||
epoch,
|
||||
self.pipeline.id);
|
||||
self.pipeline.render_chan.send(UnusedBufferMsg(cell.take().buffers));
|
||||
self.pipeline.render_chan.send(UnusedBufferMsg(new_buffers.buffers));
|
||||
return None;
|
||||
}
|
||||
|
||||
{
|
||||
// Block here to prevent double mutable borrow of self.
|
||||
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,
|
||||
};
|
||||
|
||||
let mut unused_tiles = ~[];
|
||||
// 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,
|
||||
buffer.screen_pos.origin.y,
|
||||
buffer.resolution, buffer));
|
||||
|
@ -623,15 +622,15 @@ impl CompositorLayer {
|
|||
for child_layer in self.children.mut_iter() {
|
||||
match child_layer.child.add_buffers(graphics_context,
|
||||
pipeline_id,
|
||||
cell.take(),
|
||||
new_buffers,
|
||||
epoch) {
|
||||
None => return None,
|
||||
Some(buffers) => cell.put_back(buffers),
|
||||
Some(buffers) => new_buffers = buffers,
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
@ -643,7 +642,7 @@ impl CompositorLayer {
|
|||
Some(i) => {
|
||||
let mut child = self.children.remove(i);
|
||||
match self.quadtree {
|
||||
NoTree(*) => {} // Nothing to do
|
||||
NoTree(..) => {} // Nothing to do
|
||||
Tree(ref mut quadtree) => {
|
||||
match child.container.scissor {
|
||||
Some(rect) => {
|
||||
|
@ -670,7 +669,7 @@ impl CompositorLayer {
|
|||
pub fn invalidate_rect(&mut self, pipeline_id: PipelineId, rect: Rect<f32>) -> bool {
|
||||
if self.pipeline.id == pipeline_id {
|
||||
let quadtree = match self.quadtree {
|
||||
NoTree(*) => return true, // Nothing to do
|
||||
NoTree(..) => return true, // Nothing to do
|
||||
Tree(ref mut quadtree) => quadtree,
|
||||
};
|
||||
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
|
||||
// tile requests. If layers are moved, resized, or deleted, these portions may be updated.
|
||||
fn set_occlusions(&mut self) {
|
||||
let quadtree = match self.quadtree {
|
||||
NoTree(*) => return, // Cannot calculate occlusions
|
||||
NoTree(..) => return, // Cannot calculate occlusions
|
||||
Tree(ref mut quadtree) => quadtree,
|
||||
};
|
||||
for child in self.children.iter().filter(|x| !x.child.hidden) {
|
||||
|
@ -726,7 +704,7 @@ impl CompositorLayer {
|
|||
/// reused.
|
||||
fn clear(&mut self) {
|
||||
match self.quadtree {
|
||||
NoTree(*) => {}
|
||||
NoTree(..) => {}
|
||||
Tree(ref mut quadtree) => {
|
||||
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.
|
||||
pub fn forget_all_tiles(&mut self) {
|
||||
match self.quadtree {
|
||||
NoTree(*) => {}
|
||||
NoTree(..) => {}
|
||||
Tree(ref mut quadtree) => {
|
||||
let tiles = quadtree.collect_tiles();
|
||||
for tile in tiles.move_iter() {
|
||||
|
|
|
@ -19,7 +19,6 @@ use servo_msg::compositor_msg::{ScriptListener, Tile};
|
|||
use servo_msg::constellation_msg::{ConstellationChan, PipelineId, ExitMsg};
|
||||
use servo_util::time::ProfilerChan;
|
||||
use std::comm::{Chan, SharedChan, Port};
|
||||
use std::comm;
|
||||
use std::num::Orderable;
|
||||
|
||||
#[cfg(target_os="linux")]
|
||||
|
@ -54,7 +53,9 @@ impl ScriptListener for CompositorChan {
|
|||
}
|
||||
|
||||
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.
|
||||
impl RenderListener for CompositorChan {
|
||||
fn get_graphics_metadata(&self) -> Option<NativeGraphicsMetadata> {
|
||||
let (port, chan) = comm::stream();
|
||||
let (port, chan) = Chan::new();
|
||||
self.chan.send(GetGraphicsMetadata(chan));
|
||||
port.recv()
|
||||
}
|
||||
|
@ -99,10 +100,12 @@ impl RenderListener for CompositorChan {
|
|||
}
|
||||
|
||||
impl CompositorChan {
|
||||
pub fn new(chan: Chan<Msg>) -> CompositorChan {
|
||||
CompositorChan {
|
||||
chan: SharedChan::new(chan),
|
||||
}
|
||||
pub fn new() -> (Port<Msg>, CompositorChan) {
|
||||
let (port, chan) = SharedChan::new();
|
||||
let compositor_chan = CompositorChan {
|
||||
chan: chan,
|
||||
};
|
||||
(port, compositor_chan)
|
||||
}
|
||||
|
||||
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.
|
||||
pub enum Msg {
|
||||
/// Requests that the compositor shut down.
|
||||
Exit,
|
||||
Exit(Chan<()>),
|
||||
/// 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
|
||||
/// is the pixel format.
|
||||
|
|
|
@ -38,7 +38,10 @@ impl NullCompositor {
|
|||
fn handle_message(&self) {
|
||||
loop {
|
||||
match self.port.recv() {
|
||||
Exit => break,
|
||||
Exit(chan) => {
|
||||
chan.send(());
|
||||
break
|
||||
}
|
||||
|
||||
GetGraphicsMetadata(chan) => {
|
||||
chan.send(None);
|
||||
|
@ -52,9 +55,9 @@ impl NullCompositor {
|
|||
// we'll notice and think about whether it needs a response, like
|
||||
// SetIds.
|
||||
|
||||
NewLayer(*) | SetLayerPageSize(*) | SetLayerClipRect(*) | DeleteLayer(*) |
|
||||
Paint(*) | InvalidateRect(*) | ChangeReadyState(*) | ChangeRenderState(*)|
|
||||
ScrollFragmentPoint(*) | SetUnRenderedColor(*)
|
||||
NewLayer(..) | SetLayerPageSize(..) | SetLayerClipRect(..) | DeleteLayer(..) |
|
||||
Paint(..) | InvalidateRect(..) | ChangeReadyState(..) | ChangeRenderState(..)|
|
||||
ScrollFragmentPoint(..) | SetUnRenderedColor(..)
|
||||
=> ()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,8 +18,6 @@ use servo_msg::compositor_msg::Tile;
|
|||
#[cfg(test)]
|
||||
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
|
||||
/// at this level are in pixel coordinates.
|
||||
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.
|
||||
/// 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.
|
||||
|
@ -137,73 +121,17 @@ impl<T: Tile> Quadtree<T> {
|
|||
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.
|
||||
pub fn get_all_tiles<'r>(&'r self) -> ~[&'r T] {
|
||||
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
|
||||
/// 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
|
||||
/// 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.
|
||||
#[cfg(test)]
|
||||
pub fn get_tile_rects_pixel(&mut self, window: Rect<int>, scale: f32) -> (~[BufferRequest], ~[T]) {
|
||||
let (ret, unused, _) = self.root.get_tile_rects(
|
||||
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.
|
||||
/// Might be useful later on, but resize() should be used for now.
|
||||
/// TODO: return tiles after shrinking
|
||||
#[cfg(test)]
|
||||
pub fn bad_resize(&mut self, width: uint, height: uint) {
|
||||
self.clip_size = Size2D(width, height);
|
||||
let longer = width.max(&height);
|
||||
|
@ -301,11 +230,6 @@ impl<T: Tile> Quadtree<T> {
|
|||
pub fn collect_tiles(&mut self) -> ~[T] {
|
||||
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> {
|
||||
|
@ -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.
|
||||
fn get_all_tiles<'r>(&'r self) -> ~[&'r T] {
|
||||
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);
|
||||
|
||||
// Figure out which quadrants the window is in
|
||||
let builder = |push: &fn(Quadrant)| {
|
||||
let builder = |push: |Quadrant|| {
|
||||
match (w_tl_quad, w_br_quad) {
|
||||
(tl, br) if tl as int == br as int => {
|
||||
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]
|
||||
|
|
|
@ -20,10 +20,7 @@ use servo_net::resource_task::ResourceTask;
|
|||
use servo_net::resource_task;
|
||||
use servo_util::time::ProfilerChan;
|
||||
use servo_util::url::make_url;
|
||||
use std::comm::Port;
|
||||
use std::comm;
|
||||
use std::hashmap::{HashMap, HashSet};
|
||||
use std::task::spawn_with;
|
||||
use std::util::replace;
|
||||
|
||||
/// 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
|
||||
impl Clone for 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()
|
||||
};
|
||||
});
|
||||
FrameTree {
|
||||
pipeline: self.pipeline,
|
||||
parent: self.parent.clone(),
|
||||
|
@ -90,41 +87,46 @@ pub struct SendableChildFrameTree {
|
|||
rect: Option<Rect<f32>>,
|
||||
}
|
||||
|
||||
impl SendableFrameTree {
|
||||
fn contains(&self, id: PipelineId) -> bool {
|
||||
self.pipeline.id == id ||
|
||||
do self.children.iter().any |&SendableChildFrameTree { frame_tree: ref frame_tree, _ }| {
|
||||
frame_tree.contains(id)
|
||||
}
|
||||
}
|
||||
// impl SendableFrameTree {
|
||||
// fn contains(&self, id: PipelineId) -> bool {
|
||||
// self.pipeline.id == id ||
|
||||
// self.children.iter().any(|&SendableChildFrameTree { frame_tree: ref frame_tree, .. }| {
|
||||
// frame_tree.contains(id)
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
|
||||
enum ReplaceResult {
|
||||
ReplacedNode(@mut FrameTree),
|
||||
OriginalNode(@mut FrameTree),
|
||||
}
|
||||
|
||||
impl FrameTree {
|
||||
fn contains(@mut self, id: PipelineId) -> bool {
|
||||
do self.iter().any |frame_tree| {
|
||||
self.iter().any(|frame_tree| {
|
||||
id == frame_tree.pipeline.id
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the frame tree whose key is id
|
||||
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
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// 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.
|
||||
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() {
|
||||
let mut child = frame_tree.children.mut_iter()
|
||||
.find(|child| child.frame_tree.pipeline.id == id);
|
||||
for child in child.mut_iter() {
|
||||
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 {
|
||||
|
@ -162,7 +164,7 @@ impl Iterator<@mut FrameTree> for FrameTreeIterator {
|
|||
fn next(&mut self) -> Option<@mut FrameTree> {
|
||||
if !self.stack.is_empty() {
|
||||
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);
|
||||
}
|
||||
Some(next)
|
||||
|
@ -223,15 +225,15 @@ impl NavigationContext {
|
|||
|
||||
/// Returns the frame trees whose keys are pipeline_id.
|
||||
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)
|
||||
};
|
||||
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)
|
||||
};
|
||||
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)
|
||||
};
|
||||
});
|
||||
from_prev.chain(from_current).chain(from_next).collect()
|
||||
}
|
||||
|
||||
|
@ -241,36 +243,25 @@ impl NavigationContext {
|
|||
let from_prev = self.previous.iter();
|
||||
|
||||
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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Constellation {
|
||||
pub fn start(constellation_port: Port<Msg>,
|
||||
constellation_chan: ConstellationChan,
|
||||
compositor_chan: CompositorChan,
|
||||
pub fn start(compositor_chan: CompositorChan,
|
||||
opts: &Opts,
|
||||
resource_task: ResourceTask,
|
||||
image_cache_task: ImageCacheTask,
|
||||
profiler_chan: ProfilerChan) {
|
||||
do spawn_with((constellation_port,
|
||||
constellation_chan.clone(),
|
||||
compositor_chan,
|
||||
resource_task,
|
||||
image_cache_task,
|
||||
profiler_chan,
|
||||
opts.clone()))
|
||||
|(constellation_port,
|
||||
constellation_chan,
|
||||
compositor_chan,
|
||||
resource_task,
|
||||
image_cache_task,
|
||||
profiler_chan,
|
||||
opts)| {
|
||||
profiler_chan: ProfilerChan)
|
||||
-> ConstellationChan {
|
||||
let (constellation_port, constellation_chan) = ConstellationChan::new();
|
||||
let constellation_chan_clone = constellation_chan.clone();
|
||||
let opts_clone = opts.clone();
|
||||
spawn(proc() {
|
||||
let mut constellation = Constellation {
|
||||
chan: constellation_chan,
|
||||
chan: constellation_chan_clone,
|
||||
request_port: constellation_port,
|
||||
compositor_chan: compositor_chan,
|
||||
resource_task: resource_task,
|
||||
|
@ -282,10 +273,11 @@ impl Constellation {
|
|||
pending_sizes: HashMap::new(),
|
||||
profiler_chan: profiler_chan,
|
||||
window_size: Size2D(500u, 500u),
|
||||
opts: opts
|
||||
opts: opts_clone,
|
||||
};
|
||||
constellation.run();
|
||||
}
|
||||
});
|
||||
constellation_chan
|
||||
}
|
||||
|
||||
fn run(&mut self) {
|
||||
|
@ -313,9 +305,9 @@ impl Constellation {
|
|||
/// 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] {
|
||||
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)
|
||||
};
|
||||
});
|
||||
matching_navi_frames.move_iter().chain(matching_pending_frames).collect()
|
||||
}
|
||||
|
||||
|
@ -323,6 +315,7 @@ impl Constellation {
|
|||
fn handle_request(&mut self, request: Msg) -> bool {
|
||||
match request {
|
||||
ExitMsg(sender) => {
|
||||
debug!("constellation exiting");
|
||||
self.handle_exit(sender);
|
||||
return false;
|
||||
}
|
||||
|
@ -499,9 +492,9 @@ impl Constellation {
|
|||
// and add the new pipeline to their sub frames.
|
||||
let frame_trees: ~[@mut FrameTree] = {
|
||||
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)
|
||||
};
|
||||
});
|
||||
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.
|
||||
// If it is not found, it simply means that this pipeline will not receive
|
||||
// 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
|
||||
};
|
||||
});
|
||||
for &pending_index in pending_index.iter() {
|
||||
let frame_change = self.pending_frames.swap_remove(pending_index);
|
||||
let to_add = frame_change.after;
|
||||
|
@ -742,9 +735,9 @@ impl Constellation {
|
|||
/// Called when the window is resized.
|
||||
fn handle_resized_window_msg(&mut self, new_size: Size2D<uint>) {
|
||||
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");
|
||||
pipeline.script_chan.send(ResizeMsg(pipeline.id, new_size));
|
||||
pipeline.script_chan.try_send(ResizeMsg(pipeline.id, new_size));
|
||||
already_seen.insert(pipeline.id);
|
||||
}
|
||||
for frame_tree in self.navigation_context.previous.iter()
|
||||
|
@ -752,7 +745,7 @@ impl Constellation {
|
|||
let pipeline = &frame_tree.pipeline;
|
||||
if !already_seen.contains(&pipeline.id) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -774,7 +767,7 @@ impl Constellation {
|
|||
fn close_pipelines(&mut self, frame_tree: @mut FrameTree) {
|
||||
// TODO(tkuehn): should only exit once per unique script task,
|
||||
// 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();
|
||||
self.pipelines.remove(&pipeline.id);
|
||||
}
|
||||
|
@ -809,9 +802,9 @@ impl Constellation {
|
|||
}
|
||||
|
||||
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()));
|
||||
match port.try_recv() {
|
||||
match port.recv_opt() {
|
||||
Some(()) => {
|
||||
for frame in frame_tree.iter() {
|
||||
frame.pipeline.grant_paint_permission();
|
||||
|
|
|
@ -11,11 +11,8 @@ use layout::wrapper::LayoutNode;
|
|||
|
||||
use extra::arc::{Arc, RWArc};
|
||||
use std::cast;
|
||||
use std::cell::Cell;
|
||||
use std::comm;
|
||||
use std::libc::uintptr_t;
|
||||
use std::rt;
|
||||
use std::task;
|
||||
use std::vec;
|
||||
use style::{TNode, Stylist, cascade};
|
||||
use style::{Before, After};
|
||||
|
@ -27,22 +24,23 @@ pub trait MatchMethods {
|
|||
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) {
|
||||
let style_attribute = do self.with_element |element| {
|
||||
let style_attribute = self.with_element(|element| {
|
||||
match *element.style_attribute() {
|
||||
None => None,
|
||||
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) => {
|
||||
layout_data.applicable_declarations = stylist.get_applicable_declarations(
|
||||
layout_data.data.applicable_declarations = stylist.get_applicable_declarations(
|
||||
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));
|
||||
layout_data.after_applicable_declarations = stylist.get_applicable_declarations(
|
||||
layout_data.data.after_applicable_declarations = stylist.get_applicable_declarations(
|
||||
self, None, Some(After));
|
||||
}
|
||||
None => fail!("no layout data")
|
||||
|
@ -60,8 +58,7 @@ impl<'self> MatchMethods for LayoutNode<'self> {
|
|||
}
|
||||
}
|
||||
|
||||
let (port, chan) = comm::stream();
|
||||
let chan = comm::SharedChan::new(chan);
|
||||
let (port, chan) = SharedChan::new();
|
||||
let mut num_spawned = 0;
|
||||
|
||||
for nodes in nodes_per_task.move_iter() {
|
||||
|
@ -77,20 +74,20 @@ impl<'self> MatchMethods for LayoutNode<'self> {
|
|||
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 {
|
||||
cast::transmute(evil)
|
||||
cast::transmute(evil.take_unwrap())
|
||||
};
|
||||
|
||||
let nodes = Cell::new(nodes);
|
||||
do stylist.read |stylist| {
|
||||
let nodes = nodes.take();
|
||||
stylist.read(|stylist| {
|
||||
for node in nodes.iter() {
|
||||
node.match_node(stylist);
|
||||
}
|
||||
}
|
||||
});
|
||||
chan.send(());
|
||||
}
|
||||
});
|
||||
num_spawned += 1;
|
||||
}
|
||||
}
|
||||
|
@ -100,9 +97,6 @@ impl<'self> MatchMethods for LayoutNode<'self> {
|
|||
}
|
||||
|
||||
fn cascade_subtree(&self, parent: Option<LayoutNode>) {
|
||||
let layout_data = unsafe {
|
||||
self.borrow_layout_data_unchecked().as_ref().unwrap()
|
||||
};
|
||||
macro_rules! cascade_node(
|
||||
($applicable_declarations: ident, $style: ident) => {{
|
||||
let parent_style = match parent {
|
||||
|
@ -110,18 +104,21 @@ impl<'self> MatchMethods for LayoutNode<'self> {
|
|||
None => None
|
||||
};
|
||||
|
||||
let computed_values = Arc::new(cascade(
|
||||
layout_data.$applicable_declarations,
|
||||
parent_style.map(|parent_style| parent_style.get())));
|
||||
let computed_values = {
|
||||
let layout_data_ref = self.borrow_layout_data();
|
||||
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"),
|
||||
Some(ref mut layout_data) => {
|
||||
let style = &mut layout_data.$style;
|
||||
let style = &mut layout_data.data.$style;
|
||||
match *style {
|
||||
None => (),
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
@ -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!(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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ pub trait StyledNode {
|
|||
fn restyle_damage(&self) -> RestyleDamage;
|
||||
}
|
||||
|
||||
impl<'self> StyledNode for LayoutNode<'self> {
|
||||
impl<'ln> StyledNode for LayoutNode<'ln> {
|
||||
#[inline]
|
||||
fn style<'a>(&'a self) -> &'a Arc<ComputedValues> {
|
||||
self.get_css_select_results()
|
||||
|
|
|
@ -18,7 +18,7 @@ pub trait NodeUtil {
|
|||
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
|
||||
* Returns the style results for the given node. If CSS selector
|
||||
|
@ -27,18 +27,15 @@ impl<'self> NodeUtil for LayoutNode<'self> {
|
|||
#[inline]
|
||||
fn get_css_select_results<'a>(&'a self) -> &'a Arc<ComputedValues> {
|
||||
unsafe {
|
||||
cast::transmute_region(self.borrow_layout_data_unchecked()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.style
|
||||
.as_ref()
|
||||
.unwrap())
|
||||
let layout_data_ref = self.borrow_layout_data();
|
||||
cast::transmute_region(layout_data_ref.get().as_ref().unwrap().data.style.as_ref().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
/// Does this node have a computed style yet?
|
||||
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.
|
||||
|
@ -52,10 +49,11 @@ impl<'self> NodeUtil for LayoutNode<'self> {
|
|||
RestyleDamage::none()
|
||||
};
|
||||
|
||||
self.borrow_layout_data()
|
||||
.ptr
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
let layout_data_ref = self.borrow_layout_data();
|
||||
layout_data_ref
|
||||
.get()
|
||||
.get_ref()
|
||||
.data
|
||||
.restyle_damage
|
||||
.map(|x| RestyleDamage::from_int(x))
|
||||
.unwrap_or(default)
|
||||
|
@ -63,10 +61,10 @@ impl<'self> NodeUtil for LayoutNode<'self> {
|
|||
|
||||
/// Set the restyle damage field.
|
||||
fn set_restyle_damage(self, damage: RestyleDamage) {
|
||||
match *self.mutate_layout_data().ptr {
|
||||
Some(ref mut data) => data.restyle_damage = Some(damage.to_int()),
|
||||
let mut layout_data_ref = self.mutate_layout_data();
|
||||
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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
//! CSS block formatting contexts.
|
||||
|
||||
use layout::box::Box;
|
||||
use layout::box_::Box;
|
||||
use layout::context::LayoutContext;
|
||||
use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData};
|
||||
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::float_context::{FloatContext, PlacementInfo, Invalid, FloatType};
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::cell::RefCell;
|
||||
use geom::{Point2D, Rect, SideOffsets2D};
|
||||
use gfx::display_list::DisplayList;
|
||||
use servo_util::geometry::Au;
|
||||
|
@ -53,7 +53,7 @@ pub struct BlockFlow {
|
|||
base: FlowData,
|
||||
|
||||
/// The associated box.
|
||||
box: Option<Box>,
|
||||
box_: Option<Box>,
|
||||
|
||||
/// Whether this block flow is the root flow.
|
||||
is_root: bool,
|
||||
|
@ -66,25 +66,25 @@ impl BlockFlow {
|
|||
pub fn new(base: FlowData) -> BlockFlow {
|
||||
BlockFlow {
|
||||
base: base,
|
||||
box: None,
|
||||
box_: None,
|
||||
is_root: false,
|
||||
float: None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_box(base: FlowData, box: Box) -> BlockFlow {
|
||||
pub fn from_box(base: FlowData, box_: Box) -> BlockFlow {
|
||||
BlockFlow {
|
||||
base: base,
|
||||
box: Some(box),
|
||||
box_: Some(box_),
|
||||
is_root: false,
|
||||
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 {
|
||||
base: base,
|
||||
box: Some(box),
|
||||
box_: Some(box_),
|
||||
is_root: false,
|
||||
float: Some(~FloatedBlockInfo::new(float_type))
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ impl BlockFlow {
|
|||
pub fn new_root(base: FlowData) -> BlockFlow {
|
||||
BlockFlow {
|
||||
base: base,
|
||||
box: None,
|
||||
box_: None,
|
||||
is_root: true,
|
||||
float: None
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ impl BlockFlow {
|
|||
pub fn new_float(base: FlowData, float_type: FloatType) -> BlockFlow {
|
||||
BlockFlow {
|
||||
base: base,
|
||||
box: None,
|
||||
box_: None,
|
||||
is_root: false,
|
||||
float: Some(~FloatedBlockInfo::new(float_type))
|
||||
}
|
||||
|
@ -113,10 +113,10 @@ impl BlockFlow {
|
|||
}
|
||||
|
||||
pub fn teardown(&mut self) {
|
||||
for box in self.box.iter() {
|
||||
box.teardown();
|
||||
for box_ in self.box_.iter() {
|
||||
box_.teardown();
|
||||
}
|
||||
self.box = None;
|
||||
self.box_ = None;
|
||||
self.float = None;
|
||||
}
|
||||
|
||||
|
@ -172,9 +172,9 @@ impl BlockFlow {
|
|||
(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) {
|
||||
let style = box.style();
|
||||
let style = box_.style();
|
||||
|
||||
let (width, maybe_margin_left, maybe_margin_right) =
|
||||
(MaybeAuto::from_style(style.Box.width, remaining_width),
|
||||
|
@ -215,8 +215,8 @@ impl BlockFlow {
|
|||
return (width, margin_left, margin_right);
|
||||
}
|
||||
|
||||
fn compute_float_margins(&self, box: &Box, remaining_width: Au) -> (Au, Au, Au) {
|
||||
let style = box.style();
|
||||
fn compute_float_margins(&self, box_: &Box, remaining_width: Au) -> (Au, Au, Au) {
|
||||
let style = box_.style();
|
||||
let margin_left = MaybeAuto::from_style(style.Margin.margin_left,
|
||||
remaining_width).specified_or_zero();
|
||||
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 float_ctx = Invalid;
|
||||
|
||||
for box in self.box.iter() {
|
||||
clearance = match box.clear() {
|
||||
for box_ in self.box_.iter() {
|
||||
clearance = match box_.clear() {
|
||||
None => Au::new(0),
|
||||
Some(clear) => {
|
||||
self.base.floats_in.clearance(clear)
|
||||
}
|
||||
};
|
||||
|
||||
top_offset = clearance + box.margin.get().top + box.border.get().top +
|
||||
box.padding.get().top;
|
||||
top_offset = clearance + box_.margin.get().top + box_.border.get().top +
|
||||
box_.padding.get().top;
|
||||
cur_y = cur_y + top_offset;
|
||||
bottom_offset = box.margin.get().bottom + box.border.get().bottom +
|
||||
box.padding.get().bottom;
|
||||
left_offset = box.offset();
|
||||
bottom_offset = box_.margin.get().bottom + box_.border.get().bottom +
|
||||
box_.padding.get().bottom;
|
||||
left_offset = box_.offset();
|
||||
}
|
||||
|
||||
if inorder {
|
||||
|
@ -279,17 +279,17 @@ impl BlockFlow {
|
|||
let mut top_margin_collapsible = false;
|
||||
let mut bottom_margin_collapsible = false;
|
||||
let mut first_in_flow = true;
|
||||
for box in self.box.iter() {
|
||||
if !self.is_root && box.border.get().top == Au(0) && box.padding.get().top == Au(0) {
|
||||
collapsible = box.margin.get().top;
|
||||
for box_ in self.box_.iter() {
|
||||
if !self.is_root && box_.border.get().top == Au(0) && box_.padding.get().top == Au(0) {
|
||||
collapsible = box_.margin.get().top;
|
||||
top_margin_collapsible = true;
|
||||
}
|
||||
if !self.is_root && box.border.get().bottom == Au(0) &&
|
||||
box.padding.get().bottom == Au(0) {
|
||||
if !self.is_root && box_.border.get().bottom == Au(0) &&
|
||||
box_.padding.get().bottom == Au(0) {
|
||||
bottom_margin_collapsible = true;
|
||||
}
|
||||
margin_top = box.margin.get().top;
|
||||
margin_bottom = box.margin.get().bottom;
|
||||
margin_top = box_.margin.get().top;
|
||||
margin_bottom = box_.margin.get().bottom;
|
||||
}
|
||||
|
||||
for kid in self.base.child_iter() {
|
||||
|
@ -332,8 +332,8 @@ impl BlockFlow {
|
|||
cur_y - top_offset - collapsing
|
||||
};
|
||||
|
||||
for box in self.box.iter() {
|
||||
let style = box.style();
|
||||
for box_ in self.box_.iter() {
|
||||
let style = box_.style();
|
||||
|
||||
// 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
|
||||
|
@ -345,9 +345,9 @@ impl BlockFlow {
|
|||
}
|
||||
|
||||
let mut noncontent_height = Au::new(0);
|
||||
for box in self.box.iter() {
|
||||
let mut position = box.position.get();
|
||||
let mut margin = box.margin.get();
|
||||
for box_ in self.box_.iter() {
|
||||
let mut position = box_.position.get();
|
||||
let mut margin = box_.margin.get();
|
||||
|
||||
// The associated box is the border box of this flow.
|
||||
margin.top = margin_top;
|
||||
|
@ -355,14 +355,14 @@ impl BlockFlow {
|
|||
|
||||
position.origin.y = clearance + margin.top;
|
||||
|
||||
noncontent_height = box.padding.get().top + box.padding.get().bottom +
|
||||
box.border.get().top + box.border.get().bottom;
|
||||
noncontent_height = box_.padding.get().top + box_.padding.get().bottom +
|
||||
box_.border.get().top + box_.border.get().bottom;
|
||||
position.size.height = height + noncontent_height;
|
||||
|
||||
noncontent_height = noncontent_height + clearance + margin.top + margin.bottom;
|
||||
|
||||
box.position.set(position);
|
||||
box.margin.set(margin);
|
||||
box_.position.set(position);
|
||||
box_.margin.set(margin);
|
||||
}
|
||||
|
||||
self.base.position.size.height = height + noncontent_height;
|
||||
|
@ -384,19 +384,19 @@ impl BlockFlow {
|
|||
let mut full_noncontent_width = Au(0);
|
||||
let mut margin_height = Au(0);
|
||||
|
||||
for box in self.box.iter() {
|
||||
height = box.position.get().size.height;
|
||||
clearance = match box.clear() {
|
||||
for box_ in self.box_.iter() {
|
||||
height = box_.position.get().size.height;
|
||||
clearance = match box_.clear() {
|
||||
None => Au(0),
|
||||
Some(clear) => self.base.floats_in.clearance(clear),
|
||||
};
|
||||
|
||||
let noncontent_width = box.padding.get().left + box.padding.get().right +
|
||||
box.border.get().left + box.border.get().right;
|
||||
let noncontent_width = box_.padding.get().left + box_.padding.get().right +
|
||||
box_.border.get().left + box_.border.get().right;
|
||||
|
||||
full_noncontent_width = noncontent_width + box.margin.get().left +
|
||||
box.margin.get().right;
|
||||
margin_height = box.margin.get().top + box.margin.get().bottom;
|
||||
full_noncontent_width = noncontent_width + box_.margin.get().left +
|
||||
box_.margin.get().right;
|
||||
margin_height = box_.margin.get().top + box_.margin.get().bottom;
|
||||
}
|
||||
|
||||
let info = PlacementInfo {
|
||||
|
@ -427,8 +427,8 @@ impl BlockFlow {
|
|||
let mut cur_y = Au(0);
|
||||
let mut top_offset = Au(0);
|
||||
|
||||
for box in self.box.iter() {
|
||||
top_offset = box.margin.get().top + box.border.get().top + box.padding.get().top;
|
||||
for box_ in self.box_.iter() {
|
||||
top_offset = box_.margin.get().top + box_.border.get().top + box_.padding.get().top;
|
||||
cur_y = cur_y + top_offset;
|
||||
}
|
||||
|
||||
|
@ -441,31 +441,31 @@ impl BlockFlow {
|
|||
let mut height = cur_y - top_offset;
|
||||
|
||||
let mut noncontent_height;
|
||||
let box = self.box.as_ref().unwrap();
|
||||
let mut position = box.position.get();
|
||||
let box_ = self.box_.as_ref().unwrap();
|
||||
let mut position = box_.position.get();
|
||||
|
||||
// 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 +
|
||||
box.border.get().top + box.border.get().bottom;
|
||||
noncontent_height = box_.padding.get().top + box_.padding.get().bottom +
|
||||
box_.border.get().top + box_.border.get().bottom;
|
||||
|
||||
//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();
|
||||
|
||||
height = geometry::max(height, height_prop) + noncontent_height;
|
||||
debug!("assign_height_float -- height: {}", height);
|
||||
|
||||
position.size.height = height;
|
||||
box.position.set(position);
|
||||
box_.position.set(position);
|
||||
}
|
||||
|
||||
pub fn build_display_list_block<E:ExtraDisplayListData>(
|
||||
&mut self,
|
||||
builder: &DisplayListBuilder,
|
||||
dirty: &Rect<Au>,
|
||||
list: &Cell<DisplayList<E>>)
|
||||
list: &RefCell<DisplayList<E>>)
|
||||
-> bool {
|
||||
if self.is_float() {
|
||||
return self.build_display_list_float(builder, dirty, list);
|
||||
|
@ -479,8 +479,8 @@ impl BlockFlow {
|
|||
debug!("build_display_list_block: adding display element");
|
||||
|
||||
// add box that starts block context
|
||||
for box in self.box.iter() {
|
||||
box.build_display_list(builder, dirty, self.base.abs_position, (&*self) as &Flow, list)
|
||||
for box_ in self.box_.iter() {
|
||||
box_.build_display_list(builder, dirty, self.base.abs_position, (&*self) as &Flow, list)
|
||||
}
|
||||
|
||||
// TODO: handle any out-of-flow elements
|
||||
|
@ -497,7 +497,7 @@ impl BlockFlow {
|
|||
&mut self,
|
||||
builder: &DisplayListBuilder,
|
||||
dirty: &Rect<Au>,
|
||||
list: &Cell<DisplayList<E>>)
|
||||
list: &RefCell<DisplayList<E>>)
|
||||
-> bool {
|
||||
let abs_rect = Rect(self.base.abs_position, self.base.position.size);
|
||||
if !abs_rect.intersects(dirty) {
|
||||
|
@ -506,8 +506,8 @@ impl BlockFlow {
|
|||
|
||||
let offset = self.base.abs_position + self.float.get_ref().rel_pos;
|
||||
// add box that starts block context
|
||||
for box in self.box.iter() {
|
||||
box.build_display_list(builder, dirty, offset, (&*self) as &Flow, list)
|
||||
for box_ in self.box_.iter() {
|
||||
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.
|
||||
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.
|
||||
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;
|
||||
pref_width = pref_width + this_preferred_width;
|
||||
}
|
||||
|
@ -612,17 +612,17 @@ impl Flow for BlockFlow {
|
|||
self.base.flags.set_inorder(false);
|
||||
}
|
||||
|
||||
for box in self.box.iter() {
|
||||
let style = box.style();
|
||||
for box_ in self.box_.iter() {
|
||||
let style = box_.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);
|
||||
|
||||
// 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.
|
||||
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.
|
||||
let margin_top = MaybeAuto::from_style(style.Margin.margin_top,
|
||||
|
@ -631,25 +631,25 @@ impl Flow for BlockFlow {
|
|||
remaining_width).specified_or_zero();
|
||||
|
||||
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 {
|
||||
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_bottom,
|
||||
margin_left));
|
||||
|
||||
x_offset = box.offset();
|
||||
x_offset = box_.offset();
|
||||
remaining_width = width;
|
||||
|
||||
// The associated box is the border box of this flow.
|
||||
let position_ref = box.position.mutate();
|
||||
position_ref.ptr.origin.x = box.margin.get().left;
|
||||
let padding_and_borders = box.padding.get().left + box.padding.get().right +
|
||||
box.border.get().left + box.border.get().right;
|
||||
position_ref.ptr.size.width = remaining_width + padding_and_borders;
|
||||
let mut position_ref = box_.position.borrow_mut();
|
||||
position_ref.get().origin.x = box_.margin.get().left;
|
||||
let padding_and_borders = box_.padding.get().left + box_.padding.get().right +
|
||||
box_.border.get().left + box_.border.get().right;
|
||||
position_ref.get().size.width = remaining_width + padding_and_borders;
|
||||
}
|
||||
|
||||
if self.is_float() {
|
||||
|
@ -722,24 +722,24 @@ impl Flow for BlockFlow {
|
|||
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
|
||||
// top margin if the parent has no top border, no top padding.
|
||||
if *first_in_flow && top_margin_collapsible {
|
||||
// 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.
|
||||
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
|
||||
// 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;
|
||||
*margin_top = box.margin.get().top;
|
||||
*margin_top = box_.margin.get().top;
|
||||
}
|
||||
}
|
||||
// The bottom margin of an in-flow block-level element collapses
|
||||
// with the top margin of its next in-flow block-level sibling.
|
||||
*collapsing = geometry::min(box.margin.get().top, *collapsible);
|
||||
*collapsible = box.margin.get().bottom;
|
||||
*collapsing = geometry::min(box_.margin.get().top, *collapsible);
|
||||
*collapsible = box_.margin.get().bottom;
|
||||
}
|
||||
|
||||
*first_in_flow = false;
|
||||
|
@ -757,7 +757,7 @@ impl Flow for BlockFlow {
|
|||
} else {
|
||||
~"BlockFlow: "
|
||||
};
|
||||
txt.append(match self.box {
|
||||
txt.append(match self.box_ {
|
||||
Some(ref rb) => rb.debug_str(),
|
||||
None => ~"",
|
||||
})
|
||||
|
|
|
@ -22,9 +22,8 @@ use servo_net::local_image_cache::LocalImageCache;
|
|||
use servo_util::geometry::Au;
|
||||
use servo_util::geometry;
|
||||
use servo_util::range::*;
|
||||
use servo_util::slot::Slot;
|
||||
use std::cast;
|
||||
use std::cell::Cell;
|
||||
use std::cell::RefCell;
|
||||
use std::cmp::ApproxEq;
|
||||
use std::num::Zero;
|
||||
use style::{ComputedValues, TElement, TNode, cascade};
|
||||
|
@ -71,24 +70,24 @@ pub struct Box {
|
|||
style: Arc<ComputedValues>,
|
||||
|
||||
/// The position of this box relative to its owning flow.
|
||||
position: Slot<Rect<Au>>,
|
||||
position: RefCell<Rect<Au>>,
|
||||
|
||||
/// The border of the content 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.
|
||||
padding: Slot<SideOffsets2D<Au>>,
|
||||
padding: RefCell<SideOffsets2D<Au>>,
|
||||
|
||||
/// 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.
|
||||
specific: SpecificBoxInfo,
|
||||
|
||||
/// positioned box offsets
|
||||
position_offsets: Slot<SideOffsets2D<Au>>,
|
||||
position_offsets: RefCell<SideOffsets2D<Au>>,
|
||||
}
|
||||
|
||||
/// Info specific to the kind of box. Keep this enum small.
|
||||
|
@ -105,7 +104,7 @@ pub enum SpecificBoxInfo {
|
|||
#[deriving(Clone)]
|
||||
pub struct ImageBoxInfo {
|
||||
/// The image held within this box.
|
||||
image: Slot<ImageHolder>,
|
||||
image: RefCell<ImageHolder>,
|
||||
/// The width attribute supplied by the DOM, if any.
|
||||
dom_width: Option<Au>,
|
||||
/// The height attribute supplied by the DOM, if any.
|
||||
|
@ -129,7 +128,7 @@ impl 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_height: convert_length(node, "height"),
|
||||
}
|
||||
|
@ -139,7 +138,8 @@ impl ImageBoxInfo {
|
|||
fn image_width(&self) -> Au {
|
||||
// TODO(brson): Consult margins and borders?
|
||||
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 {
|
||||
// TODO(brson): Consult margins and borders?
|
||||
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 {
|
||||
node: OpaqueNode::from_layout_node(&node),
|
||||
style: node_style,
|
||||
position: Slot::init(Au::zero_rect()),
|
||||
border: Slot::init(Zero::zero()),
|
||||
padding: Slot::init(Zero::zero()),
|
||||
margin: Slot::init(Zero::zero()),
|
||||
position: RefCell::new(Au::zero_rect()),
|
||||
border: RefCell::new(Zero::zero()),
|
||||
padding: RefCell::new(Zero::zero()),
|
||||
margin: RefCell::new(Zero::zero()),
|
||||
specific: specific,
|
||||
position_offsets: Slot::init(Zero::zero()),
|
||||
position_offsets: RefCell::new(Zero::zero()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -279,12 +280,12 @@ impl Box {
|
|||
Box {
|
||||
node: self.node,
|
||||
style: self.style.clone(),
|
||||
position: Slot::init(Rect(self.position.get().origin, size)),
|
||||
border: Slot::init(self.border.get()),
|
||||
padding: Slot::init(self.padding.get()),
|
||||
margin: Slot::init(self.margin.get()),
|
||||
position: RefCell::new(Rect(self.position.get().origin, size)),
|
||||
border: RefCell::new(self.border.get()),
|
||||
padding: RefCell::new(self.padding.get()),
|
||||
margin: RefCell::new(self.margin.get()),
|
||||
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
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
match self.line_height() {
|
||||
line_height::Normal => font_size.scale_by(1.14),
|
||||
|
@ -408,11 +404,11 @@ impl Box {
|
|||
debug!("(font style) start");
|
||||
|
||||
// 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 {
|
||||
font_family::FamilyName(ref name) => (*name).clone(),
|
||||
}
|
||||
};
|
||||
});
|
||||
debug!("(font style) font families: `{:?}`", font_families);
|
||||
|
||||
let font_size = my_style.Font.font_size.to_f64().unwrap() / 60.0;
|
||||
|
@ -465,7 +461,7 @@ impl Box {
|
|||
/// and so on.
|
||||
pub fn is_replaced(&self) -> bool {
|
||||
match self.specific {
|
||||
ImageBox(*) => true,
|
||||
ImageBox(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -473,7 +469,7 @@ impl Box {
|
|||
/// Returns true if this element can be split. This is true for text boxes.
|
||||
pub fn can_split(&self) -> bool {
|
||||
match self.specific {
|
||||
ScannedTextBox(*) => true,
|
||||
ScannedTextBox(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -496,7 +492,7 @@ impl Box {
|
|||
/// necessary.
|
||||
pub fn paint_background_if_applicable<E:ExtraDisplayListData>(
|
||||
&self,
|
||||
list: &Cell<DisplayList<E>>,
|
||||
list: &RefCell<DisplayList<E>>,
|
||||
absolute_bounds: &Rect<Au>) {
|
||||
// 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
|
||||
|
@ -505,7 +501,7 @@ impl Box {
|
|||
let style = self.style();
|
||||
let background_color = style.resolve_color(style.Background.background_color);
|
||||
if !background_color.alpha.approx_eq(&0.0) {
|
||||
list.with_mut_ref(|list| {
|
||||
list.with_mut(|list| {
|
||||
let solid_color_display_item = ~SolidColorDisplayItem {
|
||||
base: BaseDisplayItem {
|
||||
bounds: *absolute_bounds,
|
||||
|
@ -523,7 +519,7 @@ impl Box {
|
|||
/// necessary.
|
||||
pub fn paint_borders_if_applicable<E:ExtraDisplayListData>(
|
||||
&self,
|
||||
list: &Cell<DisplayList<E>>,
|
||||
list: &RefCell<DisplayList<E>>,
|
||||
abs_bounds: &Rect<Au>) {
|
||||
// Fast path.
|
||||
let border = self.border.get();
|
||||
|
@ -542,7 +538,7 @@ impl Box {
|
|||
let left_style = style.Border.border_left_style;
|
||||
|
||||
// Append the border to the display list.
|
||||
do list.with_mut_ref |list| {
|
||||
list.with_mut(|list| {
|
||||
let border_display_item = ~BorderDisplayItem {
|
||||
base: BaseDisplayItem {
|
||||
bounds: *abs_bounds,
|
||||
|
@ -560,7 +556,7 @@ impl Box {
|
|||
};
|
||||
|
||||
list.append_item(BorderDisplayItemClass(border_display_item))
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Adds the display items for this box to the given display list.
|
||||
|
@ -583,7 +579,7 @@ impl Box {
|
|||
dirty: &Rect<Au>,
|
||||
offset: Point2D<Au>,
|
||||
flow: &Flow,
|
||||
list: &Cell<DisplayList<E>>) {
|
||||
list: &RefCell<DisplayList<E>>) {
|
||||
let box_bounds = self.position.get();
|
||||
let absolute_box_bounds = box_bounds.translate(&offset);
|
||||
debug!("Box::build_display_list at rel={}, abs={}: {:s}",
|
||||
|
@ -607,7 +603,7 @@ impl Box {
|
|||
match self.specific {
|
||||
UnscannedTextBox(_) => fail!("Shouldn't see unscanned boxes here."),
|
||||
ScannedTextBox(ref text_box) => {
|
||||
do list.with_mut_ref |list| {
|
||||
list.with_mut(|list| {
|
||||
let item = ~ClipDisplayItem {
|
||||
base: BaseDisplayItem {
|
||||
bounds: absolute_box_bounds,
|
||||
|
@ -617,7 +613,7 @@ impl Box {
|
|||
need_clip: false
|
||||
};
|
||||
list.append_item(ClipDisplayItemClass(item));
|
||||
}
|
||||
});
|
||||
|
||||
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());
|
||||
|
||||
// Create the text box.
|
||||
do list.with_mut_ref |list| {
|
||||
list.with_mut(|list| {
|
||||
let text_display_item = ~TextDisplayItem {
|
||||
base: BaseDisplayItem {
|
||||
bounds: absolute_box_bounds,
|
||||
|
@ -642,7 +638,7 @@ impl Box {
|
|||
};
|
||||
|
||||
list.append_item(TextDisplayItemClass(text_display_item))
|
||||
}
|
||||
});
|
||||
|
||||
// Draw debug frames for text bounds.
|
||||
//
|
||||
|
@ -652,7 +648,7 @@ impl Box {
|
|||
// Compute the text box bounds and draw a border surrounding them.
|
||||
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 {
|
||||
base: BaseDisplayItem {
|
||||
bounds: absolute_box_bounds,
|
||||
|
@ -664,7 +660,7 @@ impl Box {
|
|||
|
||||
};
|
||||
list.append_item(BorderDisplayItemClass(border_display_item))
|
||||
}
|
||||
});
|
||||
|
||||
// Draw a rectangle representing the baselines.
|
||||
//
|
||||
|
@ -674,7 +670,7 @@ impl Box {
|
|||
let baseline = Rect(absolute_box_bounds.origin + Point2D(Au(0), ascent),
|
||||
Size2D(absolute_box_bounds.size.width, Au(0)));
|
||||
|
||||
do list.with_mut_ref |list| {
|
||||
list.with_mut(|list| {
|
||||
let border_display_item = ~BorderDisplayItem {
|
||||
base: BaseDisplayItem {
|
||||
bounds: baseline,
|
||||
|
@ -686,13 +682,11 @@ impl Box {
|
|||
|
||||
};
|
||||
list.append_item(BorderDisplayItemClass(border_display_item))
|
||||
}
|
||||
|
||||
()
|
||||
});
|
||||
});
|
||||
},
|
||||
GenericBox | IframeBox(_) => {
|
||||
do list.with_mut_ref |list| {
|
||||
GenericBox | IframeBox(..) => {
|
||||
list.with_mut(|list| {
|
||||
let item = ~ClipDisplayItem {
|
||||
base: BaseDisplayItem {
|
||||
bounds: absolute_box_bounds,
|
||||
|
@ -702,14 +696,14 @@ impl Box {
|
|||
need_clip: self.needs_clip()
|
||||
};
|
||||
list.append_item(ClipDisplayItemClass(item));
|
||||
}
|
||||
});
|
||||
|
||||
// FIXME(pcwalton): This is a bit of an abuse of the logging infrastructure. We
|
||||
// should have a real `SERVO_DEBUG` system.
|
||||
debug!("{:?}", {
|
||||
let debug_border = SideOffsets2D::new_all_same(Au::from_px(1));
|
||||
|
||||
do list.with_mut_ref |list| {
|
||||
list.with_mut(|list| {
|
||||
let border_display_item = ~BorderDisplayItem {
|
||||
base: BaseDisplayItem {
|
||||
bounds: absolute_box_bounds,
|
||||
|
@ -721,13 +715,11 @@ impl Box {
|
|||
|
||||
};
|
||||
list.append_item(BorderDisplayItemClass(border_display_item))
|
||||
}
|
||||
|
||||
()
|
||||
});
|
||||
});
|
||||
},
|
||||
ImageBox(ref image_box) => {
|
||||
do list.with_mut_ref |list| {
|
||||
list.with_mut(|list| {
|
||||
let item = ~ClipDisplayItem {
|
||||
base: BaseDisplayItem {
|
||||
bounds: absolute_box_bounds,
|
||||
|
@ -737,14 +729,15 @@ impl Box {
|
|||
need_clip: false
|
||||
};
|
||||
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) => {
|
||||
debug!("(building display list) building image box");
|
||||
|
||||
// Place the image into the display list.
|
||||
do list.with_mut_ref |list| {
|
||||
list.with_mut(|list| {
|
||||
let image_display_item = ~ImageDisplayItem {
|
||||
base: BaseDisplayItem {
|
||||
bounds: absolute_box_bounds,
|
||||
|
@ -752,8 +745,8 @@ impl Box {
|
|||
},
|
||||
image: image.clone(),
|
||||
};
|
||||
list.append_item(ImageDisplayItemClass(image_display_item))
|
||||
}
|
||||
list.append_item(ImageDisplayItemClass(image_display_item));
|
||||
});
|
||||
}
|
||||
None => {
|
||||
// No image data at all? Do nothing.
|
||||
|
@ -809,7 +802,7 @@ impl Box {
|
|||
|
||||
(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)
|
||||
}
|
||||
|
@ -822,11 +815,12 @@ impl Box {
|
|||
match self.specific {
|
||||
GenericBox | IframeBox(_) => Au(0),
|
||||
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);
|
||||
|
||||
// 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);
|
||||
|
||||
height
|
||||
|
@ -955,11 +949,11 @@ impl Box {
|
|||
match self.specific {
|
||||
GenericBox | IframeBox(_) => {
|
||||
// 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) => {
|
||||
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(_) => {
|
||||
// Scanned text boxes will have already had their widths assigned by this point.
|
|
@ -22,8 +22,8 @@
|
|||
|
||||
use css::node_style::StyledNode;
|
||||
use layout::block::BlockFlow;
|
||||
use layout::box::{Box, GenericBox, IframeBox, IframeBoxInfo, ImageBox, ImageBoxInfo};
|
||||
use layout::box::{UnscannedTextBox, UnscannedTextBoxInfo};
|
||||
use layout::box_::{Box, GenericBox, IframeBox, IframeBoxInfo, ImageBox, ImageBoxInfo};
|
||||
use layout::box_::{UnscannedTextBox, UnscannedTextBoxInfo};
|
||||
use layout::context::LayoutContext;
|
||||
use layout::float_context::FloatType;
|
||||
use layout::flow::{Flow, FlowData, MutableFlowUtils};
|
||||
|
@ -35,10 +35,11 @@ use layout::wrapper::{LayoutNode, PostorderNodeMutTraversal};
|
|||
use script::dom::element::{HTMLIframeElementTypeId, HTMLImageElementTypeId};
|
||||
use script::dom::node::{CommentNodeTypeId, DoctypeNodeTypeId, DocumentFragmentNodeTypeId};
|
||||
use script::dom::node::{DocumentNodeTypeId, ElementNodeTypeId, TextNodeTypeId};
|
||||
use servo_util::slot::Slot;
|
||||
use std::util;
|
||||
use style::computed_values::{display, float};
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::util;
|
||||
|
||||
/// The results of flow construction for a DOM node.
|
||||
pub enum ConstructionResult {
|
||||
/// 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
|
||||
/// done for this node.
|
||||
FlowConstructionResult(~Flow:),
|
||||
FlowConstructionResult(~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.
|
||||
|
@ -102,7 +103,7 @@ struct InlineBlockSplit {
|
|||
predecessor_boxes: ~[Box],
|
||||
|
||||
/// The flow that caused this {ib} split.
|
||||
flow: ~Flow:,
|
||||
flow: ~Flow,
|
||||
}
|
||||
|
||||
/// Methods on optional vectors.
|
||||
|
@ -169,24 +170,24 @@ impl<T> OptVector<T> for Option<~[T]> {
|
|||
}
|
||||
|
||||
/// An object that knows how to create flows.
|
||||
pub struct FlowConstructor<'self> {
|
||||
pub struct FlowConstructor<'a> {
|
||||
/// The layout context.
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// 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.
|
||||
pub fn init<'a>(layout_context: &'a mut LayoutContext) -> FlowConstructor<'a> {
|
||||
FlowConstructor {
|
||||
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
|
||||
/// otherwise.
|
||||
#[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 {
|
||||
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);
|
||||
flow.add_new_child(inline_flow)
|
||||
}
|
||||
|
@ -244,7 +245,7 @@ impl<'self> FlowConstructor<'self> {
|
|||
/// the given flow.
|
||||
fn flush_inline_boxes_to_flow_if_necessary(&mut self,
|
||||
opt_boxes: &mut Option<~[Box]>,
|
||||
flow: &mut ~Flow:,
|
||||
flow: &mut ~Flow,
|
||||
node: LayoutNode) {
|
||||
let opt_boxes = util::replace(opt_boxes, None);
|
||||
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
|
||||
/// whether {ib} splits needed to happen.
|
||||
fn build_children_of_block_flow(&mut self,
|
||||
flow: &mut ~Flow:,
|
||||
flow: &mut ~Flow,
|
||||
node: LayoutNode) {
|
||||
// Gather up boxes for the inline flows we might need to create.
|
||||
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
|
||||
/// other `BlockFlow`s or `InlineFlow`s underneath it, depending on whether {ib} splits needed
|
||||
/// 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 box = self.build_box_for_node(node);
|
||||
let mut flow = ~BlockFlow::from_box(base, box) as ~Flow:;
|
||||
let box_ = self.build_box_for_node(node);
|
||||
let mut flow = ~BlockFlow::from_box(base, box_) as ~Flow;
|
||||
self.build_children_of_block_flow(&mut flow, node);
|
||||
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
|
||||
/// a `BlockFlow` underneath it.
|
||||
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 box = self.build_box_for_node(node);
|
||||
let mut flow = ~BlockFlow::float_from_box(base, float_type, box) as ~Flow:;
|
||||
let box_ = self.build_box_for_node(node);
|
||||
let mut flow = ~BlockFlow::float_from_box(base, float_type, box_) as ~Flow;
|
||||
self.build_children_of_block_flow(&mut flow, node);
|
||||
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
|
||||
// reason LLVM's inlining heuristics go awry here.
|
||||
#[inline(always)]
|
||||
|
@ -528,7 +529,7 @@ trait NodeUtils {
|
|||
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 {
|
||||
match self.type_id() {
|
||||
TextNodeTypeId |
|
||||
|
@ -543,17 +544,19 @@ impl<'self> NodeUtils for LayoutNode<'self> {
|
|||
|
||||
#[inline(always)]
|
||||
fn set_flow_construction_result(self, result: ConstructionResult) {
|
||||
match *self.mutate_layout_data().ptr {
|
||||
Some(ref mut layout_data) => layout_data.flow_construction_result = result,
|
||||
let mut layout_data_ref = self.mutate_layout_data();
|
||||
match *layout_data_ref.get() {
|
||||
Some(ref mut layout_data) => layout_data.data.flow_construction_result = result,
|
||||
None => fail!("no layout data"),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
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) => {
|
||||
util::replace(&mut layout_data.flow_construction_result, NoConstructionResult)
|
||||
util::replace(&mut layout_data.data.flow_construction_result, NoConstructionResult)
|
||||
}
|
||||
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. :(
|
||||
let mut found_nonwhitespace = false;
|
||||
let mut result = ~[];
|
||||
for box in boxes.move_iter() {
|
||||
if !found_nonwhitespace && box.is_whitespace_only() {
|
||||
for box_ in boxes.move_iter() {
|
||||
if !found_nonwhitespace && box_.is_whitespace_only() {
|
||||
debug!("stripping ignorable whitespace from start");
|
||||
continue
|
||||
}
|
||||
|
||||
found_nonwhitespace = true;
|
||||
result.push(box)
|
||||
result.push(box_)
|
||||
}
|
||||
|
||||
*opt_boxes = Some(result)
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
//! Constructs display lists from boxes.
|
||||
|
||||
use layout::box::Box;
|
||||
use layout::box_::Box;
|
||||
use layout::context::LayoutContext;
|
||||
use layout::util::OpaqueNode;
|
||||
|
||||
|
@ -12,14 +12,14 @@ use gfx;
|
|||
use style;
|
||||
|
||||
pub trait ExtraDisplayListData {
|
||||
fn new(box: &Box) -> Self;
|
||||
fn new(box_: &Box) -> Self;
|
||||
}
|
||||
|
||||
pub type Nothing = ();
|
||||
|
||||
impl ExtraDisplayListData for OpaqueNode {
|
||||
fn new(box: &Box) -> OpaqueNode {
|
||||
box.node
|
||||
fn new(box_: &Box) -> OpaqueNode {
|
||||
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
|
||||
/// support display-list-based hit testing and so forth.
|
||||
pub struct DisplayListBuilder<'self> {
|
||||
ctx: &'self LayoutContext,
|
||||
pub struct DisplayListBuilder<'a> {
|
||||
ctx: &'a LayoutContext,
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
@ -4,23 +4,29 @@
|
|||
|
||||
//! 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 script::layout_interface::LayoutChan;
|
||||
|
||||
/// Functionality useful for querying the layout-specific data on DOM nodes.
|
||||
pub trait LayoutAuxMethods {
|
||||
fn initialize_layout_data(self);
|
||||
fn initialize_style_for_subtree(self);
|
||||
fn initialize_layout_data(self, chan: LayoutChan);
|
||||
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.
|
||||
///
|
||||
/// FIXME(pcwalton): Do this as part of box building instead of in a traversal.
|
||||
fn initialize_layout_data(self) {
|
||||
let layout_data_handle = self.mutate_layout_data();
|
||||
match *layout_data_handle.ptr {
|
||||
None => *layout_data_handle.ptr = Some(~LayoutData::new()),
|
||||
fn initialize_layout_data(self, chan: LayoutChan) {
|
||||
let mut layout_data_ref = self.mutate_layout_data();
|
||||
match *layout_data_ref.get() {
|
||||
None => {
|
||||
*layout_data_ref.get() = Some(LayoutDataWrapper {
|
||||
chan: Some(chan),
|
||||
data: ~PrivateLayoutData::new(),
|
||||
});
|
||||
}
|
||||
Some(_) => {}
|
||||
}
|
||||
}
|
||||
|
@ -28,9 +34,9 @@ impl<'self> LayoutAuxMethods for LayoutNode<'self> {
|
|||
/// Resets layout data and styles for a Node tree.
|
||||
///
|
||||
/// 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() {
|
||||
n.initialize_layout_data();
|
||||
n.initialize_layout_data(chan.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,7 +77,7 @@ impl FloatContext {
|
|||
}
|
||||
|
||||
#[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 {
|
||||
Invalid => fail!("Float context no longer available"),
|
||||
Valid(ref mut base) => callback(&mut *base)
|
||||
|
@ -85,7 +85,7 @@ impl FloatContext {
|
|||
}
|
||||
|
||||
#[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 {
|
||||
Invalid => fail!("Float context no longer available"),
|
||||
Valid(ref base) => callback(&*base)
|
||||
|
@ -94,46 +94,46 @@ impl FloatContext {
|
|||
|
||||
#[inline(always)]
|
||||
pub fn translate(&mut self, trans: Point2D<Au>) -> FloatContext {
|
||||
do self.with_mut_base |base| {
|
||||
self.with_mut_base(|base| {
|
||||
base.translate(trans);
|
||||
}
|
||||
});
|
||||
replace(self, Invalid)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
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)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn add_float(&mut self, info: &PlacementInfo) -> FloatContext{
|
||||
do self.with_mut_base |base| {
|
||||
self.with_mut_base(|base| {
|
||||
base.add_float(info);
|
||||
}
|
||||
});
|
||||
replace(self, Invalid)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn place_between_floats(&self, info: &PlacementInfo) -> Rect<Au> {
|
||||
do self.with_base |base| {
|
||||
self.with_base(|base| {
|
||||
base.place_between_floats(info)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn last_float_pos(&mut self) -> Point2D<Au> {
|
||||
do self.with_base |base| {
|
||||
self.with_base(|base| {
|
||||
base.last_float_pos()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn clearance(&self, clear: ClearType) -> Au {
|
||||
do self.with_base |base| {
|
||||
self.with_base(|base| {
|
||||
base.clearance(clear)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -288,24 +288,6 @@ impl FloatContextBase {
|
|||
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
|
||||
/// will result in the rectange not colliding with any floats. Returns
|
||||
/// None if that height is infinite.
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
use css::node_style::StyledNode;
|
||||
use layout::block::BlockFlow;
|
||||
use layout::box::Box;
|
||||
use layout::box_::Box;
|
||||
use layout::context::LayoutContext;
|
||||
use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData};
|
||||
use layout::float_context::{FloatContext, Invalid};
|
||||
|
@ -42,7 +42,7 @@ use geom::rect::Rect;
|
|||
use gfx::display_list::{ClipDisplayItemClass, DisplayList};
|
||||
use servo_util::geometry::Au;
|
||||
use std::cast;
|
||||
use std::cell::Cell;
|
||||
use std::cell::RefCell;
|
||||
use style::ComputedValues;
|
||||
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.
|
||||
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()
|
||||
}
|
||||
|
||||
|
@ -140,12 +140,12 @@ pub fn mut_base<'a>(this: &'a mut Flow) -> &'a mut FlowData {
|
|||
}
|
||||
|
||||
/// 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()
|
||||
}
|
||||
|
||||
/// 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()
|
||||
}
|
||||
|
||||
|
@ -183,13 +183,13 @@ pub trait MutableFlowUtils {
|
|||
// Mutators
|
||||
|
||||
/// 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.
|
||||
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.
|
||||
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.
|
||||
fn remove_first(self);
|
||||
|
@ -205,7 +205,7 @@ pub trait MutableFlowUtils {
|
|||
self,
|
||||
builder: &DisplayListBuilder,
|
||||
dirty: &Rect<Au>,
|
||||
list: &Cell<DisplayList<E>>)
|
||||
list: &RefCell<DisplayList<E>>)
|
||||
-> bool;
|
||||
}
|
||||
|
||||
|
@ -385,7 +385,7 @@ pub struct FlowData {
|
|||
restyle_damage: RestyleDamage,
|
||||
|
||||
/// The children of this flow.
|
||||
children: DList<~Flow:>,
|
||||
children: DList<~Flow>,
|
||||
|
||||
/* TODO (Issue #87): debug only */
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'self> ImmutableFlowUtils for &'self Flow {
|
||||
impl<'a> ImmutableFlowUtils for &'a Flow {
|
||||
/// Returns true if this flow is a block or a float flow.
|
||||
fn is_block_like(self) -> bool {
|
||||
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.
|
||||
fn traverse_preorder<T:PreorderFlowTraversal>(self, traversal: &mut T) -> bool {
|
||||
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.
|
||||
fn add_new_child(self, new_child: ~Flow:) {
|
||||
fn add_new_child(self, new_child: ~Flow) {
|
||||
mut_base(self).children.push_back(new_child)
|
||||
}
|
||||
|
||||
/// 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())
|
||||
}
|
||||
|
||||
/// 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())
|
||||
}
|
||||
|
||||
|
@ -587,7 +587,7 @@ impl<'self> MutableFlowUtils for &'self mut Flow {
|
|||
self,
|
||||
builder: &DisplayListBuilder,
|
||||
dirty: &Rect<Au>,
|
||||
list: &Cell<DisplayList<E>>)
|
||||
list: &RefCell<DisplayList<E>>)
|
||||
-> bool {
|
||||
debug!("Flow: building display list for f{}", base(self).id);
|
||||
match self.class() {
|
||||
|
@ -596,20 +596,21 @@ impl<'self> MutableFlowUtils for &'self mut Flow {
|
|||
_ => 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;
|
||||
}
|
||||
|
||||
let child_list = ~Cell::new(DisplayList::new());
|
||||
let child_list = ~RefCell::new(DisplayList::new());
|
||||
for kid in child_iter(self) {
|
||||
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| {
|
||||
match *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
|
||||
},
|
||||
_ => false,
|
||||
|
@ -620,7 +621,7 @@ impl<'self> MutableFlowUtils for &'self mut Flow {
|
|||
fail!("fail to find parent item");
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,14 +3,14 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use css::node_style::StyledNode;
|
||||
use layout::box::{Box, CannotSplit, GenericBox, IframeBox, ImageBox, ScannedTextBox, SplitDidFit};
|
||||
use layout::box::{SplitDidNotFit, UnscannedTextBox};
|
||||
use layout::box_::{Box, CannotSplit, GenericBox, IframeBox, ImageBox, ScannedTextBox, SplitDidFit};
|
||||
use layout::box_::{SplitDidNotFit, UnscannedTextBox};
|
||||
use layout::context::LayoutContext;
|
||||
use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData};
|
||||
use layout::flow::{FlowClass, Flow, FlowData, InlineFlowClass};
|
||||
use layout::flow;
|
||||
use layout::float_context::FloatContext;
|
||||
use layout::util::{ElementMapping};
|
||||
use layout::util::ElementMapping;
|
||||
use layout::float_context::{PlacementInfo, FloatLeft};
|
||||
|
||||
use extra::container::Deque;
|
||||
|
@ -19,7 +19,7 @@ use geom::{Point2D, Rect, Size2D};
|
|||
use gfx::display_list::DisplayList;
|
||||
use servo_util::geometry::Au;
|
||||
use servo_util::range::Range;
|
||||
use std::cell::Cell;
|
||||
use std::cell::RefCell;
|
||||
use std::u16;
|
||||
use std::util;
|
||||
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 {
|
||||
self.floats.clone()
|
||||
}
|
||||
|
@ -119,13 +107,13 @@ impl LineboxScanner {
|
|||
if flow.boxes.is_empty() {
|
||||
break;
|
||||
}
|
||||
let box = flow.boxes.remove(0); // FIXME: use a linkedlist
|
||||
debug!("LineboxScanner: Working with box from box list: b{}", box.debug_id());
|
||||
box
|
||||
let box_ = flow.boxes.remove(0); // FIXME: use a linkedlist
|
||||
debug!("LineboxScanner: Working with box from box list: b{}", box_.debug_id());
|
||||
box_
|
||||
} else {
|
||||
let box = self.work_list.pop_front().unwrap();
|
||||
debug!("LineboxScanner: Working with box from work list: b{}", box.debug_id());
|
||||
box
|
||||
let box_ = self.work_list.pop_front().unwrap();
|
||||
debug!("LineboxScanner: Working with box from work list: b{}", box_.debug_id());
|
||||
box_
|
||||
};
|
||||
|
||||
let box_was_appended = self.try_append_to_line(cur_box, flow);
|
||||
|
@ -413,8 +401,8 @@ impl LineboxScanner {
|
|||
}
|
||||
|
||||
// An unconditional push
|
||||
fn push_box_to_line(&mut self, box: Box) {
|
||||
debug!("LineboxScanner: Pushing box {} to line {:u}", box.debug_id(), self.lines.len());
|
||||
fn push_box_to_line(&mut self, box_: Box) {
|
||||
debug!("LineboxScanner: Pushing box {} to line {:u}", box_.debug_id(), self.lines.len());
|
||||
|
||||
if self.pending_line.range.length() == 0 {
|
||||
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.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,
|
||||
box.position.get().size.height);
|
||||
self.new_boxes.push(box);
|
||||
box_.position.get().size.height);
|
||||
self.new_boxes.push(box_);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -467,8 +455,8 @@ impl InlineFlow {
|
|||
}
|
||||
|
||||
pub fn teardown(&mut self) {
|
||||
for box in self.boxes.iter() {
|
||||
box.teardown();
|
||||
for box_ in self.boxes.iter() {
|
||||
box_.teardown();
|
||||
}
|
||||
self.boxes = ~[];
|
||||
}
|
||||
|
@ -477,7 +465,7 @@ impl InlineFlow {
|
|||
&self,
|
||||
builder: &DisplayListBuilder,
|
||||
dirty: &Rect<Au>,
|
||||
list: &Cell<DisplayList<E>>)
|
||||
list: &RefCell<DisplayList<E>>)
|
||||
-> bool {
|
||||
let abs_rect = Rect(self.base.abs_position, self.base.position.size);
|
||||
if !abs_rect.intersects(dirty) {
|
||||
|
@ -490,8 +478,8 @@ impl InlineFlow {
|
|||
self.base.id,
|
||||
self.boxes.len());
|
||||
|
||||
for box in self.boxes.iter() {
|
||||
box.build_display_list(builder, dirty, self.base.abs_position, (&*self) as &Flow, list)
|
||||
for box_ in self.boxes.iter() {
|
||||
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
|
||||
|
@ -590,9 +578,9 @@ impl InlineFlow {
|
|||
};
|
||||
|
||||
for i in line.range.eachi() {
|
||||
let box = &boxes[i];
|
||||
let size = box.position.get().size;
|
||||
box.position.set(Rect(Point2D(offset_x, box.position.get().origin.y), size));
|
||||
let box_ = &boxes[i];
|
||||
let size = box_.position.get().size;
|
||||
box_.position.set(Rect(Point2D(offset_x, box_.position.get().origin.y), size));
|
||||
offset_x = offset_x + size.width;
|
||||
}
|
||||
}
|
||||
|
@ -623,10 +611,10 @@ impl Flow for InlineFlow {
|
|||
let mut min_width = Au::new(0);
|
||||
let mut pref_width = Au::new(0);
|
||||
|
||||
for box in self.boxes.iter() {
|
||||
debug!("Flow[{:d}]: measuring {:s}", self.base.id, box.debug_str());
|
||||
for box_ in self.boxes.iter() {
|
||||
debug!("Flow[{:d}]: measuring {:s}", self.base.id, box_.debug_str());
|
||||
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);
|
||||
pref_width = Au::max(pref_width, this_preferred_width);
|
||||
}
|
||||
|
@ -647,8 +635,8 @@ impl Flow for InlineFlow {
|
|||
|
||||
{
|
||||
let this = &mut *self;
|
||||
for box in this.boxes.iter() {
|
||||
box.assign_width();
|
||||
for box_ in this.boxes.iter() {
|
||||
box_.assign_width();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -736,9 +724,9 @@ impl Flow for InlineFlow {
|
|||
let noncontent_height = top + bottom;
|
||||
height = height + noncontent_height;
|
||||
|
||||
let position_ref = cur_box.position.mutate();
|
||||
position_ref.ptr.size.height = height;
|
||||
position_ref.ptr.translate(&Point2D(Au::new(0), -height));
|
||||
let mut position_ref = cur_box.position.borrow_mut();
|
||||
position_ref.get().size.height = height;
|
||||
position_ref.get().translate(&Point2D(Au::new(0), -height));
|
||||
|
||||
let ascent = height + bottom;
|
||||
(height, Au::new(0), ascent)
|
||||
|
@ -818,7 +806,7 @@ impl Flow for InlineFlow {
|
|||
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'
|
||||
|
@ -847,7 +835,7 @@ impl Flow for InlineFlow {
|
|||
_ => 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ use layout::flow::{Flow, ImmutableFlowUtils, MutableFlowUtils, PreorderFlowTrave
|
|||
use layout::flow::{PostorderFlowTraversal};
|
||||
use layout::flow;
|
||||
use layout::incremental::{RestyleDamage};
|
||||
use layout::util::{LayoutData, LayoutDataAccess, OpaqueNode};
|
||||
use layout::util::{LayoutDataAccess, OpaqueNode, LayoutDataWrapper};
|
||||
use layout::wrapper::LayoutNode;
|
||||
|
||||
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::{ContentBoxesQuery, ContentBoxesResponse, ExitNowMsg, LayoutQuery};
|
||||
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::{ReflowForDisplay, ReflowMsg};
|
||||
use script::script_task::{ReflowCompleteMsg, ScriptChan, SendEventMsg};
|
||||
|
@ -46,20 +46,22 @@ use servo_util::time::{ProfilerChan, profile};
|
|||
use servo_util::time;
|
||||
use std::cast::transmute;
|
||||
use std::cast;
|
||||
use std::cell::Cell;
|
||||
use std::cell::RefCell;
|
||||
use std::comm::Port;
|
||||
use std::task;
|
||||
use std::util;
|
||||
use style::{AuthorOrigin, Stylesheet, Stylist};
|
||||
|
||||
/// Information needed by the layout task.
|
||||
struct LayoutTask {
|
||||
pub struct LayoutTask {
|
||||
/// The ID of the pipeline that we belong to.
|
||||
id: PipelineId,
|
||||
|
||||
/// The port on which we receive messages.
|
||||
port: Port<Msg>,
|
||||
|
||||
//// The channel to send messages to ourself.
|
||||
chan: LayoutChan,
|
||||
|
||||
/// The channel on which messages can be sent to the constellation.
|
||||
constellation_chan: ConstellationChan,
|
||||
|
||||
|
@ -132,9 +134,9 @@ impl PreorderFlowTraversal for PropagateDamageTraversal {
|
|||
|
||||
/// The bubble-widths traversal, the first part of layout computation. This computes preferred
|
||||
/// 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]
|
||||
fn process(&mut self, flow: &mut Flow) -> bool {
|
||||
flow.bubble_widths(**self);
|
||||
|
@ -151,9 +153,9 @@ impl<'self> PostorderFlowTraversal for BubbleWidthsTraversal<'self> {
|
|||
}
|
||||
|
||||
/// 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]
|
||||
fn process(&mut self, flow: &mut Flow) -> bool {
|
||||
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
|
||||
/// computation. Determines the final heights for all layout objects, computes positions, and
|
||||
/// 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]
|
||||
fn process(&mut self, flow: &mut Flow) -> bool {
|
||||
flow.assign_height(**self);
|
||||
|
@ -186,10 +188,10 @@ struct LayoutImageResponder {
|
|||
}
|
||||
|
||||
impl ImageResponder for LayoutImageResponder {
|
||||
fn respond(&self) -> ~fn(ImageResponseMsg) {
|
||||
fn respond(&self) -> proc(ImageResponseMsg) {
|
||||
let id = self.id.clone();
|
||||
let script_chan = self.script_chan.clone();
|
||||
let f: ~fn(ImageResponseMsg) = |_| {
|
||||
let f: proc(ImageResponseMsg) = proc(_) {
|
||||
script_chan.send(SendEventMsg(id.clone(), ReflowEvent))
|
||||
};
|
||||
f
|
||||
|
@ -200,6 +202,7 @@ impl LayoutTask {
|
|||
/// Spawns a new layout task.
|
||||
pub fn create(id: PipelineId,
|
||||
port: Port<Msg>,
|
||||
chan: LayoutChan,
|
||||
constellation_chan: ConstellationChan,
|
||||
script_chan: ScriptChan,
|
||||
render_chan: RenderChan<OpaqueNode>,
|
||||
|
@ -207,11 +210,11 @@ impl LayoutTask {
|
|||
opts: Opts,
|
||||
profiler_chan: ProfilerChan,
|
||||
shutdown_chan: Chan<()>) {
|
||||
spawn_with!(task::task(), [port, constellation_chan, script_chan,
|
||||
render_chan, img_cache_task, profiler_chan, shutdown_chan], {
|
||||
{ // Ensures LayoutTask gets destroyed before we send the shutdown message
|
||||
spawn(proc() {
|
||||
{ // Ensures layout task is destroyed before we send shutdown message
|
||||
let mut layout = LayoutTask::new(id,
|
||||
port,
|
||||
chan,
|
||||
constellation_chan,
|
||||
script_chan,
|
||||
render_chan,
|
||||
|
@ -220,7 +223,6 @@ impl LayoutTask {
|
|||
profiler_chan);
|
||||
layout.start();
|
||||
}
|
||||
|
||||
shutdown_chan.send(());
|
||||
});
|
||||
}
|
||||
|
@ -228,6 +230,7 @@ impl LayoutTask {
|
|||
/// Creates a new `LayoutTask` structure.
|
||||
fn new(id: PipelineId,
|
||||
port: Port<Msg>,
|
||||
chan: LayoutChan,
|
||||
constellation_chan: ConstellationChan,
|
||||
script_chan: ScriptChan,
|
||||
render_chan: RenderChan<OpaqueNode>,
|
||||
|
@ -239,6 +242,7 @@ impl LayoutTask {
|
|||
LayoutTask {
|
||||
id: id,
|
||||
port: port,
|
||||
chan: chan,
|
||||
constellation_chan: constellation_chan,
|
||||
script_chan: script_chan,
|
||||
render_chan: render_chan,
|
||||
|
@ -281,17 +285,15 @@ impl LayoutTask {
|
|||
match self.port.recv() {
|
||||
AddStylesheetMsg(sheet) => self.handle_add_stylesheet(sheet),
|
||||
ReflowMsg(data) => {
|
||||
let data = Cell::new(data);
|
||||
|
||||
do profile(time::LayoutPerformCategory, self.profiler_chan.clone()) {
|
||||
self.handle_reflow(data.take());
|
||||
}
|
||||
profile(time::LayoutPerformCategory, self.profiler_chan.clone(), || {
|
||||
self.handle_reflow(data);
|
||||
});
|
||||
}
|
||||
QueryMsg(query) => {
|
||||
let query = Cell::new(query);
|
||||
do profile(time::LayoutQueryCategory, self.profiler_chan.clone()) {
|
||||
self.handle_query(query.take());
|
||||
}
|
||||
let mut query = Some(query);
|
||||
profile(time::LayoutQueryCategory, self.profiler_chan.clone(), || {
|
||||
self.handle_query(query.take_unwrap());
|
||||
});
|
||||
}
|
||||
ReapLayoutDataMsg(dead_layout_data) => {
|
||||
unsafe {
|
||||
|
@ -340,16 +342,16 @@ impl LayoutTask {
|
|||
/// Shuts down the layout task now. If there are any DOM nodes left, layout will now (safely)
|
||||
/// crash.
|
||||
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));
|
||||
response_port.recv()
|
||||
}
|
||||
|
||||
fn handle_add_stylesheet(&mut self, sheet: Stylesheet) {
|
||||
let sheet = Cell::new(sheet);
|
||||
do self.stylist.write |stylist| {
|
||||
stylist.add_stylesheet(sheet.take(), AuthorOrigin);
|
||||
}
|
||||
let mut sheet = Some(sheet);
|
||||
self.stylist.write(|stylist| {
|
||||
stylist.add_stylesheet(sheet.take_unwrap(), AuthorOrigin);
|
||||
});
|
||||
}
|
||||
|
||||
/// Builds the flow tree.
|
||||
|
@ -359,12 +361,13 @@ impl LayoutTask {
|
|||
/// is intertwined with selector matching, making it difficult to compare directly. It is
|
||||
/// marked `#[inline(never)]` to aid benchmarking in sampling profilers.
|
||||
#[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));
|
||||
|
||||
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) => {
|
||||
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"),
|
||||
};
|
||||
|
@ -436,18 +439,18 @@ impl LayoutTask {
|
|||
// Initialize layout data for each node.
|
||||
//
|
||||
// FIXME: This is inefficient. We don't need an entire traversal to do this!
|
||||
do profile(time::LayoutAuxInitCategory, self.profiler_chan.clone()) {
|
||||
node.initialize_style_for_subtree();
|
||||
}
|
||||
profile(time::LayoutAuxInitCategory, self.profiler_chan.clone(), || {
|
||||
node.initialize_style_for_subtree(self.chan.clone());
|
||||
});
|
||||
|
||||
// Perform CSS selector matching if necessary.
|
||||
match data.damage.level {
|
||||
ReflowDocumentDamage => {}
|
||||
_ => {
|
||||
do profile(time::LayoutSelectorMatchCategory, self.profiler_chan.clone()) {
|
||||
profile(time::LayoutSelectorMatchCategory, self.profiler_chan.clone(), || {
|
||||
node.match_subtree(self.stylist.clone());
|
||||
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
|
||||
// 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)
|
||||
}
|
||||
});
|
||||
|
||||
debug!("layout: constraint solving done:");
|
||||
debug!("{:?}", layout_root.dump());
|
||||
|
||||
// Build the display list if necessary, and send it to the renderer.
|
||||
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 display_list = ~Cell::new(DisplayList::<OpaqueNode>::new());
|
||||
let display_list = ~RefCell::new(DisplayList::<OpaqueNode>::new());
|
||||
let dirty = flow::base(layout_root).position.clone();
|
||||
let display_list_builder = DisplayListBuilder {
|
||||
ctx: &layout_ctx,
|
||||
};
|
||||
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);
|
||||
|
||||
|
@ -516,7 +519,7 @@ impl LayoutTask {
|
|||
self.display_list = Some(display_list.clone());
|
||||
|
||||
self.render_chan.send(RenderMsg(render_layer));
|
||||
} // time(layout: display list building)
|
||||
});
|
||||
}
|
||||
|
||||
// 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
|
||||
/// because it contains local managed pointers.
|
||||
unsafe fn handle_reap_layout_data(&self, layout_data: LayoutDataRef) {
|
||||
let ptr: &mut Option<~LayoutData> = cast::transmute(layout_data.borrow_unchecked());
|
||||
*ptr = None
|
||||
let mut layout_data_ref = layout_data.borrow_mut();
|
||||
let _: Option<LayoutDataWrapper> = cast::transmute(
|
||||
util::replace(layout_data_ref.get(), None));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
//! Text layout.
|
||||
|
||||
use layout::box::{Box, ScannedTextBox, ScannedTextBoxInfo, UnscannedTextBox};
|
||||
use layout::box_::{Box, ScannedTextBox, ScannedTextBoxInfo, UnscannedTextBox};
|
||||
use layout::context::LayoutContext;
|
||||
use layout::flow::Flow;
|
||||
|
||||
|
@ -15,7 +15,7 @@ use servo_util::range::Range;
|
|||
use std::vec;
|
||||
|
||||
/// A stack-allocated object for scanning an inline flow into `TextRun`-containing `TextBox`es.
|
||||
struct TextRunScanner {
|
||||
pub struct TextRunScanner {
|
||||
clump: Range,
|
||||
}
|
||||
|
||||
|
@ -123,7 +123,7 @@ impl TextRunScanner {
|
|||
// 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.
|
||||
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: {} ({})",
|
||||
self.clump,
|
||||
|
@ -142,7 +142,7 @@ impl TextRunScanner {
|
|||
|
||||
// First, transform/compress text of all the nodes.
|
||||
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
|
||||
// `transform_text`, so that boxes starting and/or ending with whitespace can
|
||||
// be compressed correctly with respect to the text run.
|
||||
|
@ -157,7 +157,7 @@ impl TextRunScanner {
|
|||
last_whitespace_in_clump);
|
||||
last_whitespace_in_clump = new_whitespace;
|
||||
new_str
|
||||
};
|
||||
});
|
||||
new_whitespace = last_whitespace_in_clump;
|
||||
|
||||
// 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.
|
||||
let clump = self.clump;
|
||||
let run = if clump.length() != 0 && run_str.len() > 0 {
|
||||
fontgroup.with_borrow( |fg| {
|
||||
fg.fonts[0].with_mut_borrow( |font| {
|
||||
fontgroup.borrow().with(|fg| {
|
||||
fg.fonts[0].borrow().with_mut(|font| {
|
||||
Some(Arc::new(~TextRun::new(font, run_str.clone(), decoration)))
|
||||
})
|
||||
})
|
||||
|
@ -216,14 +216,14 @@ impl TextRunScanner {
|
|||
} // End of match.
|
||||
|
||||
debug!("--- In boxes: ---");
|
||||
for (i, box) in in_boxes.iter().enumerate() {
|
||||
debug!("{:u} --> {:s}", i, box.debug_str());
|
||||
for (i, box_) in in_boxes.iter().enumerate() {
|
||||
debug!("{:u} --> {:s}", i, box_.debug_str());
|
||||
}
|
||||
debug!("------------------");
|
||||
|
||||
debug!("--- Out boxes: ---");
|
||||
for (i, box) in out_boxes.iter().enumerate() {
|
||||
debug!("{:u} --> {:s}", i, box.debug_str());
|
||||
for (i, box_) in out_boxes.iter().enumerate() {
|
||||
debug!("{:u} --> {:s}", i, box_.debug_str());
|
||||
}
|
||||
debug!("------------------");
|
||||
|
||||
|
|
|
@ -2,15 +2,16 @@
|
|||
* 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/. */
|
||||
|
||||
use layout::box::Box;
|
||||
use layout::box_::Box;
|
||||
use layout::construct::{ConstructionResult, NoConstructionResult};
|
||||
use layout::wrapper::LayoutNode;
|
||||
|
||||
use extra::arc::Arc;
|
||||
use script::dom::node::AbstractNode;
|
||||
use script::layout_interface::LayoutChan;
|
||||
use servo_util::range::Range;
|
||||
use servo_util::slot::{MutSlotRef, SlotRef};
|
||||
use std::cast;
|
||||
use std::cell::{Ref, RefMut};
|
||||
use std::iter::Enumerate;
|
||||
use std::libc::uintptr_t;
|
||||
use std::vec::VecIterator;
|
||||
|
@ -31,7 +32,7 @@ impl NodeRange {
|
|||
}
|
||||
}
|
||||
|
||||
struct ElementMapping {
|
||||
pub struct ElementMapping {
|
||||
priv entries: ~[NodeRange],
|
||||
}
|
||||
|
||||
|
@ -46,7 +47,7 @@ impl ElementMapping {
|
|||
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() {
|
||||
if !callback(nr) {
|
||||
break
|
||||
|
@ -63,14 +64,14 @@ impl ElementMapping {
|
|||
let entries = &mut self.entries;
|
||||
|
||||
debug!("--- Old boxes: ---");
|
||||
for (i, box) in old_boxes.iter().enumerate() {
|
||||
debug!("{:u} --> {:s}", i, box.debug_str());
|
||||
for (i, box_) in old_boxes.iter().enumerate() {
|
||||
debug!("{:u} --> {:s}", i, box_.debug_str());
|
||||
}
|
||||
debug!("------------------");
|
||||
|
||||
debug!("--- New boxes: ---");
|
||||
for (i, box) in new_boxes.iter().enumerate() {
|
||||
debug!("{:u} --> {:s}", i, box.debug_str());
|
||||
for (i, box_) in new_boxes.iter().enumerate() {
|
||||
debug!("{:u} --> {:s}", i, box_.debug_str());
|
||||
}
|
||||
debug!("------------------");
|
||||
|
||||
|
@ -125,7 +126,7 @@ impl ElementMapping {
|
|||
}
|
||||
|
||||
/// Data that layout associates with a node.
|
||||
pub struct LayoutData {
|
||||
pub struct PrivateLayoutData {
|
||||
/// The results of CSS matching for this node.
|
||||
before_applicable_declarations: ~[Arc<~[PropertyDeclaration]>],
|
||||
|
||||
|
@ -148,10 +149,10 @@ pub struct LayoutData {
|
|||
flow_construction_result: ConstructionResult,
|
||||
}
|
||||
|
||||
impl LayoutData {
|
||||
impl PrivateLayoutData {
|
||||
/// Creates new layout data.
|
||||
pub fn new() -> LayoutData {
|
||||
LayoutData {
|
||||
pub fn new() -> PrivateLayoutData {
|
||||
PrivateLayoutData {
|
||||
applicable_declarations: ~[],
|
||||
before_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.
|
||||
pub trait LayoutDataAccess {
|
||||
/// Borrows the layout data without checks.
|
||||
///
|
||||
/// 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.
|
||||
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.
|
||||
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)]
|
||||
unsafe fn borrow_layout_data_unchecked<'a>(&'a self) -> &'a Option<~LayoutData> {
|
||||
cast::transmute(self.get().layout_data.borrow_unchecked())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn borrow_layout_data<'a>(&'a self) -> SlotRef<'a,Option<~LayoutData>> {
|
||||
fn borrow_layout_data<'a>(&'a self) -> Ref<'a,Option<LayoutDataWrapper>> {
|
||||
unsafe {
|
||||
cast::transmute(self.get().layout_data.borrow())
|
||||
}
|
||||
}
|
||||
|
||||
#[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 {
|
||||
cast::transmute(self.get().layout_data.mutate())
|
||||
cast::transmute(self.get().layout_data.borrow_mut())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
/// only ever see these and must never see instances of `AbstractNode`.
|
||||
#[deriving(Clone, Eq)]
|
||||
pub struct LayoutNode<'self> {
|
||||
pub struct LayoutNode<'a> {
|
||||
/// The wrapped node.
|
||||
priv node: AbstractNode,
|
||||
|
||||
/// 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.
|
||||
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 = ();
|
||||
f(LayoutNode {
|
||||
node: node,
|
||||
|
@ -48,7 +48,7 @@ impl<'self> LayoutNode<'self> {
|
|||
}
|
||||
|
||||
/// 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 {
|
||||
node: node,
|
||||
chain: self.chain,
|
||||
|
@ -62,14 +62,14 @@ impl<'self> LayoutNode<'self> {
|
|||
}
|
||||
|
||||
/// Returns the first child of this node.
|
||||
pub fn first_child(&self) -> Option<LayoutNode<'self>> {
|
||||
pub fn first_child(&self) -> Option<LayoutNode<'ln>> {
|
||||
unsafe {
|
||||
self.node.first_child().map(|node| self.new_with_this_lifetime(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 {
|
||||
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.
|
||||
///
|
||||
/// 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 = ~[];
|
||||
gather_layout_nodes(self, &mut nodes, false);
|
||||
LayoutTreeIterator::new(nodes)
|
||||
}
|
||||
|
||||
/// Returns an iterator over this node's children.
|
||||
pub fn children(&self) -> LayoutNodeChildrenIterator<'self> {
|
||||
pub fn children(&self) -> LayoutNodeChildrenIterator<'ln> {
|
||||
LayoutNodeChildrenIterator {
|
||||
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.
|
||||
///
|
||||
/// 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() {
|
||||
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.
|
||||
///
|
||||
/// 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() {
|
||||
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.
|
||||
///
|
||||
/// 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)
|
||||
}
|
||||
|
||||
|
@ -228,20 +228,20 @@ impl<'self> LayoutNode<'self> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'self> TNode<LayoutElement<'self>> for LayoutNode<'self> {
|
||||
fn parent_node(&self) -> Option<LayoutNode<'self>> {
|
||||
impl<'ln> TNode<LayoutElement<'ln>> for LayoutNode<'ln> {
|
||||
fn parent_node(&self) -> Option<LayoutNode<'ln>> {
|
||||
unsafe {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
match self.node.type_id() {
|
||||
ElementNodeTypeId(*) => true,
|
||||
ElementNodeTypeId(..) => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
fn is_document(&self) -> bool {
|
||||
match self.node.type_id() {
|
||||
DocumentNodeTypeId(*) => true,
|
||||
DocumentNodeTypeId(..) => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
/// If this is an element, accesses the element data. Fails if this is not an element node.
|
||||
#[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| {
|
||||
// FIXME(pcwalton): Workaround until Rust gets multiple lifetime parameters on
|
||||
// implementations.
|
||||
|
@ -276,16 +276,16 @@ impl<'self> TNode<LayoutElement<'self>> for LayoutNode<'self> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct LayoutNodeChildrenIterator<'self> {
|
||||
priv current_node: Option<LayoutNode<'self>>,
|
||||
pub struct LayoutNodeChildrenIterator<'a> {
|
||||
priv current_node: Option<LayoutNode<'a>>,
|
||||
}
|
||||
|
||||
impl<'self> Iterator<LayoutNode<'self>> for LayoutNodeChildrenIterator<'self> {
|
||||
fn next(&mut self) -> Option<LayoutNode<'self>> {
|
||||
impl<'a> Iterator<LayoutNode<'a>> for LayoutNodeChildrenIterator<'a> {
|
||||
fn next(&mut self) -> Option<LayoutNode<'a>> {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -294,13 +294,13 @@ impl<'self> Iterator<LayoutNode<'self>> for LayoutNodeChildrenIterator<'self> {
|
|||
// Easy for preorder; harder for postorder.
|
||||
//
|
||||
// FIXME(pcwalton): Parallelism! Eventually this should just be nuked.
|
||||
pub struct LayoutTreeIterator<'self> {
|
||||
priv nodes: ~[LayoutNode<'self>],
|
||||
pub struct LayoutTreeIterator<'a> {
|
||||
priv nodes: ~[LayoutNode<'a>],
|
||||
priv index: uint,
|
||||
}
|
||||
|
||||
impl<'self> LayoutTreeIterator<'self> {
|
||||
fn new(nodes: ~[LayoutNode<'self>]) -> LayoutTreeIterator<'self> {
|
||||
impl<'a> LayoutTreeIterator<'a> {
|
||||
fn new(nodes: ~[LayoutNode<'a>]) -> LayoutTreeIterator<'a> {
|
||||
LayoutTreeIterator {
|
||||
nodes: nodes,
|
||||
index: 0,
|
||||
|
@ -308,8 +308,8 @@ impl<'self> LayoutTreeIterator<'self> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'self> Iterator<LayoutNode<'self>> for LayoutTreeIterator<'self> {
|
||||
fn next(&mut self) -> Option<LayoutNode<'self>> {
|
||||
impl<'a> Iterator<LayoutNode<'a>> for LayoutTreeIterator<'a> {
|
||||
fn next(&mut self) -> Option<LayoutNode<'a>> {
|
||||
if self.index >= self.nodes.len() {
|
||||
None
|
||||
} else {
|
||||
|
@ -360,17 +360,17 @@ pub trait PostorderNodeMutTraversal {
|
|||
}
|
||||
|
||||
/// A wrapper around elements that ensures layout can only ever access safe properties.
|
||||
pub struct LayoutElement<'self> {
|
||||
priv element: &'self Element,
|
||||
pub struct LayoutElement<'le> {
|
||||
priv element: &'le Element,
|
||||
}
|
||||
|
||||
impl<'self> LayoutElement<'self> {
|
||||
pub fn style_attribute(&self) -> &'self Option<PropertyDeclarationBlock> {
|
||||
impl<'le> LayoutElement<'le> {
|
||||
pub fn style_attribute(&self) -> &'le Option<PropertyDeclarationBlock> {
|
||||
&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 {
|
||||
self.element.tag_name.as_slice()
|
||||
}
|
||||
|
|
|
@ -2,26 +2,10 @@
|
|||
* 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/. */
|
||||
#[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
|
||||
// move-from-closure error. This is sugar around the function spawn_with,
|
||||
// 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(
|
||||
($bitfieldname:ident, $getter:ident, $setter:ident, $value:expr) => (
|
||||
|
|
|
@ -15,12 +15,10 @@ use script::layout_interface::LayoutChan;
|
|||
use script::script_task::LoadMsg;
|
||||
use script::script_task::{AttachLayoutMsg, NewLayoutInfo, ScriptTask, ScriptChan};
|
||||
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::resource_task::ResourceTask;
|
||||
use servo_util::time::ProfilerChan;
|
||||
use std::task;
|
||||
use std::comm;
|
||||
|
||||
/// A uniquely-identifiable pipeline of script task, layout task, and render task.
|
||||
pub struct Pipeline {
|
||||
|
@ -55,10 +53,10 @@ impl Pipeline {
|
|||
opts: Opts,
|
||||
script_pipeline: &Pipeline)
|
||||
-> Pipeline {
|
||||
let (layout_port, layout_chan) = special_stream!(LayoutChan);
|
||||
let (render_port, render_chan) = special_stream!(RenderChan);
|
||||
let (render_shutdown_port, render_shutdown_chan) = comm::stream();
|
||||
let (layout_shutdown_port, layout_shutdown_chan) = comm::stream();
|
||||
let (layout_port, layout_chan) = LayoutChan::new();
|
||||
let (render_port, render_chan) = RenderChan::new();
|
||||
let (render_shutdown_port, render_shutdown_chan) = Chan::new();
|
||||
let (layout_shutdown_port, layout_shutdown_chan) = Chan::new();
|
||||
|
||||
RenderTask::create(id,
|
||||
render_port,
|
||||
|
@ -70,6 +68,7 @@ impl Pipeline {
|
|||
|
||||
LayoutTask::create(id,
|
||||
layout_port,
|
||||
layout_chan.clone(),
|
||||
constellation_chan,
|
||||
script_pipeline.script_chan.clone(),
|
||||
render_chan.clone(),
|
||||
|
@ -105,11 +104,11 @@ impl Pipeline {
|
|||
window_size: Size2D<uint>,
|
||||
opts: Opts)
|
||||
-> Pipeline {
|
||||
let (script_port, script_chan) = special_stream!(ScriptChan);
|
||||
let (layout_port, layout_chan) = special_stream!(LayoutChan);
|
||||
let (render_port, render_chan) = special_stream!(RenderChan);
|
||||
let (render_shutdown_port, render_shutdown_chan) = comm::stream();
|
||||
let (layout_shutdown_port, layout_shutdown_chan) = comm::stream();
|
||||
let (script_port, script_chan) = ScriptChan::new();
|
||||
let (layout_port, layout_chan) = LayoutChan::new();
|
||||
let (render_port, render_chan) = RenderChan::new();
|
||||
let (render_shutdown_port, render_shutdown_chan) = Chan::new();
|
||||
let (layout_shutdown_port, layout_shutdown_chan) = Chan::new();
|
||||
let pipeline = Pipeline::new(id,
|
||||
subpage_id,
|
||||
script_chan.clone(),
|
||||
|
@ -118,25 +117,8 @@ impl Pipeline {
|
|||
layout_shutdown_port,
|
||||
render_shutdown_port);
|
||||
|
||||
// Wrap task creation within a supervised task so that failure will
|
||||
// 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();
|
||||
// FIXME(#1434): add back failure supervision
|
||||
|
||||
spawn_with!(supervised_task, [
|
||||
script_port,
|
||||
resource_task,
|
||||
render_port,
|
||||
layout_port,
|
||||
constellation_chan,
|
||||
image_cache_task,
|
||||
profiler_chan,
|
||||
layout_shutdown_chan,
|
||||
render_shutdown_chan
|
||||
], {
|
||||
ScriptTask::create(id,
|
||||
compositor_chan.clone(),
|
||||
layout_chan.clone(),
|
||||
|
@ -157,6 +139,7 @@ impl Pipeline {
|
|||
|
||||
LayoutTask::create(id,
|
||||
layout_port,
|
||||
layout_chan.clone(),
|
||||
constellation_chan,
|
||||
script_chan.clone(),
|
||||
render_chan.clone(),
|
||||
|
@ -164,19 +147,6 @@ impl Pipeline {
|
|||
opts.clone(),
|
||||
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
|
||||
}
|
||||
|
@ -215,9 +185,9 @@ impl Pipeline {
|
|||
}
|
||||
|
||||
pub fn reload(&mut self) {
|
||||
do self.url.clone().map() |url| {
|
||||
self.url.clone().map(|url| {
|
||||
self.load(url);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
pub fn exit(&self) {
|
||||
|
@ -226,8 +196,8 @@ impl Pipeline {
|
|||
|
||||
// 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
|
||||
self.render_shutdown_port.try_recv();
|
||||
self.layout_shutdown_port.try_recv();
|
||||
self.render_shutdown_port.recv_opt();
|
||||
self.layout_shutdown_port.recv_opt();
|
||||
}
|
||||
|
||||
pub fn to_sendable(&self) -> CompositionPipeline {
|
||||
|
|
|
@ -30,9 +30,7 @@ impl ApplicationMethods for Application {
|
|||
fn new() -> Application {
|
||||
// Per GLFW docs it's safe to set the error callback before calling
|
||||
// glfwInit(), and this way we notice errors from init too.
|
||||
do glfw::set_error_callback |_error_code, description| {
|
||||
error!("GLFW error: {:s}", description);
|
||||
};
|
||||
glfw::set_error_callback(~glfw::LogErrorHandler);
|
||||
glfw::init();
|
||||
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.
|
||||
pub struct Window {
|
||||
glfw_window: glfw::Window,
|
||||
|
@ -90,18 +120,24 @@ impl WindowMethods<Application> for Window {
|
|||
install_local_window(window);
|
||||
|
||||
// Register event handlers.
|
||||
do window.glfw_window.set_framebuffer_size_callback |_win, width, height| {
|
||||
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)
|
||||
}
|
||||
do window.glfw_window.set_key_callback |_win, key, _scancode, action, mods| {
|
||||
window.glfw_window.set_framebuffer_size_callback(
|
||||
glfw_callback!(glfw::FramebufferSizeCallback(_win: &glfw::Window, width: i32, height: i32) {
|
||||
local_window().event_queue.push(ResizeWindowEvent(width as uint, height as uint));
|
||||
}));
|
||||
window.glfw_window.set_refresh_callback(
|
||||
glfw_callback!(glfw::WindowRefreshCallback(_win: &glfw::Window) {
|
||||
local_window().event_queue.push(RefreshWindowEvent);
|
||||
}));
|
||||
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) {
|
||||
if action == glfw::Press {
|
||||
local_window().handle_key(key, mods)
|
||||
}
|
||||
}
|
||||
do window.glfw_window.set_mouse_button_callback |win, button, action, _mods| {
|
||||
}));
|
||||
window.glfw_window.set_mouse_button_callback(
|
||||
glfw_callback!(glfw::MouseButtonCallback(win: &glfw::Window, button: glfw::MouseButton,
|
||||
action: glfw::Action, _mods: glfw::Modifiers) {
|
||||
let (x, y) = win.get_cursor_pos();
|
||||
//handle hidpi displays, since GLFW returns non-hi-def coordinates.
|
||||
let (backing_size, _) = win.get_framebuffer_size();
|
||||
|
@ -112,10 +148,11 @@ impl WindowMethods<Application> for Window {
|
|||
if button == glfw::MouseButtonLeft || button == glfw::MouseButtonRight {
|
||||
local_window().handle_mouse(button, action, x as i32, y as i32);
|
||||
}
|
||||
}
|
||||
do window.glfw_window.set_scroll_callback |win, x_offset, y_offset| {
|
||||
let dx = (x_offset as f32) * 30.0;
|
||||
let dy = (y_offset as f32) * 30.0;
|
||||
}));
|
||||
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();
|
||||
//handle hidpi displays, since GLFW returns non-hi-def coordinates.
|
||||
|
@ -126,7 +163,7 @@ impl WindowMethods<Application> for Window {
|
|||
let y = y as f32 * hidpi;
|
||||
|
||||
local_window().event_queue.push(ScrollWindowEvent(Point2D(dx, dy), Point2D(x as i32, y as i32)));
|
||||
}
|
||||
}));
|
||||
|
||||
window
|
||||
}
|
||||
|
|
|
@ -7,22 +7,22 @@
|
|||
use windowing::{ApplicationMethods, WindowEvent, WindowMethods};
|
||||
use windowing::{IdleWindowEvent, ResizeWindowEvent, LoadUrlWindowEvent, MouseWindowEventClass};
|
||||
use windowing::{ScrollWindowEvent, ZoomWindowEvent, NavigationWindowEvent, FinishedWindowEvent};
|
||||
use windowing::{QuitWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEvent, MouseWindowMouseUpEvent};
|
||||
use windowing::{MouseWindowClickEvent, MouseWindowMouseDownEvent, MouseWindowMouseUpEvent};
|
||||
use windowing::{Forward, Back};
|
||||
|
||||
use alert::{Alert, AlertMethods};
|
||||
use std::libc::c_int;
|
||||
use std::libc::{c_int, c_uchar};
|
||||
use std::local_data;
|
||||
use geom::point::Point2D;
|
||||
use geom::size::Size2D;
|
||||
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;
|
||||
|
||||
static THROBBER: [char, ..8] = [ '⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷' ];
|
||||
// static THROBBER: [char, ..8] = [ '⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷' ];
|
||||
|
||||
/// A structure responsible for setting up and tearing down the entire windowing system.
|
||||
pub struct Application;
|
||||
|
@ -85,20 +85,34 @@ impl WindowMethods<Application> for Window {
|
|||
// 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.
|
||||
do glut::display_func || {
|
||||
debug!("GLUT display func registered");
|
||||
|
||||
struct DisplayCallbackState;
|
||||
impl glut::DisplayCallback for DisplayCallbackState {
|
||||
fn call(&self) {
|
||||
debug!("GLUT display func registgered");
|
||||
}
|
||||
do glut::reshape_func(window.glut_window) |width, height| {
|
||||
}
|
||||
glut::display_func(~DisplayCallbackState);
|
||||
struct ReshapeCallbackState;
|
||||
impl glut::ReshapeCallback for ReshapeCallbackState {
|
||||
fn call(&self, width: c_int, height: c_int) {
|
||||
local_window().event_queue.push(ResizeWindowEvent(width as uint, height as uint))
|
||||
}
|
||||
do glut::keyboard_func |key, _, _| {
|
||||
}
|
||||
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)
|
||||
}
|
||||
do glut::mouse_func |button, state, x, y| {
|
||||
}
|
||||
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 {
|
||||
} 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)));
|
||||
|
@ -110,6 +124,8 @@ impl WindowMethods<Application> for Window {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
glut::mouse_func(~MouseCallbackState);
|
||||
|
||||
window
|
||||
}
|
||||
|
@ -165,28 +181,28 @@ impl WindowMethods<Application> for Window {
|
|||
|
||||
impl Window {
|
||||
/// Helper function to set the window title in accordance with the ready state.
|
||||
fn update_window_title(&self) {
|
||||
let throbber = THROBBER[self.throbber_frame];
|
||||
match self.ready_state {
|
||||
Blank => {
|
||||
glut::set_window_title(self.glut_window, "Blank")
|
||||
}
|
||||
Loading => {
|
||||
glut::set_window_title(self.glut_window, format!("{:c} Loading . Servo", throbber))
|
||||
}
|
||||
PerformingLayout => {
|
||||
glut::set_window_title(self.glut_window, format!("{:c} Performing Layout . Servo", throbber))
|
||||
}
|
||||
FinishedLoading => {
|
||||
match self.render_state {
|
||||
RenderingRenderState => {
|
||||
glut::set_window_title(self.glut_window, format!("{:c} Rendering . Servo", throbber))
|
||||
}
|
||||
IdleRenderState => glut::set_window_title(self.glut_window, "Servo"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// fn update_window_title(&self) {
|
||||
// let throbber = THROBBER[self.throbber_frame];
|
||||
// match self.ready_state {
|
||||
// Blank => {
|
||||
// glut::set_window_title(self.glut_window, "Blank")
|
||||
// }
|
||||
// Loading => {
|
||||
// glut::set_window_title(self.glut_window, format!("{:c} Loading . Servo", throbber))
|
||||
// }
|
||||
// PerformingLayout => {
|
||||
// glut::set_window_title(self.glut_window, format!("{:c} Performing Layout . Servo", throbber))
|
||||
// }
|
||||
// FinishedLoading => {
|
||||
// match self.render_state {
|
||||
// RenderingRenderState => {
|
||||
// glut::set_window_title(self.glut_window, format!("{:c} Rendering . Servo", throbber))
|
||||
// }
|
||||
// IdleRenderState => glut::set_window_title(self.glut_window, "Servo"),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
/// Helper function to handle keyboard events.
|
||||
fn handle_key(&self, key: u8) {
|
||||
|
|
|
@ -2,21 +2,16 @@
|
|||
* 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/. */
|
||||
|
||||
#[link(name = "servo",
|
||||
vers = "0.1",
|
||||
uuid = "637ffc98-9058-471d-9de7-abfc49ef0549",
|
||||
url = "http://servo.org/")];
|
||||
|
||||
#[crate_id = "github.com/mozilla/servo"];
|
||||
#[comment = "The Servo Parallel Browser Project"];
|
||||
#[license = "MPL"];
|
||||
#[crate_type = "lib"];
|
||||
|
||||
#[feature(globs, macro_rules, managed_boxes)];
|
||||
|
||||
extern mod alert;
|
||||
extern mod azure;
|
||||
extern mod geom;
|
||||
extern mod gfx (name = "gfx");
|
||||
extern mod gfx;
|
||||
#[cfg(not(target_os="android"))]
|
||||
extern mod glfw;
|
||||
#[cfg(target_os="android")]
|
||||
|
@ -26,39 +21,50 @@ extern mod layers;
|
|||
extern mod opengles;
|
||||
extern mod png;
|
||||
extern mod script;
|
||||
extern mod servo_net (name = "net");
|
||||
extern mod servo_msg (name = "msg");
|
||||
extern mod servo_util (name = "util");
|
||||
extern mod servo_net = "net";
|
||||
extern mod servo_msg = "msg";
|
||||
extern mod servo_util = "util";
|
||||
extern mod style;
|
||||
extern mod sharegl;
|
||||
extern mod stb_image;
|
||||
|
||||
extern mod extra;
|
||||
extern mod green;
|
||||
extern mod native;
|
||||
|
||||
#[cfg(target_os="macos")]
|
||||
extern mod core_graphics;
|
||||
#[cfg(target_os="macos")]
|
||||
extern mod core_text;
|
||||
|
||||
#[cfg(not(test))]
|
||||
use compositing::{CompositorChan, CompositorTask};
|
||||
#[cfg(not(test))]
|
||||
use constellation::Constellation;
|
||||
use servo_msg::constellation_msg::{ConstellationChan, InitLoadUrlMsg};
|
||||
#[cfg(not(test))]
|
||||
use servo_msg::constellation_msg::InitLoadUrlMsg;
|
||||
|
||||
#[cfg(not(test))]
|
||||
use gfx::opts;
|
||||
|
||||
#[cfg(not(test))]
|
||||
use servo_net::image_cache_task::ImageCacheTask;
|
||||
#[cfg(not(test))]
|
||||
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::text;
|
||||
pub use servo_util::url::make_url;
|
||||
use std::comm;
|
||||
|
||||
#[cfg(not(test))]
|
||||
use std::os;
|
||||
#[cfg(not(test), target_os="android")]
|
||||
use std::str;
|
||||
use std::task::spawn_with;
|
||||
#[cfg(not(test))]
|
||||
use std::task::TaskOpts;
|
||||
|
||||
|
||||
#[path="compositing/compositor_task.rs"]
|
||||
pub mod compositing;
|
||||
|
@ -78,7 +84,7 @@ pub mod pipeline;
|
|||
|
||||
pub mod layout {
|
||||
pub mod block;
|
||||
pub mod box;
|
||||
pub mod box_;
|
||||
pub mod construct;
|
||||
pub mod context;
|
||||
pub mod display_list_builder;
|
||||
|
@ -106,15 +112,15 @@ pub mod util;
|
|||
#[cfg(not(test), target_os="macos")]
|
||||
#[start]
|
||||
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()))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(not(test), target_os="android")]
|
||||
#[no_mangle]
|
||||
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] = ~[];
|
||||
for i in range(0u, argc as uint) {
|
||||
unsafe {
|
||||
|
@ -122,53 +128,51 @@ pub extern "C" fn android_start(argc: int, argv: **u8) -> int {
|
|||
}
|
||||
}
|
||||
run(opts::from_cmdline_args(args))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
fn run(opts: Opts) {
|
||||
let (exit_response_from_constellation, exit_chan) = comm::stream();
|
||||
let (profiler_port, profiler_chan) = special_stream!(ProfilerChan);
|
||||
let (compositor_port, compositor_chan) = special_stream!(CompositorChan);
|
||||
let (constellation_port, constellation_chan) = special_stream!(ConstellationChan);
|
||||
let mut pool = green::SchedPool::new(green::PoolConfig::new());
|
||||
|
||||
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,
|
||||
constellation_chan.clone(),
|
||||
profiler_chan.clone(),
|
||||
compositor_chan,
|
||||
opts.clone()))
|
||||
|(constellation_port,
|
||||
constellation_chan,
|
||||
profiler_chan,
|
||||
compositor_chan,
|
||||
opts)| {
|
||||
let opts = &opts;
|
||||
let opts_clone = opts.clone();
|
||||
let profiler_chan_clone = profiler_chan.clone();
|
||||
|
||||
let (result_port, result_chan) = Chan::new();
|
||||
pool.spawn(TaskOpts::new(), proc() {
|
||||
let opts = &opts_clone;
|
||||
// Create a Servo instance.
|
||||
let resource_task = ResourceTask();
|
||||
let image_cache_task = ImageCacheTask(resource_task.clone());
|
||||
Constellation::start(constellation_port,
|
||||
constellation_chan.clone(),
|
||||
compositor_chan,
|
||||
let constellation_chan = Constellation::start(compositor_chan,
|
||||
opts,
|
||||
resource_task,
|
||||
image_cache_task,
|
||||
profiler_chan.clone());
|
||||
profiler_chan_clone);
|
||||
|
||||
// Send the constallation Chan as the result
|
||||
result_chan.send(constellation_chan.clone());
|
||||
|
||||
// Send the URL command to the constellation.
|
||||
for filename in opts.urls.iter() {
|
||||
constellation_chan.send(InitLoadUrlMsg(make_url(filename.clone(), None)))
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let constellation_chan = result_port.recv();
|
||||
|
||||
debug!("preparing to enter main loop");
|
||||
CompositorTask::create(opts,
|
||||
compositor_port,
|
||||
constellation_chan.clone(),
|
||||
constellation_chan,
|
||||
profiler_chan,
|
||||
exit_chan,
|
||||
exit_response_from_constellation);
|
||||
|
||||
pool.shutdown();
|
||||
}
|
||||
|
||||
|
|
|
@ -2,26 +2,20 @@
|
|||
* 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/. */
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::comm;
|
||||
use std::comm::{Chan, Port};
|
||||
use std::task;
|
||||
|
||||
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();
|
||||
pub fn spawn_listener<A: Send>(f: proc(Port<A>)) -> Chan<A> {
|
||||
let (setup_po, setup_ch) = Chan::new();
|
||||
spawn(proc() {
|
||||
let (po, ch) = Chan::new();
|
||||
setup_ch.send(ch);
|
||||
f(po);
|
||||
}
|
||||
});
|
||||
setup_po.recv()
|
||||
}
|
||||
|
||||
pub fn spawn_conversation<A: Send, B: Send>(f: ~fn(Port<A>, Chan<B>)) -> (Port<B>, Chan<A>) {
|
||||
let (from_child, to_parent) = comm::stream();
|
||||
let to_parent = Cell::new(to_parent);
|
||||
pub fn spawn_conversation<A: Send, B: Send>(f: proc(Port<A>, Chan<B>)) -> (Port<B>, Chan<A>) {
|
||||
let (from_child, to_parent) = Chan::new();
|
||||
let to_child = do spawn_listener |from_parent| {
|
||||
f(from_parent, to_parent.take())
|
||||
f(from_parent, to_parent)
|
||||
};
|
||||
(from_child, to_child)
|
||||
}
|
||||
|
|
|
@ -14,8 +14,9 @@ use std::comm::{Chan, SharedChan};
|
|||
pub struct ConstellationChan(SharedChan<Msg>);
|
||||
|
||||
impl ConstellationChan {
|
||||
pub fn new(chan: Chan<Msg>) -> ConstellationChan {
|
||||
ConstellationChan(SharedChan::new(chan))
|
||||
pub fn new() -> (Port<Msg>, ConstellationChan) {
|
||||
let (port, chan) = SharedChan::new();
|
||||
(port, ConstellationChan(chan))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,5 +54,6 @@ pub enum NavigationDirection {
|
|||
|
||||
#[deriving(Clone, Eq, IterBytes)]
|
||||
pub struct PipelineId(uint);
|
||||
|
||||
#[deriving(Clone, Eq, IterBytes)]
|
||||
pub struct SubpageId(uint);
|
||||
|
|
|
@ -2,10 +2,7 @@
|
|||
* 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/. */
|
||||
|
||||
#[link(name = "msg",
|
||||
vers = "0.1",
|
||||
uuid = "4c6054e4-2a7b-4fae-b0c8-6d04416b2bf2",
|
||||
url = "http://servo.org/")];
|
||||
#[crate_id = "github.com/mozilla/servo#msg:0.1"];
|
||||
#[crate_type = "lib"];
|
||||
|
||||
extern mod azure;
|
||||
|
|
|
@ -11,7 +11,7 @@ use http::headers::test_utils::from_stream_with_str;
|
|||
use http::headers::content_type::MediaType;
|
||||
|
||||
pub fn factory() -> LoaderTask {
|
||||
|url, start_chan| {
|
||||
proc(url, start_chan) {
|
||||
// NB: we don't spawn a new task.
|
||||
// Hypothesis: data URLs are too small for parallel base64 etc. to be worth it.
|
||||
// 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());
|
||||
|
||||
// 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 {
|
||||
start_sending(start_chan, metadata).send(Done(Err(())));
|
||||
return;
|
||||
|
@ -49,7 +49,7 @@ fn load(url: Url, start_chan: Chan<LoadResponse>) {
|
|||
|
||||
if is_base64 {
|
||||
match parts[1].from_base64() {
|
||||
Err(*) => {
|
||||
Err(..) => {
|
||||
progress_chan.send(Done(Err(())));
|
||||
}
|
||||
Ok(data) => {
|
||||
|
@ -71,9 +71,8 @@ fn assert_parse(url: &'static str,
|
|||
charset: Option<~str>,
|
||||
data: Option<~[u8]>) {
|
||||
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);
|
||||
|
||||
let response = start_port.recv();
|
||||
|
|
|
@ -5,23 +5,21 @@
|
|||
use resource_task::{ProgressMsg, Metadata, Payload, Done, LoaderTask, start_sending};
|
||||
use servo_util::io::result;
|
||||
|
||||
use std::comm::Chan;
|
||||
use std::rt::io::file;
|
||||
use std::rt::io::{FileStream, Reader, EndOfFile, Open, Read, ignore_io_error};
|
||||
use std::task;
|
||||
use std::io;
|
||||
use std::io::File;
|
||||
|
||||
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<(), ()> {
|
||||
loop {
|
||||
match (do result {
|
||||
match (result(|| {
|
||||
let data = reader.read_bytes(READ_SIZE);
|
||||
progress_chan.send(Payload(data));
|
||||
}) {
|
||||
})) {
|
||||
Ok(()) => (),
|
||||
Err(e) => match e.kind {
|
||||
EndOfFile => return Ok(()),
|
||||
io::EndOfFile => return Ok(()),
|
||||
_ => return Err(()),
|
||||
}
|
||||
}
|
||||
|
@ -29,21 +27,22 @@ fn read_all(reader: &mut FileStream, progress_chan: &Chan<ProgressMsg>)
|
|||
}
|
||||
|
||||
pub fn factory() -> LoaderTask {
|
||||
let f: LoaderTask = |url, start_chan| {
|
||||
let f: LoaderTask = proc(url, start_chan) {
|
||||
assert!("file" == url.scheme);
|
||||
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.
|
||||
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) => {
|
||||
let res = read_all(reader, &progress_chan);
|
||||
let res = read_all(reader as &mut io::Stream, &progress_chan);
|
||||
progress_chan.send(Done(res));
|
||||
}
|
||||
None => {
|
||||
progress_chan.send(Done(Err(())));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
};
|
||||
f
|
||||
}
|
||||
|
|
|
@ -4,19 +4,16 @@
|
|||
|
||||
use resource_task::{Metadata, Payload, Done, LoadResponse, LoaderTask, start_sending};
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::vec;
|
||||
use extra::url::Url;
|
||||
use http::client::RequestWriter;
|
||||
use http::method::Get;
|
||||
use http::headers::HeaderEnum;
|
||||
use std::rt::io::Reader;
|
||||
use std::io::Reader;
|
||||
|
||||
pub fn factory() -> LoaderTask {
|
||||
let f: LoaderTask = |url, start_chan| {
|
||||
let url = Cell::new(url);
|
||||
let start_chan = Cell::new(start_chan);
|
||||
spawn(|| load(url.take(), start_chan.take()))
|
||||
let f: LoaderTask = proc(url, start_chan) {
|
||||
spawn(proc() load(url, start_chan))
|
||||
};
|
||||
f
|
||||
}
|
||||
|
@ -63,10 +60,10 @@ fn load(mut url: Url, start_chan: Chan<LoadResponse>) {
|
|||
loop {
|
||||
let mut buf = vec::with_capacity(1024);
|
||||
|
||||
unsafe { vec::raw::set_len(&mut buf, 1024) };
|
||||
unsafe { buf.set_len(1024); }
|
||||
match response.read(buf) {
|
||||
Some(len) => {
|
||||
unsafe { vec::raw::set_len(&mut buf, len) };
|
||||
unsafe { buf.set_len(len); }
|
||||
progress_chan.send(Payload(buf));
|
||||
}
|
||||
None => {
|
||||
|
|
|
@ -64,12 +64,12 @@ impl ImageHolder {
|
|||
/// Query and update the current image size.
|
||||
pub fn get_size(&mut self) -> Option<Size2D<int>> {
|
||||
debug!("get_size() {}", self.url.to_str());
|
||||
do self.get_image().map |img| {
|
||||
self.get_image().map(|img| {
|
||||
let img_ref = img.get();
|
||||
self.cached_size = Size2D(img_ref.width as int,
|
||||
img_ref.height as int);
|
||||
self.cached_size.clone()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_image(&mut self) -> Option<Arc<~Image>> {
|
||||
|
|
|
@ -7,8 +7,7 @@ use resource_task;
|
|||
use resource_task::ResourceTask;
|
||||
use servo_util::url::{UrlMap, url_map};
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::comm::{Chan, Port, SharedChan, stream};
|
||||
use std::comm::{Chan, Port, SharedChan};
|
||||
use std::task::spawn;
|
||||
use std::to_str::ToStr;
|
||||
use std::util::replace;
|
||||
|
@ -24,7 +23,7 @@ pub enum Msg {
|
|||
// FIXME: We can probably get rid of this Cell now
|
||||
// FIXME: make this priv after visibility rules change
|
||||
/// 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
|
||||
Decode(Url),
|
||||
|
@ -40,12 +39,16 @@ pub enum Msg {
|
|||
/// Wait for an image to become available (or fail to load).
|
||||
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
|
||||
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)]
|
||||
|
@ -59,11 +62,11 @@ impl Eq for ImageResponseMsg {
|
|||
fn eq(&self, other: &ImageResponseMsg) -> bool {
|
||||
// FIXME: Bad copies
|
||||
match (self.clone(), other.clone()) {
|
||||
(ImageReady(*), ImageReady(*)) => fail!(~"unimplemented comparison"),
|
||||
(ImageReady(..), ImageReady(..)) => fail!(~"unimplemented comparison"),
|
||||
(ImageNotReady, ImageNotReady) => 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>;
|
||||
|
||||
type DecoderFactory = ~fn() -> ~fn(&[u8]) -> Option<Image>;
|
||||
|
||||
pub fn ImageCacheTask(resource_task: ResourceTask) -> ImageCacheTask {
|
||||
ImageCacheTask_(resource_task, default_decoder_factory)
|
||||
#[deriving(Clone)]
|
||||
pub struct ImageCacheTask {
|
||||
chan: SharedChan<Msg>,
|
||||
}
|
||||
|
||||
pub fn ImageCacheTask_(resource_task: ResourceTask, decoder_factory: DecoderFactory)
|
||||
-> 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);
|
||||
type DecoderFactory = fn() -> proc(&[u8]) -> Option<Image>;
|
||||
|
||||
let (port, chan) = stream();
|
||||
let chan = SharedChan::new(chan);
|
||||
let port_cell = Cell::new(port);
|
||||
let chan_cell = Cell::new(chan.clone());
|
||||
pub fn ImageCacheTask(resource_task: ResourceTask) -> ImageCacheTask {
|
||||
let (port, chan) = SharedChan::new();
|
||||
let chan_clone = chan.clone();
|
||||
|
||||
do spawn {
|
||||
spawn(proc() {
|
||||
let mut cache = ImageCache {
|
||||
resource_task: resource_task.clone(),
|
||||
decoder_factory: decoder_factory_cell.take(),
|
||||
port: port_cell.take(),
|
||||
chan: chan_cell.take(),
|
||||
port: port,
|
||||
chan: chan_clone,
|
||||
state_map: url_map(),
|
||||
wait_map: url_map(),
|
||||
need_exit: None
|
||||
};
|
||||
cache.run();
|
||||
}
|
||||
});
|
||||
|
||||
chan
|
||||
ImageCacheTask {
|
||||
chan: chan,
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: make this priv after visibility rules change
|
||||
pub fn SyncImageCacheTask(resource_task: ResourceTask) -> ImageCacheTask {
|
||||
let (port, chan) = stream();
|
||||
let port_cell = Cell::new(port);
|
||||
let (port, chan) = SharedChan::new();
|
||||
|
||||
do spawn {
|
||||
let port = port_cell.take();
|
||||
spawn(proc() {
|
||||
let inner_cache = ImageCacheTask(resource_task.clone());
|
||||
|
||||
loop {
|
||||
|
@ -131,16 +124,16 @@ pub fn SyncImageCacheTask(resource_task: ResourceTask) -> ImageCacheTask {
|
|||
msg => inner_cache.send(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
SharedChan::new(chan)
|
||||
ImageCacheTask {
|
||||
chan: chan,
|
||||
}
|
||||
}
|
||||
|
||||
struct ImageCache {
|
||||
/// A handle to the resource task for fetching the image binaries
|
||||
resource_task: ResourceTask,
|
||||
/// Creates image decoders
|
||||
decoder_factory: DecoderFactory,
|
||||
/// The port on which we'll receive client requests
|
||||
port: Port<Msg>,
|
||||
/// A copy of the shared chan to give to child tasks
|
||||
|
@ -156,7 +149,7 @@ struct ImageCache {
|
|||
enum ImageState {
|
||||
Init,
|
||||
Prefetching(AfterPrefetch),
|
||||
Prefetched(Cell<~[u8]>),
|
||||
Prefetched(~[u8]),
|
||||
Decoding,
|
||||
Decoded(Arc<~Image>),
|
||||
Failed
|
||||
|
@ -170,29 +163,39 @@ enum AfterPrefetch {
|
|||
|
||||
impl ImageCache {
|
||||
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 {
|
||||
let msg = self.port.recv();
|
||||
|
||||
for handler in msg_handlers.iter() {
|
||||
(*handler)(&msg)
|
||||
}
|
||||
|
||||
debug!("image_cache_task: received: {:?}", msg);
|
||||
|
||||
match msg {
|
||||
Prefetch(url) => self.prefetch(url),
|
||||
StorePrefetchedImageData(url, data) => {
|
||||
store_prefetched_chan.map(|chan| {
|
||||
chan.send(());
|
||||
});
|
||||
store_prefetched_chan = None;
|
||||
|
||||
self.store_prefetched_image_data(url, data);
|
||||
}
|
||||
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),
|
||||
WaitForImage(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) => {
|
||||
assert!(self.need_exit.is_none());
|
||||
self.need_exit = Some(response);
|
||||
|
@ -208,10 +211,10 @@ impl ImageCache {
|
|||
let mut can_exit = true;
|
||||
for (_, state) in self.state_map.iter() {
|
||||
match *state {
|
||||
Prefetching(*) => can_exit = false,
|
||||
Prefetching(..) => can_exit = false,
|
||||
Decoding => can_exit = false,
|
||||
|
||||
Init | Prefetched(*) | Decoded(*) | Failed => ()
|
||||
Init | Prefetched(..) | Decoded(..) | Failed => ()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -243,45 +246,44 @@ impl ImageCache {
|
|||
Init => {
|
||||
let to_cache = self.chan.clone();
|
||||
let resource_task = self.resource_task.clone();
|
||||
let url_cell = Cell::new(url.clone());
|
||||
let url_clone = url.clone();
|
||||
|
||||
do spawn {
|
||||
let url = url_cell.take();
|
||||
spawn(proc() {
|
||||
let url = url_clone;
|
||||
debug!("image_cache_task: started fetch for {:s}", url.to_str());
|
||||
|
||||
let image = load_image_data(url.clone(), resource_task.clone());
|
||||
|
||||
let result = if image.is_ok() {
|
||||
Ok(Cell::new(image.unwrap()))
|
||||
Ok(image.unwrap())
|
||||
} else {
|
||||
Err(())
|
||||
};
|
||||
to_cache.send(StorePrefetchedImageData(url.clone(), result));
|
||||
debug!("image_cache_task: ended fetch for {:s}", (url.clone()).to_str());
|
||||
}
|
||||
});
|
||||
|
||||
self.set_state(url, Prefetching(DoNotDecode));
|
||||
}
|
||||
|
||||
Prefetching(*) | Prefetched(*) | Decoding | Decoded(*) | Failed => {
|
||||
Prefetching(..) | Prefetched(..) | Decoding | Decoded(..) | Failed => {
|
||||
// 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()) {
|
||||
Prefetching(next_step) => {
|
||||
match data {
|
||||
Ok(data_cell) => {
|
||||
let data = data_cell.take();
|
||||
self.set_state(url.clone(), Prefetched(Cell::new(data)));
|
||||
Ok(data) => {
|
||||
self.set_state(url.clone(), Prefetched(data));
|
||||
match next_step {
|
||||
DoDecode => self.decode(url),
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
Err(*) => {
|
||||
Err(..) => {
|
||||
self.set_state(url.clone(), Failed);
|
||||
self.purge_waiters(url, || ImageFailed);
|
||||
}
|
||||
|
@ -289,9 +291,9 @@ impl ImageCache {
|
|||
}
|
||||
|
||||
Init
|
||||
| Prefetched(*)
|
||||
| Prefetched(..)
|
||||
| Decoding
|
||||
| Decoded(*)
|
||||
| Decoded(..)
|
||||
| Failed => {
|
||||
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
|
||||
}
|
||||
|
||||
Prefetched(data_cell) => {
|
||||
assert!(!data_cell.is_empty());
|
||||
|
||||
let data = data_cell.take();
|
||||
Prefetched(data) => {
|
||||
let to_cache = self.chan.clone();
|
||||
let url_cell = Cell::new(url.clone());
|
||||
let decode = (self.decoder_factory)();
|
||||
let url_clone = url.clone();
|
||||
|
||||
do spawn {
|
||||
let url = url_cell.take();
|
||||
spawn(proc() {
|
||||
let url = url_clone;
|
||||
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() {
|
||||
Some(Arc::new(~image.unwrap()))
|
||||
} else {
|
||||
|
@ -330,12 +328,12 @@ impl ImageCache {
|
|||
};
|
||||
to_cache.send(StoreImage(url.clone(), image));
|
||||
debug!("image_cache_task: ended image decode for {:s}", url.to_str());
|
||||
}
|
||||
});
|
||||
|
||||
self.set_state(url, Decoding);
|
||||
}
|
||||
|
||||
Decoding | Decoded(*) | Failed => {
|
||||
Decoding | Decoded(..) | Failed => {
|
||||
// We've already begun decoding
|
||||
}
|
||||
}
|
||||
|
@ -358,9 +356,9 @@ impl ImageCache {
|
|||
}
|
||||
|
||||
Init
|
||||
| Prefetching(*)
|
||||
| Prefetched(*)
|
||||
| Decoded(*)
|
||||
| Prefetching(..)
|
||||
| Prefetched(..)
|
||||
| Decoded(..)
|
||||
| Failed => {
|
||||
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) {
|
||||
Some(waiters) => {
|
||||
unsafe {
|
||||
|
@ -387,7 +385,7 @@ impl ImageCache {
|
|||
match self.get_state(url.clone()) {
|
||||
Init => fail!(~"request for image before prefetch"),
|
||||
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),
|
||||
Decoded(image) => response.send(ImageReady(image.clone())),
|
||||
Failed => response.send(ImageFailed),
|
||||
|
@ -398,16 +396,16 @@ impl ImageCache {
|
|||
match self.get_state(url.clone()) {
|
||||
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 => {
|
||||
// We don't have this image yet
|
||||
if self.wait_map.contains_key(&url) {
|
||||
let waiters = self.wait_map.find_mut(&url).unwrap();
|
||||
let mut response = Some(response);
|
||||
unsafe {
|
||||
let res = Cell::new(response);
|
||||
waiters.unsafe_access( |waiters| {
|
||||
waiters.push(res.take());
|
||||
waiters.unsafe_access(|waiters| {
|
||||
waiters.push(response.take().unwrap());
|
||||
});
|
||||
}
|
||||
} else {
|
||||
|
@ -434,14 +432,34 @@ trait ImageCacheTaskClient {
|
|||
|
||||
impl ImageCacheTaskClient for ImageCacheTask {
|
||||
fn exit(&self) {
|
||||
let (response_port, response_chan) = stream();
|
||||
let (response_port, response_chan) = Chan::new();
|
||||
self.send(Exit(response_chan));
|
||||
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], ()> {
|
||||
let (response_port, response_chan) = stream();
|
||||
let (response_port, response_chan) = Chan::new();
|
||||
resource_task.send(resource_task::Load(url, response_chan));
|
||||
|
||||
let mut image_data = ~[];
|
||||
|
@ -452,38 +470,29 @@ fn load_image_data(url: Url, resource_task: ResourceTask) -> Result<~[u8], ()> {
|
|||
resource_task::Payload(data) => {
|
||||
image_data.push_all(data);
|
||||
}
|
||||
resource_task::Done(result::Ok(*)) => {
|
||||
resource_task::Done(result::Ok(..)) => {
|
||||
return Ok(image_data);
|
||||
}
|
||||
resource_task::Done(result::Err(*)) => {
|
||||
resource_task::Done(result::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)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use std::comm;
|
||||
use std::comm::{Port, SharedChan};
|
||||
use std::result;
|
||||
use std::cell::Cell;
|
||||
|
||||
use resource_task;
|
||||
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 servo_util::url::make_url;
|
||||
|
||||
fn mock_resource_task(on_load: ~fn(resource: Chan<resource_task::ProgressMsg>)) -> ResourceTask {
|
||||
let chan = do spawn_listener |port: Port<resource_task::ControlMsg>| {
|
||||
fn mock_resource_task(on_load: proc(resource: SharedChan<resource_task::ProgressMsg>)) -> ResourceTask {
|
||||
spawn_listener(proc(port: Port<resource_task::ControlMsg>) {
|
||||
loop {
|
||||
match port.recv() {
|
||||
resource_task::Load(_, response) => {
|
||||
|
@ -493,13 +502,12 @@ mod tests {
|
|||
resource_task::Exit => break
|
||||
}
|
||||
}
|
||||
};
|
||||
SharedChan::new(chan)
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
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 _url = make_url(~"file", None);
|
||||
|
@ -511,24 +519,24 @@ mod tests {
|
|||
#[test]
|
||||
#[should_fail]
|
||||
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 url = make_url(~"file", None);
|
||||
|
||||
let (port, chan) = stream();
|
||||
let (port, chan) = Chan::new();
|
||||
image_cache_task.send(GetImage(url, chan));
|
||||
port.recv();
|
||||
}
|
||||
|
||||
#[test]
|
||||
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(());
|
||||
response.send(resource_task::Done(result::Ok(())));
|
||||
};
|
||||
response.send(resource_task::Done(Ok(())));
|
||||
});
|
||||
|
||||
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
||||
let url = make_url(~"file", None);
|
||||
|
@ -539,47 +547,14 @@ mod tests {
|
|||
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]
|
||||
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(());
|
||||
response.send(resource_task::Done(result::Ok(())));
|
||||
};
|
||||
response.send(resource_task::Done(Ok(())));
|
||||
});
|
||||
|
||||
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
||||
let url = make_url(~"file", None);
|
||||
|
@ -589,27 +564,27 @@ mod tests {
|
|||
url_requested.recv();
|
||||
image_cache_task.exit();
|
||||
mock_resource_task.send(resource_task::Exit);
|
||||
assert!(!url_requested.peek())
|
||||
assert!(url_requested.try_recv().is_none())
|
||||
}
|
||||
|
||||
#[test]
|
||||
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
|
||||
// the image
|
||||
wait_port.recv();
|
||||
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 url = make_url(~"file", None);
|
||||
|
||||
image_cache_task.send(Prefetch(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));
|
||||
assert!(response_port.recv() == ImageNotReady);
|
||||
wait_chan.send(());
|
||||
|
@ -619,30 +594,23 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
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::Done(result::Ok(())));
|
||||
};
|
||||
response.send(resource_task::Done(Ok(())));
|
||||
});
|
||||
|
||||
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
||||
let url = make_url(~"file", None);
|
||||
|
||||
let (wait_for_image, wait_for_image_chan) = comm::stream();
|
||||
|
||||
image_cache_task.send(OnMsg(|msg| {
|
||||
match *msg {
|
||||
StoreImage(*) => wait_for_image_chan.send(()),
|
||||
_ => ()
|
||||
}
|
||||
}));
|
||||
let join_port = image_cache_task.wait_for_store();
|
||||
|
||||
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_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));
|
||||
match response_port.recv() {
|
||||
ImageReady(_) => (),
|
||||
|
@ -655,31 +623,24 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
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::Done(result::Ok(())));
|
||||
};
|
||||
response.send(resource_task::Done(Ok(())));
|
||||
});
|
||||
|
||||
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
||||
let url = make_url(~"file", None);
|
||||
|
||||
let (wait_for_image, wait_for_image_chan) = comm::stream();
|
||||
|
||||
image_cache_task.send(OnMsg(|msg| {
|
||||
match *msg {
|
||||
StoreImage(*) => wait_for_image_chan.send(()),
|
||||
_ => ()
|
||||
}
|
||||
}));
|
||||
let join_port = image_cache_task.wait_for_store();
|
||||
|
||||
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_image.recv();
|
||||
join_port.recv();
|
||||
|
||||
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));
|
||||
match response_port.recv() {
|
||||
ImageReady(_) => (),
|
||||
|
@ -693,17 +654,17 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
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 {
|
||||
match port.recv() {
|
||||
resource_task::Load(_, response) => {
|
||||
let chan = start_sending(response, Metadata::default(make_url(~"file:///fake", None)));
|
||||
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(());
|
||||
}
|
||||
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 url = make_url(~"file", None);
|
||||
|
@ -732,22 +692,22 @@ mod tests {
|
|||
|
||||
// Our resource task should not have received another request for the image
|
||||
// because it's already cached
|
||||
assert!(!image_bin_sent.peek());
|
||||
assert!(image_bin_sent.try_recv().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
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 {
|
||||
match port.recv() {
|
||||
resource_task::Load(_, response) => {
|
||||
let chan = start_sending(response, Metadata::default(make_url(~"file:///fake", None)));
|
||||
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(());
|
||||
}
|
||||
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 url = make_url(~"file", None);
|
||||
|
@ -778,36 +737,29 @@ mod tests {
|
|||
|
||||
// Our resource task should not have received another request for the image
|
||||
// because it's already cached
|
||||
assert!(!image_bin_sent.peek());
|
||||
assert!(image_bin_sent.try_recv().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
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()));
|
||||
// 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 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(()),
|
||||
_ => ()
|
||||
}
|
||||
}));
|
||||
let join_port = image_cache_task.wait_for_store_prefetched();
|
||||
|
||||
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();
|
||||
join_port.recv();
|
||||
|
||||
let (response_port, response_chan) = stream();
|
||||
let (response_port, response_chan) = Chan::new();
|
||||
image_cache_task.send(GetImage(url, response_chan));
|
||||
match response_port.recv() {
|
||||
ImageFailed => (),
|
||||
|
@ -820,31 +772,24 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
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()));
|
||||
// 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 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(()),
|
||||
_ => ()
|
||||
}
|
||||
}));
|
||||
let join_port = image_cache_task.wait_for_store_prefetched();
|
||||
|
||||
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();
|
||||
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));
|
||||
match response_port.recv() {
|
||||
ImageFailed => (),
|
||||
|
@ -852,7 +797,7 @@ mod tests {
|
|||
}
|
||||
|
||||
// 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));
|
||||
match response_port.recv() {
|
||||
ImageFailed => (),
|
||||
|
@ -863,87 +808,27 @@ mod tests {
|
|||
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]
|
||||
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
|
||||
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 url = make_url(~"file", None);
|
||||
|
||||
let (wait_for_decode, wait_for_decode_chan) = comm::stream();
|
||||
|
||||
image_cache_task.send(OnMsg(|msg| {
|
||||
match *msg {
|
||||
StoreImage(*) => wait_for_decode_chan.send(()),
|
||||
_ => ()
|
||||
}
|
||||
}));
|
||||
let join_port = image_cache_task.wait_for_store();
|
||||
|
||||
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_decode.recv();
|
||||
join_port.recv();
|
||||
|
||||
// Make the request
|
||||
let (response_port, response_chan) = stream();
|
||||
let (response_port, response_chan) = Chan::new();
|
||||
image_cache_task.send(GetImage(url, response_chan));
|
||||
|
||||
match response_port.recv() {
|
||||
|
@ -957,33 +842,26 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
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::Done(result::Ok(())));
|
||||
};
|
||||
response.send(resource_task::Done(Ok(())));
|
||||
});
|
||||
|
||||
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
||||
let url = make_url(~"file", None);
|
||||
|
||||
let (wait_for_decode, wait_for_decode_chan) = comm::stream();
|
||||
|
||||
image_cache_task.send(OnMsg(|msg| {
|
||||
match *msg {
|
||||
StoreImage(*) => wait_for_decode_chan.send(()),
|
||||
_ => ()
|
||||
}
|
||||
}));
|
||||
let join_port = image_cache_task.wait_for_store();
|
||||
|
||||
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_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));
|
||||
match response_port.recv() {
|
||||
ImageReady(*) => (),
|
||||
ImageReady(..) => (),
|
||||
_ => fail!("bleh")
|
||||
}
|
||||
|
||||
|
@ -993,13 +871,13 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
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();
|
||||
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 url = make_url(~"file", None);
|
||||
|
@ -1007,13 +885,13 @@ mod tests {
|
|||
image_cache_task.send(Prefetch(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));
|
||||
|
||||
wait_chan.send(());
|
||||
|
||||
match response_port.recv() {
|
||||
ImageReady(*) => (),
|
||||
ImageReady(..) => (),
|
||||
_ => fail!("bleh")
|
||||
}
|
||||
|
||||
|
@ -1023,13 +901,13 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
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();
|
||||
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 url = make_url(~"file", None);
|
||||
|
@ -1037,7 +915,7 @@ mod tests {
|
|||
image_cache_task.send(Prefetch(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));
|
||||
|
||||
wait_chan.send(());
|
||||
|
@ -1053,10 +931,10 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
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::Done(result::Ok(())));
|
||||
};
|
||||
response.send(resource_task::Done(Ok(())));
|
||||
});
|
||||
|
||||
let image_cache_task = SyncImageCacheTask(mock_resource_task.clone());
|
||||
let url = make_url(~"file", None);
|
||||
|
@ -1064,7 +942,7 @@ mod tests {
|
|||
image_cache_task.send(Prefetch(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));
|
||||
match response_port.recv() {
|
||||
ImageReady(_) => (),
|
||||
|
|
|
@ -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::{ImageResponseMsg, Prefetch, WaitForImage};
|
||||
|
||||
use std::comm;
|
||||
use std::comm::Port;
|
||||
use std::task;
|
||||
use servo_util::url::{UrlMap, url_map};
|
||||
use extra::url::Url;
|
||||
|
||||
pub trait ImageResponder {
|
||||
fn respond(&self) -> ~fn(ImageResponseMsg);
|
||||
fn respond(&self) -> proc(ImageResponseMsg);
|
||||
}
|
||||
|
||||
pub fn LocalImageCache(image_cache_task: ImageCacheTask) -> LocalImageCache {
|
||||
|
@ -90,13 +89,13 @@ impl LocalImageCache {
|
|||
|
||||
match state.last_response {
|
||||
ImageReady(ref image) => {
|
||||
let (port, chan) = comm::stream();
|
||||
let (port, chan) = Chan::new();
|
||||
chan.send(ImageReady(image.clone()));
|
||||
return port;
|
||||
}
|
||||
ImageNotReady => {
|
||||
if last_round == self.round_number {
|
||||
let (port, chan) = comm::stream();
|
||||
let (port, chan) = Chan::new();
|
||||
chan.send(ImageNotReady);
|
||||
return port;
|
||||
} else {
|
||||
|
@ -105,14 +104,14 @@ impl LocalImageCache {
|
|||
}
|
||||
}
|
||||
ImageFailed => {
|
||||
let (port, chan) = comm::stream();
|
||||
let (port, chan) = Chan::new();
|
||||
chan.send(ImageFailed);
|
||||
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));
|
||||
|
||||
let response = response_port.recv();
|
||||
|
@ -128,7 +127,7 @@ impl LocalImageCache {
|
|||
let on_image_available = self.on_image_available.as_ref().unwrap().respond();
|
||||
let url = (*url).clone();
|
||||
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));
|
||||
on_image_available(response_port.recv());
|
||||
}
|
||||
|
@ -144,7 +143,7 @@ impl LocalImageCache {
|
|||
};
|
||||
self.get_state(url).last_response = response_copy;
|
||||
|
||||
let (port, chan) = comm::stream();
|
||||
let (port, chan) = Chan::new();
|
||||
chan.send(response);
|
||||
return port;
|
||||
}
|
||||
|
|
|
@ -2,17 +2,14 @@
|
|||
* 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/. */
|
||||
|
||||
#[link(name = "net",
|
||||
vers = "0.1",
|
||||
uuid = "69c2b7b7-0d7d-4514-a48a-0eed61476039",
|
||||
url = "http://servo.org/")];
|
||||
#[crate_id = "github.com/mozilla/servo#net:0.1"];
|
||||
#[crate_type = "lib"];
|
||||
|
||||
#[feature(globs, managed_boxes)];
|
||||
|
||||
extern mod geom;
|
||||
extern mod http;
|
||||
extern mod servo_util (name = "util");
|
||||
extern mod servo_util = "util";
|
||||
extern mod stb_image;
|
||||
extern mod extra;
|
||||
extern mod png;
|
||||
|
|
|
@ -8,9 +8,7 @@ use file_loader;
|
|||
use http_loader;
|
||||
use data_loader;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::comm::{Chan, Port, SharedChan};
|
||||
use std::comm;
|
||||
use extra::url::Url;
|
||||
use util::spawn_listener;
|
||||
use http::headers::content_type::MediaType;
|
||||
|
@ -87,8 +85,8 @@ pub enum ProgressMsg {
|
|||
|
||||
/// For use by loaders in responding to a Load message.
|
||||
pub fn start_sending(start_chan: Chan<LoadResponse>,
|
||||
metadata: Metadata) -> Chan<ProgressMsg> {
|
||||
let (progress_port, progress_chan) = comm::stream();
|
||||
metadata: Metadata) -> SharedChan<ProgressMsg> {
|
||||
let (progress_port, progress_chan) = SharedChan::new();
|
||||
start_chan.send(LoadResponse {
|
||||
metadata: metadata,
|
||||
progress_port: progress_port,
|
||||
|
@ -99,7 +97,7 @@ pub fn start_sending(start_chan: Chan<LoadResponse>,
|
|||
/// Convenience function for synchronously loading a whole resource.
|
||||
pub fn load_whole_resource(resource_task: &ResourceTask, url: Url)
|
||||
-> Result<(Metadata, ~[u8]), ()> {
|
||||
let (start_port, start_chan) = comm::stream();
|
||||
let (start_port, start_chan) = Chan::new();
|
||||
resource_task.send(Load(url, start_chan));
|
||||
let response = start_port.recv();
|
||||
|
||||
|
@ -116,7 +114,7 @@ pub fn load_whole_resource(resource_task: &ResourceTask, url: Url)
|
|||
/// Handle to a resource task
|
||||
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
|
||||
|
@ -137,12 +135,11 @@ pub fn ResourceTask() -> ResourceTask {
|
|||
}
|
||||
|
||||
fn create_resource_task_with_loaders(loaders: ~[(~str, LoaderTaskFactory)]) -> ResourceTask {
|
||||
let loaders_cell = Cell::new(loaders);
|
||||
let chan = do spawn_listener |from_client| {
|
||||
let chan = spawn_listener(proc(from_client) {
|
||||
// TODO: change copy to move once we can move out of closures
|
||||
ResourceManager(from_client, loaders_cell.take()).start()
|
||||
};
|
||||
SharedChan::new(chan)
|
||||
ResourceManager(from_client, loaders).start()
|
||||
});
|
||||
chan
|
||||
}
|
||||
|
||||
pub struct ResourceManager {
|
||||
|
@ -211,7 +208,7 @@ fn test_exit() {
|
|||
#[test]
|
||||
fn test_bad_scheme() {
|
||||
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));
|
||||
let response = start.recv();
|
||||
match response.progress_port.recv() {
|
||||
|
@ -226,7 +223,7 @@ static snicklefritz_payload: [u8, ..3] = [1, 2, 3];
|
|||
|
||||
#[cfg(test)]
|
||||
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));
|
||||
progress_chan.send(Payload(snicklefritz_payload.into_owned()));
|
||||
progress_chan.send(Done(Ok(())));
|
||||
|
@ -238,7 +235,7 @@ fn snicklefritz_loader_factory() -> LoaderTask {
|
|||
fn should_delegate_to_scheme_loader() {
|
||||
let loader_factories = ~[(~"snicklefritz", snicklefritz_loader_factory)];
|
||||
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));
|
||||
|
||||
let response = start.recv();
|
||||
|
|
|
@ -2,14 +2,13 @@
|
|||
* 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/. */
|
||||
|
||||
use std::comm;
|
||||
use std::comm::{Chan, Port};
|
||||
use std::task;
|
||||
|
||||
pub fn spawn_listener<A: Send>(f: ~fn(Port<A>)) -> Chan<A> {
|
||||
let (setup_port, setup_chan) = comm::stream();
|
||||
pub fn spawn_listener<A: Send>(f: proc(Port<A>)) -> SharedChan<A> {
|
||||
let (setup_port, setup_chan) = Chan::new();
|
||||
do task::spawn {
|
||||
let (port, chan) = comm::stream();
|
||||
let (port, chan) = SharedChan::new();
|
||||
setup_chan.send(chan);
|
||||
f(port);
|
||||
}
|
||||
|
|
|
@ -43,7 +43,6 @@ impl CallbackInterface {
|
|||
}
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
pub fn GetCallableProperty(&self, cx: *JSContext, name: *libc::c_char, callable: &mut JSVal) -> bool {
|
||||
unsafe {
|
||||
if JS_GetProperty(cx, self.callback, name, &*callable) == 0 {
|
||||
|
@ -65,7 +64,6 @@ pub fn GetJSObjectFromCallback<T: CallbackContainer>(callback: &T) -> *JSObject
|
|||
callback.callback()
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
pub fn WrapCallThisObject<T: 'static + CallbackContainer + Reflectable>(cx: *JSContext,
|
||||
_scope: *JSObject,
|
||||
p: @mut T) -> *JSObject {
|
||||
|
|
|
@ -1091,7 +1091,7 @@ for (uint32_t i = 0; i < length; ++i) {
|
|||
return handleDefault(
|
||||
conversionCode,
|
||||
("static data: [u8, ..%s] = [ %s ];\n"
|
||||
"%s = str::from_utf8(data)" %
|
||||
"%s = str::from_utf8(data).to_owned()" %
|
||||
(len(defaultValue.value) + 1,
|
||||
", ".join(["'" + char + "' as u8" for char in defaultValue.value] + ["0"]),
|
||||
varName)))
|
||||
|
@ -2173,7 +2173,7 @@ class CGImports(CGWrapper):
|
|||
# Allow unreachable_code because we use 'break' in a way that sometimes produces
|
||||
# two 'break's in a row. See for example CallbackMember.getArgConversions.
|
||||
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),
|
||||
''])
|
||||
CGWrapper.__init__(self, child,
|
||||
|
@ -2454,16 +2454,14 @@ class CGAbstractMethod(CGThing):
|
|||
def _decorators(self):
|
||||
decorators = []
|
||||
if self.alwaysInline:
|
||||
# FIXME Rust #8801 #[inline(always)] and #[fixed_stack_segment] not compatible
|
||||
# decorators.append('#[inline(always)]')
|
||||
pass
|
||||
decorators.append('#[inline(always)]')
|
||||
elif self.inline:
|
||||
#decorators.append('inline')
|
||||
pass
|
||||
if self.extern:
|
||||
decorators.append('extern')
|
||||
if not self.extern:
|
||||
decorators.append('#[fixed_stack_segment]')
|
||||
pass
|
||||
if self.static:
|
||||
#decorators.append('static')
|
||||
pass
|
||||
|
@ -3522,6 +3520,7 @@ class CGEnum(CGThing):
|
|||
|
||||
def define(self):
|
||||
return """
|
||||
#[repr(uint)]
|
||||
pub enum valuelist {
|
||||
%s
|
||||
}
|
||||
|
@ -3576,7 +3575,7 @@ class ClassMethod(ClassItem):
|
|||
ClassItem.__init__(self, name, visibility)
|
||||
|
||||
def getDecorators(self, declaring):
|
||||
decorators = ['#[fixed_stack_segment]']
|
||||
decorators = []
|
||||
if self.inline:
|
||||
decorators.append('inline')
|
||||
if declaring:
|
||||
|
@ -4150,8 +4149,8 @@ class CGProxyUnwrap(CGAbstractMethod):
|
|||
obj = js::UnwrapObject(obj);
|
||||
}*/
|
||||
//MOZ_ASSERT(IsProxy(obj));
|
||||
let box: *Box<%s> = cast::transmute(RUST_JSVAL_TO_PRIVATE(GetProxyPrivate(obj)));
|
||||
return ptr::to_unsafe_ptr(&(*box).data);""" % (self.descriptor.concreteType)
|
||||
let box_: *Box<%s> = cast::transmute(RUST_JSVAL_TO_PRIVATE(GetProxyPrivate(obj)));
|
||||
return ptr::to_unsafe_ptr(&(*box_).data);""" % (self.descriptor.concreteType)
|
||||
|
||||
class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod):
|
||||
def __init__(self, descriptor):
|
||||
|
@ -4443,9 +4442,9 @@ class CGDOMJSProxyHandler_obj_toString(CGAbstractExternMethod):
|
|||
JSString* jsresult;
|
||||
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)
|
||||
}""" % self.descriptor.name
|
||||
})""" % self.descriptor.name
|
||||
|
||||
def definition_body(self):
|
||||
return self.getBody()
|
||||
|
@ -4907,7 +4906,6 @@ class CGDictionary(CGThing):
|
|||
" return true;\n"
|
||||
" }\n"
|
||||
"\n" if not self.workers else "") +
|
||||
" #[fixed_stack_segment]\n" +
|
||||
" pub fn Init(&mut self, cx: *JSContext, val: JSVal) -> JSBool {\n"
|
||||
" unsafe {\n" +
|
||||
# NOTE: jsids are per-runtime, so don't use them in workers
|
||||
|
|
|
@ -13,14 +13,12 @@ pub trait JSValConvertible {
|
|||
|
||||
|
||||
impl JSValConvertible for i64 {
|
||||
#[fixed_stack_segment]
|
||||
fn to_jsval(&self) -> JSVal {
|
||||
unsafe {
|
||||
RUST_DOUBLE_TO_JSVAL(*self as f64)
|
||||
}
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
fn from_jsval(val: JSVal) -> Option<i64> {
|
||||
unsafe {
|
||||
Some(RUST_JSVAL_TO_DOUBLE(val) as i64)
|
||||
|
@ -29,14 +27,12 @@ impl JSValConvertible for i64 {
|
|||
}
|
||||
|
||||
impl JSValConvertible for u32 {
|
||||
#[fixed_stack_segment]
|
||||
fn to_jsval(&self) -> JSVal {
|
||||
unsafe {
|
||||
RUST_UINT_TO_JSVAL(*self)
|
||||
}
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
fn from_jsval(val: JSVal) -> Option<u32> {
|
||||
unsafe {
|
||||
Some(RUST_JSVAL_TO_INT(val) as u32)
|
||||
|
@ -45,14 +41,12 @@ impl JSValConvertible for u32 {
|
|||
}
|
||||
|
||||
impl JSValConvertible for i32 {
|
||||
#[fixed_stack_segment]
|
||||
fn to_jsval(&self) -> JSVal {
|
||||
unsafe {
|
||||
RUST_UINT_TO_JSVAL(*self as u32)
|
||||
}
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
fn from_jsval(val: JSVal) -> Option<i32> {
|
||||
unsafe {
|
||||
Some(RUST_JSVAL_TO_INT(val) as i32)
|
||||
|
@ -61,14 +55,12 @@ impl JSValConvertible for i32 {
|
|||
}
|
||||
|
||||
impl JSValConvertible for u16 {
|
||||
#[fixed_stack_segment]
|
||||
fn to_jsval(&self) -> JSVal {
|
||||
unsafe {
|
||||
RUST_UINT_TO_JSVAL(*self as u32)
|
||||
}
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
fn from_jsval(val: JSVal) -> Option<u16> {
|
||||
unsafe {
|
||||
Some(RUST_JSVAL_TO_INT(val) as u16)
|
||||
|
@ -97,14 +89,12 @@ impl JSValConvertible for bool {
|
|||
}
|
||||
|
||||
impl JSValConvertible for f32 {
|
||||
#[fixed_stack_segment]
|
||||
fn to_jsval(&self) -> JSVal {
|
||||
unsafe {
|
||||
RUST_DOUBLE_TO_JSVAL(*self as f64)
|
||||
}
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
fn from_jsval(val: JSVal) -> Option<f32> {
|
||||
unsafe {
|
||||
Some(RUST_JSVAL_TO_DOUBLE(val) as f32)
|
||||
|
@ -113,14 +103,12 @@ impl JSValConvertible for f32 {
|
|||
}
|
||||
|
||||
impl JSValConvertible for f64 {
|
||||
#[fixed_stack_segment]
|
||||
fn to_jsval(&self) -> JSVal {
|
||||
unsafe {
|
||||
RUST_DOUBLE_TO_JSVAL(*self as f64)
|
||||
}
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
fn from_jsval(val: JSVal) -> Option<f64> {
|
||||
unsafe {
|
||||
Some(RUST_JSVAL_TO_DOUBLE(val) as f64)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* 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/. */
|
||||
|
||||
use dom::bindings::utils::{Reflectable, Reflector, Traceable};
|
||||
use dom::bindings::utils::{Reflectable, Reflector, Traceable, trace_reflector};
|
||||
use dom::types::*;
|
||||
use dom::node::AbstractNode;
|
||||
|
||||
|
@ -23,7 +23,6 @@ impl Reflectable for AbstractNode {
|
|||
|
||||
impl Traceable for Node {
|
||||
fn trace(&self, tracer: *mut JSTracer) {
|
||||
#[fixed_stack_segment]
|
||||
fn trace_node(tracer: *mut JSTracer, node: Option<AbstractNode>, name: &str) {
|
||||
if node.is_none() {
|
||||
return;
|
||||
|
@ -35,10 +34,10 @@ impl Traceable for Node {
|
|||
unsafe {
|
||||
(*tracer).debugPrinter = ptr::null();
|
||||
(*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;
|
||||
JS_CallTracer(cast::transmute(tracer), obj, JSTRACE_OBJECT as u32);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
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.next_sibling, "next sibling");
|
||||
trace_node(tracer, self.prev_sibling, "prev sibling");
|
||||
let owner_doc = self.owner_doc();
|
||||
trace_reflector(tracer, "document", owner_doc.reflector());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
desc: *JSPropertyDescriptor) -> JSBool {
|
||||
unsafe {
|
||||
|
@ -72,7 +71,6 @@ pub extern fn defineProperty(cx: *JSContext, proxy: *JSObject, id: jsid,
|
|||
defineProperty_(cx, proxy, id, desc)
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
pub fn _obj_toString(cx: *JSContext, className: *libc::c_char) -> *JSString {
|
||||
unsafe {
|
||||
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 + "]";
|
||||
for (i, c) in result.iter().enumerate() {
|
||||
for (i, c) in result.chars().enumerate() {
|
||||
*chars.offset(i as int) = c as jschar;
|
||||
}
|
||||
*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 {
|
||||
unsafe {
|
||||
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 {
|
||||
unsafe {
|
||||
assert!(is_dom_proxy(obj));
|
||||
|
|
|
@ -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::{JSContext, JSObject, JSBool, jsid, JSClass, JSNative, JSTracer};
|
||||
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::{JS_IsExceptionPending};
|
||||
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::jsapi::{JSVal, JSString};
|
||||
|
||||
#[fixed_stack_segment]
|
||||
pub fn is_null(v: JSVal) -> bool {
|
||||
unsafe { RUST_JSVAL_IS_NULL(v) == 1 }
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
pub fn is_undefined(v: JSVal) -> bool {
|
||||
unsafe { RUST_JSVAL_IS_VOID(v) == 1 }
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
pub fn is_string(v: JSVal) -> bool {
|
||||
unsafe { RUST_JSVAL_IS_STRING(v) == 1 }
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
pub unsafe fn to_string(v: JSVal) -> *JSString {
|
||||
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 {
|
||||
unsafe {
|
||||
(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 {
|
||||
let clasp = JS_GetClass(obj);
|
||||
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 {
|
||||
let slot = dom_object_slot(obj);
|
||||
let val = JS_GetReservedSlot(obj, slot);
|
||||
cast::transmute(RUST_JSVAL_TO_PRIVATE(val))
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
pub unsafe fn get_dom_class(obj: *JSObject) -> Result<DOMClass, ()> {
|
||||
let clasp = JS_GetClass(obj);
|
||||
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, ()> {
|
||||
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 {
|
||||
debug!("good prototype");
|
||||
Ok(unwrap(obj))
|
||||
|
@ -202,11 +194,10 @@ pub fn unwrap_object<T>(obj: *JSObject, proto_id: PrototypeList::id::ID, proto_d
|
|||
debug!("bad prototype");
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
pub fn unwrap_value<T>(val: *JSVal, proto_id: PrototypeList::id::ID, proto_depth: uint) -> Result<T, ()> {
|
||||
unsafe {
|
||||
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> {
|
||||
let y: *Box<T> = cast::transmute(x);
|
||||
cast::forget(x);
|
||||
y
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
pub fn jsstring_to_str(cx: *JSContext, s: *JSString) -> ~str {
|
||||
unsafe {
|
||||
let length = 0;
|
||||
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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
pub fn jsid_to_str(cx: *JSContext, id: jsid) -> ~str {
|
||||
unsafe {
|
||||
assert!(RUST_JSID_IS_STRING(id) != 0);
|
||||
|
@ -245,7 +233,6 @@ pub enum StringificationBehavior {
|
|||
Empty,
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
pub fn jsval_to_str(cx: *JSContext, v: JSVal,
|
||||
nullBehavior: StringificationBehavior) -> Result<~str, ()> {
|
||||
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>, ()> {
|
||||
if jsval::is_null(v) || jsval::is_undefined(v) {
|
||||
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 {
|
||||
do string.to_utf16().as_imm_buf |buf, len| {
|
||||
let jsstr = JS_NewUCStringCopyN(cx, buf, len as libc::size_t);
|
||||
let string_utf16 = string.to_utf16();
|
||||
let jsstr = JS_NewUCStringCopyN(cx, string_utf16.as_ptr(), string_utf16.len() as libc::size_t);
|
||||
if jsstr.is_null() {
|
||||
// FIXME: is there something else we should do on failure?
|
||||
JSVAL_NULL
|
||||
} else {
|
||||
RUST_STRING_TO_JSVAL(jsstr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
pub unsafe fn domstring_to_jsval(cx: *JSContext, string: Option<DOMString>) -> JSVal {
|
||||
match string {
|
||||
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
|
||||
// LSetDOMProperty. Those constants need to be changed accordingly if this value
|
||||
// changes.
|
||||
static JSCLASS_DOM_GLOBAL: u32 = js::JSCLASS_USERBIT1;
|
||||
pub static JSCLASS_DOM_GLOBAL: u32 = js::JSCLASS_USERBIT1;
|
||||
|
||||
pub struct NativeProperties {
|
||||
staticMethods: *JSFunctionSpec,
|
||||
|
@ -379,7 +362,6 @@ pub struct DOMJSClass {
|
|||
dom_class: DOMClass
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
pub fn GetProtoOrIfaceArray(global: *JSObject) -> **JSObject {
|
||||
unsafe {
|
||||
/*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,
|
||||
protoProto: *JSObject, protoClass: *JSClass,
|
||||
constructorClass: *JSClass, constructor: Option<JSNative>,
|
||||
|
@ -415,11 +396,11 @@ pub fn CreateInterfaceObjects2(cx: *JSContext, global: *JSObject, receiver: *JSO
|
|||
|
||||
let mut interface = ptr::null();
|
||||
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,
|
||||
constructor, ctorNargs, proto,
|
||||
staticMethods, constants, s)
|
||||
};
|
||||
});
|
||||
if interface.is_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,
|
||||
constructorClass: *JSClass, constructorNative: Option<JSNative>,
|
||||
ctorNargs: u32, proto: *JSObject,
|
||||
|
@ -467,11 +447,11 @@ fn CreateInterfaceObject(cx: *JSContext, global: *JSObject, receiver: *JSObject,
|
|||
}
|
||||
|
||||
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,
|
||||
InterfaceObjectToString,
|
||||
0, 0)
|
||||
};
|
||||
});
|
||||
if toString.is_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 {
|
||||
let mut i = 0;
|
||||
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 {
|
||||
unsafe {
|
||||
JS_DefineFunctions(cx, obj, methods) != 0
|
||||
}
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
fn DefineProperties(cx: *JSContext, obj: *JSObject, properties: *JSPropertySpec) -> bool {
|
||||
unsafe {
|
||||
JS_DefineProperties(cx, obj, properties) != 0
|
||||
}
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
fn CreateInterfacePrototypeObject(cx: *JSContext, global: *JSObject,
|
||||
parentProto: *JSObject, protoClass: *JSClass,
|
||||
methods: *JSFunctionSpec,
|
||||
|
@ -592,17 +568,16 @@ pub trait Traceable {
|
|||
fn trace(&self, trc: *mut JSTracer);
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
pub fn trace_reflector(tracer: *mut JSTracer, description: &str, reflector: &Reflector) {
|
||||
unsafe {
|
||||
do description.to_c_str().with_ref |name| {
|
||||
description.to_c_str().with_ref(|name| {
|
||||
(*tracer).debugPrinter = ptr::null();
|
||||
(*tracer).debugPrintIndex = -1;
|
||||
(*tracer).debugPrintArg = name as *libc::c_void;
|
||||
debug!("tracing {:s}", description);
|
||||
JS_CallTracer(tracer as *JSTracer, reflector.get_jsobject(),
|
||||
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()));
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
pub fn initialize_global(global: *JSObject) {
|
||||
let protoArray = @mut ([0 as *JSObject, ..PrototypeList::id::_ID_Count as uint]);
|
||||
unsafe {
|
||||
//XXXjdm we should be storing the box pointer instead of the inner
|
||||
let box = squirrel_away(protoArray);
|
||||
let inner = ptr::to_unsafe_ptr(&(*box).data);
|
||||
let box_ = squirrel_away(protoArray);
|
||||
let inner = ptr::to_unsafe_ptr(&(*box_).data);
|
||||
JS_SetReservedSlot(global,
|
||||
DOM_PROTOTYPE_SLOT,
|
||||
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,
|
||||
vp: *mut JSVal) -> JSBool {
|
||||
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,
|
||||
vp: *JSVal) -> bool {
|
||||
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> {
|
||||
unsafe {
|
||||
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,
|
||||
wrapper: *JSObject,
|
||||
id: jsid,
|
||||
|
@ -754,7 +724,7 @@ pub fn XrayResolveProperty(cx: *JSContext,
|
|||
|
||||
RUST_SET_JITINFO(fun, attr.getter.info);
|
||||
let funobj = JS_GetFunctionObject(fun);
|
||||
(*desc).getter = Some(funobj as JSPropertyOp);
|
||||
(*desc).getter = Some(cast::transmute(funobj));
|
||||
(*desc).attrs |= JSPROP_GETTER;
|
||||
if attr.setter.op.is_some() {
|
||||
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);
|
||||
let funobj = JS_GetFunctionObject(fun);
|
||||
(*desc).setter = Some(funobj as JSStrictPropertyOp);
|
||||
(*desc).setter = Some(cast::transmute(funobj));
|
||||
(*desc).attrs |= JSPROP_SETTER;
|
||||
} else {
|
||||
(*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> {
|
||||
unsafe {
|
||||
let s = JS_InternString(cx, chars);
|
||||
|
@ -824,7 +793,6 @@ pub struct EnumEntry {
|
|||
length: uint
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
pub fn FindEnumStringIndex(cx: *JSContext,
|
||||
v: JSVal,
|
||||
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;
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
pub fn IsConvertibleToCallbackInterface(cx: *JSContext, obj: *JSObject) -> bool {
|
||||
unsafe {
|
||||
JS_ObjectIsDate(cx, obj) == 0 && JS_ObjectIsRegExp(cx, obj) == 0
|
||||
}
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
pub fn CreateDOMGlobal(cx: *JSContext, class: *JSClass) -> *JSObject {
|
||||
unsafe {
|
||||
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.
|
||||
#[fixed_stack_segment]
|
||||
fn global_object_for_js_object(obj: *JSObject) -> *Box<window::Window> {
|
||||
unsafe {
|
||||
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 {
|
||||
unsafe {
|
||||
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.
|
||||
#[fixed_stack_segment]
|
||||
pub fn global_object_for_dom_object<T: Reflectable>(obj: &mut T) -> *Box<window::Window> {
|
||||
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())
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
pub fn throw_method_failed_with_details<T>(cx: *JSContext,
|
||||
result: Result<T, Error>,
|
||||
interface: &'static str,
|
||||
|
@ -929,9 +891,9 @@ pub fn throw_method_failed_with_details<T>(cx: *JSContext,
|
|||
assert!(result.is_err());
|
||||
assert!(unsafe { JS_IsExceptionPending(cx) } == 0);
|
||||
let message = format!("Method failed: {}.{}", interface, member);
|
||||
do message.with_c_str |string| {
|
||||
message.with_c_str(|string| {
|
||||
unsafe { ReportError(cx, string) };
|
||||
}
|
||||
});
|
||||
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 seen_colon = false;
|
||||
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) {
|
||||
return InvalidXMLName;
|
||||
}
|
||||
|
|
|
@ -55,17 +55,12 @@ impl AbstractDocument {
|
|||
}
|
||||
}
|
||||
|
||||
unsafe fn transmute<T, R>(&self, f: &fn(&T) -> R) -> R {
|
||||
let box: *Box<T> = cast::transmute(self.document);
|
||||
f(&(*box).data)
|
||||
unsafe fn transmute<T, R>(&self, f: |&T| -> R) -> R {
|
||||
let box_: *Box<T> = cast::transmute(self.document);
|
||||
f(&(*box_).data)
|
||||
}
|
||||
|
||||
unsafe fn transmute_mut<T, R>(&self, f: &fn(&mut T) -> 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 {
|
||||
pub fn with_html<R>(&self, callback: |&HTMLDocument| -> R) -> R {
|
||||
match self.document().doctype {
|
||||
HTML => unsafe { self.transmute(callback) },
|
||||
_ => fail!("attempt to downcast a non-HTMLDocument to HTMLDocument")
|
||||
|
@ -105,9 +100,9 @@ impl Document {
|
|||
let document = reflect_dom_object(document, window, wrap_fn);
|
||||
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 {
|
||||
document: unsafe { cast::transmute(document) }
|
||||
document: unsafe { cast::transmute_copy(&document) }
|
||||
};
|
||||
abstract.mut_document().node.set_owner_doc(abstract);
|
||||
abstract
|
||||
|
@ -165,10 +160,6 @@ impl Document {
|
|||
self.node.child_elements().next()
|
||||
}
|
||||
|
||||
fn get_cx(&self) -> *JSContext {
|
||||
self.window.get_cx()
|
||||
}
|
||||
|
||||
pub fn GetElementsByTagName(&self, tag: DOMString) -> @mut HTMLCollection {
|
||||
self.createHTMLCollection(|elem| eq_slice(elem.tag_name, tag))
|
||||
}
|
||||
|
@ -238,9 +229,9 @@ impl Document {
|
|||
}
|
||||
for child in node.children() {
|
||||
if child.is_text() {
|
||||
do child.with_imm_text() |text| {
|
||||
child.with_imm_text(|text| {
|
||||
title = title + text.element.Data();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -249,7 +240,7 @@ impl Document {
|
|||
}
|
||||
}
|
||||
}
|
||||
let v: ~[&str] = title.word_iter().collect();
|
||||
let v: ~[&str] = title.words().collect();
|
||||
title = v.connect(" ");
|
||||
title = title.trim().to_owned();
|
||||
title
|
||||
|
@ -295,12 +286,12 @@ impl Document {
|
|||
}
|
||||
|
||||
fn get_html_element(&self) -> Option<AbstractNode> {
|
||||
do self.GetDocumentElement().filtered |root| {
|
||||
self.GetDocumentElement().filtered(|root| {
|
||||
match root.type_id() {
|
||||
ElementNodeTypeId(HTMLHtmlElementTypeId) => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/#dom-document-head
|
||||
|
@ -316,13 +307,13 @@ impl Document {
|
|||
match self.get_html_element() {
|
||||
None => None,
|
||||
Some(root) => {
|
||||
do root.children().find |child| {
|
||||
root.children().find(|child| {
|
||||
match child.type_id() {
|
||||
ElementNodeTypeId(HTMLBodyElementTypeId) |
|
||||
ElementNodeTypeId(HTMLFrameSetElementTypeId) => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -365,18 +356,18 @@ impl Document {
|
|||
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 = ~[];
|
||||
match self.GetDocumentElement() {
|
||||
None => {},
|
||||
Some(root) => {
|
||||
for child in root.traverse_preorder() {
|
||||
if child.is_element() {
|
||||
do child.with_imm_element |elem| {
|
||||
child.with_imm_element(|elem| {
|
||||
if callback(elem) {
|
||||
elements.push(child);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -435,25 +426,24 @@ impl Document {
|
|||
}
|
||||
|
||||
#[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() {
|
||||
if !node.is_element() {
|
||||
continue;
|
||||
}
|
||||
|
||||
do node.with_imm_element |element| {
|
||||
node.with_imm_element(|element| {
|
||||
match element.get_attr(Null, "id") {
|
||||
Some(id) => {
|
||||
callback(&id.to_str(), &node);
|
||||
}
|
||||
None => ()
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl Traceable for Document {
|
||||
#[fixed_stack_segment]
|
||||
fn trace(&self, tracer: *mut JSTracer) {
|
||||
self.node.trace(tracer);
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ use layout_interface::{ContentBoxesResponse, ContentChangedDocumentDamage};
|
|||
use layout_interface::{MatchSelectorsDocumentDamage};
|
||||
use style;
|
||||
|
||||
use std::comm;
|
||||
use std::str::eq;
|
||||
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 {
|
||||
Element {
|
||||
node: Node::new_inherited(ElementNodeTypeId(type_id), document),
|
||||
|
@ -175,7 +174,7 @@ impl<'self> Element {
|
|||
//FIXME: Throw for XML-invalid names
|
||||
//FIXME: Throw for XMLNS-invalid names
|
||||
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())
|
||||
} else {
|
||||
(None, name.clone())
|
||||
|
@ -238,14 +237,14 @@ impl<'self> Element {
|
|||
// This hardcoding is awful.
|
||||
match abstract_self.type_id() {
|
||||
ElementNodeTypeId(HTMLImageElementTypeId) => {
|
||||
do abstract_self.with_mut_image_element |image| {
|
||||
abstract_self.with_mut_image_element(|image| {
|
||||
image.AfterSetAttr(local_name.clone(), value.clone());
|
||||
}
|
||||
});
|
||||
}
|
||||
ElementNodeTypeId(HTMLIframeElementTypeId) => {
|
||||
do abstract_self.with_mut_iframe_element |iframe| {
|
||||
abstract_self.with_mut_iframe_element(|iframe| {
|
||||
iframe.AfterSetAttr(local_name.clone(), value.clone());
|
||||
}
|
||||
});
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
|
@ -390,18 +389,18 @@ impl Element {
|
|||
let win = self.node.owner_doc().document().window;
|
||||
let node = abstract_self;
|
||||
assert!(node.is_element());
|
||||
let (port, chan) = comm::stream();
|
||||
let (port, chan) = Chan::new();
|
||||
let rects =
|
||||
match win.page.query_layout(ContentBoxesQuery(node, chan), port) {
|
||||
ContentBoxesResponse(rects) => {
|
||||
do rects.map |r| {
|
||||
rects.map(|r| {
|
||||
ClientRect::new(
|
||||
win,
|
||||
r.origin.y,
|
||||
r.origin.y + r.size.height,
|
||||
r.origin.x,
|
||||
r.origin.x + r.size.width)
|
||||
}
|
||||
})
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -412,7 +411,7 @@ impl Element {
|
|||
let win = self.node.owner_doc().document().window;
|
||||
let node = abstract_self;
|
||||
assert!(node.is_element());
|
||||
let (port, chan) = comm::stream();
|
||||
let (port, chan) = Chan::new();
|
||||
match win.page.query_layout(ContentBoxQuery(node, chan), port) {
|
||||
ContentBoxResponse(rect) => {
|
||||
ClientRect::new(
|
||||
|
|
|
@ -35,9 +35,9 @@ pub enum EventPhase {
|
|||
}
|
||||
|
||||
impl AbstractEvent {
|
||||
pub fn from_box(box: *mut Box<Event>) -> AbstractEvent {
|
||||
pub fn from_box(box_: *mut Box<Event>) -> AbstractEvent {
|
||||
AbstractEvent {
|
||||
event: box
|
||||
event: box_
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,15 +47,15 @@ impl AbstractEvent {
|
|||
|
||||
fn transmute<'a, T>(&'a self) -> &'a T {
|
||||
unsafe {
|
||||
let box: *Box<T> = self.event as *Box<T>;
|
||||
&(*box).data
|
||||
let box_: *Box<T> = self.event as *Box<T>;
|
||||
&(*box_).data
|
||||
}
|
||||
}
|
||||
|
||||
fn transmute_mut<'a, T>(&'a self) -> &'a mut T {
|
||||
unsafe {
|
||||
let box: *mut Box<T> = self.event as *mut Box<T>;
|
||||
&mut (*box).data
|
||||
let box_: *mut Box<T> = self.event as *mut Box<T>;
|
||||
&mut (*box_).data
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -44,9 +44,9 @@ pub struct AbstractEventTarget {
|
|||
}
|
||||
|
||||
impl AbstractEventTarget {
|
||||
pub fn from_box<T>(box: *mut Box<T>) -> AbstractEventTarget {
|
||||
pub fn from_box<T>(box_: *mut Box<T>) -> 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 {
|
||||
unsafe {
|
||||
let box: *Box<T> = self.eventtarget as *Box<T>;
|
||||
&(*box).data
|
||||
let box_: *Box<T> = self.eventtarget as *Box<T>;
|
||||
&(*box_).data
|
||||
}
|
||||
}
|
||||
|
||||
fn transmute_mut<'a, T>(&'a mut self) -> &'a mut T {
|
||||
unsafe {
|
||||
let box: *mut Box<T> = self.eventtarget as *mut Box<T>;
|
||||
&mut (*box).data
|
||||
let box_: *mut Box<T> = self.eventtarget as *mut Box<T>;
|
||||
&mut (*box_).data
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,17 +127,17 @@ impl EventTarget {
|
|||
}
|
||||
|
||||
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()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_listeners_for(&self, type_: &str, desired_phase: ListenerPhase)
|
||||
-> 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);
|
||||
filtered.map(|entry| entry.listener).collect()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn AddEventListener(&mut self,
|
||||
|
|
|
@ -95,7 +95,7 @@ impl HTMLIFrameElement {
|
|||
pub fn AfterSetAttr(&mut self, name: DOMString, value: DOMString) {
|
||||
if "sandbox" == name {
|
||||
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
|
||||
let word_lower = word.to_ascii_lower();
|
||||
modes |= match word_lower.as_slice() {
|
||||
|
|
|
@ -112,7 +112,7 @@ impl HTMLImageElement {
|
|||
pub fn Width(&self, abstract_self: AbstractNode) -> u32 {
|
||||
let node = &self.htmlelement.element.node;
|
||||
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) {
|
||||
ContentBoxResponse(rect) => {
|
||||
to_px(rect.size.width) as u32
|
||||
|
@ -129,7 +129,7 @@ impl HTMLImageElement {
|
|||
pub fn Height(&self, abstract_self: AbstractNode) -> u32 {
|
||||
let node = &self.htmlelement.element.node;
|
||||
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) {
|
||||
ContentBoxResponse(rect) => {
|
||||
to_px(rect.size.height) as u32
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
|
||||
use dom::bindings::utils::{DOMString, null_str_as_empty};
|
||||
use dom::bindings::utils::{ErrorResult, Fallible, NotFound, HierarchyRequest};
|
||||
use dom::bindings::utils;
|
||||
use dom::characterdata::CharacterData;
|
||||
use dom::document::{AbstractDocument, DocumentTypeId};
|
||||
use dom::documenttype::DocumentType;
|
||||
|
@ -20,12 +19,15 @@ use dom::nodelist::{NodeList};
|
|||
use dom::text::Text;
|
||||
|
||||
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::unstable::raw::Box;
|
||||
use std::util;
|
||||
use std::cast::transmute;
|
||||
use std::cell::{RefCell, Ref, RefMut};
|
||||
use std::iter::Filter;
|
||||
use std::util;
|
||||
use std::unstable::raw::Box;
|
||||
|
||||
//
|
||||
// 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.
|
||||
#[deriving(Eq)]
|
||||
pub struct AbstractNode {
|
||||
priv obj: *mut Box<Node>,
|
||||
priv obj: *mut (),
|
||||
}
|
||||
|
||||
/// An HTML node.
|
||||
|
@ -109,30 +111,43 @@ impl Drop for Node {
|
|||
}
|
||||
|
||||
/// Encapsulates the abstract layout data.
|
||||
pub struct LayoutData {
|
||||
priv chan: Option<LayoutChan>,
|
||||
priv data: *(),
|
||||
}
|
||||
|
||||
pub struct LayoutDataRef {
|
||||
priv data: Slot<Option<*()>>,
|
||||
data_cell: RefCell<Option<LayoutData>>,
|
||||
}
|
||||
|
||||
impl LayoutDataRef {
|
||||
#[inline]
|
||||
pub fn init() -> LayoutDataRef {
|
||||
pub fn new() -> 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 {
|
||||
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]
|
||||
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
|
||||
|
@ -141,17 +156,15 @@ impl LayoutDataRef {
|
|||
///
|
||||
/// FIXME(pcwalton): Enforce this invariant via the type system. Will require traversal
|
||||
/// functions to be trusted, but c'est la vie.
|
||||
#[inline]
|
||||
pub unsafe fn borrow_unchecked<'a>(&'a self) -> &'a () {
|
||||
cast::transmute(self.data.borrow_unchecked())
|
||||
}
|
||||
// #[inline]
|
||||
// pub unsafe fn borrow_unchecked<'a>(&'a self) -> &'a () {
|
||||
// self.data.borrow_unchecked()
|
||||
// }
|
||||
|
||||
/// Borrows the layout data immutably. This function is *not* thread-safe.
|
||||
#[inline]
|
||||
pub fn borrow<'a>(&'a self) -> SlotRef<'a,()> {
|
||||
unsafe {
|
||||
cast::transmute(self.data.borrow())
|
||||
}
|
||||
pub fn borrow<'a>(&'a self) -> Ref<'a,Option<LayoutData>> {
|
||||
self.data_cell.borrow()
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// on it. This has already resulted in one bug!
|
||||
#[inline]
|
||||
pub fn mutate<'a>(&'a self) -> MutSlotRef<'a,()> {
|
||||
unsafe {
|
||||
cast::transmute(self.data.mutate())
|
||||
}
|
||||
pub fn borrow_mut<'a>(&'a self) -> RefMut<'a,Option<LayoutData>> {
|
||||
self.data_cell.borrow_mut()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -193,13 +204,15 @@ impl Clone for AbstractNode {
|
|||
impl AbstractNode {
|
||||
pub fn node<'a>(&'a self) -> &'a Node {
|
||||
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 {
|
||||
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 {
|
||||
match self.type_id() {
|
||||
ElementNodeTypeId(*) => true,
|
||||
ElementNodeTypeId(..) => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_document(&self) -> bool {
|
||||
match self.type_id() {
|
||||
DocumentNodeTypeId(*) => true,
|
||||
DocumentNodeTypeId(..) => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'self> AbstractNode {
|
||||
impl<'a> AbstractNode {
|
||||
// Unsafe accessors
|
||||
|
||||
pub unsafe fn as_cacheable_wrapper(&self) -> @mut Reflectable {
|
||||
|
@ -252,7 +265,7 @@ impl<'self> AbstractNode {
|
|||
/// FIXME(pcwalton): Mark unsafe?
|
||||
pub fn from_box<T>(ptr: *mut Box<T>) -> AbstractNode {
|
||||
AbstractNode {
|
||||
obj: ptr as *mut Box<Node>
|
||||
obj: ptr as *mut ()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -291,27 +304,27 @@ impl<'self> AbstractNode {
|
|||
// 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 {
|
||||
let node_box: *mut Box<Node> = transmute(self.obj);
|
||||
let node = &mut (*node_box).data;
|
||||
let old = node.abstract;
|
||||
node.abstract = Some(self);
|
||||
let box: *Box<T> = transmute(self.obj);
|
||||
let rv = f(&(*box).data);
|
||||
let box_: *Box<T> = transmute(self.obj);
|
||||
let rv = f(&(*box_).data);
|
||||
node.abstract = old;
|
||||
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 {
|
||||
let node_box: *mut Box<Node> = transmute(self.obj);
|
||||
let node = &mut (*node_box).data;
|
||||
let old = node.abstract;
|
||||
node.abstract = Some(self);
|
||||
let box: *Box<T> = transmute(self.obj);
|
||||
let rv = f(cast::transmute(&(*box).data));
|
||||
let box_: *Box<T> = transmute(self.obj);
|
||||
let rv = f(cast::transmute(&(*box_).data));
|
||||
node.abstract = old;
|
||||
rv
|
||||
}
|
||||
|
@ -323,14 +336,14 @@ impl<'self> AbstractNode {
|
|||
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() {
|
||||
fail!(~"node is not characterdata");
|
||||
}
|
||||
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() {
|
||||
fail!(~"node is not characterdata");
|
||||
}
|
||||
|
@ -341,14 +354,14 @@ impl<'self> AbstractNode {
|
|||
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() {
|
||||
fail!(~"node is not doctype");
|
||||
}
|
||||
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() {
|
||||
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() {
|
||||
fail!(~"node is not text");
|
||||
}
|
||||
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() {
|
||||
fail!(~"node is not text");
|
||||
}
|
||||
|
@ -390,7 +403,7 @@ impl<'self> AbstractNode {
|
|||
}
|
||||
|
||||
// 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() {
|
||||
fail!(~"node is not an element");
|
||||
}
|
||||
|
@ -398,7 +411,7 @@ impl<'self> AbstractNode {
|
|||
}
|
||||
|
||||
// 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() {
|
||||
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() {
|
||||
fail!(~"node is not an image element");
|
||||
}
|
||||
|
@ -424,7 +437,7 @@ impl<'self> AbstractNode {
|
|||
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() {
|
||||
fail!(~"node is not an iframe element");
|
||||
}
|
||||
|
@ -440,12 +453,12 @@ impl<'self> AbstractNode {
|
|||
}
|
||||
|
||||
pub unsafe fn raw_object(self) -> *mut Box<Node> {
|
||||
self.obj
|
||||
cast::transmute(self.obj)
|
||||
}
|
||||
|
||||
pub fn from_raw(raw: *mut Box<Node>) -> AbstractNode {
|
||||
AbstractNode {
|
||||
obj: raw
|
||||
obj: raw as *mut ()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -479,10 +492,6 @@ impl<'self> AbstractNode {
|
|||
// Convenience accessors
|
||||
//
|
||||
|
||||
fn is_leaf(&self) -> bool {
|
||||
self.first_child().is_none()
|
||||
}
|
||||
|
||||
pub fn children(&self) -> AbstractNodeChildrenIterator {
|
||||
self.node().children()
|
||||
}
|
||||
|
@ -610,35 +619,6 @@ impl AbstractNode {
|
|||
child_node.set_next_sibling(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 {
|
||||
fn next(&mut self) -> Option<AbstractNode> {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -766,9 +746,9 @@ impl Node {
|
|||
assert!(node.reflector().get_jsobject().is_null());
|
||||
let node = reflect_dom_object(node, document.document().window, wrap_fn);
|
||||
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 {
|
||||
obj: unsafe { transmute(node) },
|
||||
obj: unsafe { cast::transmute_copy(&node) },
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -798,16 +778,19 @@ impl Node {
|
|||
|
||||
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.
|
||||
pub unsafe fn reap_layout_data(&mut self) {
|
||||
if self.layout_data.is_present() {
|
||||
let layout_data = util::replace(&mut self.layout_data, LayoutDataRef::init());
|
||||
let js_window = utils::global_object_for_dom_object(self);
|
||||
(*js_window).data.page.reap_dead_layout_data(layout_data)
|
||||
let layout_data = util::replace(&mut self.layout_data, LayoutDataRef::new());
|
||||
let layout_chan = layout_data.take_chan();
|
||||
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 {
|
||||
match self.type_id {
|
||||
ElementNodeTypeId(*) => {
|
||||
do abstract_self.with_imm_element |element| {
|
||||
ElementNodeTypeId(..) => {
|
||||
abstract_self.with_imm_element(|element| {
|
||||
element.TagName()
|
||||
}
|
||||
})
|
||||
}
|
||||
CommentNodeTypeId => ~"#comment",
|
||||
TextNodeTypeId => ~"#text",
|
||||
DoctypeNodeTypeId => {
|
||||
do abstract_self.with_imm_doctype |doctype| {
|
||||
abstract_self.with_imm_doctype(|doctype| {
|
||||
doctype.name.clone()
|
||||
}
|
||||
})
|
||||
},
|
||||
DocumentFragmentNodeTypeId => ~"#document-fragment",
|
||||
DocumentNodeTypeId(_) => ~"#document"
|
||||
|
@ -848,7 +831,7 @@ impl Node {
|
|||
|
||||
pub fn GetOwnerDocument(&self) -> Option<AbstractDocument> {
|
||||
match self.type_id {
|
||||
ElementNodeTypeId(*) |
|
||||
ElementNodeTypeId(..) |
|
||||
CommentNodeTypeId |
|
||||
TextNodeTypeId |
|
||||
DoctypeNodeTypeId |
|
||||
|
@ -889,9 +872,9 @@ impl Node {
|
|||
match self.type_id {
|
||||
// ProcessingInstruction
|
||||
CommentNodeTypeId | TextNodeTypeId => {
|
||||
do abstract_self.with_imm_characterdata() |characterdata| {
|
||||
abstract_self.with_imm_characterdata(|characterdata| {
|
||||
Some(characterdata.Data())
|
||||
}
|
||||
})
|
||||
}
|
||||
_ => {
|
||||
None
|
||||
|
@ -906,21 +889,21 @@ impl Node {
|
|||
|
||||
pub fn GetTextContent(&self, abstract_self: AbstractNode) -> Option<DOMString> {
|
||||
match self.type_id {
|
||||
DocumentFragmentNodeTypeId | ElementNodeTypeId(*) => {
|
||||
DocumentFragmentNodeTypeId | ElementNodeTypeId(..) => {
|
||||
let mut content = ~"";
|
||||
for node in abstract_self.traverse_preorder() {
|
||||
if node.is_text() {
|
||||
do node.with_imm_text() |text| {
|
||||
node.with_imm_text(|text| {
|
||||
content = content + text.element.Data();
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Some(content)
|
||||
}
|
||||
CommentNodeTypeId | TextNodeTypeId => {
|
||||
do abstract_self.with_imm_characterdata() |characterdata| {
|
||||
abstract_self.with_imm_characterdata(|characterdata| {
|
||||
Some(characterdata.Data())
|
||||
}
|
||||
})
|
||||
}
|
||||
DoctypeNodeTypeId | DocumentNodeTypeId(_) => {
|
||||
None
|
||||
|
@ -968,9 +951,9 @@ impl Node {
|
|||
|
||||
// Step 1.
|
||||
match parent.type_id() {
|
||||
DocumentNodeTypeId(*) |
|
||||
DocumentNodeTypeId(..) |
|
||||
DocumentFragmentNodeTypeId |
|
||||
ElementNodeTypeId(*) => (),
|
||||
ElementNodeTypeId(..) => (),
|
||||
_ => {
|
||||
return Err(HierarchyRequest);
|
||||
},
|
||||
|
@ -999,7 +982,7 @@ impl Node {
|
|||
TextNodeTypeId |
|
||||
// ProcessingInstructionNodeTypeId |
|
||||
CommentNodeTypeId => (),
|
||||
DocumentNodeTypeId(*) => return Err(HierarchyRequest),
|
||||
DocumentNodeTypeId(..) => return Err(HierarchyRequest),
|
||||
}
|
||||
|
||||
// Step 5.
|
||||
|
@ -1241,7 +1224,7 @@ impl Node {
|
|||
-> ErrorResult {
|
||||
let value = null_str_as_empty(&value);
|
||||
match self.type_id {
|
||||
DocumentFragmentNodeTypeId | ElementNodeTypeId(*) => {
|
||||
DocumentFragmentNodeTypeId | ElementNodeTypeId(..) => {
|
||||
// Step 1-2.
|
||||
let node = if value.len() == 0 {
|
||||
None
|
||||
|
@ -1255,13 +1238,13 @@ impl Node {
|
|||
CommentNodeTypeId | TextNodeTypeId => {
|
||||
self.wait_until_safe_to_modify_dom();
|
||||
|
||||
do abstract_self.with_mut_characterdata() |characterdata| {
|
||||
abstract_self.with_mut_characterdata(|characterdata| {
|
||||
characterdata.data = value.clone();
|
||||
|
||||
// Notify the document that the content of this node is different
|
||||
let document = self.owner_doc();
|
||||
document.document().content_changed();
|
||||
}
|
||||
})
|
||||
}
|
||||
DoctypeNodeTypeId | DocumentNodeTypeId(_) => {}
|
||||
}
|
||||
|
|
|
@ -18,19 +18,17 @@ use servo_msg::compositor_msg::ScriptListener;
|
|||
use servo_net::image_cache_task::ImageCacheTask;
|
||||
|
||||
use js::glue::*;
|
||||
use js::jsapi::{JSObject, JSContext, JS_DefineProperty};
|
||||
use js::jsapi::{JSPropertyOp, JSStrictPropertyOp, JSTracer};
|
||||
use js::jsapi::{JSObject, JSContext, JS_DefineProperty, JSTracer, JSVal};
|
||||
use js::{JSVAL_NULL, JSPROP_ENUMERATE};
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::comm;
|
||||
use std::cast;
|
||||
use std::comm::SharedChan;
|
||||
use std::comm::Select;
|
||||
use std::hashmap::HashSet;
|
||||
use std::io::timer::Timer;
|
||||
use std::num;
|
||||
use std::ptr;
|
||||
use std::int;
|
||||
use std::rt::io::timer::Timer;
|
||||
use std::task::spawn_with;
|
||||
use js::jsapi::JSVal;
|
||||
use std::to_bytes::Cb;
|
||||
|
||||
pub enum TimerControlMsg {
|
||||
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
|
||||
}
|
||||
|
||||
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 {
|
||||
eventtarget: EventTarget,
|
||||
page: @mut Page,
|
||||
|
@ -47,7 +68,7 @@ pub struct Window {
|
|||
location: Option<@mut Location>,
|
||||
navigator: Option<@mut Navigator>,
|
||||
image_cache_task: ImageCacheTask,
|
||||
active_timers: ~HashSet<i32>,
|
||||
active_timers: ~HashSet<TimerHandle>,
|
||||
next_timer_handle: i32,
|
||||
}
|
||||
|
||||
|
@ -61,6 +82,9 @@ impl Window {
|
|||
impl Drop for Window {
|
||||
fn drop(&mut self) {
|
||||
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 {
|
||||
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;
|
||||
self.next_timer_handle += 1;
|
||||
|
||||
// Post a delayed message to the per-window timer task; it will dispatch 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();
|
||||
do spawn {
|
||||
let mut tm = tm.take();
|
||||
tm.sleep(timeout);
|
||||
spawn(proc() {
|
||||
let mut tm = tm;
|
||||
let mut timeout_port = tm.oneshot(timeout);
|
||||
let mut cancel_port = cancel_port;
|
||||
|
||||
let select = Select::new();
|
||||
let timeout_handle = select.add(&mut timeout_port);
|
||||
let _cancel_handle = select.add(&mut cancel_port);
|
||||
let id = select.wait();
|
||||
if id == timeout_handle.id {
|
||||
chan.send(TimerMessage_Fire(~TimerData {
|
||||
handle: handle,
|
||||
funval: callback,
|
||||
args: ~[]
|
||||
args: ~[],
|
||||
}));
|
||||
}
|
||||
self.active_timers.insert(handle);
|
||||
});
|
||||
self.active_timers.insert(TimerHandle { handle: handle, cancel_chan: Some(cancel_chan) });
|
||||
handle
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -199,7 +234,6 @@ impl Window {
|
|||
self.page.join_layout();
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
pub fn new(cx: *JSContext,
|
||||
page: @mut Page,
|
||||
script_chan: ScriptChan,
|
||||
|
@ -212,9 +246,9 @@ impl Window {
|
|||
script_chan: script_chan.clone(),
|
||||
compositor: compositor,
|
||||
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();
|
||||
do spawn_with(script_chan) |script_chan| {
|
||||
spawn(proc() {
|
||||
loop {
|
||||
match timer_port.recv() {
|
||||
TimerMessage_Close => break,
|
||||
|
@ -222,8 +256,8 @@ impl Window {
|
|||
TimerMessage_TriggerExit => script_chan.send(ExitWindowMsg(id)),
|
||||
}
|
||||
}
|
||||
}
|
||||
SharedChan::new(timer_chan)
|
||||
});
|
||||
timer_chan
|
||||
},
|
||||
location: None,
|
||||
navigator: None,
|
||||
|
@ -236,13 +270,13 @@ impl Window {
|
|||
unsafe {
|
||||
let fn_names = ["window","self"];
|
||||
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,
|
||||
RUST_OBJECT_TO_JSVAL(global),
|
||||
Some(GetJSClassHookStubPointer(PROPERTY_STUB) as JSPropertyOp),
|
||||
Some(GetJSClassHookStubPointer(STRICT_PROPERTY_STUB) as JSStrictPropertyOp),
|
||||
Some(cast::transmute(GetJSClassHookStubPointer(PROPERTY_STUB))),
|
||||
Some(cast::transmute(GetJSClassHookStubPointer(STRICT_PROPERTY_STUB))),
|
||||
JSPROP_ENUMERATE);
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -4,10 +4,7 @@
|
|||
|
||||
/// 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::task;
|
||||
use encoding::EncodingRef;
|
||||
use encoding::all::UTF_8;
|
||||
use style::Stylesheet;
|
||||
|
@ -23,25 +20,22 @@ pub enum StylesheetProvenance {
|
|||
pub fn spawn_css_parser(provenance: StylesheetProvenance,
|
||||
resource_task: ResourceTask)
|
||||
-> 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
|
||||
let environment_encoding = UTF_8 as EncodingRef;
|
||||
|
||||
let provenance_cell = Cell::new(provenance);
|
||||
do task::spawn {
|
||||
spawn(proc() {
|
||||
// TODO: CSS parsing should take a base URL.
|
||||
let _url = do provenance_cell.with_ref |p| {
|
||||
match *p {
|
||||
let _url = match provenance {
|
||||
UrlProvenance(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) => {
|
||||
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));
|
||||
let LoadResponse { metadata: metadata, progress_port: progress_port }
|
||||
= input_port.recv();
|
||||
|
@ -56,7 +50,7 @@ pub fn spawn_css_parser(provenance: StylesheetProvenance,
|
|||
}
|
||||
};
|
||||
result_chan.send(sheet);
|
||||
}
|
||||
});
|
||||
|
||||
return result_port;
|
||||
}
|
||||
|
@ -69,7 +63,7 @@ impl Iterator<~[u8]> for ProgressMsgPortIterator {
|
|||
fn next(&mut self) -> Option<~[u8]> {
|
||||
match self.progress_port.recv() {
|
||||
Payload(data) => Some(data),
|
||||
Done(*) => None
|
||||
Done(..) => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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_util::url::make_url;
|
||||
use std::cast;
|
||||
use std::cell::Cell;
|
||||
use std::cell::RefCell;
|
||||
use std::comm::{Port, SharedChan};
|
||||
use std::comm;
|
||||
use std::from_str::FromStr;
|
||||
use std::str::eq_slice;
|
||||
use std::str;
|
||||
|
@ -107,11 +106,11 @@ fn css_link_listener(to_parent: SharedChan<HtmlDiscoveryMessage>,
|
|||
let mut result_vec = ~[];
|
||||
|
||||
loop {
|
||||
match from_parent.recv() {
|
||||
CSSTaskNewFile(provenance) => {
|
||||
match from_parent.recv_opt() {
|
||||
Some(CSSTaskNewFile(provenance)) => {
|
||||
result_vec.push(spawn_css_parser(provenance, resource_task.clone()));
|
||||
}
|
||||
CSSTaskExit => {
|
||||
Some(CSSTaskExit) | None => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -120,7 +119,7 @@ fn css_link_listener(to_parent: SharedChan<HtmlDiscoveryMessage>,
|
|||
// Send the sheets back in order
|
||||
// FIXME: Shouldn't wait until after we've recieved CSSTaskExit to start sending these
|
||||
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 = ~[];
|
||||
|
||||
loop {
|
||||
match from_parent.recv() {
|
||||
JSTaskNewFile(url) => {
|
||||
match from_parent.recv_opt() {
|
||||
Some(JSTaskNewFile(url)) => {
|
||||
match load_whole_resource(&resource_task, url.clone()) {
|
||||
Err(_) => {
|
||||
error!("error loading script {:s}", url.to_str());
|
||||
}
|
||||
Ok((metadata, bytes)) => {
|
||||
result_vec.push(JSFile {
|
||||
data: str::from_utf8(bytes),
|
||||
data: str::from_utf8(bytes).to_owned(),
|
||||
url: metadata.final_url,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
JSTaskNewInlineScript(data, url) => {
|
||||
Some(JSTaskNewInlineScript(data, url)) => {
|
||||
result_vec.push(JSFile { data: data, url: url });
|
||||
}
|
||||
JSTaskExit => {
|
||||
Some(JSTaskExit) | None => {
|
||||
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
|
||||
|
@ -253,30 +252,23 @@ pub fn parse_html(cx: *JSContext,
|
|||
// Spawn a CSS parser to receive links to CSS style sheets.
|
||||
let resource_task2 = resource_task.clone();
|
||||
|
||||
let (discovery_port, discovery_chan) = comm::stream();
|
||||
let discovery_chan = SharedChan::new(discovery_chan);
|
||||
|
||||
let stylesheet_chan = Cell::new(discovery_chan.clone());
|
||||
let (css_msg_port, css_msg_chan) = comm::stream();
|
||||
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);
|
||||
let (discovery_port, discovery_chan) = SharedChan::new();
|
||||
let stylesheet_chan = discovery_chan.clone();
|
||||
let (css_msg_port, css_chan) = SharedChan::new();
|
||||
spawn(proc() {
|
||||
css_link_listener(stylesheet_chan, css_msg_port, resource_task2.clone());
|
||||
});
|
||||
|
||||
// Spawn a JS parser to receive JavaScript.
|
||||
let resource_task2 = resource_task.clone();
|
||||
let js_result_chan = Cell::new(discovery_chan.clone());
|
||||
let (js_msg_port, js_msg_chan) = comm::stream();
|
||||
let js_msg_port = Cell::new(js_msg_port);
|
||||
do spawn {
|
||||
js_script_listener(js_result_chan.take(), js_msg_port.take(), resource_task2.clone());
|
||||
}
|
||||
let js_chan = SharedChan::new(js_msg_chan);
|
||||
let js_result_chan = discovery_chan.clone();
|
||||
let (js_msg_port, js_chan) = SharedChan::new();
|
||||
spawn(proc() {
|
||||
js_script_listener(js_result_chan, js_msg_port, resource_task2.clone());
|
||||
});
|
||||
|
||||
// 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));
|
||||
let load_response = input_port.recv();
|
||||
|
||||
|
@ -305,9 +297,10 @@ pub fn parse_html(cx: *JSContext,
|
|||
parser.enable_styling(true);
|
||||
|
||||
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);
|
||||
|
||||
parser.set_tree_handler(~hubbub::TreeHandler {
|
||||
let next_subpage_id = RefCell::new(next_subpage_id);
|
||||
|
||||
let tree_handler = hubbub::TreeHandler {
|
||||
create_comment: |data: ~str| {
|
||||
debug!("create comment");
|
||||
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);
|
||||
|
||||
debug!("-- attach attrs");
|
||||
do node.as_mut_element |element| {
|
||||
node.as_mut_element(|element| {
|
||||
for attr in tag.attributes.iter() {
|
||||
element.set_attr(node,
|
||||
attr.name.clone(),
|
||||
attr.value.clone());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Spawn additional parsing, network loads, etc. from tag and attrs
|
||||
match node.type_id() {
|
||||
// Handle CSS style sheets from <link> elements
|
||||
ElementNodeTypeId(HTMLLinkElementTypeId) => {
|
||||
do node.with_imm_element |element| {
|
||||
node.with_imm_element(|element| {
|
||||
match (element.get_attr(Null, "rel"), element.get_attr(Null, "href")) {
|
||||
(Some(rel), Some(href)) => {
|
||||
if "stylesheet" == rel {
|
||||
|
@ -356,13 +349,12 @@ pub fn parse_html(cx: *JSContext,
|
|||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ElementNodeTypeId(HTMLIframeElementTypeId) => {
|
||||
let iframe_chan = Cell::new(discovery_chan.clone());
|
||||
do node.with_mut_iframe_element |iframe_element| {
|
||||
let iframe_chan = iframe_chan.take();
|
||||
let iframe_chan = discovery_chan.clone();
|
||||
node.with_mut_iframe_element(|iframe_element| {
|
||||
let sandboxed = iframe_element.is_sandboxed();
|
||||
let elem = &mut iframe_element.htmlelement.element;
|
||||
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());
|
||||
|
||||
// Subpage Id
|
||||
let subpage_id = next_subpage_id.take();
|
||||
next_subpage_id.put_back(SubpageId(*subpage_id + 1));
|
||||
let subpage_id = next_subpage_id.get();
|
||||
next_subpage_id.set(SubpageId(*subpage_id + 1));
|
||||
|
||||
// Pipeline Id
|
||||
let pipeline_id = {
|
||||
|
@ -388,15 +380,15 @@ pub fn parse_html(cx: *JSContext,
|
|||
subpage_id,
|
||||
sandboxed)));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//FIXME: This should be taken care of by set_attr, but we don't have
|
||||
// access to a window so HTMLImageElement::AfterSetAttr bails.
|
||||
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()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_ => {}
|
||||
|
@ -460,7 +452,7 @@ pub fn parse_html(cx: *JSContext,
|
|||
complete_script: |script| {
|
||||
unsafe {
|
||||
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") {
|
||||
Some(src) => {
|
||||
debug!("found script: {:s}", src);
|
||||
|
@ -472,16 +464,16 @@ pub fn parse_html(cx: *JSContext,
|
|||
debug!("iterating over children {:?}", scriptnode.first_child());
|
||||
for child in scriptnode.children() {
|
||||
debug!("child = {:?}", child);
|
||||
do child.with_imm_text() |text| {
|
||||
child.with_imm_text(|text| {
|
||||
data.push(text.element.data.to_str()); // FIXME: Bad copy.
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
debug!("script data = {:?}", data);
|
||||
js_chan2.send(JSTaskNewInlineScript(data.concat(), url3.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
debug!("complete script");
|
||||
},
|
||||
|
@ -490,23 +482,22 @@ pub fn parse_html(cx: *JSContext,
|
|||
unsafe {
|
||||
let style: AbstractNode = NodeWrapping::from_hubbub_node(style);
|
||||
let url = FromStr::from_str("http://example.com/"); // FIXME
|
||||
let url_cell = Cell::new(url);
|
||||
|
||||
let mut data = ~[];
|
||||
debug!("iterating over children {:?}", style.first_child());
|
||||
for child in style.children() {
|
||||
debug!("child = {:?}", child);
|
||||
do child.with_imm_text() |text| {
|
||||
child.with_imm_text(|text| {
|
||||
data.push(text.element.data.to_str()); // FIXME: Bad copy.
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
parser.set_tree_handler(&tree_handler);
|
||||
debug!("set tree handler");
|
||||
|
||||
debug!("loaded page");
|
||||
|
@ -516,10 +507,10 @@ pub fn parse_html(cx: *JSContext,
|
|||
debug!("received data");
|
||||
parser.parse_chunk(data);
|
||||
}
|
||||
Done(Err(*)) => {
|
||||
Done(Err(..)) => {
|
||||
fail!("Failed to load page URL {:s}", url.to_str());
|
||||
}
|
||||
Done(*) => {
|
||||
Done(..) => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -122,9 +122,11 @@ pub struct Reflow {
|
|||
/// Encapsulates a channel to the layout task.
|
||||
#[deriving(Clone)]
|
||||
pub struct LayoutChan(SharedChan<Msg>);
|
||||
|
||||
impl LayoutChan {
|
||||
pub fn new(chan: Chan<Msg>) -> LayoutChan {
|
||||
LayoutChan(SharedChan::new(chan))
|
||||
pub fn new() -> (Port<Msg>, LayoutChan) {
|
||||
let (port, chan) = SharedChan::new();
|
||||
(port, LayoutChan(chan))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,14 +2,11 @@
|
|||
* 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/. */
|
||||
|
||||
#[link(name = "script",
|
||||
vers = "0.1",
|
||||
uuid = "536a45e2-b605-4ee0-b54c-466810f1ffc1",
|
||||
url = "http://servo.org/")];
|
||||
#[crate_id = "github.com/mozilla/servo#script:0.1"];
|
||||
#[crate_type = "lib"];
|
||||
|
||||
#[comment = "The Servo Parallel Browser Project"];
|
||||
#[license = "MPL"];
|
||||
#[crate_type = "lib"];
|
||||
|
||||
#[feature(globs, macro_rules, struct_variant, managed_boxes)];
|
||||
|
||||
|
@ -17,11 +14,12 @@ extern mod geom;
|
|||
extern mod hubbub;
|
||||
extern mod encoding;
|
||||
extern mod js;
|
||||
extern mod servo_net (name = "net");
|
||||
extern mod servo_util (name = "util");
|
||||
extern mod servo_net = "net";
|
||||
extern mod servo_util = "util";
|
||||
extern mod style;
|
||||
extern mod servo_msg (name = "msg");
|
||||
extern mod servo_msg = "msg";
|
||||
extern mod extra;
|
||||
extern mod native;
|
||||
|
||||
// Macros
|
||||
mod macros;
|
||||
|
|
|
@ -14,15 +14,15 @@ use dom::event::Event;
|
|||
use dom::eventtarget::AbstractEventTarget;
|
||||
use dom::htmldocument::HTMLDocument;
|
||||
use dom::namespace::Null;
|
||||
use dom::node::{AbstractNode, LayoutDataRef};
|
||||
use dom::window::{TimerData, Window};
|
||||
use dom::node::AbstractNode;
|
||||
use dom::window::{TimerData, TimerHandle, Window};
|
||||
use html::hubbub_html_parser::HtmlParserResult;
|
||||
use html::hubbub_html_parser::{HtmlDiscoveredStyle, HtmlDiscoveredIFrame, HtmlDiscoveredScript};
|
||||
use html::hubbub_html_parser;
|
||||
use layout_interface::{AddStylesheetMsg, DocumentDamage};
|
||||
use layout_interface::{ContentBoxQuery, ContentBoxResponse};
|
||||
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::ContentChangedDocumentDamage;
|
||||
use layout_interface;
|
||||
|
@ -46,12 +46,9 @@ use servo_net::image_cache_task::ImageCacheTask;
|
|||
use servo_net::resource_task::ResourceTask;
|
||||
use servo_util::geometry::to_frac_px;
|
||||
use servo_util::url::make_url;
|
||||
use std::cell::Cell;
|
||||
use std::comm::{Port, SharedChan};
|
||||
use std::comm;
|
||||
use std::ptr;
|
||||
use std::str::eq_slice;
|
||||
use std::task::{spawn_sched, SingleThreaded};
|
||||
use std::util::replace;
|
||||
|
||||
/// Messages used to control the script task.
|
||||
|
@ -90,8 +87,9 @@ pub struct ScriptChan(SharedChan<ScriptMsg>);
|
|||
|
||||
impl ScriptChan {
|
||||
/// Creates a new script chan.
|
||||
pub fn new(chan: Chan<ScriptMsg>) -> ScriptChan {
|
||||
ScriptChan(SharedChan::new(chan))
|
||||
pub fn new() -> (Port<ScriptMsg>, ScriptChan) {
|
||||
let (port, chan) = SharedChan::new();
|
||||
(port, ScriptChan(chan))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -140,8 +138,8 @@ pub struct PageTree {
|
|||
inner: ~[PageTree],
|
||||
}
|
||||
|
||||
pub struct PageTreeIterator<'self> {
|
||||
priv stack: ~[&'self mut PageTree],
|
||||
pub struct PageTreeIterator<'a> {
|
||||
priv stack: ~[&'a mut 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> {
|
||||
if !self.stack.is_empty() {
|
||||
let next = self.stack.pop();
|
||||
|
@ -254,11 +252,13 @@ impl Page {
|
|||
let join_port = replace(&mut self.layout_join_port, None);
|
||||
match join_port {
|
||||
Some(ref join_port) => {
|
||||
if !join_port.peek() {
|
||||
match join_port.try_recv() {
|
||||
None => {
|
||||
info!("script: waiting on layout");
|
||||
}
|
||||
|
||||
join_port.recv();
|
||||
}
|
||||
Some(_) => {}
|
||||
}
|
||||
|
||||
debug!("script: layout joined")
|
||||
}
|
||||
|
@ -307,7 +307,7 @@ impl Page {
|
|||
compositor.set_ready_state(PerformingLayout);
|
||||
|
||||
// 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.last_reflow_id += 1;
|
||||
|
@ -359,11 +359,6 @@ impl Page {
|
|||
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.
|
||||
|
@ -412,7 +407,6 @@ pub struct ScriptTask {
|
|||
}
|
||||
|
||||
/// Returns the relevant page from the associated JS Context.
|
||||
#[fixed_stack_segment]
|
||||
pub fn page_from_context(js_context: *JSContext) -> *mut Page {
|
||||
unsafe {
|
||||
JS_GetContextPrivate(js_context) as *mut Page
|
||||
|
@ -468,24 +462,7 @@ impl ScriptTask {
|
|||
resource_task: ResourceTask,
|
||||
image_cache_task: ImageCacheTask,
|
||||
window_size: Size2D<uint>) {
|
||||
let parms = Cell::new((compositor,
|
||||
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();
|
||||
spawn(proc() {
|
||||
let script_task = ScriptTask::new(id,
|
||||
@compositor as @ScriptListener,
|
||||
layout_chan,
|
||||
|
@ -496,7 +473,7 @@ impl ScriptTask {
|
|||
image_cache_task,
|
||||
window_size);
|
||||
script_task.start();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Handle incoming control messages.
|
||||
|
@ -520,12 +497,13 @@ impl ScriptTask {
|
|||
|
||||
// Store new resizes, and gather all other events.
|
||||
let mut sequential = ~[];
|
||||
loop {
|
||||
|
||||
// Receive at least one message so we don't spinloop.
|
||||
let event = self.port.recv();
|
||||
let mut event = self.port.recv();
|
||||
|
||||
loop {
|
||||
match event {
|
||||
ResizeMsg(id, size) => {
|
||||
debug!("script got resize message");
|
||||
let page = self.page_tree.find(id).expect("resize sent to nonexistent pipeline").page;
|
||||
page.resize_event = Some(size);
|
||||
}
|
||||
|
@ -534,9 +512,9 @@ impl ScriptTask {
|
|||
}
|
||||
}
|
||||
|
||||
// Break if there are no more messages.
|
||||
if !self.port.peek() {
|
||||
break;
|
||||
match self.port.try_recv() {
|
||||
None => break,
|
||||
Some(ev) => event = ev,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -556,7 +534,7 @@ impl ScriptTask {
|
|||
self.handle_exit_window_msg(id);
|
||||
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.
|
||||
#[fixed_stack_segment]
|
||||
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
|
||||
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;
|
||||
if !window.active_timers.contains(&timer_data.handle) {
|
||||
if !window.active_timers.contains(&TimerHandle { handle: timer_data.handle, cancel_chan: None }) {
|
||||
return;
|
||||
}
|
||||
window.active_timers.remove(&TimerHandle { handle: timer_data.handle, cancel_chan: None });
|
||||
unsafe {
|
||||
let this_value = if timer_data.args.len() > 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.
|
||||
let document = HTMLDocument::new(window);
|
||||
|
||||
let html_parsing_result = hubbub_html_parser::parse_html(cx.ptr,
|
||||
document,
|
||||
url.clone(),
|
||||
|
@ -736,7 +713,7 @@ impl ScriptTask {
|
|||
|
||||
let mut js_scripts = None;
|
||||
loop {
|
||||
match discovery_port.try_recv() {
|
||||
match discovery_port.recv_opt() {
|
||||
Some(HtmlDiscoveredScript(scripts)) => {
|
||||
assert!(js_scripts.is_none());
|
||||
js_scripts = Some(scripts);
|
||||
|
@ -805,20 +782,20 @@ impl ScriptTask {
|
|||
None => {
|
||||
let doc_node = AbstractNode::from_document(document);
|
||||
let mut anchors = doc_node.traverse_preorder().filter(|node| node.is_anchor_element());
|
||||
do anchors.find |node| {
|
||||
do node.with_imm_element |elem| {
|
||||
anchors.find(|node| {
|
||||
node.with_imm_element(|elem| {
|
||||
match elem.get_attr(Null, "name") {
|
||||
Some(name) => eq_slice(name, fragid),
|
||||
None => false
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
ContentBoxResponse(rect) => {
|
||||
let point = Point2D(to_frac_px(rect.origin.x).to_f32().unwrap(),
|
||||
|
@ -870,7 +847,7 @@ impl ScriptTask {
|
|||
if root.is_none() {
|
||||
return;
|
||||
}
|
||||
let (port, chan) = comm::stream();
|
||||
let (port, chan) = Chan::new();
|
||||
match page.query_layout(HitTestQuery(root.unwrap(), point, chan), port) {
|
||||
Ok(node) => match node {
|
||||
HitTestResponse(node) => {
|
||||
|
@ -886,11 +863,11 @@ impl ScriptTask {
|
|||
}
|
||||
}
|
||||
if node.is_element() {
|
||||
do node.with_imm_element |element| {
|
||||
node.with_imm_element(|element| {
|
||||
if "a" == element.tag_name {
|
||||
self.load_url_from_element(page, element)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -899,8 +876,8 @@ impl ScriptTask {
|
|||
}
|
||||
}
|
||||
}
|
||||
MouseDownEvent(*) => {}
|
||||
MouseUpEvent(*) => {}
|
||||
MouseDownEvent(..) => {}
|
||||
MouseUpEvent(..) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -910,9 +887,9 @@ impl ScriptTask {
|
|||
for href in attr.iter() {
|
||||
debug!("ScriptTask: clicked on link to {:s}", *href);
|
||||
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()
|
||||
};
|
||||
});
|
||||
debug!("ScriptTask: current url is {:?}", 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();
|
||||
|
||||
// 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));
|
||||
response_port.recv();
|
||||
|
||||
// Destroy all nodes.
|
||||
//
|
||||
// If there was a leak, the layout task will soon crash safely when it detects that local data
|
||||
// is missing from its heap.
|
||||
//
|
||||
// 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 all nodes. Setting frame and js_info to None will trigger our
|
||||
// compartment to shutdown, run GC, etc.
|
||||
page.frame = None;
|
||||
page.js_info = None;
|
||||
|
||||
// Destroy the layout task. If there were node leaks, layout will now crash safely.
|
||||
page.layout_chan.send(layout_interface::ExitNowMsg);
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ pub mod specified {
|
|||
_ => None
|
||||
}
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
pub fn parse(input: &ComponentValue) -> Option<Length> {
|
||||
Length::parse_internal(input, /* negative_ok = */ true)
|
||||
}
|
||||
|
@ -87,6 +88,7 @@ pub mod specified {
|
|||
_ => None
|
||||
}
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
#[inline]
|
||||
pub fn parse(input: &ComponentValue) -> Option<LengthOrPercentage> {
|
||||
LengthOrPercentage::parse_internal(input, /* negative_ok = */ true)
|
||||
|
@ -145,6 +147,7 @@ pub mod specified {
|
|||
_ => None
|
||||
}
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
#[inline]
|
||||
pub fn parse(input: &ComponentValue) -> Option<LengthOrPercentageOrNone> {
|
||||
LengthOrPercentageOrNone::parse_internal(input, /* negative_ok = */ true)
|
||||
|
|
|
@ -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, ());
|
||||
let result = f();
|
||||
local_data::pop(silence_errors);
|
||||
|
|
|
@ -121,12 +121,12 @@ pub fn parse_media_query_list(input: &[ComponentValue]) -> MediaQueryList {
|
|||
|
||||
impl MediaQueryList {
|
||||
pub fn evaluate(&self, device: &Device) -> bool {
|
||||
do self.media_queries.iter().any |mq| {
|
||||
self.media_queries.iter().any(|mq| {
|
||||
match mq.media_type {
|
||||
MediaType(media_type) => media_type == device.media_type,
|
||||
All => true,
|
||||
}
|
||||
// TODO: match Level 3 expressions
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ pub trait TNode<E:TElement> : Clone {
|
|||
fn is_element(&self) -> bool;
|
||||
|
||||
/// 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 {
|
||||
|
|
|
@ -74,8 +74,8 @@ pub mod longhands {
|
|||
pub fn parse_declared(input: &[ComponentValue])
|
||||
-> Option<DeclaredValue<SpecifiedValue>> {
|
||||
match CSSWideKeyword::parse(input) {
|
||||
Some(Left(keyword)) => Some(CSSWideKeyword(keyword)),
|
||||
Some(Right(Unset)) => Some(CSSWideKeyword(${
|
||||
Some(Some(keyword)) => Some(CSSWideKeyword(keyword)),
|
||||
Some(None) => Some(CSSWideKeyword(${
|
||||
"Inherit" if inherited else "Initial"})),
|
||||
None => parse_specified(input),
|
||||
}
|
||||
|
@ -118,14 +118,14 @@ pub mod longhands {
|
|||
${to_rust_ident(values.split()[0])}
|
||||
}
|
||||
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() {
|
||||
% for value in values.split():
|
||||
"${value}" => Some(${to_rust_ident(value)}),
|
||||
% endfor
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
</%self:single_component_value>
|
||||
</%def>
|
||||
|
@ -648,12 +648,12 @@ pub mod longhands {
|
|||
/// <length> | <percentage>
|
||||
/// TODO: support <absolute-size> and <relative-size>
|
||||
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 {
|
||||
specified::LP_Length(value) => value,
|
||||
specified::LP_Percentage(value) => specified::Em(value),
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
</%self:single_component_value>
|
||||
|
||||
|
@ -767,9 +767,9 @@ pub mod shorthands {
|
|||
|
||||
// TODO: other background-* properties
|
||||
<%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) }
|
||||
}
|
||||
})
|
||||
</%self:shorthand>
|
||||
|
||||
${four_sides_shorthand("margin", "margin-%s", "margin_top::from_component_value")}
|
||||
|
@ -818,13 +818,13 @@ pub mod shorthands {
|
|||
'border-%s-%s' % (side, prop)
|
||||
for prop in ['color', 'style', 'width']
|
||||
)}">
|
||||
do parse_border(input).map |(color, style, width)| {
|
||||
parse_border(input).map(|(color, style, width)| {
|
||||
Longhands {
|
||||
% for prop in ["color", "style", "width"]:
|
||||
${"border_%s_%s: %s," % (side, prop, prop)}
|
||||
% endfor
|
||||
}
|
||||
}
|
||||
})
|
||||
</%self:shorthand>
|
||||
% endfor
|
||||
|
||||
|
@ -833,7 +833,7 @@ pub mod shorthands {
|
|||
for side in ['top', 'right', 'bottom', 'left']
|
||||
for prop in ['color', 'style', 'width']
|
||||
)}">
|
||||
do parse_border(input).map |(color, style, width)| {
|
||||
parse_border(input).map(|(color, style, width)| {
|
||||
Longhands {
|
||||
% for side in ["top", "right", "bottom", "left"]:
|
||||
% for prop in ["color", "style", "width"]:
|
||||
|
@ -841,7 +841,7 @@ pub mod shorthands {
|
|||
% endfor
|
||||
% endfor
|
||||
}
|
||||
}
|
||||
})
|
||||
</%self:shorthand>
|
||||
|
||||
<%self:shorthand name="font" sub_properties="font-style font-variant font-weight
|
||||
|
@ -966,18 +966,16 @@ pub enum CSSWideKeyword {
|
|||
Inherit,
|
||||
}
|
||||
|
||||
struct Unset;
|
||||
|
||||
impl CSSWideKeyword {
|
||||
pub fn parse(input: &[ComponentValue]) -> Option<Either<CSSWideKeyword, Unset>> {
|
||||
do one_component_value(input).and_then(get_ident_lower).and_then |keyword| {
|
||||
pub fn parse(input: &[ComponentValue]) -> Option<Option<CSSWideKeyword>> {
|
||||
one_component_value(input).and_then(get_ident_lower).and_then(|keyword| {
|
||||
match keyword.as_slice() {
|
||||
"initial" => Some(Left(Initial)),
|
||||
"inherit" => Some(Left(Inherit)),
|
||||
"unset" => Some(Right(Unset)),
|
||||
"initial" => Some(Some(Initial)),
|
||||
"inherit" => Some(Some(Inherit)),
|
||||
"unset" => Some(None),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1018,14 +1016,14 @@ impl PropertyDeclaration {
|
|||
% endfor
|
||||
% for shorthand in SHORTHANDS:
|
||||
"${shorthand.name}" => match CSSWideKeyword::parse(value) {
|
||||
Some(Left(keyword)) => {
|
||||
Some(Some(keyword)) => {
|
||||
% for sub_property in shorthand.sub_properties:
|
||||
result_list.push(${sub_property.ident}_declaration(
|
||||
CSSWideKeyword(keyword)
|
||||
));
|
||||
% endfor
|
||||
},
|
||||
Some(Right(Unset)) => {
|
||||
Some(None) => {
|
||||
% for sub_property in shorthand.sub_properties:
|
||||
result_list.push(${sub_property.ident}_declaration(
|
||||
CSSWideKeyword(${
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use extra::arc::Arc;
|
||||
use extra::sort::tim_sort;
|
||||
use std::ascii::StrAsciiExt;
|
||||
use std::hashmap::HashMap;
|
||||
use std::str;
|
||||
|
@ -86,11 +85,9 @@ impl SelectorMap {
|
|||
|
||||
match element.get_attr(None, "class") {
|
||||
Some(ref class_attr) => {
|
||||
for class in class_attr.split_iter(SELECTOR_WHITESPACE) {
|
||||
SelectorMap::get_matching_rules_from_hash(node,
|
||||
&self.class_hash,
|
||||
class,
|
||||
matching_rules_list)
|
||||
for class in class_attr.split(SELECTOR_WHITESPACE) {
|
||||
SelectorMap::get_matching_rules_from_hash(
|
||||
node, &self.class_hash, class, matching_rules_list);
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
|
@ -108,7 +105,13 @@ impl SelectorMap {
|
|||
});
|
||||
|
||||
// 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,
|
||||
|
@ -292,11 +295,11 @@ impl Stylist {
|
|||
);
|
||||
|
||||
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!(important);
|
||||
self.rules_source_order += 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// 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 Rule {
|
||||
declarations,
|
||||
_
|
||||
..
|
||||
} = rule;
|
||||
declarations
|
||||
});
|
||||
|
@ -436,9 +439,9 @@ impl Ord for Rule {
|
|||
|
||||
fn matches_compound_selector<E:TElement,N:TNode<E>>(selector: &CompoundSelector, element: &N)
|
||||
-> bool {
|
||||
if !do selector.simple_selectors.iter().all |simple_selector| {
|
||||
if !selector.simple_selectors.iter().all(|simple_selector| {
|
||||
matches_simple_selector(simple_selector, element)
|
||||
} {
|
||||
}) {
|
||||
return false
|
||||
}
|
||||
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: intern element names
|
||||
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())
|
||||
}
|
||||
})
|
||||
}
|
||||
NamespaceSelector(ref url) => {
|
||||
do element.with_element |element: &E| {
|
||||
element.with_element(|element: &E| {
|
||||
element.get_namespace_url() == url.as_slice()
|
||||
}
|
||||
})
|
||||
}
|
||||
// TODO: case-sensitivity depends on the document type and quirks mode
|
||||
// TODO: cache and intern IDs on elements.
|
||||
IDSelector(ref id) => {
|
||||
do element.with_element |element: &E| {
|
||||
element.with_element(|element: &E| {
|
||||
match element.get_attr(None, "id") {
|
||||
Some(attr) => str::eq_slice(attr, *id),
|
||||
None => false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
// TODO: cache and intern classe names on elements.
|
||||
ClassSelector(ref class) => {
|
||||
do element.with_element |element: &E| {
|
||||
element.with_element(|element: &E| {
|
||||
match element.get_attr(None, "class") {
|
||||
None => false,
|
||||
// TODO: case-sensitivity depends on the document type and quirks mode
|
||||
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),
|
||||
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| {
|
||||
attr_value.split_iter(SELECTOR_WHITESPACE).any(|v| v == value.as_slice())
|
||||
},
|
||||
AttrIncludes(ref attr, ref value) => match_attribute(attr, element, |attr_value| {
|
||||
attr_value.split(SELECTOR_WHITESPACE).any(|v| v == value.as_slice())
|
||||
}),
|
||||
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())
|
||||
},
|
||||
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())
|
||||
},
|
||||
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())
|
||||
},
|
||||
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())
|
||||
},
|
||||
}),
|
||||
|
||||
|
||||
AnyLink => {
|
||||
do element.with_element |element: &E| {
|
||||
element.with_element(|element: &E| {
|
||||
element.get_link().is_some()
|
||||
}
|
||||
})
|
||||
}
|
||||
Link => {
|
||||
do element.with_element |element: &E| {
|
||||
element.with_element(|element: &E| {
|
||||
match element.get_link() {
|
||||
Some(url) => !url_is_visited(url),
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
Visited => {
|
||||
do element.with_element |element: &E| {
|
||||
element.with_element(|element: &E| {
|
||||
match element.get_link() {
|
||||
Some(url) => url_is_visited(url),
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
FirstChild => matches_first_child(element),
|
||||
|
@ -583,7 +586,8 @@ fn url_is_visited(_url: &str) -> bool {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn matches_generic_nth_child<E:TElement,
|
||||
fn matches_generic_nth_child<'a,
|
||||
E:TElement,
|
||||
N:TNode<E>>(
|
||||
element: &N,
|
||||
a: i32,
|
||||
|
@ -601,15 +605,6 @@ fn matches_generic_nth_child<E:TElement,
|
|||
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;
|
||||
loop {
|
||||
if is_from_end {
|
||||
|
@ -626,12 +621,14 @@ fn matches_generic_nth_child<E:TElement,
|
|||
|
||||
if node.is_element() {
|
||||
if is_of_type {
|
||||
do node.with_element |node: &E| {
|
||||
if element_local_name == node.get_local_name() &&
|
||||
element_namespace == node.get_namespace_url() {
|
||||
element.with_element(|element: &E| {
|
||||
node.with_element(|node: &E| {
|
||||
if element.get_local_name() == node.get_local_name() &&
|
||||
element.get_namespace_url() == node.get_namespace_url() {
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
} else {
|
||||
index += 1;
|
||||
}
|
||||
|
@ -704,18 +701,17 @@ fn match_attribute<E:TElement,
|
|||
N:TNode<E>>(
|
||||
attr: &AttrSelector,
|
||||
element: &N,
|
||||
f: &fn(&str) -> bool)
|
||||
f: |&str| -> bool)
|
||||
-> bool {
|
||||
do element.with_element |element: &E| {
|
||||
element.with_element(|element: &E| {
|
||||
// FIXME: avoid .clone() here? See #1367
|
||||
match element.get_attr(attr.namespace.clone(), attr.name) {
|
||||
None => false,
|
||||
Some(value) => f(value)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use extra::arc::Arc;
|
||||
|
|
|
@ -27,9 +27,6 @@ pub struct Selector {
|
|||
specificity: u32,
|
||||
}
|
||||
|
||||
pub static STYLE_ATTRIBUTE_SPECIFICITY: u32 = 1 << 31;
|
||||
|
||||
|
||||
#[deriving(Eq, Clone)]
|
||||
pub enum PseudoElement {
|
||||
Before,
|
||||
|
@ -203,19 +200,19 @@ fn compute_specificity(mut selector: &CompoundSelector,
|
|||
specificity: &mut Specificity) {
|
||||
for simple_selector in simple_selectors.iter() {
|
||||
match simple_selector {
|
||||
&LocalNameSelector(*) => specificity.element_selectors += 1,
|
||||
&IDSelector(*) => specificity.id_selectors += 1,
|
||||
&ClassSelector(*)
|
||||
| &AttrExists(*) | &AttrEqual(*) | &AttrIncludes(*) | &AttrDashMatch(*)
|
||||
| &AttrPrefixMatch(*) | &AttrSubstringMatch(*) | &AttrSuffixMatch(*)
|
||||
&LocalNameSelector(..) => specificity.element_selectors += 1,
|
||||
&IDSelector(..) => specificity.id_selectors += 1,
|
||||
&ClassSelector(..)
|
||||
| &AttrExists(..) | &AttrEqual(..) | &AttrIncludes(..) | &AttrDashMatch(..)
|
||||
| &AttrPrefixMatch(..) | &AttrSubstringMatch(..) | &AttrSuffixMatch(..)
|
||||
| &AnyLink | &Link | &Visited
|
||||
| &FirstChild | &LastChild | &OnlyChild | &Root
|
||||
// | &Empty | &Lang(*)
|
||||
| &NthChild(*) | &NthLastChild(*)
|
||||
| &NthOfType(*) | &NthLastOfType(*)
|
||||
| &NthChild(..) | &NthLastChild(..)
|
||||
| &NthOfType(..) | &NthLastOfType(..)
|
||||
| &FirstOfType | &LastOfType | &OnlyOfType
|
||||
=> specificity.class_like_selectors += 1,
|
||||
&NamespaceSelector(*) => (),
|
||||
&NamespaceSelector(..) => (),
|
||||
&Negation(ref negated)
|
||||
=> simple_selectors_specificity(negated.as_slice(), specificity),
|
||||
}
|
||||
|
|
|
@ -2,21 +2,18 @@
|
|||
* 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/. */
|
||||
|
||||
#[link(name = "style",
|
||||
vers = "0.1",
|
||||
uuid = "4a50ca00-3283-11e3-aa6e-0800200c9a66",
|
||||
url = "http://servo.org/")];
|
||||
#[crate_id = "github.com/mozilla/servo#style:0.1"];
|
||||
#[crate_type = "lib"];
|
||||
|
||||
#[comment = "The Servo Parallel Browser Project"];
|
||||
#[license = "MPL"];
|
||||
#[crate_type = "lib"];
|
||||
|
||||
#[feature(globs, macro_rules, managed_boxes)];
|
||||
|
||||
extern mod extra;
|
||||
extern mod cssparser;
|
||||
extern mod encoding;
|
||||
extern mod servo_util (name = "util");
|
||||
extern mod servo_util = "util";
|
||||
|
||||
|
||||
// Public API
|
||||
|
|
|
@ -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,
|
||||
callback: &fn(&StyleRule)) {
|
||||
callback: |&StyleRule|) {
|
||||
for rule in rules.iter() {
|
||||
match *rule {
|
||||
CSSStyleRule(ref rule) => callback(rule),
|
||||
|
|
|
@ -7,7 +7,7 @@ use std::hashmap::HashMap;
|
|||
pub trait Cache<K: Eq, V: Clone> {
|
||||
fn insert(&mut self, key: K, value: 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);
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
Some(value) => value,
|
||||
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()
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
Some(pos) => self.touch(pos),
|
||||
None => {
|
||||
|
@ -191,7 +191,7 @@ fn test_lru_cache() {
|
|||
assert!(cache.find(&4).is_some()); // (2, 4) (no change)
|
||||
|
||||
// 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(&2).is_none()); // (4, 1) (no change)
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* 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/. */
|
||||
|
||||
use std::rt::io;
|
||||
use std::rt::io::Writer;
|
||||
use std::io;
|
||||
use std::io::Writer;
|
||||
use std::vec::raw::buf_as_slice;
|
||||
use std::cast::transmute;
|
||||
use std::mem::size_of;
|
||||
|
|
|
@ -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 {
|
||||
/// FIXME(pcwalton): Workaround for lack of cross crate inlining of newtype structs!
|
||||
#[inline]
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* 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/. */
|
||||
|
||||
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
|
||||
/// 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
|
||||
/// 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 ret = io_error::cond.trap(|e| err = Some(e)).inside(cb);
|
||||
match err {
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -4,25 +4,36 @@
|
|||
|
||||
//! Timing functions.
|
||||
|
||||
use extra::sort::tim_sort;
|
||||
use extra::time::precise_time_ns;
|
||||
use extra::treemap::TreeMap;
|
||||
use std::comm::{Port, SendDeferred, SharedChan};
|
||||
use std::comm::{Port, SharedChan};
|
||||
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
|
||||
#[deriving(Clone)]
|
||||
pub struct ProfilerChan(SharedChan<ProfilerMsg>);
|
||||
|
||||
impl ProfilerChan {
|
||||
pub fn new(chan: Chan<ProfilerMsg>) -> ProfilerChan {
|
||||
ProfilerChan(SharedChan::new(chan))
|
||||
}
|
||||
|
||||
pub fn send_deferred(&self, msg: ProfilerMsg) {
|
||||
(**self).send_deferred(msg);
|
||||
pub fn send(&self, msg: ProfilerMsg) {
|
||||
(**self).send(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,32 +111,35 @@ pub struct 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 {
|
||||
Some(period) => {
|
||||
let period = (period * 1000f64) as u64;
|
||||
do spawn {
|
||||
let mut timer = Timer::new().unwrap();
|
||||
let chan = chan.clone();
|
||||
spawn(proc() {
|
||||
loop {
|
||||
timer.sleep(period);
|
||||
Timer::sleep(period);
|
||||
if !chan.try_send(PrintMsg) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
// Spawn the profiler
|
||||
do spawn_with(port) |port| {
|
||||
spawn(proc() {
|
||||
let mut profiler = Profiler::new(port);
|
||||
profiler.start();
|
||||
}
|
||||
});
|
||||
}
|
||||
None => {
|
||||
// no-op to handle profiler messages when the profiler is inactive
|
||||
do spawn_with(port) |port| {
|
||||
while port.try_recv().is_some() {}
|
||||
}
|
||||
spawn(proc() {
|
||||
while port.recv_opt().is_some() {}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ProfilerChan(chan)
|
||||
}
|
||||
|
||||
pub fn new(port: Port<ProfilerMsg>) -> Profiler {
|
||||
|
@ -138,7 +152,7 @@ impl Profiler {
|
|||
|
||||
pub fn start(&mut self) {
|
||||
loop {
|
||||
let msg = self.port.try_recv();
|
||||
let msg = self.port.recv_opt();
|
||||
match msg {
|
||||
Some (msg) => self.handle_msg(msg),
|
||||
None => break
|
||||
|
@ -151,7 +165,7 @@ impl Profiler {
|
|||
TimeMsg(category, t) => self.buckets.find_mut(&category).unwrap().push(t),
|
||||
PrintMsg => match self.last_msg {
|
||||
// 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() {
|
||||
// FIXME(XXX): TreeMap currently lacks mut_iter()
|
||||
let mut data = data.clone();
|
||||
tim_sort(data);
|
||||
data.sort_by(|a, b| {
|
||||
if a < b {
|
||||
Less
|
||||
} else {
|
||||
Greater
|
||||
}
|
||||
});
|
||||
let data_len = data.len();
|
||||
if data_len > 0 {
|
||||
let (mean, median, &min, &max) =
|
||||
|
@ -184,17 +204,17 @@ impl Profiler {
|
|||
|
||||
pub fn profile<T>(category: ProfilerCategory,
|
||||
profiler_chan: ProfilerChan,
|
||||
callback: &fn() -> T)
|
||||
callback: || -> T)
|
||||
-> T {
|
||||
let start_time = precise_time_ns();
|
||||
let val = callback();
|
||||
let end_time = precise_time_ns();
|
||||
let ms = ((end_time - start_time) as f64 / 1000000f64);
|
||||
profiler_chan.send_deferred(TimeMsg(category, ms));
|
||||
profiler_chan.send(TimeMsg(category, ms));
|
||||
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 val = callback();
|
||||
let end_time = precise_time_ns();
|
||||
|
|
|
@ -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
|
||||
// src="..." block. Whitespace intended as content should be
|
||||
// %-encoded or base64'd.
|
||||
str_url.iter().filter(|&c| !c.is_whitespace()).collect()
|
||||
str_url.chars().filter(|&c| !c.is_whitespace()).collect()
|
||||
},
|
||||
_ => str_url
|
||||
}
|
||||
|
|
|
@ -2,10 +2,7 @@
|
|||
* 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/. */
|
||||
|
||||
#[link(name = "util",
|
||||
vers = "0.1",
|
||||
uuid = "48421f49-17cf-41c5-a68e-ff669ff2ecd5",
|
||||
url = "http://servo.org/")];
|
||||
#[crate_id = "github.com/mozilla/servo#util:0.1"];
|
||||
#[crate_type = "lib"];
|
||||
|
||||
#[feature(macro_rules, managed_boxes)];
|
||||
|
@ -16,7 +13,6 @@ extern mod geom;
|
|||
pub mod cache;
|
||||
pub mod geometry;
|
||||
pub mod range;
|
||||
pub mod slot;
|
||||
pub mod time;
|
||||
pub mod url;
|
||||
pub mod vec;
|
||||
|
|
|
@ -4,13 +4,13 @@
|
|||
|
||||
use std::cmp::{Ord, Eq};
|
||||
|
||||
pub trait BinarySearchMethods<'self, T: Ord + Eq> {
|
||||
fn binary_search(&self, key: &T) -> Option<&'self T>;
|
||||
pub trait BinarySearchMethods<'a, T: Ord + Eq> {
|
||||
fn binary_search(&self, key: &T) -> Option<&'a T>;
|
||||
fn binary_search_index(&self, key: &T) -> Option<uint>;
|
||||
}
|
||||
|
||||
impl<'self, T: Ord + Eq> BinarySearchMethods<'self, T> for &'self [T] {
|
||||
fn binary_search(&self, key: &T) -> Option<&'self T> {
|
||||
impl<'a, T: Ord + Eq> BinarySearchMethods<'a, T> for &'a [T] {
|
||||
fn binary_search(&self, key: &T) -> Option<&'a T> {
|
||||
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]) {
|
||||
let mut i = 0;
|
||||
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]) {
|
||||
let mut i = 0;
|
||||
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 {
|
||||
match a {
|
||||
None => false,
|
||||
|
@ -70,9 +73,8 @@ pub fn zip_copies<A: Clone, B: Clone>(avec: &[A], bvec: &[B]) -> ~[(A,B)] {
|
|||
.collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_find_all_elements() {
|
||||
#[test];
|
||||
|
||||
let arr_odd = [1, 2, 4, 6, 7, 8, 9];
|
||||
let arr_even = [1, 2, 5, 6, 7, 8, 9, 42];
|
||||
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]
|
||||
fn should_not_find_missing_elements() {
|
||||
#[test];
|
||||
|
||||
let arr_odd = [1, 2, 4, 6, 7, 8, 9];
|
||||
let arr_even = [1, 2, 5, 6, 7, 8, 9, 42];
|
||||
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
Loading…
Add table
Add a link
Reference in a new issue