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
|
url = https://github.com/mozilla-servo/skia.git
|
||||||
[submodule "src/compiler/rust"]
|
[submodule "src/compiler/rust"]
|
||||||
path = src/compiler/rust
|
path = src/compiler/rust
|
||||||
url = https://github.com/mozilla/rust.git
|
url = https://github.com/mozilla-servo/rust.git
|
||||||
[submodule "src/support/alert/rust-alert"]
|
[submodule "src/support/alert/rust-alert"]
|
||||||
path = src/support/alert/rust-alert
|
path = src/support/alert/rust-alert
|
||||||
url = https://github.com/mozilla-servo/rust-alert.git
|
url = https://github.com/mozilla-servo/rust-alert.git
|
||||||
|
@ -112,7 +112,7 @@
|
||||||
branch = rust-servo
|
branch = rust-servo
|
||||||
[submodule "src/support/egl/rust-egl"]
|
[submodule "src/support/egl/rust-egl"]
|
||||||
path = src/support/egl/rust-egl
|
path = src/support/egl/rust-egl
|
||||||
url = https://github.com/webconvforge/rust-egl.git
|
url = https://github.com/mozilla-servo/rust-egl.git
|
||||||
[submodule "src/platform/android/servo-android-glue"]
|
[submodule "src/platform/android/servo-android-glue"]
|
||||||
path = src/platform/android/servo-android-glue
|
path = src/platform/android/servo-android-glue
|
||||||
url = https://github.com/webconvforge/servo-android-glue.git
|
url = https://github.com/webconvforge/servo-android-glue.git
|
||||||
|
|
2
configure
vendored
2
configure
vendored
|
@ -615,7 +615,7 @@ then
|
||||||
cd ${CFG_BUILD_DIR}src/compiler/rust
|
cd ${CFG_BUILD_DIR}src/compiler/rust
|
||||||
RUST_CONFIGURE_ARGS="--enable-debug"
|
RUST_CONFIGURE_ARGS="--enable-debug"
|
||||||
if [ $CFG_OSTYPE = "linux-androideabi" ]; then
|
if [ $CFG_OSTYPE = "linux-androideabi" ]; then
|
||||||
RUST_CONFIGURE_ARGS="--target-triples=arm-linux-androideabi --android-cross-path=${CFG_ANDROID_CROSS_PATH}"
|
RUST_CONFIGURE_ARGS="--target=arm-linux-androideabi --android-cross-path=${CFG_ANDROID_CROSS_PATH}"
|
||||||
fi
|
fi
|
||||||
${CFG_SRC_DIR}src/compiler/rust/configure ${RUST_CONFIGURE_ARGS}
|
${CFG_SRC_DIR}src/compiler/rust/configure ${RUST_CONFIGURE_ARGS}
|
||||||
cd ${CFG_BUILD_DIR}
|
cd ${CFG_BUILD_DIR}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit f6b236b9d2780edc1336ea5f62c2ba0fed6e34c5
|
Subproject commit d3b3c66a3a54a0455b068ede8fe2f48ed99ca908
|
|
@ -1,4 +1,4 @@
|
||||||
# If this file is modified, then rust will be forcibly cleaned and then rebuilt.
|
# If this file is modified, then rust will be forcibly cleaned and then rebuilt.
|
||||||
# The actual contents of this file do not matter, but to trigger a change on the
|
# The actual contents of this file do not matter, but to trigger a change on the
|
||||||
# build bots then the contents should be changed so git updates the mtime.
|
# build bots then the contents should be changed so git updates the mtime.
|
||||||
2014-01-02
|
2014-01-08
|
||||||
|
|
|
@ -150,14 +150,14 @@ pub struct ClipDisplayItem<E> {
|
||||||
need_clip: bool
|
need_clip: bool
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum DisplayItemIterator<'self,E> {
|
pub enum DisplayItemIterator<'a,E> {
|
||||||
EmptyDisplayItemIterator,
|
EmptyDisplayItemIterator,
|
||||||
ParentDisplayItemIterator(VecIterator<'self,DisplayItem<E>>),
|
ParentDisplayItemIterator(VecIterator<'a,DisplayItem<E>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self,E> Iterator<&'self DisplayItem<E>> for DisplayItemIterator<'self,E> {
|
impl<'a,E> Iterator<&'a DisplayItem<E>> for DisplayItemIterator<'a,E> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn next(&mut self) -> Option<&'self DisplayItem<E>> {
|
fn next(&mut self) -> Option<&'a DisplayItem<E>> {
|
||||||
match *self {
|
match *self {
|
||||||
EmptyDisplayItemIterator => None,
|
EmptyDisplayItemIterator => None,
|
||||||
ParentDisplayItemIterator(ref mut subiterator) => subiterator.next(),
|
ParentDisplayItemIterator(ref mut subiterator) => subiterator.next(),
|
||||||
|
@ -192,12 +192,12 @@ impl<E> DisplayItem<E> {
|
||||||
let text_run = text.text_run.get();
|
let text_run = text.text_run.get();
|
||||||
let font = render_context.font_ctx.get_font_by_descriptor(&text_run.font_descriptor).unwrap();
|
let font = render_context.font_ctx.get_font_by_descriptor(&text_run.font_descriptor).unwrap();
|
||||||
|
|
||||||
let font_metrics = font.with_borrow( |font| {
|
let font_metrics = font.borrow().with(|font| {
|
||||||
font.metrics.clone()
|
font.metrics.clone()
|
||||||
});
|
});
|
||||||
let origin = text.base.bounds.origin;
|
let origin = text.base.bounds.origin;
|
||||||
let baseline_origin = Point2D(origin.x, origin.y + font_metrics.ascent);
|
let baseline_origin = Point2D(origin.x, origin.y + font_metrics.ascent);
|
||||||
font.with_mut_borrow( |font| {
|
font.borrow().with_mut(|font| {
|
||||||
font.draw_text_into_context(render_context,
|
font.draw_text_into_context(render_context,
|
||||||
text.text_run.get(),
|
text.text_run.get(),
|
||||||
&text.range,
|
&text.range,
|
||||||
|
@ -264,10 +264,10 @@ impl<E> DisplayItem<E> {
|
||||||
pub fn children<'a>(&'a self) -> DisplayItemIterator<'a,E> {
|
pub fn children<'a>(&'a self) -> DisplayItemIterator<'a,E> {
|
||||||
match *self {
|
match *self {
|
||||||
ClipDisplayItemClass(ref clip) => ParentDisplayItemIterator(clip.child_list.iter()),
|
ClipDisplayItemClass(ref clip) => ParentDisplayItemIterator(clip.child_list.iter()),
|
||||||
SolidColorDisplayItemClass(*) |
|
SolidColorDisplayItemClass(..) |
|
||||||
TextDisplayItemClass(*) |
|
TextDisplayItemClass(..) |
|
||||||
ImageDisplayItemClass(*) |
|
ImageDisplayItemClass(..) |
|
||||||
BorderDisplayItemClass(*) => EmptyDisplayItemIterator,
|
BorderDisplayItemClass(..) => EmptyDisplayItemIterator,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,13 +10,11 @@ use geom::{Point2D, Rect, Size2D};
|
||||||
use std::cast;
|
use std::cast;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::str;
|
use std::str;
|
||||||
use std::vec;
|
use std::rc::Rc;
|
||||||
use std::rc::RcMut;
|
use std::cell::RefCell;
|
||||||
use servo_util::cache::{Cache, HashCache};
|
use servo_util::cache::{Cache, HashCache};
|
||||||
use servo_util::range::Range;
|
use servo_util::range::Range;
|
||||||
use servo_util::time::ProfilerChan;
|
|
||||||
use style::computed_values::{text_decoration, font_weight, font_style};
|
use style::computed_values::{text_decoration, font_weight, font_style};
|
||||||
|
|
||||||
use color::Color;
|
use color::Color;
|
||||||
use font_context::FontContext;
|
use font_context::FontContext;
|
||||||
use servo_util::geometry::Au;
|
use servo_util::geometry::Au;
|
||||||
|
@ -73,7 +71,7 @@ impl FontTableTagConversions for FontTableTag {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FontTableMethods {
|
pub trait FontTableMethods {
|
||||||
fn with_buffer(&self, &fn(*u8, uint));
|
fn with_buffer(&self, |*u8, uint|);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone)]
|
||||||
|
@ -108,12 +106,6 @@ pub struct FontStyle {
|
||||||
pub type SpecifiedFontStyle = FontStyle;
|
pub type SpecifiedFontStyle = FontStyle;
|
||||||
pub type UsedFontStyle = FontStyle;
|
pub type UsedFontStyle = FontStyle;
|
||||||
|
|
||||||
// FIXME: move me to layout
|
|
||||||
struct ResolvedFont {
|
|
||||||
group: @FontGroup,
|
|
||||||
style: SpecifiedFontStyle,
|
|
||||||
}
|
|
||||||
|
|
||||||
// FontDescriptor serializes a specific font and used font style
|
// FontDescriptor serializes a specific font and used font style
|
||||||
// options, such as point size.
|
// options, such as point size.
|
||||||
|
|
||||||
|
@ -153,11 +145,11 @@ pub struct FontGroup {
|
||||||
// style of the first western font in group, which is
|
// style of the first western font in group, which is
|
||||||
// used for purposes of calculating text run metrics.
|
// used for purposes of calculating text run metrics.
|
||||||
style: UsedFontStyle,
|
style: UsedFontStyle,
|
||||||
fonts: ~[RcMut<Font>]
|
fonts: ~[Rc<RefCell<Font>>]
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FontGroup {
|
impl FontGroup {
|
||||||
pub fn new(families: ~[~str], style: &UsedFontStyle, fonts: ~[RcMut<Font>]) -> FontGroup {
|
pub fn new(families: ~[~str], style: &UsedFontStyle, fonts: ~[Rc<RefCell<Font>>]) -> FontGroup {
|
||||||
FontGroup {
|
FontGroup {
|
||||||
families: families,
|
families: families,
|
||||||
style: (*style).clone(),
|
style: (*style).clone(),
|
||||||
|
@ -173,7 +165,7 @@ impl FontGroup {
|
||||||
assert!(self.fonts.len() > 0);
|
assert!(self.fonts.len() > 0);
|
||||||
|
|
||||||
// TODO(Issue #177): Actually fall back through the FontGroup when a font is unsuitable.
|
// TODO(Issue #177): Actually fall back through the FontGroup when a font is unsuitable.
|
||||||
self.fonts[0].with_mut_borrow(|font| {
|
self.fonts[0].borrow().with_mut(|font| {
|
||||||
TextRun::new(font, text.clone(), decoration)
|
TextRun::new(font, text.clone(), decoration)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -218,18 +210,16 @@ pub struct Font {
|
||||||
style: UsedFontStyle,
|
style: UsedFontStyle,
|
||||||
metrics: FontMetrics,
|
metrics: FontMetrics,
|
||||||
backend: BackendType,
|
backend: BackendType,
|
||||||
profiler_chan: ProfilerChan,
|
|
||||||
shape_cache: HashCache<~str, Arc<GlyphStore>>,
|
shape_cache: HashCache<~str, Arc<GlyphStore>>,
|
||||||
glyph_advance_cache: HashCache<u32, FractionalPixel>,
|
glyph_advance_cache: HashCache<u32, FractionalPixel>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> Font {
|
impl<'a> Font {
|
||||||
pub fn new_from_buffer(ctx: &FontContext,
|
pub fn new_from_buffer(ctx: &FontContext,
|
||||||
buffer: ~[u8],
|
buffer: ~[u8],
|
||||||
style: &SpecifiedFontStyle,
|
style: &SpecifiedFontStyle,
|
||||||
backend: BackendType,
|
backend: BackendType)
|
||||||
profiler_chan: ProfilerChan)
|
-> Result<Rc<RefCell<Font>>, ()> {
|
||||||
-> Result<RcMut<Font>, ()> {
|
|
||||||
let handle = FontHandleMethods::new_from_buffer(&ctx.handle, buffer, style);
|
let handle = FontHandleMethods::new_from_buffer(&ctx.handle, buffer, style);
|
||||||
let handle: FontHandle = if handle.is_ok() {
|
let handle: FontHandle = if handle.is_ok() {
|
||||||
handle.unwrap()
|
handle.unwrap()
|
||||||
|
@ -240,22 +230,21 @@ impl<'self> Font {
|
||||||
let metrics = handle.get_metrics();
|
let metrics = handle.get_metrics();
|
||||||
// TODO(Issue #179): convert between specified and used font style here?
|
// TODO(Issue #179): convert between specified and used font style here?
|
||||||
|
|
||||||
return Ok(RcMut::new(Font {
|
return Ok(Rc::from_mut(RefCell::new(Font {
|
||||||
handle: handle,
|
handle: handle,
|
||||||
azure_font: None,
|
azure_font: None,
|
||||||
shaper: None,
|
shaper: None,
|
||||||
style: (*style).clone(),
|
style: (*style).clone(),
|
||||||
metrics: metrics,
|
metrics: metrics,
|
||||||
backend: backend,
|
backend: backend,
|
||||||
profiler_chan: profiler_chan,
|
|
||||||
shape_cache: HashCache::new(),
|
shape_cache: HashCache::new(),
|
||||||
glyph_advance_cache: HashCache::new(),
|
glyph_advance_cache: HashCache::new(),
|
||||||
}));
|
})));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_from_adopted_handle(_fctx: &FontContext, handle: FontHandle,
|
pub fn new_from_adopted_handle(_fctx: &FontContext, handle: FontHandle,
|
||||||
style: &SpecifiedFontStyle, backend: BackendType,
|
style: &SpecifiedFontStyle, backend: BackendType)
|
||||||
profiler_chan: ProfilerChan) -> Font {
|
-> Font {
|
||||||
let metrics = handle.get_metrics();
|
let metrics = handle.get_metrics();
|
||||||
|
|
||||||
Font {
|
Font {
|
||||||
|
@ -265,15 +254,14 @@ impl<'self> Font {
|
||||||
style: (*style).clone(),
|
style: (*style).clone(),
|
||||||
metrics: metrics,
|
metrics: metrics,
|
||||||
backend: backend,
|
backend: backend,
|
||||||
profiler_chan: profiler_chan,
|
|
||||||
shape_cache: HashCache::new(),
|
shape_cache: HashCache::new(),
|
||||||
glyph_advance_cache: HashCache::new(),
|
glyph_advance_cache: HashCache::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_from_existing_handle(fctx: &FontContext, handle: &FontHandle,
|
pub fn new_from_existing_handle(fctx: &FontContext, handle: &FontHandle,
|
||||||
style: &SpecifiedFontStyle, backend: BackendType,
|
style: &SpecifiedFontStyle, backend: BackendType)
|
||||||
profiler_chan: ProfilerChan) -> Result<RcMut<Font>,()> {
|
-> Result<Rc<RefCell<Font>>,()> {
|
||||||
|
|
||||||
// TODO(Issue #179): convert between specified and used font style here?
|
// TODO(Issue #179): convert between specified and used font style here?
|
||||||
let styled_handle = match handle.clone_with_style(&fctx.handle, style) {
|
let styled_handle = match handle.clone_with_style(&fctx.handle, style) {
|
||||||
|
@ -281,15 +269,15 @@ impl<'self> Font {
|
||||||
Err(()) => return Err(())
|
Err(()) => return Err(())
|
||||||
};
|
};
|
||||||
|
|
||||||
return Ok(RcMut::new(Font::new_from_adopted_handle(fctx, styled_handle, style, backend, profiler_chan)));
|
return Ok(Rc::from_mut(RefCell::new(Font::new_from_adopted_handle(fctx, styled_handle, style, backend))));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_shaper(&'self mut self) -> &'self Shaper {
|
fn make_shaper(&'a mut self) -> &'a Shaper {
|
||||||
// fast path: already created a shaper
|
// fast path: already created a shaper
|
||||||
match self.shaper {
|
match self.shaper {
|
||||||
Some(ref shaper) => {
|
Some(ref shaper) => {
|
||||||
let s: &'self Shaper = shaper;
|
let s: &'a Shaper = shaper;
|
||||||
return s;
|
return s;
|
||||||
},
|
},
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
|
@ -349,7 +337,6 @@ impl<'self> Font {
|
||||||
|
|
||||||
|
|
||||||
impl Font {
|
impl Font {
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn draw_text_into_context(&mut self,
|
pub fn draw_text_into_context(&mut self,
|
||||||
rctx: &RenderContext,
|
rctx: &RenderContext,
|
||||||
run: &~TextRun,
|
run: &~TextRun,
|
||||||
|
@ -399,8 +386,8 @@ impl Font {
|
||||||
if azglyph_buf_len == 0 { return; } // Otherwise the Quartz backend will assert.
|
if azglyph_buf_len == 0 { return; } // Otherwise the Quartz backend will assert.
|
||||||
|
|
||||||
let glyphbuf = struct__AzGlyphBuffer {
|
let glyphbuf = struct__AzGlyphBuffer {
|
||||||
mGlyphs: vec::raw::to_ptr(azglyphs),
|
mGlyphs: azglyphs.as_ptr(),
|
||||||
mNumGlyphs: azglyph_buf_len as uint32_t
|
mNumGlyphs: azglyph_buf_len as uint32_t
|
||||||
};
|
};
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -441,11 +428,11 @@ impl Font {
|
||||||
|
|
||||||
//FIXME (ksh8281)
|
//FIXME (ksh8281)
|
||||||
self.make_shaper();
|
self.make_shaper();
|
||||||
do self.shape_cache.find_or_create(&text) |txt| {
|
self.shape_cache.find_or_create(&text, |txt| {
|
||||||
let mut glyphs = GlyphStore::new(text.char_len(), is_whitespace);
|
let mut glyphs = GlyphStore::new(text.char_len(), is_whitespace);
|
||||||
self.shaper.get_ref().shape_text(*txt, &mut glyphs);
|
self.shaper.get_ref().shape_text(*txt, &mut glyphs);
|
||||||
Arc::new(glyphs)
|
Arc::new(glyphs)
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_descriptor(&self) -> FontDescriptor {
|
pub fn get_descriptor(&self) -> FontDescriptor {
|
||||||
|
@ -457,12 +444,12 @@ impl Font {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn glyph_h_advance(&mut self, glyph: GlyphIndex) -> FractionalPixel {
|
pub fn glyph_h_advance(&mut self, glyph: GlyphIndex) -> FractionalPixel {
|
||||||
do self.glyph_advance_cache.find_or_create(&glyph) |glyph| {
|
self.glyph_advance_cache.find_or_create(&glyph, |glyph| {
|
||||||
match self.handle.glyph_h_advance(*glyph) {
|
match self.handle.glyph_h_advance(*glyph) {
|
||||||
Some(adv) => adv,
|
Some(adv) => adv,
|
||||||
None => /* FIXME: Need fallback strategy */ 10f64 as FractionalPixel
|
None => /* FIXME: Need fallback strategy */ 10f64 as FractionalPixel
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,8 @@ use platform::font_context::FontContextHandle;
|
||||||
use azure::azure_hl::BackendType;
|
use azure::azure_hl::BackendType;
|
||||||
use std::hashmap::HashMap;
|
use std::hashmap::HashMap;
|
||||||
|
|
||||||
use std::rc::RcMut;
|
use std::rc::Rc;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
|
||||||
pub trait FontContextHandleMethods {
|
pub trait FontContextHandleMethods {
|
||||||
|
@ -23,16 +24,16 @@ pub trait FontContextHandleMethods {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FontContext {
|
pub struct FontContext {
|
||||||
instance_cache: LRUCache<FontDescriptor, RcMut<Font>>,
|
instance_cache: LRUCache<FontDescriptor, Rc<RefCell<Font>>>,
|
||||||
font_list: Option<FontList>, // only needed by layout
|
font_list: Option<FontList>, // only needed by layout
|
||||||
group_cache: LRUCache<SpecifiedFontStyle, RcMut<FontGroup>>,
|
group_cache: LRUCache<SpecifiedFontStyle, Rc<RefCell<FontGroup>>>,
|
||||||
handle: FontContextHandle,
|
handle: FontContextHandle,
|
||||||
backend: BackendType,
|
backend: BackendType,
|
||||||
generic_fonts: HashMap<~str,~str>,
|
generic_fonts: HashMap<~str,~str>,
|
||||||
profiler_chan: ProfilerChan,
|
profiler_chan: ProfilerChan,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> FontContext {
|
impl FontContext {
|
||||||
pub fn new(backend: BackendType,
|
pub fn new(backend: BackendType,
|
||||||
needs_font_list: bool,
|
needs_font_list: bool,
|
||||||
profiler_chan: ProfilerChan)
|
profiler_chan: ProfilerChan)
|
||||||
|
@ -61,11 +62,8 @@ impl<'self> FontContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_font_list(&'self self) -> &'self FontList {
|
pub fn get_resolved_font_for_style(&mut self, style: &SpecifiedFontStyle)
|
||||||
self.font_list.get_ref()
|
-> Rc<RefCell<FontGroup>> {
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_resolved_font_for_style(&mut self, style: &SpecifiedFontStyle) -> RcMut<FontGroup> {
|
|
||||||
match self.group_cache.find(style) {
|
match self.group_cache.find(style) {
|
||||||
Some(fg) => {
|
Some(fg) => {
|
||||||
debug!("font group cache hit");
|
debug!("font group cache hit");
|
||||||
|
@ -80,7 +78,8 @@ impl<'self> FontContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_font_by_descriptor(&mut self, desc: &FontDescriptor) -> Result<RcMut<Font>, ()> {
|
pub fn get_font_by_descriptor(&mut self, desc: &FontDescriptor)
|
||||||
|
-> Result<Rc<RefCell<Font>>, ()> {
|
||||||
match self.instance_cache.find(desc) {
|
match self.instance_cache.find(desc) {
|
||||||
Some(f) => {
|
Some(f) => {
|
||||||
debug!("font cache hit");
|
debug!("font cache hit");
|
||||||
|
@ -107,7 +106,7 @@ impl<'self> FontContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_font_group(&mut self, style: &SpecifiedFontStyle) -> RcMut<FontGroup> {
|
fn create_font_group(&mut self, style: &SpecifiedFontStyle) -> Rc<RefCell<FontGroup>> {
|
||||||
let mut fonts = ~[];
|
let mut fonts = ~[];
|
||||||
|
|
||||||
debug!("(create font group) --- starting ---");
|
debug!("(create font group) --- starting ---");
|
||||||
|
@ -140,8 +139,7 @@ impl<'self> FontContext {
|
||||||
Some(ref result) => {
|
Some(ref result) => {
|
||||||
found = true;
|
found = true;
|
||||||
let instance = self.get_font_by_descriptor(result);
|
let instance = self.get_font_by_descriptor(result);
|
||||||
|
instance.map(|font| fonts.push(font.clone()));
|
||||||
for font in instance.iter() { fonts.push(font.clone()); }
|
|
||||||
},
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
@ -179,10 +177,7 @@ impl<'self> FontContext {
|
||||||
match font_desc {
|
match font_desc {
|
||||||
Some(ref fd) => {
|
Some(ref fd) => {
|
||||||
let instance = self.get_font_by_descriptor(fd);
|
let instance = self.get_font_by_descriptor(fd);
|
||||||
|
instance.map(|font| fonts.push(font.clone()));
|
||||||
for font in instance.iter() {
|
|
||||||
fonts.push(font.clone());
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
None => { }
|
None => { }
|
||||||
};
|
};
|
||||||
|
@ -194,22 +189,28 @@ impl<'self> FontContext {
|
||||||
|
|
||||||
debug!("(create font group) --- finished ---");
|
debug!("(create font group) --- finished ---");
|
||||||
|
|
||||||
unsafe { RcMut::new_unchecked(FontGroup::new(style.families.clone(), &used_style, fonts)) }
|
unsafe {
|
||||||
|
Rc::new_unchecked(
|
||||||
|
RefCell::new(
|
||||||
|
FontGroup::new(style.families.to_owned(), &used_style, fonts)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_font_instance(&self, desc: &FontDescriptor) -> Result<RcMut<Font>, ()> {
|
fn create_font_instance(&self, desc: &FontDescriptor) -> Result<Rc<RefCell<Font>>, ()> {
|
||||||
return match &desc.selector {
|
return match &desc.selector {
|
||||||
// TODO(Issue #174): implement by-platform-name font selectors.
|
// TODO(Issue #174): implement by-platform-name font selectors.
|
||||||
&SelectorPlatformIdentifier(ref identifier) => {
|
&SelectorPlatformIdentifier(ref identifier) => {
|
||||||
let result_handle = self.handle.create_font_from_identifier((*identifier).clone(),
|
let result_handle = self.handle.create_font_from_identifier((*identifier).clone(),
|
||||||
desc.style.clone());
|
desc.style.clone());
|
||||||
do result_handle.and_then |handle| {
|
result_handle.and_then(|handle| {
|
||||||
Ok(RcMut::new(Font::new_from_adopted_handle(self,
|
Ok(
|
||||||
handle,
|
Rc::from_mut(
|
||||||
&desc.style,
|
RefCell::new(
|
||||||
self.backend,
|
Font::new_from_adopted_handle(self,
|
||||||
self.profiler_chan.clone())))
|
handle,
|
||||||
}
|
&desc.style,
|
||||||
|
self.backend))))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ pub struct FontList {
|
||||||
prof_chan: ProfilerChan,
|
prof_chan: ProfilerChan,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> FontList {
|
impl FontList {
|
||||||
pub fn new(fctx: &FontContextHandle,
|
pub fn new(fctx: &FontContextHandle,
|
||||||
prof_chan: ProfilerChan)
|
prof_chan: ProfilerChan)
|
||||||
-> FontList {
|
-> FontList {
|
||||||
|
@ -48,20 +48,20 @@ impl<'self> FontList {
|
||||||
// changed. Does OSX have a notification for this event?
|
// changed. Does OSX have a notification for this event?
|
||||||
//
|
//
|
||||||
// Should font families with entries be invalidated/refreshed too?
|
// Should font families with entries be invalidated/refreshed too?
|
||||||
do profile(time::GfxRegenAvailableFontsCategory, self.prof_chan.clone()) {
|
profile(time::GfxRegenAvailableFontsCategory, self.prof_chan.clone(), || {
|
||||||
self.family_map = self.handle.get_available_families();
|
self.family_map = self.handle.get_available_families();
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_font_in_family(&'self mut self,
|
pub fn find_font_in_family<'a>(&'a mut self,
|
||||||
family_name: &~str,
|
family_name: &~str,
|
||||||
style: &SpecifiedFontStyle) -> Option<&'self FontEntry> {
|
style: &SpecifiedFontStyle) -> Option<&'a FontEntry> {
|
||||||
// TODO(Issue #188): look up localized font family names if canonical name not found
|
// TODO(Issue #188): look up localized font family names if canonical name not found
|
||||||
// look up canonical name
|
// look up canonical name
|
||||||
if self.family_map.contains_key(family_name) {
|
if self.family_map.contains_key(family_name) {
|
||||||
//FIXME call twice!(ksh8281)
|
//FIXME call twice!(ksh8281)
|
||||||
debug!("FontList: Found font family with name={:s}", family_name.to_str());
|
debug!("FontList: Found font family with name={:s}", family_name.to_str());
|
||||||
let s: &'self mut FontFamily = self.family_map.get_mut(family_name);
|
let s: &'a mut FontFamily = self.family_map.get_mut(family_name);
|
||||||
// TODO(Issue #192: handle generic font families, like 'serif' and 'sans-serif'.
|
// TODO(Issue #192: handle generic font families, like 'serif' and 'sans-serif'.
|
||||||
// if such family exists, try to match style to a font
|
// if such family exists, try to match style to a font
|
||||||
let result = s.find_font_for_style(&mut self.handle, style);
|
let result = s.find_font_for_style(&mut self.handle, style);
|
||||||
|
@ -82,13 +82,13 @@ impl<'self> FontList {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Holds a specific font family, and the various
|
// Holds a specific font family, and the various
|
||||||
pub struct FontFamily<'self> {
|
pub struct FontFamily {
|
||||||
family_name: ~str,
|
family_name: ~str,
|
||||||
entries: ~[FontEntry],
|
entries: ~[FontEntry],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> FontFamily {
|
impl FontFamily {
|
||||||
pub fn new(family_name: &str) -> FontFamily {
|
pub fn new(family_name: &str) -> FontFamily {
|
||||||
FontFamily {
|
FontFamily {
|
||||||
family_name: family_name.to_str(),
|
family_name: family_name.to_str(),
|
||||||
|
@ -104,8 +104,8 @@ impl<'self> FontFamily {
|
||||||
assert!(self.entries.len() > 0)
|
assert!(self.entries.len() > 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_font_for_style(&'self mut self, list: &FontListHandle, style: &SpecifiedFontStyle)
|
pub fn find_font_for_style<'a>(&'a mut self, list: &FontListHandle, style: &SpecifiedFontStyle)
|
||||||
-> Option<&'self FontEntry> {
|
-> Option<&'a FontEntry> {
|
||||||
self.load_family_variations(list);
|
self.load_family_variations(list);
|
||||||
|
|
||||||
// TODO(Issue #189): optimize lookup for
|
// TODO(Issue #189): optimize lookup for
|
||||||
|
|
|
@ -2,10 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#[link(name = "gfx",
|
#[crate_id = "github.com/mozilla/servo#gfx:0.1"];
|
||||||
vers = "0.1",
|
|
||||||
uuid = "0106bb54-6ea9-45bf-a39e-a738621f15e5",
|
|
||||||
url = "http://servo.org/")];
|
|
||||||
#[crate_type = "lib"];
|
#[crate_type = "lib"];
|
||||||
|
|
||||||
#[feature(globs, managed_boxes, macro_rules)];
|
#[feature(globs, managed_boxes, macro_rules)];
|
||||||
|
@ -16,10 +13,10 @@ extern mod geom;
|
||||||
extern mod layers;
|
extern mod layers;
|
||||||
extern mod stb_image;
|
extern mod stb_image;
|
||||||
extern mod png;
|
extern mod png;
|
||||||
extern mod servo_net (name = "net");
|
extern mod servo_net = "net";
|
||||||
extern mod servo_util (name = "util");
|
extern mod servo_util = "util";
|
||||||
extern mod style;
|
extern mod style;
|
||||||
extern mod servo_msg (name = "msg");
|
extern mod servo_msg = "msg";
|
||||||
|
|
||||||
// Eventually we would like the shaper to be pluggable, as many operating systems have their own
|
// Eventually we would like the shaper to be pluggable, as many operating systems have their own
|
||||||
// shapers. For now, however, this is a hard dependency.
|
// shapers. For now, however, this is a hard dependency.
|
||||||
|
|
|
@ -113,9 +113,9 @@ pub fn from_cmdline_args(args: &[~str]) -> Opts {
|
||||||
};
|
};
|
||||||
|
|
||||||
// if only flag is present, default to 5 second period
|
// if only flag is present, default to 5 second period
|
||||||
let profiler_period = do opt_match.opt_default("p", "5").map |period| {
|
let profiler_period = opt_match.opt_default("p", "5").map(|period| {
|
||||||
from_str(period).unwrap()
|
from_str(period).unwrap()
|
||||||
};
|
});
|
||||||
|
|
||||||
let cpu_painting = opt_match.opt_present("c");
|
let cpu_painting = opt_match.opt_present("c");
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ pub struct FontTable {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FontTableMethods for FontTable {
|
impl FontTableMethods for FontTable {
|
||||||
fn with_buffer(&self, _blk: &fn(*u8, uint)) {
|
fn with_buffer(&self, _blk: |*u8, uint|) {
|
||||||
fail!()
|
fail!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,6 @@ pub struct FontHandle {
|
||||||
|
|
||||||
#[unsafe_destructor]
|
#[unsafe_destructor]
|
||||||
impl Drop for FontHandle {
|
impl Drop for FontHandle {
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
assert!(self.face.is_not_null());
|
assert!(self.face.is_not_null());
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -80,9 +79,7 @@ impl FontHandleMethods for FontHandle {
|
||||||
let ft_ctx: FT_Library = fctx.ctx.borrow().ctx;
|
let ft_ctx: FT_Library = fctx.ctx.borrow().ctx;
|
||||||
if ft_ctx.is_null() { return Err(()); }
|
if ft_ctx.is_null() { return Err(()); }
|
||||||
|
|
||||||
let face_result = do buf.as_imm_buf |bytes: *u8, len: uint| {
|
let face_result = create_face_from_buffer(ft_ctx, buf.as_ptr(), buf.len(), style.pt_size);
|
||||||
create_face_from_buffer(ft_ctx, bytes, len, style.pt_size)
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: this could be more simply written as result::chain
|
// TODO: this could be more simply written as result::chain
|
||||||
// and moving buf into the struct ctor, but cant' move out of
|
// and moving buf into the struct ctor, but cant' move out of
|
||||||
|
@ -99,7 +96,6 @@ impl FontHandleMethods for FontHandle {
|
||||||
Err(()) => Err(())
|
Err(()) => Err(())
|
||||||
};
|
};
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn create_face_from_buffer(lib: FT_Library, cbuf: *u8, cbuflen: uint, pt_size: f64)
|
fn create_face_from_buffer(lib: FT_Library, cbuf: *u8, cbuflen: uint, pt_size: f64)
|
||||||
-> Result<FT_Face, ()> {
|
-> Result<FT_Face, ()> {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -129,14 +125,12 @@ impl FontHandleMethods for FontHandle {
|
||||||
fn family_name(&self) -> ~str {
|
fn family_name(&self) -> ~str {
|
||||||
unsafe { str::raw::from_c_str((*self.face).family_name) }
|
unsafe { str::raw::from_c_str((*self.face).family_name) }
|
||||||
}
|
}
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn face_name(&self) -> ~str {
|
fn face_name(&self) -> ~str {
|
||||||
unsafe { str::raw::from_c_str(FT_Get_Postscript_Name(self.face)) }
|
unsafe { str::raw::from_c_str(FT_Get_Postscript_Name(self.face)) }
|
||||||
}
|
}
|
||||||
fn is_italic(&self) -> bool {
|
fn is_italic(&self) -> bool {
|
||||||
unsafe { (*self.face).style_flags & FT_STYLE_FLAG_ITALIC != 0 }
|
unsafe { (*self.face).style_flags & FT_STYLE_FLAG_ITALIC != 0 }
|
||||||
}
|
}
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn boldness(&self) -> font_weight::T {
|
fn boldness(&self) -> font_weight::T {
|
||||||
let default_weight = font_weight::Weight400;
|
let default_weight = font_weight::Weight400;
|
||||||
if unsafe { (*self.face).style_flags & FT_STYLE_FLAG_BOLD == 0 } {
|
if unsafe { (*self.face).style_flags & FT_STYLE_FLAG_BOLD == 0 } {
|
||||||
|
@ -179,7 +173,6 @@ impl FontHandleMethods for FontHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn glyph_index(&self,
|
fn glyph_index(&self,
|
||||||
codepoint: char) -> Option<GlyphIndex> {
|
codepoint: char) -> Option<GlyphIndex> {
|
||||||
assert!(self.face.is_not_null());
|
assert!(self.face.is_not_null());
|
||||||
|
@ -194,7 +187,6 @@ impl FontHandleMethods for FontHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn glyph_h_advance(&self,
|
fn glyph_h_advance(&self,
|
||||||
glyph: GlyphIndex) -> Option<FractionalPixel> {
|
glyph: GlyphIndex) -> Option<FractionalPixel> {
|
||||||
assert!(self.face.is_not_null());
|
assert!(self.face.is_not_null());
|
||||||
|
@ -216,7 +208,6 @@ impl FontHandleMethods for FontHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn get_metrics(&self) -> FontMetrics {
|
fn get_metrics(&self) -> FontMetrics {
|
||||||
/* TODO(Issue #76): complete me */
|
/* TODO(Issue #76): complete me */
|
||||||
let face = self.get_face_rec();
|
let face = self.get_face_rec();
|
||||||
|
@ -272,8 +263,7 @@ impl FontHandleMethods for FontHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> FontHandle {
|
impl<'a> FontHandle {
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn set_char_size(face: FT_Face, pt_size: f64) -> Result<(), ()>{
|
fn set_char_size(face: FT_Face, pt_size: f64) -> Result<(), ()>{
|
||||||
let char_width = float_to_fixed_ft(pt_size) as FT_F26Dot6;
|
let char_width = float_to_fixed_ft(pt_size) as FT_F26Dot6;
|
||||||
let char_height = float_to_fixed_ft(pt_size) as FT_F26Dot6;
|
let char_height = float_to_fixed_ft(pt_size) as FT_F26Dot6;
|
||||||
|
@ -286,7 +276,6 @@ impl<'self> FontHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn new_from_file(fctx: &FontContextHandle, file: &str,
|
pub fn new_from_file(fctx: &FontContextHandle, file: &str,
|
||||||
style: &SpecifiedFontStyle) -> Result<FontHandle, ()> {
|
style: &SpecifiedFontStyle) -> Result<FontHandle, ()> {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -295,10 +284,10 @@ impl<'self> FontHandle {
|
||||||
|
|
||||||
let mut face: FT_Face = ptr::null();
|
let mut face: FT_Face = ptr::null();
|
||||||
let face_index = 0 as FT_Long;
|
let face_index = 0 as FT_Long;
|
||||||
do file.to_c_str().with_ref |file_str| {
|
file.to_c_str().with_ref(|file_str| {
|
||||||
FT_New_Face(ft_ctx, file_str,
|
FT_New_Face(ft_ctx, file_str,
|
||||||
face_index, ptr::to_mut_unsafe_ptr(&mut face));
|
face_index, ptr::to_mut_unsafe_ptr(&mut face));
|
||||||
}
|
});
|
||||||
if face.is_null() {
|
if face.is_null() {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
|
@ -314,7 +303,6 @@ impl<'self> FontHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn new_from_file_unstyled(fctx: &FontContextHandle, file: ~str)
|
pub fn new_from_file_unstyled(fctx: &FontContextHandle, file: ~str)
|
||||||
-> Result<FontHandle, ()> {
|
-> Result<FontHandle, ()> {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -323,10 +311,10 @@ impl<'self> FontHandle {
|
||||||
|
|
||||||
let mut face: FT_Face = ptr::null();
|
let mut face: FT_Face = ptr::null();
|
||||||
let face_index = 0 as FT_Long;
|
let face_index = 0 as FT_Long;
|
||||||
do file.to_c_str().with_ref |file_str| {
|
file.to_c_str().with_ref(|file_str| {
|
||||||
FT_New_Face(ft_ctx, file_str,
|
FT_New_Face(ft_ctx, file_str,
|
||||||
face_index, ptr::to_mut_unsafe_ptr(&mut face));
|
face_index, ptr::to_mut_unsafe_ptr(&mut face));
|
||||||
}
|
});
|
||||||
if face.is_null() {
|
if face.is_null() {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
|
@ -339,7 +327,7 @@ impl<'self> FontHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_face_rec(&'self self) -> &'self FT_FaceRec {
|
fn get_face_rec(&'a self) -> &'a FT_FaceRec {
|
||||||
unsafe {
|
unsafe {
|
||||||
&(*self.face)
|
&(*self.face)
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,6 @@ pub struct FontContextHandle {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for FreeTypeLibraryHandle {
|
impl Drop for FreeTypeLibraryHandle {
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
assert!(self.ctx.is_not_null());
|
assert!(self.ctx.is_not_null());
|
||||||
unsafe { FT_Done_FreeType(self.ctx) };
|
unsafe { FT_Done_FreeType(self.ctx) };
|
||||||
|
@ -32,7 +31,6 @@ impl Drop for FreeTypeLibraryHandle {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FontContextHandle {
|
impl FontContextHandle {
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn new() -> FontContextHandle {
|
pub fn new() -> FontContextHandle {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ctx: FT_Library = ptr::null();
|
let ctx: FT_Library = ptr::null();
|
||||||
|
@ -49,10 +47,10 @@ impl FontContextHandleMethods for FontContextHandle {
|
||||||
fn create_font_from_identifier(&self, name: ~str, style: UsedFontStyle)
|
fn create_font_from_identifier(&self, name: ~str, style: UsedFontStyle)
|
||||||
-> Result<FontHandle, ()> {
|
-> Result<FontHandle, ()> {
|
||||||
debug!("Creating font handle for {:s}", name);
|
debug!("Creating font handle for {:s}", name);
|
||||||
do path_from_identifier(name, &style).and_then |file_name| {
|
path_from_identifier(name, &style).and_then(|file_name| {
|
||||||
debug!("Opening font face {:s}", file_name);
|
debug!("Opening font face {:s}", file_name);
|
||||||
FontHandle::new_from_file(self, file_name.to_owned(), &style)
|
FontHandle::new_from_file(self, file_name.to_owned(), &style)
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,6 @@ impl FontListHandle {
|
||||||
FontListHandle { fctx: fctx.clone() }
|
FontListHandle { fctx: fctx.clone() }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn get_available_families(&self) -> FontFamilyMap {
|
pub fn get_available_families(&self) -> FontFamilyMap {
|
||||||
let mut family_map : FontFamilyMap = HashMap::new();
|
let mut family_map : FontFamilyMap = HashMap::new();
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -50,7 +49,7 @@ impl FontListHandle {
|
||||||
let font = (*fontSet).fonts.offset(i);
|
let font = (*fontSet).fonts.offset(i);
|
||||||
let family: *FcChar8 = ptr::null();
|
let family: *FcChar8 = ptr::null();
|
||||||
let mut v: c_int = 0;
|
let mut v: c_int = 0;
|
||||||
do "family".to_c_str().with_ref |FC_FAMILY| {
|
"family".to_c_str().with_ref(|FC_FAMILY| {
|
||||||
while FcPatternGetString(*font, FC_FAMILY, v, &family) == FcResultMatch {
|
while FcPatternGetString(*font, FC_FAMILY, v, &family) == FcResultMatch {
|
||||||
let family_name = str::raw::from_c_str(family as *c_char);
|
let family_name = str::raw::from_c_str(family as *c_char);
|
||||||
debug!("Creating new FontFamily for family: {:s}", family_name);
|
debug!("Creating new FontFamily for family: {:s}", family_name);
|
||||||
|
@ -58,13 +57,12 @@ impl FontListHandle {
|
||||||
family_map.insert(family_name, new_family);
|
family_map.insert(family_name, new_family);
|
||||||
v += 1;
|
v += 1;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return family_map;
|
return family_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn load_variations_for_family(&self, family: &mut FontFamily) {
|
pub fn load_variations_for_family(&self, family: &mut FontFamily) {
|
||||||
debug!("getting variations for {:?}", family);
|
debug!("getting variations for {:?}", family);
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -73,22 +71,22 @@ impl FontListHandle {
|
||||||
let font_set_array_ptr = ptr::to_unsafe_ptr(&font_set);
|
let font_set_array_ptr = ptr::to_unsafe_ptr(&font_set);
|
||||||
let pattern = FcPatternCreate();
|
let pattern = FcPatternCreate();
|
||||||
assert!(pattern.is_not_null());
|
assert!(pattern.is_not_null());
|
||||||
do "family".to_c_str().with_ref |FC_FAMILY| {
|
"family".to_c_str().with_ref(|FC_FAMILY| {
|
||||||
do family.family_name.to_c_str().with_ref |family_name| {
|
family.family_name.to_c_str().with_ref(|family_name| {
|
||||||
let ok = FcPatternAddString(pattern, FC_FAMILY, family_name as *FcChar8);
|
let ok = FcPatternAddString(pattern, FC_FAMILY, family_name as *FcChar8);
|
||||||
assert!(ok != 0);
|
assert!(ok != 0);
|
||||||
}
|
});
|
||||||
}
|
});
|
||||||
|
|
||||||
let object_set = FcObjectSetCreate();
|
let object_set = FcObjectSetCreate();
|
||||||
assert!(object_set.is_not_null());
|
assert!(object_set.is_not_null());
|
||||||
|
|
||||||
do "file".to_c_str().with_ref |FC_FILE| {
|
"file".to_c_str().with_ref(|FC_FILE| {
|
||||||
FcObjectSetAdd(object_set, FC_FILE);
|
FcObjectSetAdd(object_set, FC_FILE);
|
||||||
}
|
});
|
||||||
do "index".to_c_str().with_ref |FC_INDEX| {
|
"index".to_c_str().with_ref(|FC_INDEX| {
|
||||||
FcObjectSetAdd(object_set, FC_INDEX);
|
FcObjectSetAdd(object_set, FC_INDEX);
|
||||||
}
|
});
|
||||||
|
|
||||||
let matches = FcFontSetList(config, font_set_array_ptr, 1, pattern, object_set);
|
let matches = FcFontSetList(config, font_set_array_ptr, 1, pattern, object_set);
|
||||||
|
|
||||||
|
@ -96,22 +94,22 @@ impl FontListHandle {
|
||||||
|
|
||||||
for i in range(0, (*matches).nfont as int) {
|
for i in range(0, (*matches).nfont as int) {
|
||||||
let font = (*matches).fonts.offset(i);
|
let font = (*matches).fonts.offset(i);
|
||||||
let file = do "file".to_c_str().with_ref |FC_FILE| {
|
let file = "file".to_c_str().with_ref(|FC_FILE| {
|
||||||
let file: *FcChar8 = ptr::null();
|
let file: *FcChar8 = ptr::null();
|
||||||
if FcPatternGetString(*font, FC_FILE, 0, &file) == FcResultMatch {
|
if FcPatternGetString(*font, FC_FILE, 0, &file) == FcResultMatch {
|
||||||
str::raw::from_c_str(file as *libc::c_char)
|
str::raw::from_c_str(file as *libc::c_char)
|
||||||
} else {
|
} else {
|
||||||
fail!();
|
fail!();
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
let index = do "index".to_c_str().with_ref |FC_INDEX| {
|
let index = "index".to_c_str().with_ref(|FC_INDEX| {
|
||||||
let index: libc::c_int = 0;
|
let index: libc::c_int = 0;
|
||||||
if FcPatternGetInteger(*font, FC_INDEX, 0, &index) == FcResultMatch {
|
if FcPatternGetInteger(*font, FC_INDEX, 0, &index) == FcResultMatch {
|
||||||
index
|
index
|
||||||
} else {
|
} else {
|
||||||
fail!();
|
fail!();
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
debug!("variation file: {}", file);
|
debug!("variation file: {}", file);
|
||||||
debug!("variation index: {}", index);
|
debug!("variation index: {}", index);
|
||||||
|
@ -141,7 +139,6 @@ struct AutoPattern {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for AutoPattern {
|
impl Drop for AutoPattern {
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
FcPatternDestroy(self.pattern);
|
FcPatternDestroy(self.pattern);
|
||||||
|
@ -149,17 +146,16 @@ impl Drop for AutoPattern {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn path_from_identifier(name: ~str, style: &UsedFontStyle) -> Result<~str, ()> {
|
pub fn path_from_identifier(name: ~str, style: &UsedFontStyle) -> Result<~str, ()> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let config = FcConfigGetCurrent();
|
let config = FcConfigGetCurrent();
|
||||||
let wrapper = AutoPattern { pattern: FcPatternCreate() };
|
let wrapper = AutoPattern { pattern: FcPatternCreate() };
|
||||||
let pattern = wrapper.pattern;
|
let pattern = wrapper.pattern;
|
||||||
let res = do "family".to_c_str().with_ref |FC_FAMILY| {
|
let res = "family".to_c_str().with_ref(|FC_FAMILY| {
|
||||||
do name.to_c_str().with_ref |family| {
|
name.to_c_str().with_ref(|family| {
|
||||||
FcPatternAddString(pattern, FC_FAMILY, family as *FcChar8)
|
FcPatternAddString(pattern, FC_FAMILY, family as *FcChar8)
|
||||||
}
|
})
|
||||||
};
|
});
|
||||||
if res != 1 {
|
if res != 1 {
|
||||||
debug!("adding family to pattern failed");
|
debug!("adding family to pattern failed");
|
||||||
return Err(());
|
return Err(());
|
||||||
|
@ -168,18 +164,18 @@ pub fn path_from_identifier(name: ~str, style: &UsedFontStyle) -> Result<~str, (
|
||||||
match style.style {
|
match style.style {
|
||||||
font_style::normal => (),
|
font_style::normal => (),
|
||||||
font_style::italic => {
|
font_style::italic => {
|
||||||
let res = do "slant".to_c_str().with_ref |FC_SLANT| {
|
let res = "slant".to_c_str().with_ref(|FC_SLANT| {
|
||||||
FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC)
|
FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC)
|
||||||
};
|
});
|
||||||
if res != 1 {
|
if res != 1 {
|
||||||
debug!("adding slant to pattern failed");
|
debug!("adding slant to pattern failed");
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
font_style::oblique => {
|
font_style::oblique => {
|
||||||
let res = do "slant".to_c_str().with_ref |FC_SLANT| {
|
let res = "slant".to_c_str().with_ref(|FC_SLANT| {
|
||||||
FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_OBLIQUE)
|
FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_OBLIQUE)
|
||||||
};
|
});
|
||||||
if res != 1 {
|
if res != 1 {
|
||||||
debug!("adding slant(oblique) to pattern failed");
|
debug!("adding slant(oblique) to pattern failed");
|
||||||
return Err(());
|
return Err(());
|
||||||
|
@ -188,9 +184,9 @@ pub fn path_from_identifier(name: ~str, style: &UsedFontStyle) -> Result<~str, (
|
||||||
}
|
}
|
||||||
|
|
||||||
if style.weight.is_bold() {
|
if style.weight.is_bold() {
|
||||||
let res = do "weight".to_c_str().with_ref |FC_WEIGHT| {
|
let res = "weight".to_c_str().with_ref(|FC_WEIGHT| {
|
||||||
FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD)
|
FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD)
|
||||||
};
|
});
|
||||||
if res != 1 {
|
if res != 1 {
|
||||||
debug!("adding weight to pattern failed");
|
debug!("adding weight to pattern failed");
|
||||||
return Err(());
|
return Err(());
|
||||||
|
@ -211,9 +207,9 @@ pub fn path_from_identifier(name: ~str, style: &UsedFontStyle) -> Result<~str, (
|
||||||
}
|
}
|
||||||
|
|
||||||
let file: *FcChar8 = ptr::null();
|
let file: *FcChar8 = ptr::null();
|
||||||
let res = do "file".to_c_str().with_ref |FC_FILE| {
|
let res = "file".to_c_str().with_ref(|FC_FILE| {
|
||||||
FcPatternGetString(result_pattern, FC_FILE, 0, &file)
|
FcPatternGetString(result_pattern, FC_FILE, 0, &file)
|
||||||
};
|
});
|
||||||
if res != FcResultMatch {
|
if res != FcResultMatch {
|
||||||
debug!("getting filename for font failed");
|
debug!("getting filename for font failed");
|
||||||
return Err(());
|
return Err(());
|
||||||
|
|
|
@ -41,7 +41,7 @@ pub struct FontTable {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FontTableMethods for FontTable {
|
impl FontTableMethods for FontTable {
|
||||||
fn with_buffer(&self, _blk: &fn(*u8, uint)) {
|
fn with_buffer(&self, _blk: |*u8, uint|) {
|
||||||
fail!()
|
fail!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,6 @@ pub struct FontHandle {
|
||||||
|
|
||||||
#[unsafe_destructor]
|
#[unsafe_destructor]
|
||||||
impl Drop for FontHandle {
|
impl Drop for FontHandle {
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
assert!(self.face.is_not_null());
|
assert!(self.face.is_not_null());
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -80,9 +79,7 @@ impl FontHandleMethods for FontHandle {
|
||||||
let ft_ctx: FT_Library = fctx.ctx.borrow().ctx;
|
let ft_ctx: FT_Library = fctx.ctx.borrow().ctx;
|
||||||
if ft_ctx.is_null() { return Err(()); }
|
if ft_ctx.is_null() { return Err(()); }
|
||||||
|
|
||||||
let face_result = do buf.as_imm_buf |bytes: *u8, len: uint| {
|
let face_result = create_face_from_buffer(ft_ctx, buf.as_ptr(), buf.len(), style.pt_size);
|
||||||
create_face_from_buffer(ft_ctx, bytes, len, style.pt_size)
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: this could be more simply written as result::chain
|
// TODO: this could be more simply written as result::chain
|
||||||
// and moving buf into the struct ctor, but cant' move out of
|
// and moving buf into the struct ctor, but cant' move out of
|
||||||
|
@ -99,7 +96,6 @@ impl FontHandleMethods for FontHandle {
|
||||||
Err(()) => Err(())
|
Err(()) => Err(())
|
||||||
};
|
};
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn create_face_from_buffer(lib: FT_Library, cbuf: *u8, cbuflen: uint, pt_size: f64)
|
fn create_face_from_buffer(lib: FT_Library, cbuf: *u8, cbuflen: uint, pt_size: f64)
|
||||||
-> Result<FT_Face, ()> {
|
-> Result<FT_Face, ()> {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -129,14 +125,12 @@ impl FontHandleMethods for FontHandle {
|
||||||
fn family_name(&self) -> ~str {
|
fn family_name(&self) -> ~str {
|
||||||
unsafe { str::raw::from_c_str((*self.face).family_name) }
|
unsafe { str::raw::from_c_str((*self.face).family_name) }
|
||||||
}
|
}
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn face_name(&self) -> ~str {
|
fn face_name(&self) -> ~str {
|
||||||
unsafe { str::raw::from_c_str(FT_Get_Postscript_Name(self.face)) }
|
unsafe { str::raw::from_c_str(FT_Get_Postscript_Name(self.face)) }
|
||||||
}
|
}
|
||||||
fn is_italic(&self) -> bool {
|
fn is_italic(&self) -> bool {
|
||||||
unsafe { (*self.face).style_flags & FT_STYLE_FLAG_ITALIC != 0 }
|
unsafe { (*self.face).style_flags & FT_STYLE_FLAG_ITALIC != 0 }
|
||||||
}
|
}
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn boldness(&self) -> font_weight::T {
|
fn boldness(&self) -> font_weight::T {
|
||||||
let default_weight = font_weight::Weight400;
|
let default_weight = font_weight::Weight400;
|
||||||
if unsafe { (*self.face).style_flags & FT_STYLE_FLAG_BOLD == 0 } {
|
if unsafe { (*self.face).style_flags & FT_STYLE_FLAG_BOLD == 0 } {
|
||||||
|
@ -179,7 +173,6 @@ impl FontHandleMethods for FontHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn glyph_index(&self,
|
fn glyph_index(&self,
|
||||||
codepoint: char) -> Option<GlyphIndex> {
|
codepoint: char) -> Option<GlyphIndex> {
|
||||||
assert!(self.face.is_not_null());
|
assert!(self.face.is_not_null());
|
||||||
|
@ -194,7 +187,6 @@ impl FontHandleMethods for FontHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn glyph_h_advance(&self,
|
fn glyph_h_advance(&self,
|
||||||
glyph: GlyphIndex) -> Option<FractionalPixel> {
|
glyph: GlyphIndex) -> Option<FractionalPixel> {
|
||||||
assert!(self.face.is_not_null());
|
assert!(self.face.is_not_null());
|
||||||
|
@ -216,7 +208,6 @@ impl FontHandleMethods for FontHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn get_metrics(&self) -> FontMetrics {
|
fn get_metrics(&self) -> FontMetrics {
|
||||||
/* TODO(Issue #76): complete me */
|
/* TODO(Issue #76): complete me */
|
||||||
let face = self.get_face_rec();
|
let face = self.get_face_rec();
|
||||||
|
@ -272,8 +263,7 @@ impl FontHandleMethods for FontHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> FontHandle {
|
impl<'a> FontHandle {
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn set_char_size(face: FT_Face, pt_size: f64) -> Result<(), ()>{
|
fn set_char_size(face: FT_Face, pt_size: f64) -> Result<(), ()>{
|
||||||
let char_width = float_to_fixed_ft(pt_size) as FT_F26Dot6;
|
let char_width = float_to_fixed_ft(pt_size) as FT_F26Dot6;
|
||||||
let char_height = float_to_fixed_ft(pt_size) as FT_F26Dot6;
|
let char_height = float_to_fixed_ft(pt_size) as FT_F26Dot6;
|
||||||
|
@ -286,7 +276,6 @@ impl<'self> FontHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn new_from_file(fctx: &FontContextHandle, file: &str,
|
pub fn new_from_file(fctx: &FontContextHandle, file: &str,
|
||||||
style: &SpecifiedFontStyle) -> Result<FontHandle, ()> {
|
style: &SpecifiedFontStyle) -> Result<FontHandle, ()> {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -295,10 +284,10 @@ impl<'self> FontHandle {
|
||||||
|
|
||||||
let mut face: FT_Face = ptr::null();
|
let mut face: FT_Face = ptr::null();
|
||||||
let face_index = 0 as FT_Long;
|
let face_index = 0 as FT_Long;
|
||||||
do file.to_c_str().with_ref |file_str| {
|
file.to_c_str().with_ref(|file_str| {
|
||||||
FT_New_Face(ft_ctx, file_str,
|
FT_New_Face(ft_ctx, file_str,
|
||||||
face_index, ptr::to_mut_unsafe_ptr(&mut face));
|
face_index, ptr::to_mut_unsafe_ptr(&mut face));
|
||||||
}
|
});
|
||||||
if face.is_null() {
|
if face.is_null() {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
|
@ -314,7 +303,6 @@ impl<'self> FontHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn new_from_file_unstyled(fctx: &FontContextHandle, file: ~str)
|
pub fn new_from_file_unstyled(fctx: &FontContextHandle, file: ~str)
|
||||||
-> Result<FontHandle, ()> {
|
-> Result<FontHandle, ()> {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -323,10 +311,10 @@ impl<'self> FontHandle {
|
||||||
|
|
||||||
let mut face: FT_Face = ptr::null();
|
let mut face: FT_Face = ptr::null();
|
||||||
let face_index = 0 as FT_Long;
|
let face_index = 0 as FT_Long;
|
||||||
do file.to_c_str().with_ref |file_str| {
|
file.to_c_str().with_ref(|file_str| {
|
||||||
FT_New_Face(ft_ctx, file_str,
|
FT_New_Face(ft_ctx, file_str,
|
||||||
face_index, ptr::to_mut_unsafe_ptr(&mut face));
|
face_index, ptr::to_mut_unsafe_ptr(&mut face));
|
||||||
}
|
});
|
||||||
if face.is_null() {
|
if face.is_null() {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
|
@ -339,7 +327,7 @@ impl<'self> FontHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_face_rec(&'self self) -> &'self FT_FaceRec {
|
fn get_face_rec(&'a self) -> &'a FT_FaceRec {
|
||||||
unsafe {
|
unsafe {
|
||||||
&(*self.face)
|
&(*self.face)
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,6 @@ pub struct FontContextHandle {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for FreeTypeLibraryHandle {
|
impl Drop for FreeTypeLibraryHandle {
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
assert!(self.ctx.is_not_null());
|
assert!(self.ctx.is_not_null());
|
||||||
unsafe { FT_Done_FreeType(self.ctx) };
|
unsafe { FT_Done_FreeType(self.ctx) };
|
||||||
|
@ -32,7 +31,6 @@ impl Drop for FreeTypeLibraryHandle {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FontContextHandle {
|
impl FontContextHandle {
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn new() -> FontContextHandle {
|
pub fn new() -> FontContextHandle {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ctx: FT_Library = ptr::null();
|
let ctx: FT_Library = ptr::null();
|
||||||
|
@ -49,10 +47,10 @@ impl FontContextHandleMethods for FontContextHandle {
|
||||||
fn create_font_from_identifier(&self, name: ~str, style: UsedFontStyle)
|
fn create_font_from_identifier(&self, name: ~str, style: UsedFontStyle)
|
||||||
-> Result<FontHandle, ()> {
|
-> Result<FontHandle, ()> {
|
||||||
debug!("Creating font handle for {:s}", name);
|
debug!("Creating font handle for {:s}", name);
|
||||||
do path_from_identifier(name, &style).and_then |file_name| {
|
path_from_identifier(name, &style).and_then(|file_name| {
|
||||||
debug!("Opening font face {:s}", file_name);
|
debug!("Opening font face {:s}", file_name);
|
||||||
FontHandle::new_from_file(self, file_name.to_owned(), &style)
|
FontHandle::new_from_file(self, file_name.to_owned(), &style)
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,6 @@ impl FontListHandle {
|
||||||
FontListHandle { fctx: fctx.clone() }
|
FontListHandle { fctx: fctx.clone() }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn get_available_families(&self) -> FontFamilyMap {
|
pub fn get_available_families(&self) -> FontFamilyMap {
|
||||||
let mut family_map : FontFamilyMap = HashMap::new();
|
let mut family_map : FontFamilyMap = HashMap::new();
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -50,7 +49,7 @@ impl FontListHandle {
|
||||||
let font = (*fontSet).fonts.offset(i);
|
let font = (*fontSet).fonts.offset(i);
|
||||||
let family: *FcChar8 = ptr::null();
|
let family: *FcChar8 = ptr::null();
|
||||||
let mut v: c_int = 0;
|
let mut v: c_int = 0;
|
||||||
do "family".to_c_str().with_ref |FC_FAMILY| {
|
"family".to_c_str().with_ref(|FC_FAMILY| {
|
||||||
while FcPatternGetString(*font, FC_FAMILY, v, &family) == FcResultMatch {
|
while FcPatternGetString(*font, FC_FAMILY, v, &family) == FcResultMatch {
|
||||||
let family_name = str::raw::from_c_str(family as *c_char);
|
let family_name = str::raw::from_c_str(family as *c_char);
|
||||||
debug!("Creating new FontFamily for family: {:s}", family_name);
|
debug!("Creating new FontFamily for family: {:s}", family_name);
|
||||||
|
@ -58,13 +57,12 @@ impl FontListHandle {
|
||||||
family_map.insert(family_name, new_family);
|
family_map.insert(family_name, new_family);
|
||||||
v += 1;
|
v += 1;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return family_map;
|
return family_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn load_variations_for_family(&self, family: &mut FontFamily) {
|
pub fn load_variations_for_family(&self, family: &mut FontFamily) {
|
||||||
debug!("getting variations for {:?}", family);
|
debug!("getting variations for {:?}", family);
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -73,22 +71,22 @@ impl FontListHandle {
|
||||||
let font_set_array_ptr = ptr::to_unsafe_ptr(&font_set);
|
let font_set_array_ptr = ptr::to_unsafe_ptr(&font_set);
|
||||||
let pattern = FcPatternCreate();
|
let pattern = FcPatternCreate();
|
||||||
assert!(pattern.is_not_null());
|
assert!(pattern.is_not_null());
|
||||||
do "family".to_c_str().with_ref |FC_FAMILY| {
|
"family".to_c_str().with_ref(|FC_FAMILY| {
|
||||||
do family.family_name.to_c_str().with_ref |family_name| {
|
family.family_name.to_c_str().with_ref(|family_name| {
|
||||||
let ok = FcPatternAddString(pattern, FC_FAMILY, family_name as *FcChar8);
|
let ok = FcPatternAddString(pattern, FC_FAMILY, family_name as *FcChar8);
|
||||||
assert!(ok != 0);
|
assert!(ok != 0);
|
||||||
}
|
});
|
||||||
}
|
});
|
||||||
|
|
||||||
let object_set = FcObjectSetCreate();
|
let object_set = FcObjectSetCreate();
|
||||||
assert!(object_set.is_not_null());
|
assert!(object_set.is_not_null());
|
||||||
|
|
||||||
do "file".to_c_str().with_ref |FC_FILE| {
|
"file".to_c_str().with_ref(|FC_FILE| {
|
||||||
FcObjectSetAdd(object_set, FC_FILE);
|
FcObjectSetAdd(object_set, FC_FILE);
|
||||||
}
|
});
|
||||||
do "index".to_c_str().with_ref |FC_INDEX| {
|
"index".to_c_str().with_ref(|FC_INDEX| {
|
||||||
FcObjectSetAdd(object_set, FC_INDEX);
|
FcObjectSetAdd(object_set, FC_INDEX);
|
||||||
}
|
});
|
||||||
|
|
||||||
let matches = FcFontSetList(config, font_set_array_ptr, 1, pattern, object_set);
|
let matches = FcFontSetList(config, font_set_array_ptr, 1, pattern, object_set);
|
||||||
|
|
||||||
|
@ -96,22 +94,22 @@ impl FontListHandle {
|
||||||
|
|
||||||
for i in range(0, (*matches).nfont as int) {
|
for i in range(0, (*matches).nfont as int) {
|
||||||
let font = (*matches).fonts.offset(i);
|
let font = (*matches).fonts.offset(i);
|
||||||
let file = do "file".to_c_str().with_ref |FC_FILE| {
|
let file = "file".to_c_str().with_ref(|FC_FILE| {
|
||||||
let file: *FcChar8 = ptr::null();
|
let file: *FcChar8 = ptr::null();
|
||||||
if FcPatternGetString(*font, FC_FILE, 0, &file) == FcResultMatch {
|
if FcPatternGetString(*font, FC_FILE, 0, &file) == FcResultMatch {
|
||||||
str::raw::from_c_str(file as *libc::c_char)
|
str::raw::from_c_str(file as *libc::c_char)
|
||||||
} else {
|
} else {
|
||||||
fail!();
|
fail!();
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
let index = do "index".to_c_str().with_ref |FC_INDEX| {
|
let index = "index".to_c_str().with_ref(|FC_INDEX| {
|
||||||
let index: libc::c_int = 0;
|
let index: libc::c_int = 0;
|
||||||
if FcPatternGetInteger(*font, FC_INDEX, 0, &index) == FcResultMatch {
|
if FcPatternGetInteger(*font, FC_INDEX, 0, &index) == FcResultMatch {
|
||||||
index
|
index
|
||||||
} else {
|
} else {
|
||||||
fail!();
|
fail!();
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
debug!("variation file: {}", file);
|
debug!("variation file: {}", file);
|
||||||
debug!("variation index: {}", index);
|
debug!("variation index: {}", index);
|
||||||
|
@ -141,7 +139,6 @@ struct AutoPattern {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for AutoPattern {
|
impl Drop for AutoPattern {
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
FcPatternDestroy(self.pattern);
|
FcPatternDestroy(self.pattern);
|
||||||
|
@ -149,17 +146,16 @@ impl Drop for AutoPattern {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn path_from_identifier(name: ~str, style: &UsedFontStyle) -> Result<~str, ()> {
|
pub fn path_from_identifier(name: ~str, style: &UsedFontStyle) -> Result<~str, ()> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let config = FcConfigGetCurrent();
|
let config = FcConfigGetCurrent();
|
||||||
let wrapper = AutoPattern { pattern: FcPatternCreate() };
|
let wrapper = AutoPattern { pattern: FcPatternCreate() };
|
||||||
let pattern = wrapper.pattern;
|
let pattern = wrapper.pattern;
|
||||||
let res = do "family".to_c_str().with_ref |FC_FAMILY| {
|
let res = "family".to_c_str().with_ref(|FC_FAMILY| {
|
||||||
do name.to_c_str().with_ref |family| {
|
name.to_c_str().with_ref(|family| {
|
||||||
FcPatternAddString(pattern, FC_FAMILY, family as *FcChar8)
|
FcPatternAddString(pattern, FC_FAMILY, family as *FcChar8)
|
||||||
}
|
})
|
||||||
};
|
});
|
||||||
if res != 1 {
|
if res != 1 {
|
||||||
debug!("adding family to pattern failed");
|
debug!("adding family to pattern failed");
|
||||||
return Err(());
|
return Err(());
|
||||||
|
@ -168,18 +164,18 @@ pub fn path_from_identifier(name: ~str, style: &UsedFontStyle) -> Result<~str, (
|
||||||
match style.style {
|
match style.style {
|
||||||
font_style::normal => (),
|
font_style::normal => (),
|
||||||
font_style::italic => {
|
font_style::italic => {
|
||||||
let res = do "slant".to_c_str().with_ref |FC_SLANT| {
|
let res = "slant".to_c_str().with_ref(|FC_SLANT| {
|
||||||
FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC)
|
FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC)
|
||||||
};
|
});
|
||||||
if res != 1 {
|
if res != 1 {
|
||||||
debug!("adding slant to pattern failed");
|
debug!("adding slant to pattern failed");
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
font_style::oblique => {
|
font_style::oblique => {
|
||||||
let res = do "slant".to_c_str().with_ref |FC_SLANT| {
|
let res = "slant".to_c_str().with_ref(|FC_SLANT| {
|
||||||
FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_OBLIQUE)
|
FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_OBLIQUE)
|
||||||
};
|
});
|
||||||
if res != 1 {
|
if res != 1 {
|
||||||
debug!("adding slant(oblique) to pattern failed");
|
debug!("adding slant(oblique) to pattern failed");
|
||||||
return Err(());
|
return Err(());
|
||||||
|
@ -188,9 +184,9 @@ pub fn path_from_identifier(name: ~str, style: &UsedFontStyle) -> Result<~str, (
|
||||||
}
|
}
|
||||||
|
|
||||||
if style.weight.is_bold() {
|
if style.weight.is_bold() {
|
||||||
let res = do "weight".to_c_str().with_ref |FC_WEIGHT| {
|
let res = "weight".to_c_str().with_ref(|FC_WEIGHT| {
|
||||||
FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD)
|
FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD)
|
||||||
};
|
});
|
||||||
if res != 1 {
|
if res != 1 {
|
||||||
debug!("adding weight to pattern failed");
|
debug!("adding weight to pattern failed");
|
||||||
return Err(());
|
return Err(());
|
||||||
|
@ -211,9 +207,9 @@ pub fn path_from_identifier(name: ~str, style: &UsedFontStyle) -> Result<~str, (
|
||||||
}
|
}
|
||||||
|
|
||||||
let file: *FcChar8 = ptr::null();
|
let file: *FcChar8 = ptr::null();
|
||||||
let res = do "file".to_c_str().with_ref |FC_FILE| {
|
let res = "file".to_c_str().with_ref(|FC_FILE| {
|
||||||
FcPatternGetString(result_pattern, FC_FILE, 0, &file)
|
FcPatternGetString(result_pattern, FC_FILE, 0, &file)
|
||||||
};
|
});
|
||||||
if res != FcResultMatch {
|
if res != FcResultMatch {
|
||||||
debug!("getting filename for font failed");
|
debug!("getting filename for font failed");
|
||||||
return Err(());
|
return Err(());
|
||||||
|
|
|
@ -29,7 +29,6 @@ use core_text::font_descriptor::{kCTFontDefaultOrientation};
|
||||||
use core_text;
|
use core_text;
|
||||||
|
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::vec;
|
|
||||||
|
|
||||||
pub struct FontTable {
|
pub struct FontTable {
|
||||||
data: CFData,
|
data: CFData,
|
||||||
|
@ -47,8 +46,8 @@ impl FontTable {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FontTableMethods for FontTable {
|
impl FontTableMethods for FontTable {
|
||||||
fn with_buffer(&self, blk: &fn(*u8, uint)) {
|
fn with_buffer(&self, blk: |*u8, uint|) {
|
||||||
blk(vec::raw::to_ptr(self.data.bytes()), self.data.len() as uint);
|
blk(self.data.bytes().as_ptr(), self.data.len() as uint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,9 +184,9 @@ impl FontHandleMethods for FontHandle {
|
||||||
|
|
||||||
fn get_table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> {
|
fn get_table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> {
|
||||||
let result: Option<CFData> = self.ctfont.get_font_table(tag);
|
let result: Option<CFData> = self.ctfont.get_font_table(tag);
|
||||||
do result.and_then |data| {
|
result.and_then(|data| {
|
||||||
Some(FontTable::wrap(data))
|
Some(FontTable::wrap(data))
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn face_identifier(&self) -> ~str {
|
fn face_identifier(&self) -> ~str {
|
||||||
|
|
|
@ -27,8 +27,8 @@ impl FontContextHandleMethods for FontContextHandle {
|
||||||
style: UsedFontStyle)
|
style: UsedFontStyle)
|
||||||
-> Result<FontHandle, ()> {
|
-> Result<FontHandle, ()> {
|
||||||
let ctfont_result = core_text::font::new_from_name(name, style.pt_size);
|
let ctfont_result = core_text::font::new_from_name(name, style.pt_size);
|
||||||
do ctfont_result.and_then |ctfont| {
|
ctfont_result.and_then(|ctfont| {
|
||||||
FontHandle::new_from_CTFont(self, ctfont)
|
FontHandle::new_from_CTFont(self, ctfont)
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,14 +18,13 @@ use geom::side_offsets::SideOffsets2D;
|
||||||
use servo_net::image::base::Image;
|
use servo_net::image::base::Image;
|
||||||
use png::{RGBA8, K8, KA8};
|
use png::{RGBA8, K8, KA8};
|
||||||
use servo_util::geometry::Au;
|
use servo_util::geometry::Au;
|
||||||
use std::vec;
|
|
||||||
use std::libc::types::common::c99::uint16_t;
|
use std::libc::types::common::c99::uint16_t;
|
||||||
use std::libc::size_t;
|
use std::libc::size_t;
|
||||||
|
|
||||||
pub struct RenderContext<'self> {
|
pub struct RenderContext<'a> {
|
||||||
draw_target: &'self DrawTarget,
|
draw_target: &'a DrawTarget,
|
||||||
font_ctx: &'self mut ~FontContext,
|
font_ctx: &'a mut ~FontContext,
|
||||||
opts: &'self Opts,
|
opts: &'a Opts,
|
||||||
/// The rectangle that this context encompasses in page coordinates.
|
/// The rectangle that this context encompasses in page coordinates.
|
||||||
page_rect: Rect<f32>,
|
page_rect: Rect<f32>,
|
||||||
/// The rectangle that this context encompasses in screen coordinates (pixels).
|
/// The rectangle that this context encompasses in screen coordinates (pixels).
|
||||||
|
@ -39,8 +38,8 @@ enum Direction {
|
||||||
Bottom
|
Bottom
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> RenderContext<'self> {
|
impl<'a> RenderContext<'a> {
|
||||||
pub fn get_draw_target(&self) -> &'self DrawTarget {
|
pub fn get_draw_target(&self) -> &'a DrawTarget {
|
||||||
self.draw_target
|
self.draw_target
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,7 +166,7 @@ impl<'self> RenderContext<'self> {
|
||||||
stroke_opts.line_width = border_width;
|
stroke_opts.line_width = border_width;
|
||||||
dash[0] = border_width * 3 as AzFloat;
|
dash[0] = border_width * 3 as AzFloat;
|
||||||
dash[1] = border_width * 3 as AzFloat;
|
dash[1] = border_width * 3 as AzFloat;
|
||||||
stroke_opts.mDashPattern = vec::raw::to_ptr(dash);
|
stroke_opts.mDashPattern = dash.as_ptr();
|
||||||
stroke_opts.mDashLength = dash.len() as size_t;
|
stroke_opts.mDashLength = dash.len() as size_t;
|
||||||
|
|
||||||
let (start, end) = match direction {
|
let (start, end) = match direction {
|
||||||
|
|
|
@ -20,7 +20,6 @@ use servo_util::time::{ProfilerChan, profile};
|
||||||
use servo_util::time;
|
use servo_util::time;
|
||||||
|
|
||||||
use std::comm::{Chan, Port, SharedChan};
|
use std::comm::{Chan, Port, SharedChan};
|
||||||
use std::task::spawn_with;
|
|
||||||
use extra::arc::Arc;
|
use extra::arc::Arc;
|
||||||
|
|
||||||
use buffer_map::BufferMap;
|
use buffer_map::BufferMap;
|
||||||
|
@ -63,24 +62,32 @@ pub fn BufferRequest(screen_rect: Rect<uint>, page_rect: Rect<f32>) -> BufferReq
|
||||||
|
|
||||||
// FIXME(rust#9155): this should be a newtype struct, but
|
// FIXME(rust#9155): this should be a newtype struct, but
|
||||||
// generic newtypes ICE when compiled cross-crate
|
// generic newtypes ICE when compiled cross-crate
|
||||||
#[deriving(Clone)]
|
|
||||||
pub struct RenderChan<T> {
|
pub struct RenderChan<T> {
|
||||||
chan: SharedChan<Msg<T>>,
|
chan: SharedChan<Msg<T>>,
|
||||||
}
|
}
|
||||||
impl<T: Send> RenderChan<T> {
|
|
||||||
pub fn new(chan: Chan<Msg<T>>) -> RenderChan<T> {
|
impl<T: Send> Clone for RenderChan<T> {
|
||||||
|
fn clone(&self) -> RenderChan<T> {
|
||||||
RenderChan {
|
RenderChan {
|
||||||
chan: SharedChan::new(chan),
|
chan: self.chan.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<T: Send> GenericChan<Msg<T>> for RenderChan<T> {
|
|
||||||
fn send(&self, msg: Msg<T>) {
|
impl<T: Send> RenderChan<T> {
|
||||||
|
pub fn new() -> (Port<Msg<T>>, RenderChan<T>) {
|
||||||
|
let (port, chan) = SharedChan::new();
|
||||||
|
let render_chan = RenderChan {
|
||||||
|
chan: chan,
|
||||||
|
};
|
||||||
|
(port, render_chan)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send(&self, msg: Msg<T>) {
|
||||||
assert!(self.try_send(msg), "RenderChan.send: render port closed")
|
assert!(self.try_send(msg), "RenderChan.send: render port closed")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
impl<T: Send> GenericSmartChan<Msg<T>> for RenderChan<T> {
|
pub fn try_send(&self, msg: Msg<T>) -> bool {
|
||||||
fn try_send(&self, msg: Msg<T>) -> bool {
|
|
||||||
self.chan.try_send(msg)
|
self.chan.try_send(msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,9 +145,7 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
|
||||||
opts: Opts,
|
opts: Opts,
|
||||||
profiler_chan: ProfilerChan,
|
profiler_chan: ProfilerChan,
|
||||||
shutdown_chan: Chan<()>) {
|
shutdown_chan: Chan<()>) {
|
||||||
do spawn_with((port, compositor, constellation_chan, opts, profiler_chan, shutdown_chan))
|
spawn(proc() {
|
||||||
|(port, compositor, constellation_chan, opts, profiler_chan, shutdown_chan)| {
|
|
||||||
|
|
||||||
{ // Ensures RenderTask and graphics context are destroyed before shutdown msg
|
{ // Ensures RenderTask and graphics context are destroyed before shutdown msg
|
||||||
let native_graphics_context = compositor.get_graphics_metadata().map(
|
let native_graphics_context = compositor.get_graphics_metadata().map(
|
||||||
|md| NativePaintingGraphicsContext::from_metadata(&md));
|
|md| NativePaintingGraphicsContext::from_metadata(&md));
|
||||||
|
@ -153,8 +158,8 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
|
||||||
compositor: compositor,
|
compositor: compositor,
|
||||||
constellation_chan: constellation_chan,
|
constellation_chan: constellation_chan,
|
||||||
font_ctx: ~FontContext::new(opts.render_backend.clone(),
|
font_ctx: ~FontContext::new(opts.render_backend.clone(),
|
||||||
false,
|
false,
|
||||||
profiler_chan.clone()),
|
profiler_chan.clone()),
|
||||||
opts: opts,
|
opts: opts,
|
||||||
profiler_chan: profiler_chan,
|
profiler_chan: profiler_chan,
|
||||||
|
|
||||||
|
@ -176,13 +181,12 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
|
||||||
render_task.start();
|
render_task.start();
|
||||||
|
|
||||||
// Destroy all the buffers.
|
// Destroy all the buffers.
|
||||||
render_task.native_graphics_context.as_ref().map(|ctx|
|
render_task.native_graphics_context.as_ref().map(
|
||||||
render_task.buffer_map.clear(ctx)
|
|ctx| render_task.buffer_map.clear(ctx));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
shutdown_chan.send(());
|
shutdown_chan.send(());
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start(&mut self) {
|
fn start(&mut self) {
|
||||||
|
@ -243,12 +247,12 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.compositor.set_render_state(RenderingRenderState);
|
self.compositor.set_render_state(RenderingRenderState);
|
||||||
do time::profile(time::RenderingCategory, self.profiler_chan.clone()) {
|
time::profile(time::RenderingCategory, self.profiler_chan.clone(), || {
|
||||||
// FIXME: Try not to create a new array here.
|
// FIXME: Try not to create a new array here.
|
||||||
let mut new_buffers = ~[];
|
let mut new_buffers = ~[];
|
||||||
|
|
||||||
// Divide up the layer into tiles.
|
// Divide up the layer into tiles.
|
||||||
do time::profile(time::RenderingPrepBuffCategory, self.profiler_chan.clone()) {
|
time::profile(time::RenderingPrepBuffCategory, self.profiler_chan.clone(), || {
|
||||||
for tile in tiles.iter() {
|
for tile in tiles.iter() {
|
||||||
let width = tile.screen_rect.size.width;
|
let width = tile.screen_rect.size.width;
|
||||||
let height = tile.screen_rect.size.height;
|
let height = tile.screen_rect.size.height;
|
||||||
|
@ -293,10 +297,10 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
|
||||||
ctx.clear();
|
ctx.clear();
|
||||||
|
|
||||||
// Draw the display list.
|
// Draw the display list.
|
||||||
do profile(time::RenderingDrawingCategory, self.profiler_chan.clone()) {
|
profile(time::RenderingDrawingCategory, self.profiler_chan.clone(), || {
|
||||||
render_layer.display_list.get().draw_into_context(&mut ctx);
|
render_layer.display_list.get().draw_into_context(&mut ctx);
|
||||||
ctx.draw_target.flush();
|
ctx.draw_target.flush();
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract the texture from the draw target and place it into its slot in the
|
// Extract the texture from the draw target and place it into its slot in the
|
||||||
|
@ -335,11 +339,11 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
do draw_target.snapshot().get_data_surface().with_data |data| {
|
draw_target.snapshot().get_data_surface().with_data(|data| {
|
||||||
buffer.native_surface.upload(native_graphics_context!(self), data);
|
buffer.native_surface.upload(native_graphics_context!(self), data);
|
||||||
debug!("RENDERER uploading to native surface {:d}",
|
debug!("RENDERER uploading to native surface {:d}",
|
||||||
buffer.native_surface.get_id() as int);
|
buffer.native_surface.get_id() as int);
|
||||||
}
|
});
|
||||||
|
|
||||||
buffer
|
buffer
|
||||||
}
|
}
|
||||||
|
@ -367,7 +371,7 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
|
||||||
|
|
||||||
new_buffers.push(buffer);
|
new_buffers.push(buffer);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
let layer_buffer_set = ~LayerBufferSet {
|
let layer_buffer_set = ~LayerBufferSet {
|
||||||
buffers: new_buffers,
|
buffers: new_buffers,
|
||||||
|
@ -380,7 +384,7 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
|
||||||
self.constellation_chan.send(RendererReadyMsg(self.id));
|
self.constellation_chan.send(RendererReadyMsg(self.id));
|
||||||
}
|
}
|
||||||
self.compositor.set_render_state(IdleRenderState);
|
self.compositor.set_render_state(IdleRenderState);
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,6 @@ use std::vec;
|
||||||
use std::util;
|
use std::util;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use geom::point::Point2D;
|
use geom::point::Point2D;
|
||||||
use extra::sort;
|
|
||||||
|
|
||||||
/// GlyphEntry is a port of Gecko's CompressedGlyph scheme for storing glyph data compactly.
|
/// GlyphEntry is a port of Gecko's CompressedGlyph scheme for storing glyph data compactly.
|
||||||
///
|
///
|
||||||
|
@ -149,8 +148,8 @@ static FLAG_NOT_LIGATURE_GROUP_START: u32 = 0x00000004;
|
||||||
|
|
||||||
static FLAG_CHAR_IS_TAB: u32 = 0x00000008;
|
static FLAG_CHAR_IS_TAB: u32 = 0x00000008;
|
||||||
static FLAG_CHAR_IS_NEWLINE: u32 = 0x00000010;
|
static FLAG_CHAR_IS_NEWLINE: u32 = 0x00000010;
|
||||||
static FLAG_CHAR_IS_LOW_SURROGATE: u32 = 0x00000020;
|
//static FLAG_CHAR_IS_LOW_SURROGATE: u32 = 0x00000020;
|
||||||
static CHAR_IDENTITY_FLAGS_MASK: u32 = 0x00000038;
|
//static CHAR_IDENTITY_FLAGS_MASK: u32 = 0x00000038;
|
||||||
|
|
||||||
fn is_simple_glyph_id(glyphId: GlyphIndex) -> bool {
|
fn is_simple_glyph_id(glyphId: GlyphIndex) -> bool {
|
||||||
((glyphId as u32) & GLYPH_ID_MASK) == glyphId
|
((glyphId as u32) & GLYPH_ID_MASK) == glyphId
|
||||||
|
@ -176,10 +175,6 @@ impl GlyphEntry {
|
||||||
self.value & GLYPH_ID_MASK
|
self.value & GLYPH_ID_MASK
|
||||||
}
|
}
|
||||||
|
|
||||||
fn offset(&self) -> Point2D<Au> {
|
|
||||||
Point2D(Au(0), Au(0))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_ligature_start(&self) -> bool {
|
fn is_ligature_start(&self) -> bool {
|
||||||
self.has_flag(!FLAG_NOT_LIGATURE_GROUP_START)
|
self.has_flag(!FLAG_NOT_LIGATURE_GROUP_START)
|
||||||
}
|
}
|
||||||
|
@ -312,7 +307,7 @@ struct DetailedGlyphStore {
|
||||||
lookup_is_sorted: bool,
|
lookup_is_sorted: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> DetailedGlyphStore {
|
impl<'a> DetailedGlyphStore {
|
||||||
fn new() -> DetailedGlyphStore {
|
fn new() -> DetailedGlyphStore {
|
||||||
DetailedGlyphStore {
|
DetailedGlyphStore {
|
||||||
detail_buffer: ~[], // TODO: default size?
|
detail_buffer: ~[], // TODO: default size?
|
||||||
|
@ -345,8 +340,8 @@ impl<'self> DetailedGlyphStore {
|
||||||
self.lookup_is_sorted = false;
|
self.lookup_is_sorted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_detailed_glyphs_for_entry(&'self self, entry_offset: uint, count: u16)
|
fn get_detailed_glyphs_for_entry(&'a self, entry_offset: uint, count: u16)
|
||||||
-> &'self [DetailedGlyph] {
|
-> &'a [DetailedGlyph] {
|
||||||
debug!("Requesting detailed glyphs[n={:u}] for entry[off={:u}]", count as uint, entry_offset);
|
debug!("Requesting detailed glyphs[n={:u}] for entry[off={:u}]", count as uint, entry_offset);
|
||||||
|
|
||||||
// FIXME: Is this right? --pcwalton
|
// FIXME: Is this right? --pcwalton
|
||||||
|
@ -375,10 +370,10 @@ impl<'self> DetailedGlyphStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_detailed_glyph_with_index(&'self self,
|
fn get_detailed_glyph_with_index(&'a self,
|
||||||
entry_offset: uint,
|
entry_offset: uint,
|
||||||
detail_offset: u16)
|
detail_offset: u16)
|
||||||
-> &'self DetailedGlyph {
|
-> &'a DetailedGlyph {
|
||||||
assert!((detail_offset as uint) <= self.detail_buffer.len());
|
assert!((detail_offset as uint) <= self.detail_buffer.len());
|
||||||
assert!(self.lookup_is_sorted);
|
assert!(self.lookup_is_sorted);
|
||||||
|
|
||||||
|
@ -411,7 +406,13 @@ impl<'self> DetailedGlyphStore {
|
||||||
let mut unsorted_records: ~[DetailedGlyphRecord] = ~[];
|
let mut unsorted_records: ~[DetailedGlyphRecord] = ~[];
|
||||||
util::swap(&mut self.detail_lookup, &mut unsorted_records);
|
util::swap(&mut self.detail_lookup, &mut unsorted_records);
|
||||||
let mut mut_records : ~[DetailedGlyphRecord] = unsorted_records;
|
let mut mut_records : ~[DetailedGlyphRecord] = unsorted_records;
|
||||||
sort::quick_sort3(mut_records);
|
mut_records.sort_by(|a, b| {
|
||||||
|
if a < b {
|
||||||
|
Less
|
||||||
|
} else {
|
||||||
|
Greater
|
||||||
|
}
|
||||||
|
});
|
||||||
let mut sorted_records = mut_records;
|
let mut sorted_records = mut_records;
|
||||||
util::swap(&mut self.detail_lookup, &mut sorted_records);
|
util::swap(&mut self.detail_lookup, &mut sorted_records);
|
||||||
|
|
||||||
|
@ -458,12 +459,12 @@ impl GlyphData {
|
||||||
// through glyphs (either for a particular TextRun offset, or all glyphs).
|
// through glyphs (either for a particular TextRun offset, or all glyphs).
|
||||||
// Rather than eagerly assembling and copying glyph data, it only retrieves
|
// Rather than eagerly assembling and copying glyph data, it only retrieves
|
||||||
// values as they are needed from the GlyphStore, using provided offsets.
|
// values as they are needed from the GlyphStore, using provided offsets.
|
||||||
enum GlyphInfo<'self> {
|
enum GlyphInfo<'a> {
|
||||||
SimpleGlyphInfo(&'self GlyphStore, uint),
|
SimpleGlyphInfo(&'a GlyphStore, uint),
|
||||||
DetailGlyphInfo(&'self GlyphStore, uint, u16)
|
DetailGlyphInfo(&'a GlyphStore, uint, u16)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> GlyphInfo<'self> {
|
impl<'a> GlyphInfo<'a> {
|
||||||
pub fn index(self) -> GlyphIndex {
|
pub fn index(self) -> GlyphIndex {
|
||||||
match self {
|
match self {
|
||||||
SimpleGlyphInfo(store, entry_i) => store.entry_buffer[entry_i].index(),
|
SimpleGlyphInfo(store, entry_i) => store.entry_buffer[entry_i].index(),
|
||||||
|
@ -492,20 +493,6 @@ impl<'self> GlyphInfo<'self> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_ligature_start(self) -> bool {
|
|
||||||
match self {
|
|
||||||
SimpleGlyphInfo(store, entry_i) => store.entry_buffer[entry_i].is_ligature_start(),
|
|
||||||
DetailGlyphInfo(store, entry_i, _) => store.entry_buffer[entry_i].is_ligature_start()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_cluster_start(self) -> bool {
|
|
||||||
match self {
|
|
||||||
SimpleGlyphInfo(store, entry_i) => store.entry_buffer[entry_i].is_cluster_start(),
|
|
||||||
DetailGlyphInfo(store, entry_i, _) => store.entry_buffer[entry_i].is_cluster_start()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public data structure and API for storing and retrieving glyph data
|
// Public data structure and API for storing and retrieving glyph data
|
||||||
|
@ -519,7 +506,7 @@ pub struct GlyphStore {
|
||||||
is_whitespace: bool,
|
is_whitespace: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> GlyphStore {
|
impl<'a> GlyphStore {
|
||||||
// Initializes the glyph store, but doesn't actually shape anything.
|
// Initializes the glyph store, but doesn't actually shape anything.
|
||||||
// Use the set_glyph, set_glyphs() methods to store glyph data.
|
// Use the set_glyph, set_glyphs() methods to store glyph data.
|
||||||
pub fn new(length: uint, is_whitespace: bool) -> GlyphStore {
|
pub fn new(length: uint, is_whitespace: bool) -> GlyphStore {
|
||||||
|
@ -606,12 +593,12 @@ impl<'self> GlyphStore {
|
||||||
self.entry_buffer[i] = entry;
|
self.entry_buffer[i] = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_glyphs_for_char_index(&'self self, i: uint) -> GlyphIterator<'self> {
|
pub fn iter_glyphs_for_char_index(&'a self, i: uint) -> GlyphIterator<'a> {
|
||||||
self.iter_glyphs_for_char_range(&Range::new(i, 1))
|
self.iter_glyphs_for_char_range(&Range::new(i, 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn iter_glyphs_for_char_range(&'self self, rang: &Range) -> GlyphIterator<'self> {
|
pub fn iter_glyphs_for_char_range(&'a self, rang: &Range) -> GlyphIterator<'a> {
|
||||||
if rang.begin() >= self.entry_buffer.len() {
|
if rang.begin() >= self.entry_buffer.len() {
|
||||||
fail!("iter_glyphs_for_range: range.begin beyond length!");
|
fail!("iter_glyphs_for_range: range.begin beyond length!");
|
||||||
}
|
}
|
||||||
|
@ -684,17 +671,17 @@ impl<'self> GlyphStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct GlyphIterator<'self> {
|
pub struct GlyphIterator<'a> {
|
||||||
priv store: &'self GlyphStore,
|
priv store: &'a GlyphStore,
|
||||||
priv char_index: uint,
|
priv char_index: uint,
|
||||||
priv char_range: iter::Range<uint>,
|
priv char_range: iter::Range<uint>,
|
||||||
priv glyph_range: Option<iter::Range<uint>>,
|
priv glyph_range: Option<iter::Range<uint>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> GlyphIterator<'self> {
|
impl<'a> GlyphIterator<'a> {
|
||||||
// Slow path when there is a glyph range.
|
// Slow path when there is a glyph range.
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn next_glyph_range(&mut self) -> Option<(uint, GlyphInfo<'self>)> {
|
fn next_glyph_range(&mut self) -> Option<(uint, GlyphInfo<'a>)> {
|
||||||
match self.glyph_range.get_mut_ref().next() {
|
match self.glyph_range.get_mut_ref().next() {
|
||||||
Some(j) => Some((self.char_index,
|
Some(j) => Some((self.char_index,
|
||||||
DetailGlyphInfo(self.store, self.char_index, j as u16))),
|
DetailGlyphInfo(self.store, self.char_index, j as u16))),
|
||||||
|
@ -709,14 +696,14 @@ impl<'self> GlyphIterator<'self> {
|
||||||
// Slow path when there is a complex glyph.
|
// Slow path when there is a complex glyph.
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn next_complex_glyph(&mut self, entry: &GlyphEntry, i: uint)
|
fn next_complex_glyph(&mut self, entry: &GlyphEntry, i: uint)
|
||||||
-> Option<(uint, GlyphInfo<'self>)> {
|
-> Option<(uint, GlyphInfo<'a>)> {
|
||||||
let glyphs = self.store.detail_store.get_detailed_glyphs_for_entry(i, entry.glyph_count());
|
let glyphs = self.store.detail_store.get_detailed_glyphs_for_entry(i, entry.glyph_count());
|
||||||
self.glyph_range = Some(range(0, glyphs.len()));
|
self.glyph_range = Some(range(0, glyphs.len()));
|
||||||
self.next()
|
self.next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> Iterator<(uint, GlyphInfo<'self>)> for GlyphIterator<'self> {
|
impl<'a> Iterator<(uint, GlyphInfo<'a>)> for GlyphIterator<'a> {
|
||||||
// I tried to start with something simpler and apply FlatMap, but the
|
// I tried to start with something simpler and apply FlatMap, but the
|
||||||
// inability to store free variables in the FlatMap struct was problematic.
|
// inability to store free variables in the FlatMap struct was problematic.
|
||||||
//
|
//
|
||||||
|
@ -724,7 +711,7 @@ impl<'self> Iterator<(uint, GlyphInfo<'self>)> for GlyphIterator<'self> {
|
||||||
// slow paths, which should not be inlined, are `next_glyph_range()` and
|
// slow paths, which should not be inlined, are `next_glyph_range()` and
|
||||||
// `next_complex_glyph()`.
|
// `next_complex_glyph()`.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn next(&mut self) -> Option<(uint, GlyphInfo<'self>)> {
|
fn next(&mut self) -> Option<(uint, GlyphInfo<'a>)> {
|
||||||
// Would use 'match' here but it borrows contents in a way that
|
// Would use 'match' here but it borrows contents in a way that
|
||||||
// interferes with mutation.
|
// interferes with mutation.
|
||||||
if self.glyph_range.is_some() {
|
if self.glyph_range.is_some() {
|
||||||
|
|
|
@ -10,15 +10,14 @@ use platform::font::FontTable;
|
||||||
use text::glyph::{GlyphStore, GlyphIndex, GlyphData};
|
use text::glyph::{GlyphStore, GlyphIndex, GlyphData};
|
||||||
use text::shaping::ShaperMethods;
|
use text::shaping::ShaperMethods;
|
||||||
use servo_util::range::Range;
|
use servo_util::range::Range;
|
||||||
use text::util::{float_to_fixed, fixed_to_float, fixed_to_rounded_int};
|
use text::util::{float_to_fixed, fixed_to_float};
|
||||||
|
|
||||||
use std::cast::transmute;
|
use std::cast::transmute;
|
||||||
use std::char;
|
use std::char;
|
||||||
use std::libc::{c_uint, c_int, c_void, c_char};
|
use std::libc::{c_uint, c_int, c_void, c_char};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::ptr::null;
|
use std::ptr::null;
|
||||||
use std::uint;
|
use std::num;
|
||||||
use std::util::ignore;
|
|
||||||
use std::vec;
|
use std::vec;
|
||||||
use geom::Point2D;
|
use geom::Point2D;
|
||||||
use harfbuzz::{hb_blob_create, hb_face_create_for_tables};
|
use harfbuzz::{hb_blob_create, hb_face_create_for_tables};
|
||||||
|
@ -63,7 +62,6 @@ pub struct ShapedGlyphEntry {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ShapedGlyphData {
|
impl ShapedGlyphData {
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn new(buffer: *hb_buffer_t) -> ShapedGlyphData {
|
pub fn new(buffer: *hb_buffer_t) -> ShapedGlyphData {
|
||||||
unsafe {
|
unsafe {
|
||||||
let glyph_count = 0;
|
let glyph_count = 0;
|
||||||
|
@ -143,7 +141,6 @@ pub struct Shaper {
|
||||||
|
|
||||||
#[unsafe_destructor]
|
#[unsafe_destructor]
|
||||||
impl Drop for Shaper {
|
impl Drop for Shaper {
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
assert!(self.hb_face.is_not_null());
|
assert!(self.hb_face.is_not_null());
|
||||||
|
@ -159,7 +156,6 @@ impl Drop for Shaper {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Shaper {
|
impl Shaper {
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn new(font: &mut Font) -> Shaper {
|
pub fn new(font: &mut Font) -> Shaper {
|
||||||
unsafe {
|
unsafe {
|
||||||
// Indirection for Rust Issue #6248, dynamic freeze scope artifically extended
|
// Indirection for Rust Issue #6248, dynamic freeze scope artifically extended
|
||||||
|
@ -200,29 +196,22 @@ impl Shaper {
|
||||||
fn fixed_to_float(i: hb_position_t) -> f64 {
|
fn fixed_to_float(i: hb_position_t) -> f64 {
|
||||||
fixed_to_float(16, i)
|
fixed_to_float(16, i)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fixed_to_rounded_int(f: hb_position_t) -> int {
|
|
||||||
fixed_to_rounded_int(16, f)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ShaperMethods for Shaper {
|
impl ShaperMethods for Shaper {
|
||||||
/// Calculate the layout metrics associated with the given text when rendered in a specific
|
/// Calculate the layout metrics associated with the given text when rendered in a specific
|
||||||
/// font.
|
/// font.
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn shape_text(&self, text: &str, glyphs: &mut GlyphStore) {
|
fn shape_text(&self, text: &str, glyphs: &mut GlyphStore) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let hb_buffer: *hb_buffer_t = hb_buffer_create();
|
let hb_buffer: *hb_buffer_t = hb_buffer_create();
|
||||||
hb_buffer_set_direction(hb_buffer, HB_DIRECTION_LTR);
|
hb_buffer_set_direction(hb_buffer, HB_DIRECTION_LTR);
|
||||||
|
|
||||||
// Using as_imm_buf because it never does a copy - we don't need the trailing null
|
// Using as_imm_buf because it never does a copy - we don't need the trailing null
|
||||||
do text.as_imm_buf |ctext: *u8, _: uint| {
|
hb_buffer_add_utf8(hb_buffer,
|
||||||
hb_buffer_add_utf8(hb_buffer,
|
text.as_ptr() as *c_char,
|
||||||
ctext as *c_char,
|
text.len() as c_int,
|
||||||
text.len() as c_int,
|
0,
|
||||||
0,
|
text.len() as c_int);
|
||||||
text.len() as c_int);
|
|
||||||
}
|
|
||||||
|
|
||||||
hb_shape(self.hb_font, hb_buffer, null(), 0);
|
hb_shape(self.hb_font, hb_buffer, null(), 0);
|
||||||
self.save_glyph_results(text, glyphs, hb_buffer);
|
self.save_glyph_results(text, glyphs, hb_buffer);
|
||||||
|
@ -261,7 +250,7 @@ impl Shaper {
|
||||||
byteToGlyph = vec::from_elem(byte_max, NO_GLYPH);
|
byteToGlyph = vec::from_elem(byte_max, NO_GLYPH);
|
||||||
} else {
|
} else {
|
||||||
byteToGlyph = vec::from_elem(byte_max, CONTINUATION_BYTE);
|
byteToGlyph = vec::from_elem(byte_max, CONTINUATION_BYTE);
|
||||||
for (i, _) in text.char_offset_iter() {
|
for (i, _) in text.char_indices() {
|
||||||
byteToGlyph[i] = NO_GLYPH;
|
byteToGlyph[i] = NO_GLYPH;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -283,7 +272,7 @@ impl Shaper {
|
||||||
|
|
||||||
debug!("text: {:s}", text);
|
debug!("text: {:s}", text);
|
||||||
debug!("(char idx): char->(glyph index):");
|
debug!("(char idx): char->(glyph index):");
|
||||||
for (i, ch) in text.char_offset_iter() {
|
for (i, ch) in text.char_indices() {
|
||||||
debug!("{:u}: {} --> {:d}", i, ch, byteToGlyph[i] as int);
|
debug!("{:u}: {} --> {:d}", i, ch, byteToGlyph[i] as int);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,7 +298,7 @@ impl Shaper {
|
||||||
// any trailing chars that do not have associated glyphs.
|
// any trailing chars that do not have associated glyphs.
|
||||||
while char_byte_span.end() < byte_max {
|
while char_byte_span.end() < byte_max {
|
||||||
let range = text.char_range_at(char_byte_span.end());
|
let range = text.char_range_at(char_byte_span.end());
|
||||||
ignore(range.ch);
|
drop(range.ch);
|
||||||
char_byte_span.extend_to(range.next);
|
char_byte_span.extend_to(range.next);
|
||||||
|
|
||||||
debug!("Processing char byte span: off={:u}, len={:u} for glyph idx={:u}",
|
debug!("Processing char byte span: off={:u}, len={:u} for glyph idx={:u}",
|
||||||
|
@ -320,7 +309,7 @@ impl Shaper {
|
||||||
debug!("Extending char byte span to include byte offset={:u} with no associated \
|
debug!("Extending char byte span to include byte offset={:u} with no associated \
|
||||||
glyph", char_byte_span.end());
|
glyph", char_byte_span.end());
|
||||||
let range = text.char_range_at(char_byte_span.end());
|
let range = text.char_range_at(char_byte_span.end());
|
||||||
ignore(range.ch);
|
drop(range.ch);
|
||||||
char_byte_span.extend_to(range.next);
|
char_byte_span.extend_to(range.next);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,7 +318,7 @@ impl Shaper {
|
||||||
let mut max_glyph_idx = glyph_span.end();
|
let mut max_glyph_idx = glyph_span.end();
|
||||||
for i in char_byte_span.eachi() {
|
for i in char_byte_span.eachi() {
|
||||||
if byteToGlyph[i] > NO_GLYPH {
|
if byteToGlyph[i] > NO_GLYPH {
|
||||||
max_glyph_idx = uint::max(byteToGlyph[i] as uint + 1, max_glyph_idx);
|
max_glyph_idx = num::max(byteToGlyph[i] as uint + 1, max_glyph_idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -390,7 +379,7 @@ impl Shaper {
|
||||||
while covered_byte_span.end() < byte_max
|
while covered_byte_span.end() < byte_max
|
||||||
&& byteToGlyph[covered_byte_span.end()] == NO_GLYPH {
|
&& byteToGlyph[covered_byte_span.end()] == NO_GLYPH {
|
||||||
let range = text.char_range_at(covered_byte_span.end());
|
let range = text.char_range_at(covered_byte_span.end());
|
||||||
ignore(range.ch);
|
drop(range.ch);
|
||||||
covered_byte_span.extend_to(range.next);
|
covered_byte_span.extend_to(range.next);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -404,7 +393,7 @@ impl Shaper {
|
||||||
|
|
||||||
// clamp to end of text. (I don't think this will be necessary, but..)
|
// clamp to end of text. (I don't think this will be necessary, but..)
|
||||||
let end = covered_byte_span.end(); // FIXME: borrow checker workaround
|
let end = covered_byte_span.end(); // FIXME: borrow checker workaround
|
||||||
covered_byte_span.extend_to(uint::min(end, byte_max));
|
covered_byte_span.extend_to(num::min(end, byte_max));
|
||||||
|
|
||||||
// fast path: 1-to-1 mapping of single char and single glyph.
|
// fast path: 1-to-1 mapping of single char and single glyph.
|
||||||
if glyph_span.length() == 1 {
|
if glyph_span.length() == 1 {
|
||||||
|
@ -443,7 +432,7 @@ impl Shaper {
|
||||||
let mut i = covered_byte_span.begin();
|
let mut i = covered_byte_span.begin();
|
||||||
loop {
|
loop {
|
||||||
let range = text.char_range_at(i);
|
let range = text.char_range_at(i);
|
||||||
ignore(range.ch);
|
drop(range.ch);
|
||||||
i = range.next;
|
i = range.next;
|
||||||
if i >= covered_byte_span.end() { break; }
|
if i >= covered_byte_span.end() { break; }
|
||||||
char_idx += 1;
|
char_idx += 1;
|
||||||
|
@ -514,14 +503,14 @@ extern fn get_font_table_func(_: *hb_face_t, tag: hb_tag_t, user_data: *c_void)
|
||||||
let skinny_font_table_ptr: *FontTable = font_table; // private context
|
let skinny_font_table_ptr: *FontTable = font_table; // private context
|
||||||
|
|
||||||
let mut blob: *hb_blob_t = null();
|
let mut blob: *hb_blob_t = null();
|
||||||
do (*skinny_font_table_ptr).with_buffer |buf: *u8, len: uint| {
|
(*skinny_font_table_ptr).with_buffer(|buf: *u8, len: uint| {
|
||||||
// HarfBuzz calls `destroy_blob_func` when the buffer is no longer needed.
|
// HarfBuzz calls `destroy_blob_func` when the buffer is no longer needed.
|
||||||
blob = hb_blob_create(buf as *c_char,
|
blob = hb_blob_create(buf as *c_char,
|
||||||
len as c_uint,
|
len as c_uint,
|
||||||
HB_MEMORY_MODE_READONLY,
|
HB_MEMORY_MODE_READONLY,
|
||||||
transmute(skinny_font_table_ptr),
|
transmute(skinny_font_table_ptr),
|
||||||
destroy_blob_func);
|
destroy_blob_func);
|
||||||
}
|
});
|
||||||
|
|
||||||
assert!(blob.is_not_null());
|
assert!(blob.is_not_null());
|
||||||
blob
|
blob
|
||||||
|
|
|
@ -22,16 +22,16 @@ pub struct TextRun {
|
||||||
glyphs: Arc<~[Arc<GlyphStore>]>,
|
glyphs: Arc<~[Arc<GlyphStore>]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SliceIterator<'self> {
|
pub struct SliceIterator<'a> {
|
||||||
priv glyph_iter: VecIterator<'self, Arc<GlyphStore>>,
|
priv glyph_iter: VecIterator<'a, Arc<GlyphStore>>,
|
||||||
priv range: Range,
|
priv range: Range,
|
||||||
priv offset: uint,
|
priv offset: uint,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> Iterator<(&'self GlyphStore, uint, Range)> for SliceIterator<'self> {
|
impl<'a> Iterator<(&'a GlyphStore, uint, Range)> for SliceIterator<'a> {
|
||||||
// inline(always) due to the inefficient rt failures messing up inline heuristics, I think.
|
// inline(always) due to the inefficient rt failures messing up inline heuristics, I think.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn next(&mut self) -> Option<(&'self GlyphStore, uint, Range)> {
|
fn next(&mut self) -> Option<(&'a GlyphStore, uint, Range)> {
|
||||||
loop {
|
loop {
|
||||||
let slice_glyphs = self.glyph_iter.next();
|
let slice_glyphs = self.glyph_iter.next();
|
||||||
if slice_glyphs.is_none() {
|
if slice_glyphs.is_none() {
|
||||||
|
@ -52,13 +52,13 @@ impl<'self> Iterator<(&'self GlyphStore, uint, Range)> for SliceIterator<'self>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LineIterator<'self> {
|
pub struct LineIterator<'a> {
|
||||||
priv range: Range,
|
priv range: Range,
|
||||||
priv clump: Option<Range>,
|
priv clump: Option<Range>,
|
||||||
priv slices: SliceIterator<'self>,
|
priv slices: SliceIterator<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> Iterator<Range> for LineIterator<'self> {
|
impl<'a> Iterator<Range> for LineIterator<'a> {
|
||||||
fn next(&mut self) -> Option<Range> {
|
fn next(&mut self) -> Option<Range> {
|
||||||
// Loop until we hit whitespace and are in a clump.
|
// Loop until we hit whitespace and are in a clump.
|
||||||
loop {
|
loop {
|
||||||
|
@ -96,7 +96,7 @@ impl<'self> Iterator<Range> for LineIterator<'self> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> TextRun {
|
impl<'a> TextRun {
|
||||||
pub fn new(font: &mut Font, text: ~str, decoration: text_decoration::T) -> TextRun {
|
pub fn new(font: &mut Font, text: ~str, decoration: text_decoration::T) -> TextRun {
|
||||||
let glyphs = TextRun::break_and_shape(font, text);
|
let glyphs = TextRun::break_and_shape(font, text);
|
||||||
|
|
||||||
|
@ -170,12 +170,12 @@ impl<'self> TextRun {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn char_len(&self) -> uint {
|
pub fn char_len(&self) -> uint {
|
||||||
do self.glyphs.get().iter().fold(0u) |len, slice_glyphs| {
|
self.glyphs.get().iter().fold(0u, |len, slice_glyphs| {
|
||||||
len + slice_glyphs.get().char_len()
|
len + slice_glyphs.get().char_len()
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn glyphs(&'self self) -> &'self ~[Arc<GlyphStore>] {
|
pub fn glyphs(&'a self) -> &'a ~[Arc<GlyphStore>] {
|
||||||
self.glyphs.get()
|
self.glyphs.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,7 +216,7 @@ impl<'self> TextRun {
|
||||||
max_piece_width
|
max_piece_width
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_slices_for_range(&'self self, range: &Range) -> SliceIterator<'self> {
|
pub fn iter_slices_for_range(&'a self, range: &Range) -> SliceIterator<'a> {
|
||||||
SliceIterator {
|
SliceIterator {
|
||||||
glyph_iter: self.glyphs.get().iter(),
|
glyph_iter: self.glyphs.get().iter(),
|
||||||
range: *range,
|
range: *range,
|
||||||
|
@ -224,7 +224,7 @@ impl<'self> TextRun {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_natural_lines_for_range(&'self self, range: &Range) -> LineIterator<'self> {
|
pub fn iter_natural_lines_for_range(&'a self, range: &Range) -> LineIterator<'a> {
|
||||||
LineIterator {
|
LineIterator {
|
||||||
range: *range,
|
range: *range,
|
||||||
clump: None,
|
clump: None,
|
||||||
|
|
|
@ -24,7 +24,7 @@ pub fn transform_text(text: &str, mode: CompressionMode, incoming_whitespace: bo
|
||||||
let mut out_str: ~str = ~"";
|
let mut out_str: ~str = ~"";
|
||||||
let out_whitespace = match mode {
|
let out_whitespace = match mode {
|
||||||
CompressNone | DiscardNewline => {
|
CompressNone | DiscardNewline => {
|
||||||
for ch in text.iter() {
|
for ch in text.chars() {
|
||||||
if is_discardable_char(ch, mode) {
|
if is_discardable_char(ch, mode) {
|
||||||
// TODO: record skipped char
|
// TODO: record skipped char
|
||||||
} else {
|
} else {
|
||||||
|
@ -40,7 +40,7 @@ pub fn transform_text(text: &str, mode: CompressionMode, incoming_whitespace: bo
|
||||||
|
|
||||||
CompressWhitespace | CompressWhitespaceNewline => {
|
CompressWhitespace | CompressWhitespaceNewline => {
|
||||||
let mut in_whitespace: bool = incoming_whitespace;
|
let mut in_whitespace: bool = incoming_whitespace;
|
||||||
for ch in text.iter() {
|
for ch in text.chars() {
|
||||||
// TODO: discard newlines between CJK chars
|
// TODO: discard newlines between CJK chars
|
||||||
let mut next_in_whitespace: bool = is_in_whitespace(ch, mode);
|
let mut next_in_whitespace: bool = is_in_whitespace(ch, mode);
|
||||||
|
|
||||||
|
|
|
@ -34,13 +34,11 @@ use png;
|
||||||
use servo_msg::compositor_msg::{Epoch, IdleRenderState, LayerBufferSet, RenderState};
|
use servo_msg::compositor_msg::{Epoch, IdleRenderState, LayerBufferSet, RenderState};
|
||||||
use servo_msg::constellation_msg::{ConstellationChan, NavigateMsg, ResizedWindowMsg, LoadUrlMsg, PipelineId};
|
use servo_msg::constellation_msg::{ConstellationChan, NavigateMsg, ResizedWindowMsg, LoadUrlMsg, PipelineId};
|
||||||
use servo_msg::constellation_msg;
|
use servo_msg::constellation_msg;
|
||||||
use servo_util::time::{profile, ProfilerChan};
|
use servo_util::time::{profile, ProfilerChan, Timer};
|
||||||
use servo_util::{time, url};
|
use servo_util::{time, url};
|
||||||
use std::comm::Port;
|
use std::comm::Port;
|
||||||
use std::num::Orderable;
|
use std::num::Orderable;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::rt::io::timer::Timer;
|
|
||||||
use std::vec;
|
|
||||||
|
|
||||||
|
|
||||||
pub struct IOCompositor {
|
pub struct IOCompositor {
|
||||||
|
@ -157,11 +155,17 @@ impl IOCompositor {
|
||||||
self.constellation_chan.send(ResizedWindowMsg(self.window_size));
|
self.constellation_chan.send(ResizedWindowMsg(self.window_size));
|
||||||
|
|
||||||
// Enter the main event loop.
|
// Enter the main event loop.
|
||||||
let mut tm = Timer::new().unwrap();
|
|
||||||
while !self.done {
|
while !self.done {
|
||||||
// Check for new messages coming from the rendering task.
|
// Check for new messages coming from the rendering task.
|
||||||
self.handle_message();
|
self.handle_message();
|
||||||
|
|
||||||
|
if (self.done) {
|
||||||
|
// We have exited the compositor and passing window
|
||||||
|
// messages to script may crash.
|
||||||
|
debug!("Exiting the compositor due to a request from script.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Check for messages coming from the windowing system.
|
// Check for messages coming from the windowing system.
|
||||||
self.handle_window_message(self.window.recv());
|
self.handle_window_message(self.window.recv());
|
||||||
|
|
||||||
|
@ -171,7 +175,7 @@ impl IOCompositor {
|
||||||
self.composite();
|
self.composite();
|
||||||
}
|
}
|
||||||
|
|
||||||
tm.sleep(10);
|
Timer::sleep(10);
|
||||||
|
|
||||||
// If a pinch-zoom happened recently, ask for tiles at the new resolution
|
// If a pinch-zoom happened recently, ask for tiles at the new resolution
|
||||||
if self.zoom_action && precise_time_s() - self.zoom_time > 0.3 {
|
if self.zoom_action && precise_time_s() - self.zoom_time > 0.3 {
|
||||||
|
@ -189,62 +193,65 @@ impl IOCompositor {
|
||||||
|
|
||||||
// Drain compositor port, sometimes messages contain channels that are blocking
|
// Drain compositor port, sometimes messages contain channels that are blocking
|
||||||
// another task from finishing (i.e. SetIds)
|
// another task from finishing (i.e. SetIds)
|
||||||
while self.port.peek() { self.port.recv(); }
|
while self.port.try_recv().is_some() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_message(&mut self) {
|
fn handle_message(&mut self) {
|
||||||
while self.port.peek() {
|
loop {
|
||||||
match self.port.recv() {
|
match self.port.try_recv() {
|
||||||
Exit => {
|
None => break,
|
||||||
self.done = true
|
|
||||||
},
|
|
||||||
|
|
||||||
ChangeReadyState(ready_state) => {
|
Some(Exit(chan)) => {
|
||||||
|
self.done = true;
|
||||||
|
chan.send(());
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(ChangeReadyState(ready_state)) => {
|
||||||
self.window.set_ready_state(ready_state);
|
self.window.set_ready_state(ready_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
ChangeRenderState(render_state) => {
|
Some(ChangeRenderState(render_state)) => {
|
||||||
self.change_render_state(render_state);
|
self.change_render_state(render_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetUnRenderedColor(_id, color) => {
|
Some(SetUnRenderedColor(_id, color)) => {
|
||||||
self.set_unrendered_color(_id, color);
|
self.set_unrendered_color(_id, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SetIds(frame_tree, response_chan, new_constellation_chan) => {
|
Some(SetIds(frame_tree, response_chan, new_constellation_chan)) => {
|
||||||
self.set_ids(frame_tree, response_chan, new_constellation_chan);
|
self.set_ids(frame_tree, response_chan, new_constellation_chan);
|
||||||
}
|
}
|
||||||
|
|
||||||
GetGraphicsMetadata(chan) => {
|
Some(GetGraphicsMetadata(chan)) => {
|
||||||
chan.send(Some(azure_hl::current_graphics_metadata()));
|
chan.send(Some(azure_hl::current_graphics_metadata()));
|
||||||
}
|
}
|
||||||
|
|
||||||
NewLayer(_id, new_size) => {
|
Some(NewLayer(_id, new_size)) => {
|
||||||
self.create_new_layer(_id, new_size);
|
self.create_new_layer(_id, new_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetLayerPageSize(id, new_size, epoch) => {
|
Some(SetLayerPageSize(id, new_size, epoch)) => {
|
||||||
self.set_layer_page_size(id, new_size, epoch);
|
self.set_layer_page_size(id, new_size, epoch);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetLayerClipRect(id, new_rect) => {
|
Some(SetLayerClipRect(id, new_rect)) => {
|
||||||
self.set_layer_clip_rect(id, new_rect);
|
self.set_layer_clip_rect(id, new_rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeleteLayer(id) => {
|
Some(DeleteLayer(id)) => {
|
||||||
self.delete_layer(id);
|
self.delete_layer(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Paint(id, new_layer_buffer_set, epoch) => {
|
Some(Paint(id, new_layer_buffer_set, epoch)) => {
|
||||||
self.paint(id, new_layer_buffer_set, epoch);
|
self.paint(id, new_layer_buffer_set, epoch);
|
||||||
}
|
}
|
||||||
|
|
||||||
InvalidateRect(id, rect) => {
|
Some(InvalidateRect(id, rect)) => {
|
||||||
self.invalidate_rect(id, rect);
|
self.invalidate_rect(id, rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
ScrollFragmentPoint(id, point) => {
|
Some(ScrollFragmentPoint(id, point)) => {
|
||||||
self.scroll_fragment_to_point(id, point);
|
self.scroll_fragment_to_point(id, point);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -601,7 +608,7 @@ impl IOCompositor {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn composite(&mut self) {
|
fn composite(&mut self) {
|
||||||
do profile(time::CompositingCategory, self.profiler_chan.clone()) {
|
profile(time::CompositingCategory, self.profiler_chan.clone(), || {
|
||||||
debug!("compositor: compositing");
|
debug!("compositor: compositing");
|
||||||
// Adjust the layer dimensions as necessary to correspond to the size of the window.
|
// Adjust the layer dimensions as necessary to correspond to the size of the window.
|
||||||
self.scene.size = self.window.size();
|
self.scene.size = self.window.size();
|
||||||
|
@ -616,7 +623,7 @@ impl IOCompositor {
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
rendergl::render_scene(self.context, &self.scene);
|
rendergl::render_scene(self.context, &self.scene);
|
||||||
}
|
});
|
||||||
|
|
||||||
// Render to PNG. We must read from the back buffer (ie, before
|
// Render to PNG. We must read from the back buffer (ie, before
|
||||||
// self.window.present()) as OpenGL ES 2 does not have glReadBuffer().
|
// self.window.present()) as OpenGL ES 2 does not have glReadBuffer().
|
||||||
|
@ -634,9 +641,10 @@ impl IOCompositor {
|
||||||
for y in range(0, height) {
|
for y in range(0, height) {
|
||||||
let dst_start = y * stride;
|
let dst_start = y * stride;
|
||||||
let src_start = (height - y - 1) * stride;
|
let src_start = (height - y - 1) * stride;
|
||||||
vec::bytes::copy_memory(pixels.mut_slice(dst_start, dst_start + stride),
|
unsafe {
|
||||||
orig_pixels.slice(src_start, src_start + stride),
|
pixels.mut_slice(dst_start, dst_start + stride)
|
||||||
stride);
|
.copy_memory(orig_pixels.slice(src_start, src_start + stride).slice_to(stride));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let img = png::Image {
|
let img = png::Image {
|
||||||
width: width as u32,
|
width: width as u32,
|
||||||
|
|
|
@ -22,7 +22,6 @@ use script::dom::event::{ClickEvent, MouseDownEvent, MouseUpEvent};
|
||||||
use script::script_task::SendEventMsg;
|
use script::script_task::SendEventMsg;
|
||||||
use servo_msg::compositor_msg::{LayerBuffer, LayerBufferSet, Epoch, Tile};
|
use servo_msg::compositor_msg::{LayerBuffer, LayerBufferSet, Epoch, Tile};
|
||||||
use servo_msg::constellation_msg::PipelineId;
|
use servo_msg::constellation_msg::PipelineId;
|
||||||
use std::cell::Cell;
|
|
||||||
use windowing::{MouseWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEvent};
|
use windowing::{MouseWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEvent};
|
||||||
use windowing::{MouseWindowMouseUpEvent};
|
use windowing::{MouseWindowMouseUpEvent};
|
||||||
use azure::azure_hl::Color;
|
use azure::azure_hl::Color;
|
||||||
|
@ -141,7 +140,7 @@ impl CompositorLayer {
|
||||||
-> CompositorLayer {
|
-> CompositorLayer {
|
||||||
let SendableFrameTree { pipeline, children } = frame_tree;
|
let SendableFrameTree { pipeline, children } = frame_tree;
|
||||||
let mut layer = CompositorLayer::new(pipeline, None, tile_size, max_mem, cpu_painting);
|
let mut layer = CompositorLayer::new(pipeline, None, tile_size, max_mem, cpu_painting);
|
||||||
layer.children = (do children.move_iter().map |child| {
|
layer.children = (children.move_iter().map(|child| {
|
||||||
let SendableChildFrameTree { frame_tree, rect } = child;
|
let SendableChildFrameTree { frame_tree, rect } = child;
|
||||||
let container = @mut ContainerLayer();
|
let container = @mut ContainerLayer();
|
||||||
match rect {
|
match rect {
|
||||||
|
@ -165,7 +164,7 @@ impl CompositorLayer {
|
||||||
child: child_layer,
|
child: child_layer,
|
||||||
container: container,
|
container: container,
|
||||||
}
|
}
|
||||||
}).collect();
|
})).collect();
|
||||||
layer.set_occlusions();
|
layer.set_occlusions();
|
||||||
layer
|
layer
|
||||||
}
|
}
|
||||||
|
@ -267,7 +266,7 @@ impl CompositorLayer {
|
||||||
let mut redisplay: bool;
|
let mut redisplay: bool;
|
||||||
{ // block here to prevent double mutable borrow of self
|
{ // block here to prevent double mutable borrow of self
|
||||||
let quadtree = match self.quadtree {
|
let quadtree = match self.quadtree {
|
||||||
NoTree(*) => fail!("CompositorLayer: cannot get buffer request for {:?},
|
NoTree(..) => fail!("CompositorLayer: cannot get buffer request for {:?},
|
||||||
no quadtree initialized", self.pipeline.id),
|
no quadtree initialized", self.pipeline.id),
|
||||||
Tree(ref mut quadtree) => quadtree,
|
Tree(ref mut quadtree) => quadtree,
|
||||||
};
|
};
|
||||||
|
@ -327,7 +326,7 @@ impl CompositorLayer {
|
||||||
let old_rect = con.scissor;
|
let old_rect = con.scissor;
|
||||||
con.scissor = Some(new_rect);
|
con.scissor = Some(new_rect);
|
||||||
match self.quadtree {
|
match self.quadtree {
|
||||||
NoTree(*) => {} // Nothing to do
|
NoTree(..) => {} // Nothing to do
|
||||||
Tree(ref mut quadtree) => {
|
Tree(ref mut quadtree) => {
|
||||||
match old_rect {
|
match old_rect {
|
||||||
Some(old_rect) => {
|
Some(old_rect) => {
|
||||||
|
@ -494,15 +493,15 @@ impl CompositorLayer {
|
||||||
// Delete old layer.
|
// Delete old layer.
|
||||||
while current_layer_child.is_some() {
|
while current_layer_child.is_some() {
|
||||||
let trash = current_layer_child.unwrap();
|
let trash = current_layer_child.unwrap();
|
||||||
do current_layer_child.unwrap().with_common |common| {
|
current_layer_child.unwrap().with_common(|common| {
|
||||||
current_layer_child = common.next_sibling;
|
current_layer_child = common.next_sibling;
|
||||||
}
|
});
|
||||||
self.root_layer.remove_child(trash);
|
self.root_layer.remove_child(trash);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add new tiles.
|
// Add new tiles.
|
||||||
let quadtree = match self.quadtree {
|
let quadtree = match self.quadtree {
|
||||||
NoTree(*) => fail!("CompositorLayer: cannot build layer tree for {:?},
|
NoTree(..) => fail!("CompositorLayer: cannot build layer tree for {:?},
|
||||||
no quadtree initialized", self.pipeline.id),
|
no quadtree initialized", self.pipeline.id),
|
||||||
Tree(ref mut quadtree) => quadtree,
|
Tree(ref mut quadtree) => quadtree,
|
||||||
};
|
};
|
||||||
|
@ -544,9 +543,9 @@ impl CompositorLayer {
|
||||||
buffer.native_surface.bind_to_texture(graphics_context, texture, size);
|
buffer.native_surface.bind_to_texture(graphics_context, texture, size);
|
||||||
|
|
||||||
// Move on to the next sibling.
|
// Move on to the next sibling.
|
||||||
do current_layer_child.unwrap().with_common |common| {
|
current_layer_child.unwrap().with_common(|common| {
|
||||||
common.next_sibling
|
common.next_sibling
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
Some(_) => fail!(~"found unexpected layer kind"),
|
Some(_) => fail!(~"found unexpected layer kind"),
|
||||||
};
|
};
|
||||||
|
@ -584,29 +583,29 @@ impl CompositorLayer {
|
||||||
pub fn add_buffers(&mut self,
|
pub fn add_buffers(&mut self,
|
||||||
graphics_context: &NativeCompositingGraphicsContext,
|
graphics_context: &NativeCompositingGraphicsContext,
|
||||||
pipeline_id: PipelineId,
|
pipeline_id: PipelineId,
|
||||||
new_buffers: ~LayerBufferSet,
|
mut new_buffers: ~LayerBufferSet,
|
||||||
epoch: Epoch)
|
epoch: Epoch)
|
||||||
-> Option<~LayerBufferSet> {
|
-> Option<~LayerBufferSet> {
|
||||||
let cell = Cell::new(new_buffers);
|
|
||||||
if self.pipeline.id == pipeline_id {
|
if self.pipeline.id == pipeline_id {
|
||||||
if self.epoch != epoch {
|
if self.epoch != epoch {
|
||||||
debug!("compositor epoch mismatch: {:?} != {:?}, id: {:?}",
|
debug!("compositor epoch mismatch: {:?} != {:?}, id: {:?}",
|
||||||
self.epoch,
|
self.epoch,
|
||||||
epoch,
|
epoch,
|
||||||
self.pipeline.id);
|
self.pipeline.id);
|
||||||
self.pipeline.render_chan.send(UnusedBufferMsg(cell.take().buffers));
|
self.pipeline.render_chan.send(UnusedBufferMsg(new_buffers.buffers));
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// Block here to prevent double mutable borrow of self.
|
// Block here to prevent double mutable borrow of self.
|
||||||
let quadtree = match self.quadtree {
|
let quadtree = match self.quadtree {
|
||||||
NoTree(*) => fail!("CompositorLayer: cannot add buffers, no quadtree initialized"),
|
NoTree(..) => fail!("CompositorLayer: cannot add buffers, no quadtree initialized"),
|
||||||
Tree(ref mut quadtree) => quadtree,
|
Tree(ref mut quadtree) => quadtree,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut unused_tiles = ~[];
|
let mut unused_tiles = ~[];
|
||||||
// move_rev_iter is more efficient
|
// move_rev_iter is more efficient
|
||||||
for buffer in cell.take().buffers.move_rev_iter() {
|
for buffer in new_buffers.buffers.move_rev_iter() {
|
||||||
unused_tiles.push_all_move(quadtree.add_tile_pixel(buffer.screen_pos.origin.x,
|
unused_tiles.push_all_move(quadtree.add_tile_pixel(buffer.screen_pos.origin.x,
|
||||||
buffer.screen_pos.origin.y,
|
buffer.screen_pos.origin.y,
|
||||||
buffer.resolution, buffer));
|
buffer.resolution, buffer));
|
||||||
|
@ -623,15 +622,15 @@ impl CompositorLayer {
|
||||||
for child_layer in self.children.mut_iter() {
|
for child_layer in self.children.mut_iter() {
|
||||||
match child_layer.child.add_buffers(graphics_context,
|
match child_layer.child.add_buffers(graphics_context,
|
||||||
pipeline_id,
|
pipeline_id,
|
||||||
cell.take(),
|
new_buffers,
|
||||||
epoch) {
|
epoch) {
|
||||||
None => return None,
|
None => return None,
|
||||||
Some(buffers) => cell.put_back(buffers),
|
Some(buffers) => new_buffers = buffers,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not found. Give the caller the buffers back.
|
// Not found. Give the caller the buffers back.
|
||||||
Some(cell.take())
|
Some(new_buffers)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deletes a specified sublayer, including hidden children. Returns false if the layer is not found.
|
// Deletes a specified sublayer, including hidden children. Returns false if the layer is not found.
|
||||||
|
@ -643,7 +642,7 @@ impl CompositorLayer {
|
||||||
Some(i) => {
|
Some(i) => {
|
||||||
let mut child = self.children.remove(i);
|
let mut child = self.children.remove(i);
|
||||||
match self.quadtree {
|
match self.quadtree {
|
||||||
NoTree(*) => {} // Nothing to do
|
NoTree(..) => {} // Nothing to do
|
||||||
Tree(ref mut quadtree) => {
|
Tree(ref mut quadtree) => {
|
||||||
match child.container.scissor {
|
match child.container.scissor {
|
||||||
Some(rect) => {
|
Some(rect) => {
|
||||||
|
@ -670,7 +669,7 @@ impl CompositorLayer {
|
||||||
pub fn invalidate_rect(&mut self, pipeline_id: PipelineId, rect: Rect<f32>) -> bool {
|
pub fn invalidate_rect(&mut self, pipeline_id: PipelineId, rect: Rect<f32>) -> bool {
|
||||||
if self.pipeline.id == pipeline_id {
|
if self.pipeline.id == pipeline_id {
|
||||||
let quadtree = match self.quadtree {
|
let quadtree = match self.quadtree {
|
||||||
NoTree(*) => return true, // Nothing to do
|
NoTree(..) => return true, // Nothing to do
|
||||||
Tree(ref mut quadtree) => quadtree,
|
Tree(ref mut quadtree) => quadtree,
|
||||||
};
|
};
|
||||||
quadtree.set_status_page(rect, Invalid, true);
|
quadtree.set_status_page(rect, Invalid, true);
|
||||||
|
@ -681,32 +680,11 @@ impl CompositorLayer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds a child.
|
|
||||||
pub fn add_child(&mut self, pipeline: CompositionPipeline, page_size: Option<Size2D<f32>>, tile_size: uint,
|
|
||||||
max_mem: Option<uint>, clipping_rect: Rect<f32>) {
|
|
||||||
let container = @mut ContainerLayer();
|
|
||||||
container.scissor = Some(clipping_rect);
|
|
||||||
container.common.set_transform(identity().translate(clipping_rect.origin.x,
|
|
||||||
clipping_rect.origin.y,
|
|
||||||
0.0));
|
|
||||||
let child = ~CompositorLayer::new(pipeline,
|
|
||||||
page_size,
|
|
||||||
tile_size,
|
|
||||||
max_mem,
|
|
||||||
self.cpu_painting);
|
|
||||||
container.add_child_start(ContainerLayerKind(child.root_layer));
|
|
||||||
self.children.push(CompositorLayerChild {
|
|
||||||
child: child,
|
|
||||||
container: container,
|
|
||||||
});
|
|
||||||
self.set_occlusions();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recursively sets occluded portions of quadtrees to Hidden, so that they do not ask for
|
// Recursively sets occluded portions of quadtrees to Hidden, so that they do not ask for
|
||||||
// tile requests. If layers are moved, resized, or deleted, these portions may be updated.
|
// tile requests. If layers are moved, resized, or deleted, these portions may be updated.
|
||||||
fn set_occlusions(&mut self) {
|
fn set_occlusions(&mut self) {
|
||||||
let quadtree = match self.quadtree {
|
let quadtree = match self.quadtree {
|
||||||
NoTree(*) => return, // Cannot calculate occlusions
|
NoTree(..) => return, // Cannot calculate occlusions
|
||||||
Tree(ref mut quadtree) => quadtree,
|
Tree(ref mut quadtree) => quadtree,
|
||||||
};
|
};
|
||||||
for child in self.children.iter().filter(|x| !x.child.hidden) {
|
for child in self.children.iter().filter(|x| !x.child.hidden) {
|
||||||
|
@ -726,7 +704,7 @@ impl CompositorLayer {
|
||||||
/// reused.
|
/// reused.
|
||||||
fn clear(&mut self) {
|
fn clear(&mut self) {
|
||||||
match self.quadtree {
|
match self.quadtree {
|
||||||
NoTree(*) => {}
|
NoTree(..) => {}
|
||||||
Tree(ref mut quadtree) => {
|
Tree(ref mut quadtree) => {
|
||||||
let mut tiles = quadtree.collect_tiles();
|
let mut tiles = quadtree.collect_tiles();
|
||||||
|
|
||||||
|
@ -759,7 +737,7 @@ impl CompositorLayer {
|
||||||
/// This is used during shutdown, when we know the render task is going away.
|
/// This is used during shutdown, when we know the render task is going away.
|
||||||
pub fn forget_all_tiles(&mut self) {
|
pub fn forget_all_tiles(&mut self) {
|
||||||
match self.quadtree {
|
match self.quadtree {
|
||||||
NoTree(*) => {}
|
NoTree(..) => {}
|
||||||
Tree(ref mut quadtree) => {
|
Tree(ref mut quadtree) => {
|
||||||
let tiles = quadtree.collect_tiles();
|
let tiles = quadtree.collect_tiles();
|
||||||
for tile in tiles.move_iter() {
|
for tile in tiles.move_iter() {
|
||||||
|
|
|
@ -19,7 +19,6 @@ use servo_msg::compositor_msg::{ScriptListener, Tile};
|
||||||
use servo_msg::constellation_msg::{ConstellationChan, PipelineId, ExitMsg};
|
use servo_msg::constellation_msg::{ConstellationChan, PipelineId, ExitMsg};
|
||||||
use servo_util::time::ProfilerChan;
|
use servo_util::time::ProfilerChan;
|
||||||
use std::comm::{Chan, SharedChan, Port};
|
use std::comm::{Chan, SharedChan, Port};
|
||||||
use std::comm;
|
|
||||||
use std::num::Orderable;
|
use std::num::Orderable;
|
||||||
|
|
||||||
#[cfg(target_os="linux")]
|
#[cfg(target_os="linux")]
|
||||||
|
@ -54,7 +53,9 @@ impl ScriptListener for CompositorChan {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn close(&self) {
|
fn close(&self) {
|
||||||
self.chan.send(Exit);
|
let (port, chan) = Chan::new();
|
||||||
|
self.chan.send(Exit(chan));
|
||||||
|
port.recv();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -62,7 +63,7 @@ impl ScriptListener for CompositorChan {
|
||||||
/// Implementation of the abstract `RenderListener` interface.
|
/// Implementation of the abstract `RenderListener` interface.
|
||||||
impl RenderListener for CompositorChan {
|
impl RenderListener for CompositorChan {
|
||||||
fn get_graphics_metadata(&self) -> Option<NativeGraphicsMetadata> {
|
fn get_graphics_metadata(&self) -> Option<NativeGraphicsMetadata> {
|
||||||
let (port, chan) = comm::stream();
|
let (port, chan) = Chan::new();
|
||||||
self.chan.send(GetGraphicsMetadata(chan));
|
self.chan.send(GetGraphicsMetadata(chan));
|
||||||
port.recv()
|
port.recv()
|
||||||
}
|
}
|
||||||
|
@ -99,10 +100,12 @@ impl RenderListener for CompositorChan {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompositorChan {
|
impl CompositorChan {
|
||||||
pub fn new(chan: Chan<Msg>) -> CompositorChan {
|
pub fn new() -> (Port<Msg>, CompositorChan) {
|
||||||
CompositorChan {
|
let (port, chan) = SharedChan::new();
|
||||||
chan: SharedChan::new(chan),
|
let compositor_chan = CompositorChan {
|
||||||
}
|
chan: chan,
|
||||||
|
};
|
||||||
|
(port, compositor_chan)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send(&self, msg: Msg) {
|
pub fn send(&self, msg: Msg) {
|
||||||
|
@ -113,7 +116,7 @@ impl CompositorChan {
|
||||||
/// Messages from the painting task and the constellation task to the compositor task.
|
/// Messages from the painting task and the constellation task to the compositor task.
|
||||||
pub enum Msg {
|
pub enum Msg {
|
||||||
/// Requests that the compositor shut down.
|
/// Requests that the compositor shut down.
|
||||||
Exit,
|
Exit(Chan<()>),
|
||||||
/// Requests the compositor's graphics metadata. Graphics metadata is what the renderer needs
|
/// Requests the compositor's graphics metadata. Graphics metadata is what the renderer needs
|
||||||
/// to create surfaces that the compositor can see. On Linux this is the X display; on Mac this
|
/// to create surfaces that the compositor can see. On Linux this is the X display; on Mac this
|
||||||
/// is the pixel format.
|
/// is the pixel format.
|
||||||
|
|
|
@ -38,7 +38,10 @@ impl NullCompositor {
|
||||||
fn handle_message(&self) {
|
fn handle_message(&self) {
|
||||||
loop {
|
loop {
|
||||||
match self.port.recv() {
|
match self.port.recv() {
|
||||||
Exit => break,
|
Exit(chan) => {
|
||||||
|
chan.send(());
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
GetGraphicsMetadata(chan) => {
|
GetGraphicsMetadata(chan) => {
|
||||||
chan.send(None);
|
chan.send(None);
|
||||||
|
@ -52,9 +55,9 @@ impl NullCompositor {
|
||||||
// we'll notice and think about whether it needs a response, like
|
// we'll notice and think about whether it needs a response, like
|
||||||
// SetIds.
|
// SetIds.
|
||||||
|
|
||||||
NewLayer(*) | SetLayerPageSize(*) | SetLayerClipRect(*) | DeleteLayer(*) |
|
NewLayer(..) | SetLayerPageSize(..) | SetLayerClipRect(..) | DeleteLayer(..) |
|
||||||
Paint(*) | InvalidateRect(*) | ChangeReadyState(*) | ChangeRenderState(*)|
|
Paint(..) | InvalidateRect(..) | ChangeReadyState(..) | ChangeRenderState(..)|
|
||||||
ScrollFragmentPoint(*) | SetUnRenderedColor(*)
|
ScrollFragmentPoint(..) | SetUnRenderedColor(..)
|
||||||
=> ()
|
=> ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,6 @@ use servo_msg::compositor_msg::Tile;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use layers::platform::surface::NativePaintingGraphicsContext;
|
use layers::platform::surface::NativePaintingGraphicsContext;
|
||||||
|
|
||||||
static HEADER: &'static str = "<!DOCTYPE html><html>";
|
|
||||||
|
|
||||||
/// Parent to all quadtree nodes. Stores variables needed at all levels. All method calls
|
/// Parent to all quadtree nodes. Stores variables needed at all levels. All method calls
|
||||||
/// at this level are in pixel coordinates.
|
/// at this level are in pixel coordinates.
|
||||||
pub struct Quadtree<T> {
|
pub struct Quadtree<T> {
|
||||||
|
@ -101,20 +99,6 @@ impl<T: Tile> Quadtree<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the maximum allowed tile size
|
|
||||||
pub fn get_tile_size(&self) -> uint {
|
|
||||||
self.max_tile_size
|
|
||||||
}
|
|
||||||
/// Get a tile at a given pixel position and scale.
|
|
||||||
pub fn get_tile_pixel<'r>(&'r self, x: uint, y: uint, scale: f32) -> &'r Option<T> {
|
|
||||||
self.root.get_tile(x as f32 / scale, y as f32 / scale)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a tile at a given page position.
|
|
||||||
pub fn get_tile_page<'r>(&'r self, x: f32, y: f32) -> &'r Option<T> {
|
|
||||||
self.root.get_tile(x, y)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add a tile associated with a given pixel position and scale.
|
/// Add a tile associated with a given pixel position and scale.
|
||||||
/// If the tile pushes the total memory over its maximum, tiles will be removed
|
/// If the tile pushes the total memory over its maximum, tiles will be removed
|
||||||
/// until total memory is below the maximum again. These tiles are returned.
|
/// until total memory is below the maximum again. These tiles are returned.
|
||||||
|
@ -137,73 +121,17 @@ impl<T: Tile> Quadtree<T> {
|
||||||
tiles
|
tiles
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a tile associated with a given page position.
|
|
||||||
/// If the tile pushes the total memory over its maximum, tiles will be removed
|
|
||||||
/// until total memory is below the maximum again. These tiles are returned.
|
|
||||||
pub fn add_tile_page(&mut self, x: f32, y: f32, scale: f32, tile: T) -> ~[T] {
|
|
||||||
let (_, tiles) = self.root.add_tile(x, y, tile, self.max_tile_size as f32 / scale);
|
|
||||||
let mut tiles = tiles;
|
|
||||||
match self.max_mem {
|
|
||||||
Some(max) => {
|
|
||||||
while self.root.tile_mem > max {
|
|
||||||
let r = self.root.remove_tile(x, y);
|
|
||||||
match r {
|
|
||||||
(Some(tile), _, _) => tiles.push(tile),
|
|
||||||
_ => fail!("Quadtree: No valid tiles to remove"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {} // Nothing to do
|
|
||||||
}
|
|
||||||
tiles
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the tile rect in screen and page coordinates for a given pixel position.
|
|
||||||
pub fn get_tile_rect_pixel(&mut self, x: uint, y: uint, scale: f32) -> BufferRequest {
|
|
||||||
self.root.get_tile_rect(x as f32 / scale, y as f32 / scale,
|
|
||||||
self.clip_size.width as f32,
|
|
||||||
self.clip_size.height as f32,
|
|
||||||
scale, self.max_tile_size as f32 / scale)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the tile rect in screen and page coordinates for a given page position.
|
|
||||||
pub fn get_tile_rect_page(&mut self, x: f32, y: f32, scale: f32) -> BufferRequest {
|
|
||||||
self.root.get_tile_rect(x, y,
|
|
||||||
self.clip_size.width as f32,
|
|
||||||
self.clip_size.height as f32,
|
|
||||||
scale, self.max_tile_size as f32 / scale)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get all the tiles in the tree.
|
/// Get all the tiles in the tree.
|
||||||
pub fn get_all_tiles<'r>(&'r self) -> ~[&'r T] {
|
pub fn get_all_tiles<'r>(&'r self) -> ~[&'r T] {
|
||||||
self.root.get_all_tiles()
|
self.root.get_all_tiles()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ask a tile to be deleted from the quadtree. This tries to delete a tile that is far from the
|
|
||||||
/// given point in pixel coordinates.
|
|
||||||
pub fn remove_tile_pixel(&mut self, x: uint, y: uint, scale: f32) -> T {
|
|
||||||
let r = self.root.remove_tile(x as f32 / scale, y as f32 / scale);
|
|
||||||
match r {
|
|
||||||
(Some(tile), _, _) => tile,
|
|
||||||
_ => fail!("Quadtree: No valid tiles to remove"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Ask a tile to be deleted from the quadtree. This tries to delete a tile that is far from the
|
|
||||||
/// given point in page coordinates.
|
|
||||||
pub fn remove_tile_page(&mut self, x: f32, y: f32) -> T {
|
|
||||||
let r = self.root.remove_tile(x, y);
|
|
||||||
match r {
|
|
||||||
(Some(tile), _, _) => tile,
|
|
||||||
_ => fail!("Quadtree: No valid tiles to remove"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Given a window rect in pixel coordinates, this function returns a list of BufferRequests for tiles that
|
/// Given a window rect in pixel coordinates, this function returns a list of BufferRequests for tiles that
|
||||||
/// need to be rendered. It also returns a vector of tiles if the window needs to be redisplayed, i.e. if
|
/// need to be rendered. It also returns a vector of tiles if the window needs to be redisplayed, i.e. if
|
||||||
/// no tiles need to be rendered, but the display tree needs to be rebuilt. This can occur when the
|
/// no tiles need to be rendered, but the display tree needs to be rebuilt. This can occur when the
|
||||||
/// user zooms out and cached tiles need to be displayed on top of higher resolution tiles.
|
/// user zooms out and cached tiles need to be displayed on top of higher resolution tiles.
|
||||||
/// When this happens, higher resolution tiles will be removed from the quadtree.
|
/// When this happens, higher resolution tiles will be removed from the quadtree.
|
||||||
|
#[cfg(test)]
|
||||||
pub fn get_tile_rects_pixel(&mut self, window: Rect<int>, scale: f32) -> (~[BufferRequest], ~[T]) {
|
pub fn get_tile_rects_pixel(&mut self, window: Rect<int>, scale: f32) -> (~[BufferRequest], ~[T]) {
|
||||||
let (ret, unused, _) = self.root.get_tile_rects(
|
let (ret, unused, _) = self.root.get_tile_rects(
|
||||||
Rect(Point2D(window.origin.x as f32 / scale, window.origin.y as f32 / scale),
|
Rect(Point2D(window.origin.x as f32 / scale, window.origin.y as f32 / scale),
|
||||||
|
@ -245,6 +173,7 @@ impl<T: Tile> Quadtree<T> {
|
||||||
/// Resize the underlying quadtree without removing tiles already in place.
|
/// Resize the underlying quadtree without removing tiles already in place.
|
||||||
/// Might be useful later on, but resize() should be used for now.
|
/// Might be useful later on, but resize() should be used for now.
|
||||||
/// TODO: return tiles after shrinking
|
/// TODO: return tiles after shrinking
|
||||||
|
#[cfg(test)]
|
||||||
pub fn bad_resize(&mut self, width: uint, height: uint) {
|
pub fn bad_resize(&mut self, width: uint, height: uint) {
|
||||||
self.clip_size = Size2D(width, height);
|
self.clip_size = Size2D(width, height);
|
||||||
let longer = width.max(&height);
|
let longer = width.max(&height);
|
||||||
|
@ -301,11 +230,6 @@ impl<T: Tile> Quadtree<T> {
|
||||||
pub fn collect_tiles(&mut self) -> ~[T] {
|
pub fn collect_tiles(&mut self) -> ~[T] {
|
||||||
self.root.collect_tiles()
|
self.root.collect_tiles()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate html to visualize the tree. For debugging purposes only.
|
|
||||||
pub fn get_html(&self) -> ~str {
|
|
||||||
format!("{:s}<body>{:s}</body></html>", HEADER, self.root.get_html())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Tile> QuadtreeNode<T> {
|
impl<T: Tile> QuadtreeNode<T> {
|
||||||
|
@ -336,20 +260,6 @@ impl<T: Tile> QuadtreeNode<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the lowest-level (highest resolution) tile associated with a given position in page coords.
|
|
||||||
fn get_tile<'r> (&'r self, x: f32, y: f32) -> &'r Option<T> {
|
|
||||||
if x >= self.origin.x + self.size || x < self.origin.x
|
|
||||||
|| y >= self.origin.y + self.size || y < self.origin.y {
|
|
||||||
fail!("Quadtree: Tried to get a tile outside of range");
|
|
||||||
}
|
|
||||||
|
|
||||||
let index = self.get_quadrant(x, y) as int;
|
|
||||||
match self.quadrants[index] {
|
|
||||||
None => &'r self.tile,
|
|
||||||
Some(ref child) => child.get_tile(x, y),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get all tiles in the tree, parents first.
|
/// Get all tiles in the tree, parents first.
|
||||||
fn get_all_tiles<'r>(&'r self) -> ~[&'r T] {
|
fn get_all_tiles<'r>(&'r self) -> ~[&'r T] {
|
||||||
let mut ret = ~[];
|
let mut ret = ~[];
|
||||||
|
@ -602,7 +512,7 @@ impl<T: Tile> QuadtreeNode<T> {
|
||||||
let w_br_quad = self.get_quadrant(w_x + w_width, w_y + w_height);
|
let w_br_quad = self.get_quadrant(w_x + w_width, w_y + w_height);
|
||||||
|
|
||||||
// Figure out which quadrants the window is in
|
// Figure out which quadrants the window is in
|
||||||
let builder = |push: &fn(Quadrant)| {
|
let builder = |push: |Quadrant|| {
|
||||||
match (w_tl_quad, w_br_quad) {
|
match (w_tl_quad, w_br_quad) {
|
||||||
(tl, br) if tl as int == br as int => {
|
(tl, br) if tl as int == br as int => {
|
||||||
push(tl);
|
push(tl);
|
||||||
|
@ -734,44 +644,6 @@ impl<T: Tile> QuadtreeNode<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate html to visualize the tree.
|
|
||||||
/// This is really inefficient, but it's for testing only.
|
|
||||||
fn get_html(&self) -> ~str {
|
|
||||||
let mut ret = ~"";
|
|
||||||
match self.tile {
|
|
||||||
Some(ref tile) => {
|
|
||||||
ret = format!("{:s}{:?}", ret, tile);
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
ret = format!("{:s}NO TILE", ret);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
match self.quadrants {
|
|
||||||
[None, None, None, None] => {}
|
|
||||||
_ => {
|
|
||||||
ret = format!("{:s}<table border=1><tr>", ret);
|
|
||||||
// FIXME: This should be inline, but currently won't compile
|
|
||||||
let quads = [TL, TR, BL, BR];
|
|
||||||
for quad in quads.iter() {
|
|
||||||
match self.quadrants[*quad as int] {
|
|
||||||
Some(ref child) => {
|
|
||||||
ret = format!("{:s}<td>{:s}</td>", ret, child.get_html());
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
ret = format!("{:s}<td>EMPTY CHILD</td>", ret);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
match *quad {
|
|
||||||
TR => ret = format!("{:s}</tr><tr>", ret),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ret = format!("{:s}</table>\n", ret);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -20,10 +20,7 @@ use servo_net::resource_task::ResourceTask;
|
||||||
use servo_net::resource_task;
|
use servo_net::resource_task;
|
||||||
use servo_util::time::ProfilerChan;
|
use servo_util::time::ProfilerChan;
|
||||||
use servo_util::url::make_url;
|
use servo_util::url::make_url;
|
||||||
use std::comm::Port;
|
|
||||||
use std::comm;
|
|
||||||
use std::hashmap::{HashMap, HashSet};
|
use std::hashmap::{HashMap, HashSet};
|
||||||
use std::task::spawn_with;
|
|
||||||
use std::util::replace;
|
use std::util::replace;
|
||||||
|
|
||||||
/// Maintains the pipelines and navigation context and grants permission to composite
|
/// Maintains the pipelines and navigation context and grants permission to composite
|
||||||
|
@ -53,9 +50,9 @@ struct FrameTree {
|
||||||
// Need to clone the FrameTrees, but _not_ the Pipelines
|
// Need to clone the FrameTrees, but _not_ the Pipelines
|
||||||
impl Clone for FrameTree {
|
impl Clone for FrameTree {
|
||||||
fn clone(&self) -> FrameTree {
|
fn clone(&self) -> FrameTree {
|
||||||
let mut children = do self.children.iter().map |child_frame_tree| {
|
let mut children = self.children.iter().map(|child_frame_tree| {
|
||||||
child_frame_tree.clone()
|
child_frame_tree.clone()
|
||||||
};
|
});
|
||||||
FrameTree {
|
FrameTree {
|
||||||
pipeline: self.pipeline,
|
pipeline: self.pipeline,
|
||||||
parent: self.parent.clone(),
|
parent: self.parent.clone(),
|
||||||
|
@ -90,41 +87,46 @@ pub struct SendableChildFrameTree {
|
||||||
rect: Option<Rect<f32>>,
|
rect: Option<Rect<f32>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SendableFrameTree {
|
// impl SendableFrameTree {
|
||||||
fn contains(&self, id: PipelineId) -> bool {
|
// fn contains(&self, id: PipelineId) -> bool {
|
||||||
self.pipeline.id == id ||
|
// self.pipeline.id == id ||
|
||||||
do self.children.iter().any |&SendableChildFrameTree { frame_tree: ref frame_tree, _ }| {
|
// self.children.iter().any(|&SendableChildFrameTree { frame_tree: ref frame_tree, .. }| {
|
||||||
frame_tree.contains(id)
|
// frame_tree.contains(id)
|
||||||
}
|
// })
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
enum ReplaceResult {
|
||||||
|
ReplacedNode(@mut FrameTree),
|
||||||
|
OriginalNode(@mut FrameTree),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FrameTree {
|
impl FrameTree {
|
||||||
fn contains(@mut self, id: PipelineId) -> bool {
|
fn contains(@mut self, id: PipelineId) -> bool {
|
||||||
do self.iter().any |frame_tree| {
|
self.iter().any(|frame_tree| {
|
||||||
id == frame_tree.pipeline.id
|
id == frame_tree.pipeline.id
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the frame tree whose key is id
|
/// Returns the frame tree whose key is id
|
||||||
fn find(@mut self, id: PipelineId) -> Option<@mut FrameTree> {
|
fn find(@mut self, id: PipelineId) -> Option<@mut FrameTree> {
|
||||||
do self.iter().find |frame_tree| {
|
self.iter().find(|frame_tree| {
|
||||||
id == frame_tree.pipeline.id
|
id == frame_tree.pipeline.id
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Replaces a node of the frame tree in place. Returns the node that was removed or the original node
|
/// Replaces a node of the frame tree in place. Returns the node that was removed or the original node
|
||||||
/// if the node to replace could not be found.
|
/// if the node to replace could not be found.
|
||||||
fn replace_child(@mut self, id: PipelineId, new_child: @mut FrameTree) -> Either<@mut FrameTree, @mut FrameTree> {
|
fn replace_child(@mut self, id: PipelineId, new_child: @mut FrameTree) -> ReplaceResult {
|
||||||
for frame_tree in self.iter() {
|
for frame_tree in self.iter() {
|
||||||
let mut child = frame_tree.children.mut_iter()
|
let mut child = frame_tree.children.mut_iter()
|
||||||
.find(|child| child.frame_tree.pipeline.id == id);
|
.find(|child| child.frame_tree.pipeline.id == id);
|
||||||
for child in child.mut_iter() {
|
for child in child.mut_iter() {
|
||||||
new_child.parent = child.frame_tree.parent;
|
new_child.parent = child.frame_tree.parent;
|
||||||
return Left(replace(&mut child.frame_tree, new_child));
|
return ReplacedNode(replace(&mut child.frame_tree, new_child));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Right(new_child)
|
OriginalNode(new_child)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_sendable(&self) -> SendableFrameTree {
|
fn to_sendable(&self) -> SendableFrameTree {
|
||||||
|
@ -162,7 +164,7 @@ impl Iterator<@mut FrameTree> for FrameTreeIterator {
|
||||||
fn next(&mut self) -> Option<@mut FrameTree> {
|
fn next(&mut self) -> Option<@mut FrameTree> {
|
||||||
if !self.stack.is_empty() {
|
if !self.stack.is_empty() {
|
||||||
let next = self.stack.pop();
|
let next = self.stack.pop();
|
||||||
for &ChildFrameTree { frame_tree, _ } in next.children.rev_iter() {
|
for &ChildFrameTree { frame_tree, .. } in next.children.rev_iter() {
|
||||||
self.stack.push(frame_tree);
|
self.stack.push(frame_tree);
|
||||||
}
|
}
|
||||||
Some(next)
|
Some(next)
|
||||||
|
@ -223,15 +225,15 @@ impl NavigationContext {
|
||||||
|
|
||||||
/// Returns the frame trees whose keys are pipeline_id.
|
/// Returns the frame trees whose keys are pipeline_id.
|
||||||
pub fn find_all(&mut self, pipeline_id: PipelineId) -> ~[@mut FrameTree] {
|
pub fn find_all(&mut self, pipeline_id: PipelineId) -> ~[@mut FrameTree] {
|
||||||
let from_current = do self.current.iter().filter_map |frame_tree| {
|
let from_current = self.current.iter().filter_map(|frame_tree| {
|
||||||
frame_tree.find(pipeline_id)
|
frame_tree.find(pipeline_id)
|
||||||
};
|
});
|
||||||
let from_next = do self.next.iter().filter_map |frame_tree| {
|
let from_next = self.next.iter().filter_map(|frame_tree| {
|
||||||
frame_tree.find(pipeline_id)
|
frame_tree.find(pipeline_id)
|
||||||
};
|
});
|
||||||
let from_prev = do self.previous.iter().filter_map |frame_tree| {
|
let from_prev = self.previous.iter().filter_map(|frame_tree| {
|
||||||
frame_tree.find(pipeline_id)
|
frame_tree.find(pipeline_id)
|
||||||
};
|
});
|
||||||
from_prev.chain(from_current).chain(from_next).collect()
|
from_prev.chain(from_current).chain(from_next).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,36 +243,25 @@ impl NavigationContext {
|
||||||
let from_prev = self.previous.iter();
|
let from_prev = self.previous.iter();
|
||||||
|
|
||||||
let mut all_contained = from_prev.chain(from_current).chain(from_next);
|
let mut all_contained = from_prev.chain(from_current).chain(from_next);
|
||||||
do all_contained.any |frame_tree| {
|
all_contained.any(|frame_tree| {
|
||||||
frame_tree.contains(pipeline_id)
|
frame_tree.contains(pipeline_id)
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Constellation {
|
impl Constellation {
|
||||||
pub fn start(constellation_port: Port<Msg>,
|
pub fn start(compositor_chan: CompositorChan,
|
||||||
constellation_chan: ConstellationChan,
|
|
||||||
compositor_chan: CompositorChan,
|
|
||||||
opts: &Opts,
|
opts: &Opts,
|
||||||
resource_task: ResourceTask,
|
resource_task: ResourceTask,
|
||||||
image_cache_task: ImageCacheTask,
|
image_cache_task: ImageCacheTask,
|
||||||
profiler_chan: ProfilerChan) {
|
profiler_chan: ProfilerChan)
|
||||||
do spawn_with((constellation_port,
|
-> ConstellationChan {
|
||||||
constellation_chan.clone(),
|
let (constellation_port, constellation_chan) = ConstellationChan::new();
|
||||||
compositor_chan,
|
let constellation_chan_clone = constellation_chan.clone();
|
||||||
resource_task,
|
let opts_clone = opts.clone();
|
||||||
image_cache_task,
|
spawn(proc() {
|
||||||
profiler_chan,
|
|
||||||
opts.clone()))
|
|
||||||
|(constellation_port,
|
|
||||||
constellation_chan,
|
|
||||||
compositor_chan,
|
|
||||||
resource_task,
|
|
||||||
image_cache_task,
|
|
||||||
profiler_chan,
|
|
||||||
opts)| {
|
|
||||||
let mut constellation = Constellation {
|
let mut constellation = Constellation {
|
||||||
chan: constellation_chan,
|
chan: constellation_chan_clone,
|
||||||
request_port: constellation_port,
|
request_port: constellation_port,
|
||||||
compositor_chan: compositor_chan,
|
compositor_chan: compositor_chan,
|
||||||
resource_task: resource_task,
|
resource_task: resource_task,
|
||||||
|
@ -282,10 +273,11 @@ impl Constellation {
|
||||||
pending_sizes: HashMap::new(),
|
pending_sizes: HashMap::new(),
|
||||||
profiler_chan: profiler_chan,
|
profiler_chan: profiler_chan,
|
||||||
window_size: Size2D(500u, 500u),
|
window_size: Size2D(500u, 500u),
|
||||||
opts: opts
|
opts: opts_clone,
|
||||||
};
|
};
|
||||||
constellation.run();
|
constellation.run();
|
||||||
}
|
});
|
||||||
|
constellation_chan
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&mut self) {
|
fn run(&mut self) {
|
||||||
|
@ -313,9 +305,9 @@ impl Constellation {
|
||||||
/// Returns both the navigation context and pending frame trees whose keys are pipeline_id.
|
/// Returns both the navigation context and pending frame trees whose keys are pipeline_id.
|
||||||
pub fn find_all(&mut self, pipeline_id: PipelineId) -> ~[@mut FrameTree] {
|
pub fn find_all(&mut self, pipeline_id: PipelineId) -> ~[@mut FrameTree] {
|
||||||
let matching_navi_frames = self.navigation_context.find_all(pipeline_id);
|
let matching_navi_frames = self.navigation_context.find_all(pipeline_id);
|
||||||
let matching_pending_frames = do self.pending_frames.iter().filter_map |frame_change| {
|
let matching_pending_frames = self.pending_frames.iter().filter_map(|frame_change| {
|
||||||
frame_change.after.find(pipeline_id)
|
frame_change.after.find(pipeline_id)
|
||||||
};
|
});
|
||||||
matching_navi_frames.move_iter().chain(matching_pending_frames).collect()
|
matching_navi_frames.move_iter().chain(matching_pending_frames).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,6 +315,7 @@ impl Constellation {
|
||||||
fn handle_request(&mut self, request: Msg) -> bool {
|
fn handle_request(&mut self, request: Msg) -> bool {
|
||||||
match request {
|
match request {
|
||||||
ExitMsg(sender) => {
|
ExitMsg(sender) => {
|
||||||
|
debug!("constellation exiting");
|
||||||
self.handle_exit(sender);
|
self.handle_exit(sender);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -499,9 +492,9 @@ impl Constellation {
|
||||||
// and add the new pipeline to their sub frames.
|
// and add the new pipeline to their sub frames.
|
||||||
let frame_trees: ~[@mut FrameTree] = {
|
let frame_trees: ~[@mut FrameTree] = {
|
||||||
let matching_navi_frames = self.navigation_context.find_all(source_pipeline_id);
|
let matching_navi_frames = self.navigation_context.find_all(source_pipeline_id);
|
||||||
let matching_pending_frames = do self.pending_frames.iter().filter_map |frame_change| {
|
let matching_pending_frames = self.pending_frames.iter().filter_map(|frame_change| {
|
||||||
frame_change.after.find(source_pipeline_id)
|
frame_change.after.find(source_pipeline_id)
|
||||||
};
|
});
|
||||||
matching_navi_frames.move_iter().chain(matching_pending_frames).collect()
|
matching_navi_frames.move_iter().chain(matching_pending_frames).collect()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -681,9 +674,9 @@ impl Constellation {
|
||||||
// Find the pending frame change whose new pipeline id is pipeline_id.
|
// Find the pending frame change whose new pipeline id is pipeline_id.
|
||||||
// If it is not found, it simply means that this pipeline will not receive
|
// If it is not found, it simply means that this pipeline will not receive
|
||||||
// permission to paint.
|
// permission to paint.
|
||||||
let pending_index = do self.pending_frames.iter().rposition |frame_change| {
|
let pending_index = self.pending_frames.iter().rposition(|frame_change| {
|
||||||
frame_change.after.pipeline.id == pipeline_id
|
frame_change.after.pipeline.id == pipeline_id
|
||||||
};
|
});
|
||||||
for &pending_index in pending_index.iter() {
|
for &pending_index in pending_index.iter() {
|
||||||
let frame_change = self.pending_frames.swap_remove(pending_index);
|
let frame_change = self.pending_frames.swap_remove(pending_index);
|
||||||
let to_add = frame_change.after;
|
let to_add = frame_change.after;
|
||||||
|
@ -742,9 +735,9 @@ impl Constellation {
|
||||||
/// Called when the window is resized.
|
/// Called when the window is resized.
|
||||||
fn handle_resized_window_msg(&mut self, new_size: Size2D<uint>) {
|
fn handle_resized_window_msg(&mut self, new_size: Size2D<uint>) {
|
||||||
let mut already_seen = HashSet::new();
|
let mut already_seen = HashSet::new();
|
||||||
for &@FrameTree { pipeline: pipeline, _ } in self.current_frame().iter() {
|
for &@FrameTree { pipeline: pipeline, .. } in self.current_frame().iter() {
|
||||||
debug!("constellation sending resize message to active frame");
|
debug!("constellation sending resize message to active frame");
|
||||||
pipeline.script_chan.send(ResizeMsg(pipeline.id, new_size));
|
pipeline.script_chan.try_send(ResizeMsg(pipeline.id, new_size));
|
||||||
already_seen.insert(pipeline.id);
|
already_seen.insert(pipeline.id);
|
||||||
}
|
}
|
||||||
for frame_tree in self.navigation_context.previous.iter()
|
for frame_tree in self.navigation_context.previous.iter()
|
||||||
|
@ -752,7 +745,7 @@ impl Constellation {
|
||||||
let pipeline = &frame_tree.pipeline;
|
let pipeline = &frame_tree.pipeline;
|
||||||
if !already_seen.contains(&pipeline.id) {
|
if !already_seen.contains(&pipeline.id) {
|
||||||
debug!("constellation sending resize message to inactive frame");
|
debug!("constellation sending resize message to inactive frame");
|
||||||
pipeline.script_chan.send(ResizeInactiveMsg(pipeline.id, new_size));
|
pipeline.script_chan.try_send(ResizeInactiveMsg(pipeline.id, new_size));
|
||||||
already_seen.insert(pipeline.id);
|
already_seen.insert(pipeline.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -774,7 +767,7 @@ impl Constellation {
|
||||||
fn close_pipelines(&mut self, frame_tree: @mut FrameTree) {
|
fn close_pipelines(&mut self, frame_tree: @mut FrameTree) {
|
||||||
// TODO(tkuehn): should only exit once per unique script task,
|
// TODO(tkuehn): should only exit once per unique script task,
|
||||||
// and then that script task will handle sub-exits
|
// and then that script task will handle sub-exits
|
||||||
for @FrameTree { pipeline, _ } in frame_tree.iter() {
|
for @FrameTree { pipeline, .. } in frame_tree.iter() {
|
||||||
pipeline.exit();
|
pipeline.exit();
|
||||||
self.pipelines.remove(&pipeline.id);
|
self.pipelines.remove(&pipeline.id);
|
||||||
}
|
}
|
||||||
|
@ -809,9 +802,9 @@ impl Constellation {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_ids(&self, frame_tree: @mut FrameTree) {
|
fn set_ids(&self, frame_tree: @mut FrameTree) {
|
||||||
let (port, chan) = comm::stream();
|
let (port, chan) = Chan::new();
|
||||||
self.compositor_chan.send(SetIds(frame_tree.to_sendable(), chan, self.chan.clone()));
|
self.compositor_chan.send(SetIds(frame_tree.to_sendable(), chan, self.chan.clone()));
|
||||||
match port.try_recv() {
|
match port.recv_opt() {
|
||||||
Some(()) => {
|
Some(()) => {
|
||||||
for frame in frame_tree.iter() {
|
for frame in frame_tree.iter() {
|
||||||
frame.pipeline.grant_paint_permission();
|
frame.pipeline.grant_paint_permission();
|
||||||
|
|
|
@ -11,11 +11,8 @@ use layout::wrapper::LayoutNode;
|
||||||
|
|
||||||
use extra::arc::{Arc, RWArc};
|
use extra::arc::{Arc, RWArc};
|
||||||
use std::cast;
|
use std::cast;
|
||||||
use std::cell::Cell;
|
|
||||||
use std::comm;
|
|
||||||
use std::libc::uintptr_t;
|
use std::libc::uintptr_t;
|
||||||
use std::rt;
|
use std::rt;
|
||||||
use std::task;
|
|
||||||
use std::vec;
|
use std::vec;
|
||||||
use style::{TNode, Stylist, cascade};
|
use style::{TNode, Stylist, cascade};
|
||||||
use style::{Before, After};
|
use style::{Before, After};
|
||||||
|
@ -27,22 +24,23 @@ pub trait MatchMethods {
|
||||||
fn cascade_subtree(&self, parent: Option<LayoutNode>);
|
fn cascade_subtree(&self, parent: Option<LayoutNode>);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> MatchMethods for LayoutNode<'self> {
|
impl<'ln> MatchMethods for LayoutNode<'ln> {
|
||||||
fn match_node(&self, stylist: &Stylist) {
|
fn match_node(&self, stylist: &Stylist) {
|
||||||
let style_attribute = do self.with_element |element| {
|
let style_attribute = self.with_element(|element| {
|
||||||
match *element.style_attribute() {
|
match *element.style_attribute() {
|
||||||
None => None,
|
None => None,
|
||||||
Some(ref style_attribute) => Some(style_attribute)
|
Some(ref style_attribute) => Some(style_attribute)
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
match *self.mutate_layout_data().ptr {
|
let mut layout_data_ref = self.mutate_layout_data();
|
||||||
|
match *layout_data_ref.get() {
|
||||||
Some(ref mut layout_data) => {
|
Some(ref mut layout_data) => {
|
||||||
layout_data.applicable_declarations = stylist.get_applicable_declarations(
|
layout_data.data.applicable_declarations = stylist.get_applicable_declarations(
|
||||||
self, style_attribute, None);
|
self, style_attribute, None);
|
||||||
layout_data.before_applicable_declarations = stylist.get_applicable_declarations(
|
layout_data.data.before_applicable_declarations = stylist.get_applicable_declarations(
|
||||||
self, None, Some(Before));
|
self, None, Some(Before));
|
||||||
layout_data.after_applicable_declarations = stylist.get_applicable_declarations(
|
layout_data.data.after_applicable_declarations = stylist.get_applicable_declarations(
|
||||||
self, None, Some(After));
|
self, None, Some(After));
|
||||||
}
|
}
|
||||||
None => fail!("no layout data")
|
None => fail!("no layout data")
|
||||||
|
@ -60,8 +58,7 @@ impl<'self> MatchMethods for LayoutNode<'self> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (port, chan) = comm::stream();
|
let (port, chan) = SharedChan::new();
|
||||||
let chan = comm::SharedChan::new(chan);
|
|
||||||
let mut num_spawned = 0;
|
let mut num_spawned = 0;
|
||||||
|
|
||||||
for nodes in nodes_per_task.move_iter() {
|
for nodes in nodes_per_task.move_iter() {
|
||||||
|
@ -77,20 +74,20 @@ impl<'self> MatchMethods for LayoutNode<'self> {
|
||||||
cast::transmute(nodes)
|
cast::transmute(nodes)
|
||||||
};
|
};
|
||||||
|
|
||||||
do task::spawn_with((evil, stylist)) |(evil, stylist)| {
|
let evil = Some(evil);
|
||||||
|
spawn(proc() {
|
||||||
|
let mut evil = evil;
|
||||||
let nodes: ~[LayoutNode] = unsafe {
|
let nodes: ~[LayoutNode] = unsafe {
|
||||||
cast::transmute(evil)
|
cast::transmute(evil.take_unwrap())
|
||||||
};
|
};
|
||||||
|
|
||||||
let nodes = Cell::new(nodes);
|
stylist.read(|stylist| {
|
||||||
do stylist.read |stylist| {
|
|
||||||
let nodes = nodes.take();
|
|
||||||
for node in nodes.iter() {
|
for node in nodes.iter() {
|
||||||
node.match_node(stylist);
|
node.match_node(stylist);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
chan.send(());
|
chan.send(());
|
||||||
}
|
});
|
||||||
num_spawned += 1;
|
num_spawned += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,9 +97,6 @@ impl<'self> MatchMethods for LayoutNode<'self> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cascade_subtree(&self, parent: Option<LayoutNode>) {
|
fn cascade_subtree(&self, parent: Option<LayoutNode>) {
|
||||||
let layout_data = unsafe {
|
|
||||||
self.borrow_layout_data_unchecked().as_ref().unwrap()
|
|
||||||
};
|
|
||||||
macro_rules! cascade_node(
|
macro_rules! cascade_node(
|
||||||
($applicable_declarations: ident, $style: ident) => {{
|
($applicable_declarations: ident, $style: ident) => {{
|
||||||
let parent_style = match parent {
|
let parent_style = match parent {
|
||||||
|
@ -110,18 +104,21 @@ impl<'self> MatchMethods for LayoutNode<'self> {
|
||||||
None => None
|
None => None
|
||||||
};
|
};
|
||||||
|
|
||||||
let computed_values = Arc::new(cascade(
|
let computed_values = {
|
||||||
layout_data.$applicable_declarations,
|
let layout_data_ref = self.borrow_layout_data();
|
||||||
parent_style.map(|parent_style| parent_style.get())));
|
let layout_data = layout_data_ref.get().as_ref().unwrap();
|
||||||
|
Arc::new(cascade(layout_data.data.$applicable_declarations, parent_style.map(|parent_style| parent_style.get())))
|
||||||
|
};
|
||||||
|
|
||||||
match *self.mutate_layout_data().ptr {
|
let mut layout_data_ref = self.mutate_layout_data();
|
||||||
|
match *layout_data_ref.get() {
|
||||||
None => fail!("no layout data"),
|
None => fail!("no layout data"),
|
||||||
Some(ref mut layout_data) => {
|
Some(ref mut layout_data) => {
|
||||||
let style = &mut layout_data.$style;
|
let style = &mut layout_data.data.$style;
|
||||||
match *style {
|
match *style {
|
||||||
None => (),
|
None => (),
|
||||||
Some(ref previous_style) => {
|
Some(ref previous_style) => {
|
||||||
layout_data.restyle_damage = Some(incremental::compute_damage(
|
layout_data.data.restyle_damage = Some(incremental::compute_damage(
|
||||||
previous_style.get(), computed_values.get()).to_int())
|
previous_style.get(), computed_values.get()).to_int())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,14 +128,22 @@ impl<'self> MatchMethods for LayoutNode<'self> {
|
||||||
}}
|
}}
|
||||||
);
|
);
|
||||||
|
|
||||||
unsafe {
|
{
|
||||||
if self.borrow_layout_data_unchecked().as_ref().unwrap().before_applicable_declarations.len() > 0 {
|
let before_len = {
|
||||||
|
let layout_data_ref = self.borrow_layout_data();
|
||||||
|
layout_data_ref.get().as_ref().unwrap().data.before_applicable_declarations.len()
|
||||||
|
};
|
||||||
|
if before_len > 0 {
|
||||||
cascade_node!(before_applicable_declarations, before_style);
|
cascade_node!(before_applicable_declarations, before_style);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cascade_node!(applicable_declarations, style);
|
cascade_node!(applicable_declarations, style);
|
||||||
unsafe {
|
{
|
||||||
if self.borrow_layout_data_unchecked().as_ref().unwrap().after_applicable_declarations.len() > 0 {
|
let after_len = {
|
||||||
|
let layout_data_ref = self.borrow_layout_data();
|
||||||
|
layout_data_ref.get().as_ref().unwrap().data.after_applicable_declarations.len()
|
||||||
|
};
|
||||||
|
if after_len > 0 {
|
||||||
cascade_node!(after_applicable_declarations, after_style);
|
cascade_node!(after_applicable_declarations, after_style);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ pub trait StyledNode {
|
||||||
fn restyle_damage(&self) -> RestyleDamage;
|
fn restyle_damage(&self) -> RestyleDamage;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> StyledNode for LayoutNode<'self> {
|
impl<'ln> StyledNode for LayoutNode<'ln> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn style<'a>(&'a self) -> &'a Arc<ComputedValues> {
|
fn style<'a>(&'a self) -> &'a Arc<ComputedValues> {
|
||||||
self.get_css_select_results()
|
self.get_css_select_results()
|
||||||
|
|
|
@ -18,7 +18,7 @@ pub trait NodeUtil {
|
||||||
fn set_restyle_damage(self, damage: RestyleDamage);
|
fn set_restyle_damage(self, damage: RestyleDamage);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> NodeUtil for LayoutNode<'self> {
|
impl<'ln> NodeUtil for LayoutNode<'ln> {
|
||||||
/**
|
/**
|
||||||
* Provides the computed style for the given node. If CSS selector
|
* Provides the computed style for the given node. If CSS selector
|
||||||
* Returns the style results for the given node. If CSS selector
|
* Returns the style results for the given node. If CSS selector
|
||||||
|
@ -27,18 +27,15 @@ impl<'self> NodeUtil for LayoutNode<'self> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_css_select_results<'a>(&'a self) -> &'a Arc<ComputedValues> {
|
fn get_css_select_results<'a>(&'a self) -> &'a Arc<ComputedValues> {
|
||||||
unsafe {
|
unsafe {
|
||||||
cast::transmute_region(self.borrow_layout_data_unchecked()
|
let layout_data_ref = self.borrow_layout_data();
|
||||||
.as_ref()
|
cast::transmute_region(layout_data_ref.get().as_ref().unwrap().data.style.as_ref().unwrap())
|
||||||
.unwrap()
|
|
||||||
.style
|
|
||||||
.as_ref()
|
|
||||||
.unwrap())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Does this node have a computed style yet?
|
/// Does this node have a computed style yet?
|
||||||
fn have_css_select_results(self) -> bool {
|
fn have_css_select_results(self) -> bool {
|
||||||
self.borrow_layout_data().ptr.as_ref().unwrap().style.is_some()
|
let layout_data_ref = self.borrow_layout_data();
|
||||||
|
layout_data_ref.get().get_ref().data.style.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the description of how to account for recent style changes.
|
/// Get the description of how to account for recent style changes.
|
||||||
|
@ -52,10 +49,11 @@ impl<'self> NodeUtil for LayoutNode<'self> {
|
||||||
RestyleDamage::none()
|
RestyleDamage::none()
|
||||||
};
|
};
|
||||||
|
|
||||||
self.borrow_layout_data()
|
let layout_data_ref = self.borrow_layout_data();
|
||||||
.ptr
|
layout_data_ref
|
||||||
.as_ref()
|
.get()
|
||||||
.unwrap()
|
.get_ref()
|
||||||
|
.data
|
||||||
.restyle_damage
|
.restyle_damage
|
||||||
.map(|x| RestyleDamage::from_int(x))
|
.map(|x| RestyleDamage::from_int(x))
|
||||||
.unwrap_or(default)
|
.unwrap_or(default)
|
||||||
|
@ -63,10 +61,10 @@ impl<'self> NodeUtil for LayoutNode<'self> {
|
||||||
|
|
||||||
/// Set the restyle damage field.
|
/// Set the restyle damage field.
|
||||||
fn set_restyle_damage(self, damage: RestyleDamage) {
|
fn set_restyle_damage(self, damage: RestyleDamage) {
|
||||||
match *self.mutate_layout_data().ptr {
|
let mut layout_data_ref = self.mutate_layout_data();
|
||||||
Some(ref mut data) => data.restyle_damage = Some(damage.to_int()),
|
match *layout_data_ref.get() {
|
||||||
|
Some(ref mut layout_data) => layout_data.data.restyle_damage = Some(damage.to_int()),
|
||||||
_ => fail!("no layout data for this node"),
|
_ => fail!("no layout data for this node"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
//! CSS block formatting contexts.
|
//! CSS block formatting contexts.
|
||||||
|
|
||||||
use layout::box::Box;
|
use layout::box_::Box;
|
||||||
use layout::context::LayoutContext;
|
use layout::context::LayoutContext;
|
||||||
use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData};
|
use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData};
|
||||||
use layout::flow::{BlockFlowClass, FlowClass, Flow, FlowData, ImmutableFlowUtils};
|
use layout::flow::{BlockFlowClass, FlowClass, Flow, FlowData, ImmutableFlowUtils};
|
||||||
|
@ -12,7 +12,7 @@ use layout::flow;
|
||||||
use layout::model::{MaybeAuto, Specified, Auto, specified_or_none, specified};
|
use layout::model::{MaybeAuto, Specified, Auto, specified_or_none, specified};
|
||||||
use layout::float_context::{FloatContext, PlacementInfo, Invalid, FloatType};
|
use layout::float_context::{FloatContext, PlacementInfo, Invalid, FloatType};
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::RefCell;
|
||||||
use geom::{Point2D, Rect, SideOffsets2D};
|
use geom::{Point2D, Rect, SideOffsets2D};
|
||||||
use gfx::display_list::DisplayList;
|
use gfx::display_list::DisplayList;
|
||||||
use servo_util::geometry::Au;
|
use servo_util::geometry::Au;
|
||||||
|
@ -53,7 +53,7 @@ pub struct BlockFlow {
|
||||||
base: FlowData,
|
base: FlowData,
|
||||||
|
|
||||||
/// The associated box.
|
/// The associated box.
|
||||||
box: Option<Box>,
|
box_: Option<Box>,
|
||||||
|
|
||||||
/// Whether this block flow is the root flow.
|
/// Whether this block flow is the root flow.
|
||||||
is_root: bool,
|
is_root: bool,
|
||||||
|
@ -66,25 +66,25 @@ impl BlockFlow {
|
||||||
pub fn new(base: FlowData) -> BlockFlow {
|
pub fn new(base: FlowData) -> BlockFlow {
|
||||||
BlockFlow {
|
BlockFlow {
|
||||||
base: base,
|
base: base,
|
||||||
box: None,
|
box_: None,
|
||||||
is_root: false,
|
is_root: false,
|
||||||
float: None
|
float: None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_box(base: FlowData, box: Box) -> BlockFlow {
|
pub fn from_box(base: FlowData, box_: Box) -> BlockFlow {
|
||||||
BlockFlow {
|
BlockFlow {
|
||||||
base: base,
|
base: base,
|
||||||
box: Some(box),
|
box_: Some(box_),
|
||||||
is_root: false,
|
is_root: false,
|
||||||
float: None
|
float: None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn float_from_box(base: FlowData, float_type: FloatType, box: Box) -> BlockFlow {
|
pub fn float_from_box(base: FlowData, float_type: FloatType, box_: Box) -> BlockFlow {
|
||||||
BlockFlow {
|
BlockFlow {
|
||||||
base: base,
|
base: base,
|
||||||
box: Some(box),
|
box_: Some(box_),
|
||||||
is_root: false,
|
is_root: false,
|
||||||
float: Some(~FloatedBlockInfo::new(float_type))
|
float: Some(~FloatedBlockInfo::new(float_type))
|
||||||
}
|
}
|
||||||
|
@ -93,7 +93,7 @@ impl BlockFlow {
|
||||||
pub fn new_root(base: FlowData) -> BlockFlow {
|
pub fn new_root(base: FlowData) -> BlockFlow {
|
||||||
BlockFlow {
|
BlockFlow {
|
||||||
base: base,
|
base: base,
|
||||||
box: None,
|
box_: None,
|
||||||
is_root: true,
|
is_root: true,
|
||||||
float: None
|
float: None
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,7 @@ impl BlockFlow {
|
||||||
pub fn new_float(base: FlowData, float_type: FloatType) -> BlockFlow {
|
pub fn new_float(base: FlowData, float_type: FloatType) -> BlockFlow {
|
||||||
BlockFlow {
|
BlockFlow {
|
||||||
base: base,
|
base: base,
|
||||||
box: None,
|
box_: None,
|
||||||
is_root: false,
|
is_root: false,
|
||||||
float: Some(~FloatedBlockInfo::new(float_type))
|
float: Some(~FloatedBlockInfo::new(float_type))
|
||||||
}
|
}
|
||||||
|
@ -113,10 +113,10 @@ impl BlockFlow {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn teardown(&mut self) {
|
pub fn teardown(&mut self) {
|
||||||
for box in self.box.iter() {
|
for box_ in self.box_.iter() {
|
||||||
box.teardown();
|
box_.teardown();
|
||||||
}
|
}
|
||||||
self.box = None;
|
self.box_ = None;
|
||||||
self.float = None;
|
self.float = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,9 +172,9 @@ impl BlockFlow {
|
||||||
(width_Au, left_margin_Au, right_margin_Au)
|
(width_Au, left_margin_Au, right_margin_Au)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compute_block_margins(&self, box: &Box, remaining_width: Au, available_width: Au)
|
fn compute_block_margins(&self, box_: &Box, remaining_width: Au, available_width: Au)
|
||||||
-> (Au, Au, Au) {
|
-> (Au, Au, Au) {
|
||||||
let style = box.style();
|
let style = box_.style();
|
||||||
|
|
||||||
let (width, maybe_margin_left, maybe_margin_right) =
|
let (width, maybe_margin_left, maybe_margin_right) =
|
||||||
(MaybeAuto::from_style(style.Box.width, remaining_width),
|
(MaybeAuto::from_style(style.Box.width, remaining_width),
|
||||||
|
@ -215,8 +215,8 @@ impl BlockFlow {
|
||||||
return (width, margin_left, margin_right);
|
return (width, margin_left, margin_right);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compute_float_margins(&self, box: &Box, remaining_width: Au) -> (Au, Au, Au) {
|
fn compute_float_margins(&self, box_: &Box, remaining_width: Au) -> (Au, Au, Au) {
|
||||||
let style = box.style();
|
let style = box_.style();
|
||||||
let margin_left = MaybeAuto::from_style(style.Margin.margin_left,
|
let margin_left = MaybeAuto::from_style(style.Margin.margin_left,
|
||||||
remaining_width).specified_or_zero();
|
remaining_width).specified_or_zero();
|
||||||
let margin_right = MaybeAuto::from_style(style.Margin.margin_right,
|
let margin_right = MaybeAuto::from_style(style.Margin.margin_right,
|
||||||
|
@ -240,20 +240,20 @@ impl BlockFlow {
|
||||||
let mut left_offset = Au::new(0);
|
let mut left_offset = Au::new(0);
|
||||||
let mut float_ctx = Invalid;
|
let mut float_ctx = Invalid;
|
||||||
|
|
||||||
for box in self.box.iter() {
|
for box_ in self.box_.iter() {
|
||||||
clearance = match box.clear() {
|
clearance = match box_.clear() {
|
||||||
None => Au::new(0),
|
None => Au::new(0),
|
||||||
Some(clear) => {
|
Some(clear) => {
|
||||||
self.base.floats_in.clearance(clear)
|
self.base.floats_in.clearance(clear)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
top_offset = clearance + box.margin.get().top + box.border.get().top +
|
top_offset = clearance + box_.margin.get().top + box_.border.get().top +
|
||||||
box.padding.get().top;
|
box_.padding.get().top;
|
||||||
cur_y = cur_y + top_offset;
|
cur_y = cur_y + top_offset;
|
||||||
bottom_offset = box.margin.get().bottom + box.border.get().bottom +
|
bottom_offset = box_.margin.get().bottom + box_.border.get().bottom +
|
||||||
box.padding.get().bottom;
|
box_.padding.get().bottom;
|
||||||
left_offset = box.offset();
|
left_offset = box_.offset();
|
||||||
}
|
}
|
||||||
|
|
||||||
if inorder {
|
if inorder {
|
||||||
|
@ -279,17 +279,17 @@ impl BlockFlow {
|
||||||
let mut top_margin_collapsible = false;
|
let mut top_margin_collapsible = false;
|
||||||
let mut bottom_margin_collapsible = false;
|
let mut bottom_margin_collapsible = false;
|
||||||
let mut first_in_flow = true;
|
let mut first_in_flow = true;
|
||||||
for box in self.box.iter() {
|
for box_ in self.box_.iter() {
|
||||||
if !self.is_root && box.border.get().top == Au(0) && box.padding.get().top == Au(0) {
|
if !self.is_root && box_.border.get().top == Au(0) && box_.padding.get().top == Au(0) {
|
||||||
collapsible = box.margin.get().top;
|
collapsible = box_.margin.get().top;
|
||||||
top_margin_collapsible = true;
|
top_margin_collapsible = true;
|
||||||
}
|
}
|
||||||
if !self.is_root && box.border.get().bottom == Au(0) &&
|
if !self.is_root && box_.border.get().bottom == Au(0) &&
|
||||||
box.padding.get().bottom == Au(0) {
|
box_.padding.get().bottom == Au(0) {
|
||||||
bottom_margin_collapsible = true;
|
bottom_margin_collapsible = true;
|
||||||
}
|
}
|
||||||
margin_top = box.margin.get().top;
|
margin_top = box_.margin.get().top;
|
||||||
margin_bottom = box.margin.get().bottom;
|
margin_bottom = box_.margin.get().bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
for kid in self.base.child_iter() {
|
for kid in self.base.child_iter() {
|
||||||
|
@ -332,8 +332,8 @@ impl BlockFlow {
|
||||||
cur_y - top_offset - collapsing
|
cur_y - top_offset - collapsing
|
||||||
};
|
};
|
||||||
|
|
||||||
for box in self.box.iter() {
|
for box_ in self.box_.iter() {
|
||||||
let style = box.style();
|
let style = box_.style();
|
||||||
|
|
||||||
// At this point, `height` is the height of the containing block, so passing `height`
|
// At this point, `height` is the height of the containing block, so passing `height`
|
||||||
// as the second argument here effectively makes percentages relative to the containing
|
// as the second argument here effectively makes percentages relative to the containing
|
||||||
|
@ -345,9 +345,9 @@ impl BlockFlow {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut noncontent_height = Au::new(0);
|
let mut noncontent_height = Au::new(0);
|
||||||
for box in self.box.iter() {
|
for box_ in self.box_.iter() {
|
||||||
let mut position = box.position.get();
|
let mut position = box_.position.get();
|
||||||
let mut margin = box.margin.get();
|
let mut margin = box_.margin.get();
|
||||||
|
|
||||||
// The associated box is the border box of this flow.
|
// The associated box is the border box of this flow.
|
||||||
margin.top = margin_top;
|
margin.top = margin_top;
|
||||||
|
@ -355,14 +355,14 @@ impl BlockFlow {
|
||||||
|
|
||||||
position.origin.y = clearance + margin.top;
|
position.origin.y = clearance + margin.top;
|
||||||
|
|
||||||
noncontent_height = box.padding.get().top + box.padding.get().bottom +
|
noncontent_height = box_.padding.get().top + box_.padding.get().bottom +
|
||||||
box.border.get().top + box.border.get().bottom;
|
box_.border.get().top + box_.border.get().bottom;
|
||||||
position.size.height = height + noncontent_height;
|
position.size.height = height + noncontent_height;
|
||||||
|
|
||||||
noncontent_height = noncontent_height + clearance + margin.top + margin.bottom;
|
noncontent_height = noncontent_height + clearance + margin.top + margin.bottom;
|
||||||
|
|
||||||
box.position.set(position);
|
box_.position.set(position);
|
||||||
box.margin.set(margin);
|
box_.margin.set(margin);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.base.position.size.height = height + noncontent_height;
|
self.base.position.size.height = height + noncontent_height;
|
||||||
|
@ -384,19 +384,19 @@ impl BlockFlow {
|
||||||
let mut full_noncontent_width = Au(0);
|
let mut full_noncontent_width = Au(0);
|
||||||
let mut margin_height = Au(0);
|
let mut margin_height = Au(0);
|
||||||
|
|
||||||
for box in self.box.iter() {
|
for box_ in self.box_.iter() {
|
||||||
height = box.position.get().size.height;
|
height = box_.position.get().size.height;
|
||||||
clearance = match box.clear() {
|
clearance = match box_.clear() {
|
||||||
None => Au(0),
|
None => Au(0),
|
||||||
Some(clear) => self.base.floats_in.clearance(clear),
|
Some(clear) => self.base.floats_in.clearance(clear),
|
||||||
};
|
};
|
||||||
|
|
||||||
let noncontent_width = box.padding.get().left + box.padding.get().right +
|
let noncontent_width = box_.padding.get().left + box_.padding.get().right +
|
||||||
box.border.get().left + box.border.get().right;
|
box_.border.get().left + box_.border.get().right;
|
||||||
|
|
||||||
full_noncontent_width = noncontent_width + box.margin.get().left +
|
full_noncontent_width = noncontent_width + box_.margin.get().left +
|
||||||
box.margin.get().right;
|
box_.margin.get().right;
|
||||||
margin_height = box.margin.get().top + box.margin.get().bottom;
|
margin_height = box_.margin.get().top + box_.margin.get().bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
let info = PlacementInfo {
|
let info = PlacementInfo {
|
||||||
|
@ -427,8 +427,8 @@ impl BlockFlow {
|
||||||
let mut cur_y = Au(0);
|
let mut cur_y = Au(0);
|
||||||
let mut top_offset = Au(0);
|
let mut top_offset = Au(0);
|
||||||
|
|
||||||
for box in self.box.iter() {
|
for box_ in self.box_.iter() {
|
||||||
top_offset = box.margin.get().top + box.border.get().top + box.padding.get().top;
|
top_offset = box_.margin.get().top + box_.border.get().top + box_.padding.get().top;
|
||||||
cur_y = cur_y + top_offset;
|
cur_y = cur_y + top_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -441,31 +441,31 @@ impl BlockFlow {
|
||||||
let mut height = cur_y - top_offset;
|
let mut height = cur_y - top_offset;
|
||||||
|
|
||||||
let mut noncontent_height;
|
let mut noncontent_height;
|
||||||
let box = self.box.as_ref().unwrap();
|
let box_ = self.box_.as_ref().unwrap();
|
||||||
let mut position = box.position.get();
|
let mut position = box_.position.get();
|
||||||
|
|
||||||
// The associated box is the border box of this flow.
|
// The associated box is the border box of this flow.
|
||||||
position.origin.y = box.margin.get().top;
|
position.origin.y = box_.margin.get().top;
|
||||||
|
|
||||||
noncontent_height = box.padding.get().top + box.padding.get().bottom +
|
noncontent_height = box_.padding.get().top + box_.padding.get().bottom +
|
||||||
box.border.get().top + box.border.get().bottom;
|
box_.border.get().top + box_.border.get().bottom;
|
||||||
|
|
||||||
//TODO(eatkinson): compute heights properly using the 'height' property.
|
//TODO(eatkinson): compute heights properly using the 'height' property.
|
||||||
let height_prop = MaybeAuto::from_style(box.style().Box.height,
|
let height_prop = MaybeAuto::from_style(box_.style().Box.height,
|
||||||
Au::new(0)).specified_or_zero();
|
Au::new(0)).specified_or_zero();
|
||||||
|
|
||||||
height = geometry::max(height, height_prop) + noncontent_height;
|
height = geometry::max(height, height_prop) + noncontent_height;
|
||||||
debug!("assign_height_float -- height: {}", height);
|
debug!("assign_height_float -- height: {}", height);
|
||||||
|
|
||||||
position.size.height = height;
|
position.size.height = height;
|
||||||
box.position.set(position);
|
box_.position.set(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_display_list_block<E:ExtraDisplayListData>(
|
pub fn build_display_list_block<E:ExtraDisplayListData>(
|
||||||
&mut self,
|
&mut self,
|
||||||
builder: &DisplayListBuilder,
|
builder: &DisplayListBuilder,
|
||||||
dirty: &Rect<Au>,
|
dirty: &Rect<Au>,
|
||||||
list: &Cell<DisplayList<E>>)
|
list: &RefCell<DisplayList<E>>)
|
||||||
-> bool {
|
-> bool {
|
||||||
if self.is_float() {
|
if self.is_float() {
|
||||||
return self.build_display_list_float(builder, dirty, list);
|
return self.build_display_list_float(builder, dirty, list);
|
||||||
|
@ -479,8 +479,8 @@ impl BlockFlow {
|
||||||
debug!("build_display_list_block: adding display element");
|
debug!("build_display_list_block: adding display element");
|
||||||
|
|
||||||
// add box that starts block context
|
// add box that starts block context
|
||||||
for box in self.box.iter() {
|
for box_ in self.box_.iter() {
|
||||||
box.build_display_list(builder, dirty, self.base.abs_position, (&*self) as &Flow, list)
|
box_.build_display_list(builder, dirty, self.base.abs_position, (&*self) as &Flow, list)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: handle any out-of-flow elements
|
// TODO: handle any out-of-flow elements
|
||||||
|
@ -497,7 +497,7 @@ impl BlockFlow {
|
||||||
&mut self,
|
&mut self,
|
||||||
builder: &DisplayListBuilder,
|
builder: &DisplayListBuilder,
|
||||||
dirty: &Rect<Au>,
|
dirty: &Rect<Au>,
|
||||||
list: &Cell<DisplayList<E>>)
|
list: &RefCell<DisplayList<E>>)
|
||||||
-> bool {
|
-> bool {
|
||||||
let abs_rect = Rect(self.base.abs_position, self.base.position.size);
|
let abs_rect = Rect(self.base.abs_position, self.base.position.size);
|
||||||
if !abs_rect.intersects(dirty) {
|
if !abs_rect.intersects(dirty) {
|
||||||
|
@ -506,8 +506,8 @@ impl BlockFlow {
|
||||||
|
|
||||||
let offset = self.base.abs_position + self.float.get_ref().rel_pos;
|
let offset = self.base.abs_position + self.float.get_ref().rel_pos;
|
||||||
// add box that starts block context
|
// add box that starts block context
|
||||||
for box in self.box.iter() {
|
for box_ in self.box_.iter() {
|
||||||
box.build_display_list(builder, dirty, offset, (&*self) as &Flow, list)
|
box_.build_display_list(builder, dirty, offset, (&*self) as &Flow, list)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -564,13 +564,13 @@ impl Flow for BlockFlow {
|
||||||
|
|
||||||
/* if not an anonymous block context, add in block box's widths.
|
/* if not an anonymous block context, add in block box's widths.
|
||||||
these widths will not include child elements, just padding etc. */
|
these widths will not include child elements, just padding etc. */
|
||||||
for box in self.box.iter() {
|
for box_ in self.box_.iter() {
|
||||||
{
|
{
|
||||||
// Can compute border width here since it doesn't depend on anything.
|
// Can compute border width here since it doesn't depend on anything.
|
||||||
box.compute_borders(box.style())
|
box_.compute_borders(box_.style())
|
||||||
}
|
}
|
||||||
|
|
||||||
let (this_minimum_width, this_preferred_width) = box.minimum_and_preferred_widths();
|
let (this_minimum_width, this_preferred_width) = box_.minimum_and_preferred_widths();
|
||||||
min_width = min_width + this_minimum_width;
|
min_width = min_width + this_minimum_width;
|
||||||
pref_width = pref_width + this_preferred_width;
|
pref_width = pref_width + this_preferred_width;
|
||||||
}
|
}
|
||||||
|
@ -612,17 +612,17 @@ impl Flow for BlockFlow {
|
||||||
self.base.flags.set_inorder(false);
|
self.base.flags.set_inorder(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
for box in self.box.iter() {
|
for box_ in self.box_.iter() {
|
||||||
let style = box.style();
|
let style = box_.style();
|
||||||
|
|
||||||
// The text alignment of a block flow is the text alignment of its box's style.
|
// The text alignment of a block flow is the text alignment of its box's style.
|
||||||
self.base.flags.set_text_align(style.Text.text_align);
|
self.base.flags.set_text_align(style.Text.text_align);
|
||||||
|
|
||||||
// Can compute padding here since we know containing block width.
|
// Can compute padding here since we know containing block width.
|
||||||
box.compute_padding(style, remaining_width);
|
box_.compute_padding(style, remaining_width);
|
||||||
|
|
||||||
// Margins are 0 right now so base.noncontent_width() is just borders + padding.
|
// Margins are 0 right now so base.noncontent_width() is just borders + padding.
|
||||||
let available_width = remaining_width - box.noncontent_width();
|
let available_width = remaining_width - box_.noncontent_width();
|
||||||
|
|
||||||
// Top and bottom margins for blocks are 0 if auto.
|
// Top and bottom margins for blocks are 0 if auto.
|
||||||
let margin_top = MaybeAuto::from_style(style.Margin.margin_top,
|
let margin_top = MaybeAuto::from_style(style.Margin.margin_top,
|
||||||
|
@ -631,25 +631,25 @@ impl Flow for BlockFlow {
|
||||||
remaining_width).specified_or_zero();
|
remaining_width).specified_or_zero();
|
||||||
|
|
||||||
let (width, margin_left, margin_right) = if self.is_float() {
|
let (width, margin_left, margin_right) = if self.is_float() {
|
||||||
self.compute_float_margins(box, remaining_width)
|
self.compute_float_margins(box_, remaining_width)
|
||||||
} else {
|
} else {
|
||||||
self.compute_block_margins(box, remaining_width, available_width)
|
self.compute_block_margins(box_, remaining_width, available_width)
|
||||||
};
|
};
|
||||||
|
|
||||||
box.margin.set(SideOffsets2D::new(margin_top,
|
box_.margin.set(SideOffsets2D::new(margin_top,
|
||||||
margin_right,
|
margin_right,
|
||||||
margin_bottom,
|
margin_bottom,
|
||||||
margin_left));
|
margin_left));
|
||||||
|
|
||||||
x_offset = box.offset();
|
x_offset = box_.offset();
|
||||||
remaining_width = width;
|
remaining_width = width;
|
||||||
|
|
||||||
// The associated box is the border box of this flow.
|
// The associated box is the border box of this flow.
|
||||||
let position_ref = box.position.mutate();
|
let mut position_ref = box_.position.borrow_mut();
|
||||||
position_ref.ptr.origin.x = box.margin.get().left;
|
position_ref.get().origin.x = box_.margin.get().left;
|
||||||
let padding_and_borders = box.padding.get().left + box.padding.get().right +
|
let padding_and_borders = box_.padding.get().left + box_.padding.get().right +
|
||||||
box.border.get().left + box.border.get().right;
|
box_.border.get().left + box_.border.get().right;
|
||||||
position_ref.ptr.size.width = remaining_width + padding_and_borders;
|
position_ref.get().size.width = remaining_width + padding_and_borders;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.is_float() {
|
if self.is_float() {
|
||||||
|
@ -722,24 +722,24 @@ impl Flow for BlockFlow {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for box in self.box.iter() {
|
for box_ in self.box_.iter() {
|
||||||
// The top margin collapses with its first in-flow block-level child's
|
// The top margin collapses with its first in-flow block-level child's
|
||||||
// top margin if the parent has no top border, no top padding.
|
// top margin if the parent has no top border, no top padding.
|
||||||
if *first_in_flow && top_margin_collapsible {
|
if *first_in_flow && top_margin_collapsible {
|
||||||
// If top-margin of parent is less than top-margin of its first child,
|
// If top-margin of parent is less than top-margin of its first child,
|
||||||
// the parent box goes down until its top is aligned with the child.
|
// the parent box goes down until its top is aligned with the child.
|
||||||
if *margin_top < box.margin.get().top {
|
if *margin_top < box_.margin.get().top {
|
||||||
// TODO: The position of child floats should be updated and this
|
// TODO: The position of child floats should be updated and this
|
||||||
// would influence clearance as well. See #725
|
// would influence clearance as well. See #725
|
||||||
let extra_margin = box.margin.get().top - *margin_top;
|
let extra_margin = box_.margin.get().top - *margin_top;
|
||||||
*top_offset = *top_offset + extra_margin;
|
*top_offset = *top_offset + extra_margin;
|
||||||
*margin_top = box.margin.get().top;
|
*margin_top = box_.margin.get().top;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// The bottom margin of an in-flow block-level element collapses
|
// The bottom margin of an in-flow block-level element collapses
|
||||||
// with the top margin of its next in-flow block-level sibling.
|
// with the top margin of its next in-flow block-level sibling.
|
||||||
*collapsing = geometry::min(box.margin.get().top, *collapsible);
|
*collapsing = geometry::min(box_.margin.get().top, *collapsible);
|
||||||
*collapsible = box.margin.get().bottom;
|
*collapsible = box_.margin.get().bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
*first_in_flow = false;
|
*first_in_flow = false;
|
||||||
|
@ -757,7 +757,7 @@ impl Flow for BlockFlow {
|
||||||
} else {
|
} else {
|
||||||
~"BlockFlow: "
|
~"BlockFlow: "
|
||||||
};
|
};
|
||||||
txt.append(match self.box {
|
txt.append(match self.box_ {
|
||||||
Some(ref rb) => rb.debug_str(),
|
Some(ref rb) => rb.debug_str(),
|
||||||
None => ~"",
|
None => ~"",
|
||||||
})
|
})
|
||||||
|
|
|
@ -22,9 +22,8 @@ use servo_net::local_image_cache::LocalImageCache;
|
||||||
use servo_util::geometry::Au;
|
use servo_util::geometry::Au;
|
||||||
use servo_util::geometry;
|
use servo_util::geometry;
|
||||||
use servo_util::range::*;
|
use servo_util::range::*;
|
||||||
use servo_util::slot::Slot;
|
|
||||||
use std::cast;
|
use std::cast;
|
||||||
use std::cell::Cell;
|
use std::cell::RefCell;
|
||||||
use std::cmp::ApproxEq;
|
use std::cmp::ApproxEq;
|
||||||
use std::num::Zero;
|
use std::num::Zero;
|
||||||
use style::{ComputedValues, TElement, TNode, cascade};
|
use style::{ComputedValues, TElement, TNode, cascade};
|
||||||
|
@ -71,24 +70,24 @@ pub struct Box {
|
||||||
style: Arc<ComputedValues>,
|
style: Arc<ComputedValues>,
|
||||||
|
|
||||||
/// The position of this box relative to its owning flow.
|
/// The position of this box relative to its owning flow.
|
||||||
position: Slot<Rect<Au>>,
|
position: RefCell<Rect<Au>>,
|
||||||
|
|
||||||
/// The border of the content box.
|
/// The border of the content box.
|
||||||
///
|
///
|
||||||
/// FIXME(pcwalton): This need not be stored in the box.
|
/// FIXME(pcwalton): This need not be stored in the box.
|
||||||
border: Slot<SideOffsets2D<Au>>,
|
border: RefCell<SideOffsets2D<Au>>,
|
||||||
|
|
||||||
/// The padding of the content box.
|
/// The padding of the content box.
|
||||||
padding: Slot<SideOffsets2D<Au>>,
|
padding: RefCell<SideOffsets2D<Au>>,
|
||||||
|
|
||||||
/// The margin of the content box.
|
/// The margin of the content box.
|
||||||
margin: Slot<SideOffsets2D<Au>>,
|
margin: RefCell<SideOffsets2D<Au>>,
|
||||||
|
|
||||||
/// Info specific to the kind of box. Keep this enum small.
|
/// Info specific to the kind of box. Keep this enum small.
|
||||||
specific: SpecificBoxInfo,
|
specific: SpecificBoxInfo,
|
||||||
|
|
||||||
/// positioned box offsets
|
/// positioned box offsets
|
||||||
position_offsets: Slot<SideOffsets2D<Au>>,
|
position_offsets: RefCell<SideOffsets2D<Au>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Info specific to the kind of box. Keep this enum small.
|
/// Info specific to the kind of box. Keep this enum small.
|
||||||
|
@ -105,7 +104,7 @@ pub enum SpecificBoxInfo {
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone)]
|
||||||
pub struct ImageBoxInfo {
|
pub struct ImageBoxInfo {
|
||||||
/// The image held within this box.
|
/// The image held within this box.
|
||||||
image: Slot<ImageHolder>,
|
image: RefCell<ImageHolder>,
|
||||||
/// The width attribute supplied by the DOM, if any.
|
/// The width attribute supplied by the DOM, if any.
|
||||||
dom_width: Option<Au>,
|
dom_width: Option<Au>,
|
||||||
/// The height attribute supplied by the DOM, if any.
|
/// The height attribute supplied by the DOM, if any.
|
||||||
|
@ -129,7 +128,7 @@ impl ImageBoxInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageBoxInfo {
|
ImageBoxInfo {
|
||||||
image: Slot::init(ImageHolder::new(image_url, local_image_cache)),
|
image: RefCell::new(ImageHolder::new(image_url, local_image_cache)),
|
||||||
dom_width: convert_length(node, "width"),
|
dom_width: convert_length(node, "width"),
|
||||||
dom_height: convert_length(node, "height"),
|
dom_height: convert_length(node, "height"),
|
||||||
}
|
}
|
||||||
|
@ -139,7 +138,8 @@ impl ImageBoxInfo {
|
||||||
fn image_width(&self) -> Au {
|
fn image_width(&self) -> Au {
|
||||||
// TODO(brson): Consult margins and borders?
|
// TODO(brson): Consult margins and borders?
|
||||||
self.dom_width.unwrap_or_else(|| {
|
self.dom_width.unwrap_or_else(|| {
|
||||||
Au::from_px(self.image.mutate().ptr.get_size().unwrap_or(Size2D(0, 0)).width)
|
let mut image_ref = self.image.borrow_mut();
|
||||||
|
Au::from_px(image_ref.get().get_size().unwrap_or(Size2D(0, 0)).width)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,7 +147,8 @@ impl ImageBoxInfo {
|
||||||
pub fn image_height(&self) -> Au {
|
pub fn image_height(&self) -> Au {
|
||||||
// TODO(brson): Consult margins and borders?
|
// TODO(brson): Consult margins and borders?
|
||||||
self.dom_height.unwrap_or_else(|| {
|
self.dom_height.unwrap_or_else(|| {
|
||||||
Au::from_px(self.image.mutate().ptr.get_size().unwrap_or(Size2D(0, 0)).height)
|
let mut image_ref = self.image.borrow_mut();
|
||||||
|
Au::from_px(image_ref.get().get_size().unwrap_or(Size2D(0, 0)).height)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -256,12 +257,12 @@ impl Box {
|
||||||
Box {
|
Box {
|
||||||
node: OpaqueNode::from_layout_node(&node),
|
node: OpaqueNode::from_layout_node(&node),
|
||||||
style: node_style,
|
style: node_style,
|
||||||
position: Slot::init(Au::zero_rect()),
|
position: RefCell::new(Au::zero_rect()),
|
||||||
border: Slot::init(Zero::zero()),
|
border: RefCell::new(Zero::zero()),
|
||||||
padding: Slot::init(Zero::zero()),
|
padding: RefCell::new(Zero::zero()),
|
||||||
margin: Slot::init(Zero::zero()),
|
margin: RefCell::new(Zero::zero()),
|
||||||
specific: specific,
|
specific: specific,
|
||||||
position_offsets: Slot::init(Zero::zero()),
|
position_offsets: RefCell::new(Zero::zero()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,12 +280,12 @@ impl Box {
|
||||||
Box {
|
Box {
|
||||||
node: self.node,
|
node: self.node,
|
||||||
style: self.style.clone(),
|
style: self.style.clone(),
|
||||||
position: Slot::init(Rect(self.position.get().origin, size)),
|
position: RefCell::new(Rect(self.position.get().origin, size)),
|
||||||
border: Slot::init(self.border.get()),
|
border: RefCell::new(self.border.get()),
|
||||||
padding: Slot::init(self.padding.get()),
|
padding: RefCell::new(self.padding.get()),
|
||||||
margin: Slot::init(self.margin.get()),
|
margin: RefCell::new(self.margin.get()),
|
||||||
specific: specific,
|
specific: specific,
|
||||||
position_offsets: Slot::init(Zero::zero())
|
position_offsets: RefCell::new(Zero::zero())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,11 +311,6 @@ impl Box {
|
||||||
self.border.get().left + self.border.get().right
|
self.border.get().left + self.border.get().right
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the size of this box.
|
|
||||||
fn set_size(&self, new_size: Size2D<Au>) {
|
|
||||||
self.position.set(Rect(self.position.get().origin, new_size))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn calculate_line_height(&self, font_size: Au) -> Au {
|
pub fn calculate_line_height(&self, font_size: Au) -> Au {
|
||||||
match self.line_height() {
|
match self.line_height() {
|
||||||
line_height::Normal => font_size.scale_by(1.14),
|
line_height::Normal => font_size.scale_by(1.14),
|
||||||
|
@ -408,11 +404,11 @@ impl Box {
|
||||||
debug!("(font style) start");
|
debug!("(font style) start");
|
||||||
|
|
||||||
// FIXME: Too much allocation here.
|
// FIXME: Too much allocation here.
|
||||||
let font_families = do my_style.Font.font_family.map |family| {
|
let font_families = my_style.Font.font_family.map(|family| {
|
||||||
match *family {
|
match *family {
|
||||||
font_family::FamilyName(ref name) => (*name).clone(),
|
font_family::FamilyName(ref name) => (*name).clone(),
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
debug!("(font style) font families: `{:?}`", font_families);
|
debug!("(font style) font families: `{:?}`", font_families);
|
||||||
|
|
||||||
let font_size = my_style.Font.font_size.to_f64().unwrap() / 60.0;
|
let font_size = my_style.Font.font_size.to_f64().unwrap() / 60.0;
|
||||||
|
@ -465,7 +461,7 @@ impl Box {
|
||||||
/// and so on.
|
/// and so on.
|
||||||
pub fn is_replaced(&self) -> bool {
|
pub fn is_replaced(&self) -> bool {
|
||||||
match self.specific {
|
match self.specific {
|
||||||
ImageBox(*) => true,
|
ImageBox(..) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -473,7 +469,7 @@ impl Box {
|
||||||
/// Returns true if this element can be split. This is true for text boxes.
|
/// Returns true if this element can be split. This is true for text boxes.
|
||||||
pub fn can_split(&self) -> bool {
|
pub fn can_split(&self) -> bool {
|
||||||
match self.specific {
|
match self.specific {
|
||||||
ScannedTextBox(*) => true,
|
ScannedTextBox(..) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -496,7 +492,7 @@ impl Box {
|
||||||
/// necessary.
|
/// necessary.
|
||||||
pub fn paint_background_if_applicable<E:ExtraDisplayListData>(
|
pub fn paint_background_if_applicable<E:ExtraDisplayListData>(
|
||||||
&self,
|
&self,
|
||||||
list: &Cell<DisplayList<E>>,
|
list: &RefCell<DisplayList<E>>,
|
||||||
absolute_bounds: &Rect<Au>) {
|
absolute_bounds: &Rect<Au>) {
|
||||||
// FIXME: This causes a lot of background colors to be displayed when they are clearly not
|
// FIXME: This causes a lot of background colors to be displayed when they are clearly not
|
||||||
// needed. We could use display list optimization to clean this up, but it still seems
|
// needed. We could use display list optimization to clean this up, but it still seems
|
||||||
|
@ -505,7 +501,7 @@ impl Box {
|
||||||
let style = self.style();
|
let style = self.style();
|
||||||
let background_color = style.resolve_color(style.Background.background_color);
|
let background_color = style.resolve_color(style.Background.background_color);
|
||||||
if !background_color.alpha.approx_eq(&0.0) {
|
if !background_color.alpha.approx_eq(&0.0) {
|
||||||
list.with_mut_ref(|list| {
|
list.with_mut(|list| {
|
||||||
let solid_color_display_item = ~SolidColorDisplayItem {
|
let solid_color_display_item = ~SolidColorDisplayItem {
|
||||||
base: BaseDisplayItem {
|
base: BaseDisplayItem {
|
||||||
bounds: *absolute_bounds,
|
bounds: *absolute_bounds,
|
||||||
|
@ -523,7 +519,7 @@ impl Box {
|
||||||
/// necessary.
|
/// necessary.
|
||||||
pub fn paint_borders_if_applicable<E:ExtraDisplayListData>(
|
pub fn paint_borders_if_applicable<E:ExtraDisplayListData>(
|
||||||
&self,
|
&self,
|
||||||
list: &Cell<DisplayList<E>>,
|
list: &RefCell<DisplayList<E>>,
|
||||||
abs_bounds: &Rect<Au>) {
|
abs_bounds: &Rect<Au>) {
|
||||||
// Fast path.
|
// Fast path.
|
||||||
let border = self.border.get();
|
let border = self.border.get();
|
||||||
|
@ -542,7 +538,7 @@ impl Box {
|
||||||
let left_style = style.Border.border_left_style;
|
let left_style = style.Border.border_left_style;
|
||||||
|
|
||||||
// Append the border to the display list.
|
// Append the border to the display list.
|
||||||
do list.with_mut_ref |list| {
|
list.with_mut(|list| {
|
||||||
let border_display_item = ~BorderDisplayItem {
|
let border_display_item = ~BorderDisplayItem {
|
||||||
base: BaseDisplayItem {
|
base: BaseDisplayItem {
|
||||||
bounds: *abs_bounds,
|
bounds: *abs_bounds,
|
||||||
|
@ -560,7 +556,7 @@ impl Box {
|
||||||
};
|
};
|
||||||
|
|
||||||
list.append_item(BorderDisplayItemClass(border_display_item))
|
list.append_item(BorderDisplayItemClass(border_display_item))
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds the display items for this box to the given display list.
|
/// Adds the display items for this box to the given display list.
|
||||||
|
@ -583,7 +579,7 @@ impl Box {
|
||||||
dirty: &Rect<Au>,
|
dirty: &Rect<Au>,
|
||||||
offset: Point2D<Au>,
|
offset: Point2D<Au>,
|
||||||
flow: &Flow,
|
flow: &Flow,
|
||||||
list: &Cell<DisplayList<E>>) {
|
list: &RefCell<DisplayList<E>>) {
|
||||||
let box_bounds = self.position.get();
|
let box_bounds = self.position.get();
|
||||||
let absolute_box_bounds = box_bounds.translate(&offset);
|
let absolute_box_bounds = box_bounds.translate(&offset);
|
||||||
debug!("Box::build_display_list at rel={}, abs={}: {:s}",
|
debug!("Box::build_display_list at rel={}, abs={}: {:s}",
|
||||||
|
@ -607,7 +603,7 @@ impl Box {
|
||||||
match self.specific {
|
match self.specific {
|
||||||
UnscannedTextBox(_) => fail!("Shouldn't see unscanned boxes here."),
|
UnscannedTextBox(_) => fail!("Shouldn't see unscanned boxes here."),
|
||||||
ScannedTextBox(ref text_box) => {
|
ScannedTextBox(ref text_box) => {
|
||||||
do list.with_mut_ref |list| {
|
list.with_mut(|list| {
|
||||||
let item = ~ClipDisplayItem {
|
let item = ~ClipDisplayItem {
|
||||||
base: BaseDisplayItem {
|
base: BaseDisplayItem {
|
||||||
bounds: absolute_box_bounds,
|
bounds: absolute_box_bounds,
|
||||||
|
@ -617,7 +613,7 @@ impl Box {
|
||||||
need_clip: false
|
need_clip: false
|
||||||
};
|
};
|
||||||
list.append_item(ClipDisplayItemClass(item));
|
list.append_item(ClipDisplayItemClass(item));
|
||||||
}
|
});
|
||||||
|
|
||||||
let color = self.style().Color.color.to_gfx_color();
|
let color = self.style().Color.color.to_gfx_color();
|
||||||
|
|
||||||
|
@ -629,7 +625,7 @@ impl Box {
|
||||||
text_flags.set_override_line_through(flow_flags.override_line_through());
|
text_flags.set_override_line_through(flow_flags.override_line_through());
|
||||||
|
|
||||||
// Create the text box.
|
// Create the text box.
|
||||||
do list.with_mut_ref |list| {
|
list.with_mut(|list| {
|
||||||
let text_display_item = ~TextDisplayItem {
|
let text_display_item = ~TextDisplayItem {
|
||||||
base: BaseDisplayItem {
|
base: BaseDisplayItem {
|
||||||
bounds: absolute_box_bounds,
|
bounds: absolute_box_bounds,
|
||||||
|
@ -642,7 +638,7 @@ impl Box {
|
||||||
};
|
};
|
||||||
|
|
||||||
list.append_item(TextDisplayItemClass(text_display_item))
|
list.append_item(TextDisplayItemClass(text_display_item))
|
||||||
}
|
});
|
||||||
|
|
||||||
// Draw debug frames for text bounds.
|
// Draw debug frames for text bounds.
|
||||||
//
|
//
|
||||||
|
@ -652,7 +648,7 @@ impl Box {
|
||||||
// Compute the text box bounds and draw a border surrounding them.
|
// Compute the text box bounds and draw a border surrounding them.
|
||||||
let debug_border = SideOffsets2D::new_all_same(Au::from_px(1));
|
let debug_border = SideOffsets2D::new_all_same(Au::from_px(1));
|
||||||
|
|
||||||
do list.with_mut_ref |list| {
|
list.with_mut(|list| {
|
||||||
let border_display_item = ~BorderDisplayItem {
|
let border_display_item = ~BorderDisplayItem {
|
||||||
base: BaseDisplayItem {
|
base: BaseDisplayItem {
|
||||||
bounds: absolute_box_bounds,
|
bounds: absolute_box_bounds,
|
||||||
|
@ -664,7 +660,7 @@ impl Box {
|
||||||
|
|
||||||
};
|
};
|
||||||
list.append_item(BorderDisplayItemClass(border_display_item))
|
list.append_item(BorderDisplayItemClass(border_display_item))
|
||||||
}
|
});
|
||||||
|
|
||||||
// Draw a rectangle representing the baselines.
|
// Draw a rectangle representing the baselines.
|
||||||
//
|
//
|
||||||
|
@ -674,7 +670,7 @@ impl Box {
|
||||||
let baseline = Rect(absolute_box_bounds.origin + Point2D(Au(0), ascent),
|
let baseline = Rect(absolute_box_bounds.origin + Point2D(Au(0), ascent),
|
||||||
Size2D(absolute_box_bounds.size.width, Au(0)));
|
Size2D(absolute_box_bounds.size.width, Au(0)));
|
||||||
|
|
||||||
do list.with_mut_ref |list| {
|
list.with_mut(|list| {
|
||||||
let border_display_item = ~BorderDisplayItem {
|
let border_display_item = ~BorderDisplayItem {
|
||||||
base: BaseDisplayItem {
|
base: BaseDisplayItem {
|
||||||
bounds: baseline,
|
bounds: baseline,
|
||||||
|
@ -686,13 +682,11 @@ impl Box {
|
||||||
|
|
||||||
};
|
};
|
||||||
list.append_item(BorderDisplayItemClass(border_display_item))
|
list.append_item(BorderDisplayItemClass(border_display_item))
|
||||||
}
|
});
|
||||||
|
|
||||||
()
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
GenericBox | IframeBox(_) => {
|
GenericBox | IframeBox(..) => {
|
||||||
do list.with_mut_ref |list| {
|
list.with_mut(|list| {
|
||||||
let item = ~ClipDisplayItem {
|
let item = ~ClipDisplayItem {
|
||||||
base: BaseDisplayItem {
|
base: BaseDisplayItem {
|
||||||
bounds: absolute_box_bounds,
|
bounds: absolute_box_bounds,
|
||||||
|
@ -702,14 +696,14 @@ impl Box {
|
||||||
need_clip: self.needs_clip()
|
need_clip: self.needs_clip()
|
||||||
};
|
};
|
||||||
list.append_item(ClipDisplayItemClass(item));
|
list.append_item(ClipDisplayItemClass(item));
|
||||||
}
|
});
|
||||||
|
|
||||||
// FIXME(pcwalton): This is a bit of an abuse of the logging infrastructure. We
|
// FIXME(pcwalton): This is a bit of an abuse of the logging infrastructure. We
|
||||||
// should have a real `SERVO_DEBUG` system.
|
// should have a real `SERVO_DEBUG` system.
|
||||||
debug!("{:?}", {
|
debug!("{:?}", {
|
||||||
let debug_border = SideOffsets2D::new_all_same(Au::from_px(1));
|
let debug_border = SideOffsets2D::new_all_same(Au::from_px(1));
|
||||||
|
|
||||||
do list.with_mut_ref |list| {
|
list.with_mut(|list| {
|
||||||
let border_display_item = ~BorderDisplayItem {
|
let border_display_item = ~BorderDisplayItem {
|
||||||
base: BaseDisplayItem {
|
base: BaseDisplayItem {
|
||||||
bounds: absolute_box_bounds,
|
bounds: absolute_box_bounds,
|
||||||
|
@ -721,13 +715,11 @@ impl Box {
|
||||||
|
|
||||||
};
|
};
|
||||||
list.append_item(BorderDisplayItemClass(border_display_item))
|
list.append_item(BorderDisplayItemClass(border_display_item))
|
||||||
}
|
});
|
||||||
|
|
||||||
()
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
ImageBox(ref image_box) => {
|
ImageBox(ref image_box) => {
|
||||||
do list.with_mut_ref |list| {
|
list.with_mut(|list| {
|
||||||
let item = ~ClipDisplayItem {
|
let item = ~ClipDisplayItem {
|
||||||
base: BaseDisplayItem {
|
base: BaseDisplayItem {
|
||||||
bounds: absolute_box_bounds,
|
bounds: absolute_box_bounds,
|
||||||
|
@ -737,14 +729,15 @@ impl Box {
|
||||||
need_clip: false
|
need_clip: false
|
||||||
};
|
};
|
||||||
list.append_item(ClipDisplayItemClass(item));
|
list.append_item(ClipDisplayItemClass(item));
|
||||||
}
|
});
|
||||||
|
|
||||||
match image_box.image.mutate().ptr.get_image() {
|
let mut image_ref = image_box.image.borrow_mut();
|
||||||
|
match image_ref.get().get_image() {
|
||||||
Some(image) => {
|
Some(image) => {
|
||||||
debug!("(building display list) building image box");
|
debug!("(building display list) building image box");
|
||||||
|
|
||||||
// Place the image into the display list.
|
// Place the image into the display list.
|
||||||
do list.with_mut_ref |list| {
|
list.with_mut(|list| {
|
||||||
let image_display_item = ~ImageDisplayItem {
|
let image_display_item = ~ImageDisplayItem {
|
||||||
base: BaseDisplayItem {
|
base: BaseDisplayItem {
|
||||||
bounds: absolute_box_bounds,
|
bounds: absolute_box_bounds,
|
||||||
|
@ -752,8 +745,8 @@ impl Box {
|
||||||
},
|
},
|
||||||
image: image.clone(),
|
image: image.clone(),
|
||||||
};
|
};
|
||||||
list.append_item(ImageDisplayItemClass(image_display_item))
|
list.append_item(ImageDisplayItemClass(image_display_item));
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
// No image data at all? Do nothing.
|
// No image data at all? Do nothing.
|
||||||
|
@ -809,7 +802,7 @@ impl Box {
|
||||||
|
|
||||||
(min_line_width, max_line_width)
|
(min_line_width, max_line_width)
|
||||||
}
|
}
|
||||||
UnscannedTextBox(*) => fail!("Unscanned text boxes should have been scanned by now!"),
|
UnscannedTextBox(..) => fail!("Unscanned text boxes should have been scanned by now!"),
|
||||||
};
|
};
|
||||||
(guessed_width + additional_minimum, guessed_width + additional_preferred)
|
(guessed_width + additional_minimum, guessed_width + additional_preferred)
|
||||||
}
|
}
|
||||||
|
@ -822,11 +815,12 @@ impl Box {
|
||||||
match self.specific {
|
match self.specific {
|
||||||
GenericBox | IframeBox(_) => Au(0),
|
GenericBox | IframeBox(_) => Au(0),
|
||||||
ImageBox(ref image_box_info) => {
|
ImageBox(ref image_box_info) => {
|
||||||
let size = image_box_info.image.mutate().ptr.get_size();
|
let mut image_ref = image_box_info.image.borrow_mut();
|
||||||
|
let size = image_ref.get().get_size();
|
||||||
let height = Au::from_px(size.unwrap_or(Size2D(0, 0)).height);
|
let height = Au::from_px(size.unwrap_or(Size2D(0, 0)).height);
|
||||||
|
|
||||||
// Eww. Refactor this.
|
// Eww. Refactor this.
|
||||||
self.position.mutate().ptr.size.height = height;
|
self.position.borrow_mut().get().size.height = height;
|
||||||
debug!("box_height: found image height: {}", height);
|
debug!("box_height: found image height: {}", height);
|
||||||
|
|
||||||
height
|
height
|
||||||
|
@ -955,11 +949,11 @@ impl Box {
|
||||||
match self.specific {
|
match self.specific {
|
||||||
GenericBox | IframeBox(_) => {
|
GenericBox | IframeBox(_) => {
|
||||||
// FIXME(pcwalton): This seems clownshoes; can we remove?
|
// FIXME(pcwalton): This seems clownshoes; can we remove?
|
||||||
self.position.mutate().ptr.size.width = Au::from_px(45)
|
self.position.borrow_mut().get().size.width = Au::from_px(45)
|
||||||
}
|
}
|
||||||
ImageBox(ref image_box_info) => {
|
ImageBox(ref image_box_info) => {
|
||||||
let image_width = image_box_info.image_width();
|
let image_width = image_box_info.image_width();
|
||||||
self.position.mutate().ptr.size.width = image_width
|
self.position.borrow_mut().get().size.width = image_width
|
||||||
}
|
}
|
||||||
ScannedTextBox(_) => {
|
ScannedTextBox(_) => {
|
||||||
// Scanned text boxes will have already had their widths assigned by this point.
|
// Scanned text boxes will have already had their widths assigned by this point.
|
|
@ -22,8 +22,8 @@
|
||||||
|
|
||||||
use css::node_style::StyledNode;
|
use css::node_style::StyledNode;
|
||||||
use layout::block::BlockFlow;
|
use layout::block::BlockFlow;
|
||||||
use layout::box::{Box, GenericBox, IframeBox, IframeBoxInfo, ImageBox, ImageBoxInfo};
|
use layout::box_::{Box, GenericBox, IframeBox, IframeBoxInfo, ImageBox, ImageBoxInfo};
|
||||||
use layout::box::{UnscannedTextBox, UnscannedTextBoxInfo};
|
use layout::box_::{UnscannedTextBox, UnscannedTextBoxInfo};
|
||||||
use layout::context::LayoutContext;
|
use layout::context::LayoutContext;
|
||||||
use layout::float_context::FloatType;
|
use layout::float_context::FloatType;
|
||||||
use layout::flow::{Flow, FlowData, MutableFlowUtils};
|
use layout::flow::{Flow, FlowData, MutableFlowUtils};
|
||||||
|
@ -35,10 +35,11 @@ use layout::wrapper::{LayoutNode, PostorderNodeMutTraversal};
|
||||||
use script::dom::element::{HTMLIframeElementTypeId, HTMLImageElementTypeId};
|
use script::dom::element::{HTMLIframeElementTypeId, HTMLImageElementTypeId};
|
||||||
use script::dom::node::{CommentNodeTypeId, DoctypeNodeTypeId, DocumentFragmentNodeTypeId};
|
use script::dom::node::{CommentNodeTypeId, DoctypeNodeTypeId, DocumentFragmentNodeTypeId};
|
||||||
use script::dom::node::{DocumentNodeTypeId, ElementNodeTypeId, TextNodeTypeId};
|
use script::dom::node::{DocumentNodeTypeId, ElementNodeTypeId, TextNodeTypeId};
|
||||||
use servo_util::slot::Slot;
|
|
||||||
use std::util;
|
|
||||||
use style::computed_values::{display, float};
|
use style::computed_values::{display, float};
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::util;
|
||||||
|
|
||||||
/// The results of flow construction for a DOM node.
|
/// The results of flow construction for a DOM node.
|
||||||
pub enum ConstructionResult {
|
pub enum ConstructionResult {
|
||||||
/// This node contributes nothing at all (`display: none`). Alternately, this is what newly
|
/// This node contributes nothing at all (`display: none`). Alternately, this is what newly
|
||||||
|
@ -47,7 +48,7 @@ pub enum ConstructionResult {
|
||||||
|
|
||||||
/// This node contributed a flow at the proper position in the tree. Nothing more needs to be
|
/// This node contributed a flow at the proper position in the tree. Nothing more needs to be
|
||||||
/// done for this node.
|
/// done for this node.
|
||||||
FlowConstructionResult(~Flow:),
|
FlowConstructionResult(~Flow),
|
||||||
|
|
||||||
/// This node contributed some object or objects that will be needed to construct a proper flow
|
/// This node contributed some object or objects that will be needed to construct a proper flow
|
||||||
/// later up the tree, but these objects have not yet found their home.
|
/// later up the tree, but these objects have not yet found their home.
|
||||||
|
@ -102,7 +103,7 @@ struct InlineBlockSplit {
|
||||||
predecessor_boxes: ~[Box],
|
predecessor_boxes: ~[Box],
|
||||||
|
|
||||||
/// The flow that caused this {ib} split.
|
/// The flow that caused this {ib} split.
|
||||||
flow: ~Flow:,
|
flow: ~Flow,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Methods on optional vectors.
|
/// Methods on optional vectors.
|
||||||
|
@ -169,24 +170,24 @@ impl<T> OptVector<T> for Option<~[T]> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An object that knows how to create flows.
|
/// An object that knows how to create flows.
|
||||||
pub struct FlowConstructor<'self> {
|
pub struct FlowConstructor<'a> {
|
||||||
/// The layout context.
|
/// The layout context.
|
||||||
///
|
///
|
||||||
/// FIXME(pcwalton): Why does this contain `@`??? That destroys parallelism!!!
|
/// FIXME(pcwalton): Why does this contain `@`??? That destroys parallelism!!!
|
||||||
layout_context: &'self mut LayoutContext,
|
layout_context: &'a mut LayoutContext,
|
||||||
|
|
||||||
/// The next flow ID to assign.
|
/// The next flow ID to assign.
|
||||||
///
|
///
|
||||||
/// FIXME(pcwalton): This is going to have to be atomic; can't we do something better?
|
/// FIXME(pcwalton): This is going to have to be atomic; can't we do something better?
|
||||||
next_flow_id: Slot<int>,
|
next_flow_id: RefCell<int>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> FlowConstructor<'self> {
|
impl<'fc> FlowConstructor<'fc> {
|
||||||
/// Creates a new flow constructor.
|
/// Creates a new flow constructor.
|
||||||
pub fn init<'a>(layout_context: &'a mut LayoutContext) -> FlowConstructor<'a> {
|
pub fn init<'a>(layout_context: &'a mut LayoutContext) -> FlowConstructor<'a> {
|
||||||
FlowConstructor {
|
FlowConstructor {
|
||||||
layout_context: layout_context,
|
layout_context: layout_context,
|
||||||
next_flow_id: Slot::init(0),
|
next_flow_id: RefCell::new(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,10 +232,10 @@ impl<'self> FlowConstructor<'self> {
|
||||||
/// `#[inline(always)]` because this is performance critical and LLVM will not inline it
|
/// `#[inline(always)]` because this is performance critical and LLVM will not inline it
|
||||||
/// otherwise.
|
/// otherwise.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn flush_inline_boxes_to_flow(&mut self, boxes: ~[Box], flow: &mut ~Flow:, node: LayoutNode) {
|
fn flush_inline_boxes_to_flow(&mut self, boxes: ~[Box], flow: &mut ~Flow, node: LayoutNode) {
|
||||||
if boxes.len() > 0 {
|
if boxes.len() > 0 {
|
||||||
let inline_base = FlowData::new(self.next_flow_id(), node);
|
let inline_base = FlowData::new(self.next_flow_id(), node);
|
||||||
let mut inline_flow = ~InlineFlow::from_boxes(inline_base, boxes) as ~Flow:;
|
let mut inline_flow = ~InlineFlow::from_boxes(inline_base, boxes) as ~Flow;
|
||||||
TextRunScanner::new().scan_for_runs(self.layout_context, inline_flow);
|
TextRunScanner::new().scan_for_runs(self.layout_context, inline_flow);
|
||||||
flow.add_new_child(inline_flow)
|
flow.add_new_child(inline_flow)
|
||||||
}
|
}
|
||||||
|
@ -244,7 +245,7 @@ impl<'self> FlowConstructor<'self> {
|
||||||
/// the given flow.
|
/// the given flow.
|
||||||
fn flush_inline_boxes_to_flow_if_necessary(&mut self,
|
fn flush_inline_boxes_to_flow_if_necessary(&mut self,
|
||||||
opt_boxes: &mut Option<~[Box]>,
|
opt_boxes: &mut Option<~[Box]>,
|
||||||
flow: &mut ~Flow:,
|
flow: &mut ~Flow,
|
||||||
node: LayoutNode) {
|
node: LayoutNode) {
|
||||||
let opt_boxes = util::replace(opt_boxes, None);
|
let opt_boxes = util::replace(opt_boxes, None);
|
||||||
if opt_boxes.len() > 0 {
|
if opt_boxes.len() > 0 {
|
||||||
|
@ -256,7 +257,7 @@ impl<'self> FlowConstructor<'self> {
|
||||||
/// other `BlockFlow`s or `InlineFlow`s will be populated underneath this node, depending on
|
/// other `BlockFlow`s or `InlineFlow`s will be populated underneath this node, depending on
|
||||||
/// whether {ib} splits needed to happen.
|
/// whether {ib} splits needed to happen.
|
||||||
fn build_children_of_block_flow(&mut self,
|
fn build_children_of_block_flow(&mut self,
|
||||||
flow: &mut ~Flow:,
|
flow: &mut ~Flow,
|
||||||
node: LayoutNode) {
|
node: LayoutNode) {
|
||||||
// Gather up boxes for the inline flows we might need to create.
|
// Gather up boxes for the inline flows we might need to create.
|
||||||
let mut opt_boxes_for_inline_flow = None;
|
let mut opt_boxes_for_inline_flow = None;
|
||||||
|
@ -342,10 +343,10 @@ impl<'self> FlowConstructor<'self> {
|
||||||
/// Builds a flow for a node with `display: block`. This yields a `BlockFlow` with possibly
|
/// Builds a flow for a node with `display: block`. This yields a `BlockFlow` with possibly
|
||||||
/// other `BlockFlow`s or `InlineFlow`s underneath it, depending on whether {ib} splits needed
|
/// other `BlockFlow`s or `InlineFlow`s underneath it, depending on whether {ib} splits needed
|
||||||
/// to happen.
|
/// to happen.
|
||||||
fn build_flow_for_block(&mut self, node: LayoutNode) -> ~Flow: {
|
fn build_flow_for_block(&mut self, node: LayoutNode) -> ~Flow {
|
||||||
let base = FlowData::new(self.next_flow_id(), node);
|
let base = FlowData::new(self.next_flow_id(), node);
|
||||||
let box = self.build_box_for_node(node);
|
let box_ = self.build_box_for_node(node);
|
||||||
let mut flow = ~BlockFlow::from_box(base, box) as ~Flow:;
|
let mut flow = ~BlockFlow::from_box(base, box_) as ~Flow;
|
||||||
self.build_children_of_block_flow(&mut flow, node);
|
self.build_children_of_block_flow(&mut flow, node);
|
||||||
flow
|
flow
|
||||||
}
|
}
|
||||||
|
@ -353,10 +354,10 @@ impl<'self> FlowConstructor<'self> {
|
||||||
/// Builds the flow for a node with `float: {left|right}`. This yields a float `BlockFlow` with
|
/// Builds the flow for a node with `float: {left|right}`. This yields a float `BlockFlow` with
|
||||||
/// a `BlockFlow` underneath it.
|
/// a `BlockFlow` underneath it.
|
||||||
fn build_flow_for_floated_block(&mut self, node: LayoutNode, float_type: FloatType)
|
fn build_flow_for_floated_block(&mut self, node: LayoutNode, float_type: FloatType)
|
||||||
-> ~Flow: {
|
-> ~Flow {
|
||||||
let base = FlowData::new(self.next_flow_id(), node);
|
let base = FlowData::new(self.next_flow_id(), node);
|
||||||
let box = self.build_box_for_node(node);
|
let box_ = self.build_box_for_node(node);
|
||||||
let mut flow = ~BlockFlow::float_from_box(base, float_type, box) as ~Flow:;
|
let mut flow = ~BlockFlow::float_from_box(base, float_type, box_) as ~Flow;
|
||||||
self.build_children_of_block_flow(&mut flow, node);
|
self.build_children_of_block_flow(&mut flow, node);
|
||||||
flow
|
flow
|
||||||
}
|
}
|
||||||
|
@ -458,7 +459,7 @@ impl<'self> FlowConstructor<'self> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> PostorderNodeMutTraversal for FlowConstructor<'self> {
|
impl<'a> PostorderNodeMutTraversal for FlowConstructor<'a> {
|
||||||
// `#[inline(always)]` because this is always called from the traversal function and for some
|
// `#[inline(always)]` because this is always called from the traversal function and for some
|
||||||
// reason LLVM's inlining heuristics go awry here.
|
// reason LLVM's inlining heuristics go awry here.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -528,7 +529,7 @@ trait NodeUtils {
|
||||||
fn swap_out_construction_result(self) -> ConstructionResult;
|
fn swap_out_construction_result(self) -> ConstructionResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> NodeUtils for LayoutNode<'self> {
|
impl<'ln> NodeUtils for LayoutNode<'ln> {
|
||||||
fn is_replaced_content(self) -> bool {
|
fn is_replaced_content(self) -> bool {
|
||||||
match self.type_id() {
|
match self.type_id() {
|
||||||
TextNodeTypeId |
|
TextNodeTypeId |
|
||||||
|
@ -543,17 +544,19 @@ impl<'self> NodeUtils for LayoutNode<'self> {
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn set_flow_construction_result(self, result: ConstructionResult) {
|
fn set_flow_construction_result(self, result: ConstructionResult) {
|
||||||
match *self.mutate_layout_data().ptr {
|
let mut layout_data_ref = self.mutate_layout_data();
|
||||||
Some(ref mut layout_data) => layout_data.flow_construction_result = result,
|
match *layout_data_ref.get() {
|
||||||
|
Some(ref mut layout_data) => layout_data.data.flow_construction_result = result,
|
||||||
None => fail!("no layout data"),
|
None => fail!("no layout data"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn swap_out_construction_result(self) -> ConstructionResult {
|
fn swap_out_construction_result(self) -> ConstructionResult {
|
||||||
match *self.mutate_layout_data().ptr {
|
let mut layout_data_ref = self.mutate_layout_data();
|
||||||
|
match *layout_data_ref.get() {
|
||||||
Some(ref mut layout_data) => {
|
Some(ref mut layout_data) => {
|
||||||
util::replace(&mut layout_data.flow_construction_result, NoConstructionResult)
|
util::replace(&mut layout_data.data.flow_construction_result, NoConstructionResult)
|
||||||
}
|
}
|
||||||
None => fail!("no layout data"),
|
None => fail!("no layout data"),
|
||||||
}
|
}
|
||||||
|
@ -568,14 +571,14 @@ fn strip_ignorable_whitespace_from_start(opt_boxes: &mut Option<~[Box]>) {
|
||||||
// FIXME(pcwalton): This is slow because vector shift is broken. :(
|
// FIXME(pcwalton): This is slow because vector shift is broken. :(
|
||||||
let mut found_nonwhitespace = false;
|
let mut found_nonwhitespace = false;
|
||||||
let mut result = ~[];
|
let mut result = ~[];
|
||||||
for box in boxes.move_iter() {
|
for box_ in boxes.move_iter() {
|
||||||
if !found_nonwhitespace && box.is_whitespace_only() {
|
if !found_nonwhitespace && box_.is_whitespace_only() {
|
||||||
debug!("stripping ignorable whitespace from start");
|
debug!("stripping ignorable whitespace from start");
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
found_nonwhitespace = true;
|
found_nonwhitespace = true;
|
||||||
result.push(box)
|
result.push(box_)
|
||||||
}
|
}
|
||||||
|
|
||||||
*opt_boxes = Some(result)
|
*opt_boxes = Some(result)
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
//! Constructs display lists from boxes.
|
//! Constructs display lists from boxes.
|
||||||
|
|
||||||
use layout::box::Box;
|
use layout::box_::Box;
|
||||||
use layout::context::LayoutContext;
|
use layout::context::LayoutContext;
|
||||||
use layout::util::OpaqueNode;
|
use layout::util::OpaqueNode;
|
||||||
|
|
||||||
|
@ -12,14 +12,14 @@ use gfx;
|
||||||
use style;
|
use style;
|
||||||
|
|
||||||
pub trait ExtraDisplayListData {
|
pub trait ExtraDisplayListData {
|
||||||
fn new(box: &Box) -> Self;
|
fn new(box_: &Box) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Nothing = ();
|
pub type Nothing = ();
|
||||||
|
|
||||||
impl ExtraDisplayListData for OpaqueNode {
|
impl ExtraDisplayListData for OpaqueNode {
|
||||||
fn new(box: &Box) -> OpaqueNode {
|
fn new(box_: &Box) -> OpaqueNode {
|
||||||
box.node
|
box_.node
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,8 +35,8 @@ impl ExtraDisplayListData for Nothing {
|
||||||
///
|
///
|
||||||
/// Right now, the builder isn't used for much, but it establishes the pattern we'll need once we
|
/// Right now, the builder isn't used for much, but it establishes the pattern we'll need once we
|
||||||
/// support display-list-based hit testing and so forth.
|
/// support display-list-based hit testing and so forth.
|
||||||
pub struct DisplayListBuilder<'self> {
|
pub struct DisplayListBuilder<'a> {
|
||||||
ctx: &'self LayoutContext,
|
ctx: &'a LayoutContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
|
@ -4,33 +4,39 @@
|
||||||
|
|
||||||
//! Code for managing the layout data in the DOM.
|
//! Code for managing the layout data in the DOM.
|
||||||
|
|
||||||
use layout::util::{LayoutData, LayoutDataAccess};
|
use layout::util::{PrivateLayoutData, LayoutDataAccess, LayoutDataWrapper};
|
||||||
use layout::wrapper::LayoutNode;
|
use layout::wrapper::LayoutNode;
|
||||||
|
use script::layout_interface::LayoutChan;
|
||||||
|
|
||||||
/// Functionality useful for querying the layout-specific data on DOM nodes.
|
/// Functionality useful for querying the layout-specific data on DOM nodes.
|
||||||
pub trait LayoutAuxMethods {
|
pub trait LayoutAuxMethods {
|
||||||
fn initialize_layout_data(self);
|
fn initialize_layout_data(self, chan: LayoutChan);
|
||||||
fn initialize_style_for_subtree(self);
|
fn initialize_style_for_subtree(self, chan: LayoutChan);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> LayoutAuxMethods for LayoutNode<'self> {
|
impl<'ln> LayoutAuxMethods for LayoutNode<'ln> {
|
||||||
/// Resets layout data and styles for the node.
|
/// Resets layout data and styles for the node.
|
||||||
///
|
///
|
||||||
/// FIXME(pcwalton): Do this as part of box building instead of in a traversal.
|
/// FIXME(pcwalton): Do this as part of box building instead of in a traversal.
|
||||||
fn initialize_layout_data(self) {
|
fn initialize_layout_data(self, chan: LayoutChan) {
|
||||||
let layout_data_handle = self.mutate_layout_data();
|
let mut layout_data_ref = self.mutate_layout_data();
|
||||||
match *layout_data_handle.ptr {
|
match *layout_data_ref.get() {
|
||||||
None => *layout_data_handle.ptr = Some(~LayoutData::new()),
|
None => {
|
||||||
|
*layout_data_ref.get() = Some(LayoutDataWrapper {
|
||||||
|
chan: Some(chan),
|
||||||
|
data: ~PrivateLayoutData::new(),
|
||||||
|
});
|
||||||
|
}
|
||||||
Some(_) => {}
|
Some(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resets layout data and styles for a Node tree.
|
/// Resets layout data and styles for a Node tree.
|
||||||
///
|
///
|
||||||
/// FIXME(pcwalton): Do this as part of box building instead of in a traversal.
|
/// FIXME(pcwalton): Do this as part of box building instead of in a traversal.
|
||||||
fn initialize_style_for_subtree(self) {
|
fn initialize_style_for_subtree(self, chan: LayoutChan) {
|
||||||
for n in self.traverse_preorder() {
|
for n in self.traverse_preorder() {
|
||||||
n.initialize_layout_data();
|
n.initialize_layout_data(chan.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ impl FloatContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn with_mut_base<R>(&mut self, callback: &fn(&mut FloatContextBase) -> R) -> R {
|
fn with_mut_base<R>(&mut self, callback: |&mut FloatContextBase| -> R) -> R {
|
||||||
match *self {
|
match *self {
|
||||||
Invalid => fail!("Float context no longer available"),
|
Invalid => fail!("Float context no longer available"),
|
||||||
Valid(ref mut base) => callback(&mut *base)
|
Valid(ref mut base) => callback(&mut *base)
|
||||||
|
@ -85,7 +85,7 @@ impl FloatContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn with_base<R>(&self, callback: &fn(&FloatContextBase) -> R) -> R {
|
pub fn with_base<R>(&self, callback: |&FloatContextBase| -> R) -> R {
|
||||||
match *self {
|
match *self {
|
||||||
Invalid => fail!("Float context no longer available"),
|
Invalid => fail!("Float context no longer available"),
|
||||||
Valid(ref base) => callback(&*base)
|
Valid(ref base) => callback(&*base)
|
||||||
|
@ -94,46 +94,46 @@ impl FloatContext {
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn translate(&mut self, trans: Point2D<Au>) -> FloatContext {
|
pub fn translate(&mut self, trans: Point2D<Au>) -> FloatContext {
|
||||||
do self.with_mut_base |base| {
|
self.with_mut_base(|base| {
|
||||||
base.translate(trans);
|
base.translate(trans);
|
||||||
}
|
});
|
||||||
replace(self, Invalid)
|
replace(self, Invalid)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn available_rect(&mut self, top: Au, height: Au, max_x: Au) -> Option<Rect<Au>> {
|
pub fn available_rect(&mut self, top: Au, height: Au, max_x: Au) -> Option<Rect<Au>> {
|
||||||
do self.with_base |base| {
|
self.with_base(|base| {
|
||||||
base.available_rect(top, height, max_x)
|
base.available_rect(top, height, max_x)
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn add_float(&mut self, info: &PlacementInfo) -> FloatContext{
|
pub fn add_float(&mut self, info: &PlacementInfo) -> FloatContext{
|
||||||
do self.with_mut_base |base| {
|
self.with_mut_base(|base| {
|
||||||
base.add_float(info);
|
base.add_float(info);
|
||||||
}
|
});
|
||||||
replace(self, Invalid)
|
replace(self, Invalid)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn place_between_floats(&self, info: &PlacementInfo) -> Rect<Au> {
|
pub fn place_between_floats(&self, info: &PlacementInfo) -> Rect<Au> {
|
||||||
do self.with_base |base| {
|
self.with_base(|base| {
|
||||||
base.place_between_floats(info)
|
base.place_between_floats(info)
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn last_float_pos(&mut self) -> Point2D<Au> {
|
pub fn last_float_pos(&mut self) -> Point2D<Au> {
|
||||||
do self.with_base |base| {
|
self.with_base(|base| {
|
||||||
base.last_float_pos()
|
base.last_float_pos()
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn clearance(&self, clear: ClearType) -> Au {
|
pub fn clearance(&self, clear: ClearType) -> Au {
|
||||||
do self.with_base |base| {
|
self.with_base(|base| {
|
||||||
base.clearance(clear)
|
base.clearance(clear)
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,24 +288,6 @@ impl FloatContextBase {
|
||||||
self.floats_used += 1;
|
self.floats_used += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the given rect overlaps with any floats.
|
|
||||||
fn collides_with_float(&self, bounds: &Rect<Au>) -> bool {
|
|
||||||
for floats in self.float_data.iter() {
|
|
||||||
for float in floats.iter() {
|
|
||||||
match *float {
|
|
||||||
None => (),
|
|
||||||
Some(data) => {
|
|
||||||
if data.bounds.translate(&self.offset).intersects(bounds) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Given the top 3 sides of the rectange, finds the largest height that
|
/// Given the top 3 sides of the rectange, finds the largest height that
|
||||||
/// will result in the rectange not colliding with any floats. Returns
|
/// will result in the rectange not colliding with any floats. Returns
|
||||||
/// None if that height is infinite.
|
/// None if that height is infinite.
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
|
|
||||||
use css::node_style::StyledNode;
|
use css::node_style::StyledNode;
|
||||||
use layout::block::BlockFlow;
|
use layout::block::BlockFlow;
|
||||||
use layout::box::Box;
|
use layout::box_::Box;
|
||||||
use layout::context::LayoutContext;
|
use layout::context::LayoutContext;
|
||||||
use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData};
|
use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData};
|
||||||
use layout::float_context::{FloatContext, Invalid};
|
use layout::float_context::{FloatContext, Invalid};
|
||||||
|
@ -42,7 +42,7 @@ use geom::rect::Rect;
|
||||||
use gfx::display_list::{ClipDisplayItemClass, DisplayList};
|
use gfx::display_list::{ClipDisplayItemClass, DisplayList};
|
||||||
use servo_util::geometry::Au;
|
use servo_util::geometry::Au;
|
||||||
use std::cast;
|
use std::cast;
|
||||||
use std::cell::Cell;
|
use std::cell::RefCell;
|
||||||
use style::ComputedValues;
|
use style::ComputedValues;
|
||||||
use style::computed_values::text_align;
|
use style::computed_values::text_align;
|
||||||
|
|
||||||
|
@ -127,7 +127,7 @@ pub fn base<'a>(this: &'a Flow) -> &'a FlowData {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterates over the children of this immutable flow.
|
/// Iterates over the children of this immutable flow.
|
||||||
pub fn imm_child_iter<'a>(flow: &'a Flow) -> DListIterator<'a,~Flow:> {
|
pub fn imm_child_iter<'a>(flow: &'a Flow) -> DListIterator<'a,~Flow> {
|
||||||
base(flow).children.iter()
|
base(flow).children.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,12 +140,12 @@ pub fn mut_base<'a>(this: &'a mut Flow) -> &'a mut FlowData {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the last child of this flow.
|
/// Returns the last child of this flow.
|
||||||
pub fn last_child<'a>(flow: &'a mut Flow) -> Option<&'a mut ~Flow:> {
|
pub fn last_child<'a>(flow: &'a mut Flow) -> Option<&'a mut ~Flow> {
|
||||||
mut_base(flow).children.back_mut()
|
mut_base(flow).children.back_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterates over the children of this flow.
|
/// Iterates over the children of this flow.
|
||||||
pub fn child_iter<'a>(flow: &'a mut Flow) -> MutDListIterator<'a,~Flow:> {
|
pub fn child_iter<'a>(flow: &'a mut Flow) -> MutDListIterator<'a,~Flow> {
|
||||||
mut_base(flow).children.mut_iter()
|
mut_base(flow).children.mut_iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,13 +183,13 @@ pub trait MutableFlowUtils {
|
||||||
// Mutators
|
// Mutators
|
||||||
|
|
||||||
/// Adds a new flow as a child of this flow.
|
/// Adds a new flow as a child of this flow.
|
||||||
fn add_new_child(self, new_child: ~Flow:);
|
fn add_new_child(self, new_child: ~Flow);
|
||||||
|
|
||||||
/// Invokes a closure with the first child of this flow.
|
/// Invokes a closure with the first child of this flow.
|
||||||
fn with_first_child<R>(self, f: &fn(Option<&mut ~Flow:>) -> R) -> R;
|
fn with_first_child<R>(self, f: |Option<&mut ~Flow>| -> R) -> R;
|
||||||
|
|
||||||
/// Invokes a closure with the last child of this flow.
|
/// Invokes a closure with the last child of this flow.
|
||||||
fn with_last_child<R>(self, f: &fn(Option<&mut ~Flow:>) -> R) -> R;
|
fn with_last_child<R>(self, f: |Option<&mut ~Flow>| -> R) -> R;
|
||||||
|
|
||||||
/// Removes the first child of this flow and destroys it.
|
/// Removes the first child of this flow and destroys it.
|
||||||
fn remove_first(self);
|
fn remove_first(self);
|
||||||
|
@ -205,7 +205,7 @@ pub trait MutableFlowUtils {
|
||||||
self,
|
self,
|
||||||
builder: &DisplayListBuilder,
|
builder: &DisplayListBuilder,
|
||||||
dirty: &Rect<Au>,
|
dirty: &Rect<Au>,
|
||||||
list: &Cell<DisplayList<E>>)
|
list: &RefCell<DisplayList<E>>)
|
||||||
-> bool;
|
-> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -385,7 +385,7 @@ pub struct FlowData {
|
||||||
restyle_damage: RestyleDamage,
|
restyle_damage: RestyleDamage,
|
||||||
|
|
||||||
/// The children of this flow.
|
/// The children of this flow.
|
||||||
children: DList<~Flow:>,
|
children: DList<~Flow>,
|
||||||
|
|
||||||
/* TODO (Issue #87): debug only */
|
/* TODO (Issue #87): debug only */
|
||||||
id: int,
|
id: int,
|
||||||
|
@ -454,12 +454,12 @@ impl FlowData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn child_iter<'a>(&'a mut self) -> MutDListIterator<'a,~Flow:> {
|
pub fn child_iter<'a>(&'a mut self) -> MutDListIterator<'a,~Flow> {
|
||||||
self.children.mut_iter()
|
self.children.mut_iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> ImmutableFlowUtils for &'self Flow {
|
impl<'a> ImmutableFlowUtils for &'a Flow {
|
||||||
/// Returns true if this flow is a block or a float flow.
|
/// Returns true if this flow is a block or a float flow.
|
||||||
fn is_block_like(self) -> bool {
|
fn is_block_like(self) -> bool {
|
||||||
match self.class() {
|
match self.class() {
|
||||||
|
@ -508,7 +508,7 @@ impl<'self> ImmutableFlowUtils for &'self Flow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> MutableFlowUtils for &'self mut Flow {
|
impl<'a> MutableFlowUtils for &'a mut Flow {
|
||||||
/// Traverses the tree in preorder.
|
/// Traverses the tree in preorder.
|
||||||
fn traverse_preorder<T:PreorderFlowTraversal>(self, traversal: &mut T) -> bool {
|
fn traverse_preorder<T:PreorderFlowTraversal>(self, traversal: &mut T) -> bool {
|
||||||
if traversal.should_prune(self) {
|
if traversal.should_prune(self) {
|
||||||
|
@ -548,17 +548,17 @@ impl<'self> MutableFlowUtils for &'self mut Flow {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a new flow as a child of this flow.
|
/// Adds a new flow as a child of this flow.
|
||||||
fn add_new_child(self, new_child: ~Flow:) {
|
fn add_new_child(self, new_child: ~Flow) {
|
||||||
mut_base(self).children.push_back(new_child)
|
mut_base(self).children.push_back(new_child)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invokes a closure with the first child of this flow.
|
/// Invokes a closure with the first child of this flow.
|
||||||
fn with_first_child<R>(self, f: &fn(Option<&mut ~Flow:>) -> R) -> R {
|
fn with_first_child<R>(self, f: |Option<&mut ~Flow>| -> R) -> R {
|
||||||
f(mut_base(self).children.front_mut())
|
f(mut_base(self).children.front_mut())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invokes a closure with the last child of this flow.
|
/// Invokes a closure with the last child of this flow.
|
||||||
fn with_last_child<R>(self, f: &fn(Option<&mut ~Flow:>) -> R) -> R {
|
fn with_last_child<R>(self, f: |Option<&mut ~Flow>| -> R) -> R {
|
||||||
f(mut_base(self).children.back_mut())
|
f(mut_base(self).children.back_mut())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -587,7 +587,7 @@ impl<'self> MutableFlowUtils for &'self mut Flow {
|
||||||
self,
|
self,
|
||||||
builder: &DisplayListBuilder,
|
builder: &DisplayListBuilder,
|
||||||
dirty: &Rect<Au>,
|
dirty: &Rect<Au>,
|
||||||
list: &Cell<DisplayList<E>>)
|
list: &RefCell<DisplayList<E>>)
|
||||||
-> bool {
|
-> bool {
|
||||||
debug!("Flow: building display list for f{}", base(self).id);
|
debug!("Flow: building display list for f{}", base(self).id);
|
||||||
match self.class() {
|
match self.class() {
|
||||||
|
@ -596,20 +596,21 @@ impl<'self> MutableFlowUtils for &'self mut Flow {
|
||||||
_ => fail!("Tried to build_display_list_recurse of flow: {:?}", self),
|
_ => fail!("Tried to build_display_list_recurse of flow: {:?}", self),
|
||||||
};
|
};
|
||||||
|
|
||||||
if list.with_mut_ref(|list| list.list.len() == 0) {
|
if list.with_mut(|list| list.list.len() == 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let child_list = ~Cell::new(DisplayList::new());
|
let child_list = ~RefCell::new(DisplayList::new());
|
||||||
for kid in child_iter(self) {
|
for kid in child_iter(self) {
|
||||||
kid.build_display_list(builder,dirty,child_list);
|
kid.build_display_list(builder,dirty,child_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
do list.with_mut_ref |list| {
|
let mut child_list = Some(child_list.unwrap());
|
||||||
|
list.with_mut(|list| {
|
||||||
let result = list.list.mut_rev_iter().position(|item| {
|
let result = list.list.mut_rev_iter().position(|item| {
|
||||||
match *item {
|
match *item {
|
||||||
ClipDisplayItemClass(ref mut item) => {
|
ClipDisplayItemClass(ref mut item) => {
|
||||||
item.child_list.push_all_move(child_list.take().list);
|
item.child_list.push_all_move(child_list.take_unwrap().list);
|
||||||
true
|
true
|
||||||
},
|
},
|
||||||
_ => false,
|
_ => false,
|
||||||
|
@ -620,7 +621,7 @@ impl<'self> MutableFlowUtils for &'self mut Flow {
|
||||||
fail!("fail to find parent item");
|
fail!("fail to find parent item");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
});
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,14 +3,14 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use css::node_style::StyledNode;
|
use css::node_style::StyledNode;
|
||||||
use layout::box::{Box, CannotSplit, GenericBox, IframeBox, ImageBox, ScannedTextBox, SplitDidFit};
|
use layout::box_::{Box, CannotSplit, GenericBox, IframeBox, ImageBox, ScannedTextBox, SplitDidFit};
|
||||||
use layout::box::{SplitDidNotFit, UnscannedTextBox};
|
use layout::box_::{SplitDidNotFit, UnscannedTextBox};
|
||||||
use layout::context::LayoutContext;
|
use layout::context::LayoutContext;
|
||||||
use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData};
|
use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData};
|
||||||
use layout::flow::{FlowClass, Flow, FlowData, InlineFlowClass};
|
use layout::flow::{FlowClass, Flow, FlowData, InlineFlowClass};
|
||||||
use layout::flow;
|
use layout::flow;
|
||||||
use layout::float_context::FloatContext;
|
use layout::float_context::FloatContext;
|
||||||
use layout::util::{ElementMapping};
|
use layout::util::ElementMapping;
|
||||||
use layout::float_context::{PlacementInfo, FloatLeft};
|
use layout::float_context::{PlacementInfo, FloatLeft};
|
||||||
|
|
||||||
use extra::container::Deque;
|
use extra::container::Deque;
|
||||||
|
@ -19,7 +19,7 @@ use geom::{Point2D, Rect, Size2D};
|
||||||
use gfx::display_list::DisplayList;
|
use gfx::display_list::DisplayList;
|
||||||
use servo_util::geometry::Au;
|
use servo_util::geometry::Au;
|
||||||
use servo_util::range::Range;
|
use servo_util::range::Range;
|
||||||
use std::cell::Cell;
|
use std::cell::RefCell;
|
||||||
use std::u16;
|
use std::u16;
|
||||||
use std::util;
|
use std::util;
|
||||||
use style::computed_values::{text_align, vertical_align};
|
use style::computed_values::{text_align, vertical_align};
|
||||||
|
@ -80,18 +80,6 @@ impl LineboxScanner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reinitialize(&mut self, float_ctx: FloatContext) {
|
|
||||||
self.floats = float_ctx;
|
|
||||||
self.new_boxes.truncate(0);
|
|
||||||
self.work_list.clear();
|
|
||||||
self.pending_line.range = Range::empty();
|
|
||||||
self.pending_line.bounds = Rect(Point2D(Au::new(0), Au::new(0)),
|
|
||||||
Size2D(Au::new(0), Au::new(0)));
|
|
||||||
self.pending_line.green_zone = Size2D(Au::new(0), Au::new(0));
|
|
||||||
self.lines.truncate(0);
|
|
||||||
self.cur_y = Au::new(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn floats_out(&mut self) -> FloatContext {
|
pub fn floats_out(&mut self) -> FloatContext {
|
||||||
self.floats.clone()
|
self.floats.clone()
|
||||||
}
|
}
|
||||||
|
@ -119,13 +107,13 @@ impl LineboxScanner {
|
||||||
if flow.boxes.is_empty() {
|
if flow.boxes.is_empty() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
let box = flow.boxes.remove(0); // FIXME: use a linkedlist
|
let box_ = flow.boxes.remove(0); // FIXME: use a linkedlist
|
||||||
debug!("LineboxScanner: Working with box from box list: b{}", box.debug_id());
|
debug!("LineboxScanner: Working with box from box list: b{}", box_.debug_id());
|
||||||
box
|
box_
|
||||||
} else {
|
} else {
|
||||||
let box = self.work_list.pop_front().unwrap();
|
let box_ = self.work_list.pop_front().unwrap();
|
||||||
debug!("LineboxScanner: Working with box from work list: b{}", box.debug_id());
|
debug!("LineboxScanner: Working with box from work list: b{}", box_.debug_id());
|
||||||
box
|
box_
|
||||||
};
|
};
|
||||||
|
|
||||||
let box_was_appended = self.try_append_to_line(cur_box, flow);
|
let box_was_appended = self.try_append_to_line(cur_box, flow);
|
||||||
|
@ -413,8 +401,8 @@ impl LineboxScanner {
|
||||||
}
|
}
|
||||||
|
|
||||||
// An unconditional push
|
// An unconditional push
|
||||||
fn push_box_to_line(&mut self, box: Box) {
|
fn push_box_to_line(&mut self, box_: Box) {
|
||||||
debug!("LineboxScanner: Pushing box {} to line {:u}", box.debug_id(), self.lines.len());
|
debug!("LineboxScanner: Pushing box {} to line {:u}", box_.debug_id(), self.lines.len());
|
||||||
|
|
||||||
if self.pending_line.range.length() == 0 {
|
if self.pending_line.range.length() == 0 {
|
||||||
assert!(self.new_boxes.len() <= (u16::max_value as uint));
|
assert!(self.new_boxes.len() <= (u16::max_value as uint));
|
||||||
|
@ -422,10 +410,10 @@ impl LineboxScanner {
|
||||||
}
|
}
|
||||||
self.pending_line.range.extend_by(1);
|
self.pending_line.range.extend_by(1);
|
||||||
self.pending_line.bounds.size.width = self.pending_line.bounds.size.width +
|
self.pending_line.bounds.size.width = self.pending_line.bounds.size.width +
|
||||||
box.position.get().size.width;
|
box_.position.get().size.width;
|
||||||
self.pending_line.bounds.size.height = Au::max(self.pending_line.bounds.size.height,
|
self.pending_line.bounds.size.height = Au::max(self.pending_line.bounds.size.height,
|
||||||
box.position.get().size.height);
|
box_.position.get().size.height);
|
||||||
self.new_boxes.push(box);
|
self.new_boxes.push(box_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -467,8 +455,8 @@ impl InlineFlow {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn teardown(&mut self) {
|
pub fn teardown(&mut self) {
|
||||||
for box in self.boxes.iter() {
|
for box_ in self.boxes.iter() {
|
||||||
box.teardown();
|
box_.teardown();
|
||||||
}
|
}
|
||||||
self.boxes = ~[];
|
self.boxes = ~[];
|
||||||
}
|
}
|
||||||
|
@ -477,7 +465,7 @@ impl InlineFlow {
|
||||||
&self,
|
&self,
|
||||||
builder: &DisplayListBuilder,
|
builder: &DisplayListBuilder,
|
||||||
dirty: &Rect<Au>,
|
dirty: &Rect<Au>,
|
||||||
list: &Cell<DisplayList<E>>)
|
list: &RefCell<DisplayList<E>>)
|
||||||
-> bool {
|
-> bool {
|
||||||
let abs_rect = Rect(self.base.abs_position, self.base.position.size);
|
let abs_rect = Rect(self.base.abs_position, self.base.position.size);
|
||||||
if !abs_rect.intersects(dirty) {
|
if !abs_rect.intersects(dirty) {
|
||||||
|
@ -490,8 +478,8 @@ impl InlineFlow {
|
||||||
self.base.id,
|
self.base.id,
|
||||||
self.boxes.len());
|
self.boxes.len());
|
||||||
|
|
||||||
for box in self.boxes.iter() {
|
for box_ in self.boxes.iter() {
|
||||||
box.build_display_list(builder, dirty, self.base.abs_position, (&*self) as &Flow, list)
|
box_.build_display_list(builder, dirty, self.base.abs_position, (&*self) as &Flow, list)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(#225): Should `inline-block` elements have flows as children of the inline flow or
|
// TODO(#225): Should `inline-block` elements have flows as children of the inline flow or
|
||||||
|
@ -590,9 +578,9 @@ impl InlineFlow {
|
||||||
};
|
};
|
||||||
|
|
||||||
for i in line.range.eachi() {
|
for i in line.range.eachi() {
|
||||||
let box = &boxes[i];
|
let box_ = &boxes[i];
|
||||||
let size = box.position.get().size;
|
let size = box_.position.get().size;
|
||||||
box.position.set(Rect(Point2D(offset_x, box.position.get().origin.y), size));
|
box_.position.set(Rect(Point2D(offset_x, box_.position.get().origin.y), size));
|
||||||
offset_x = offset_x + size.width;
|
offset_x = offset_x + size.width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -623,10 +611,10 @@ impl Flow for InlineFlow {
|
||||||
let mut min_width = Au::new(0);
|
let mut min_width = Au::new(0);
|
||||||
let mut pref_width = Au::new(0);
|
let mut pref_width = Au::new(0);
|
||||||
|
|
||||||
for box in self.boxes.iter() {
|
for box_ in self.boxes.iter() {
|
||||||
debug!("Flow[{:d}]: measuring {:s}", self.base.id, box.debug_str());
|
debug!("Flow[{:d}]: measuring {:s}", self.base.id, box_.debug_str());
|
||||||
let (this_minimum_width, this_preferred_width) =
|
let (this_minimum_width, this_preferred_width) =
|
||||||
box.minimum_and_preferred_widths();
|
box_.minimum_and_preferred_widths();
|
||||||
min_width = Au::max(min_width, this_minimum_width);
|
min_width = Au::max(min_width, this_minimum_width);
|
||||||
pref_width = Au::max(pref_width, this_preferred_width);
|
pref_width = Au::max(pref_width, this_preferred_width);
|
||||||
}
|
}
|
||||||
|
@ -647,8 +635,8 @@ impl Flow for InlineFlow {
|
||||||
|
|
||||||
{
|
{
|
||||||
let this = &mut *self;
|
let this = &mut *self;
|
||||||
for box in this.boxes.iter() {
|
for box_ in this.boxes.iter() {
|
||||||
box.assign_width();
|
box_.assign_width();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -736,9 +724,9 @@ impl Flow for InlineFlow {
|
||||||
let noncontent_height = top + bottom;
|
let noncontent_height = top + bottom;
|
||||||
height = height + noncontent_height;
|
height = height + noncontent_height;
|
||||||
|
|
||||||
let position_ref = cur_box.position.mutate();
|
let mut position_ref = cur_box.position.borrow_mut();
|
||||||
position_ref.ptr.size.height = height;
|
position_ref.get().size.height = height;
|
||||||
position_ref.ptr.translate(&Point2D(Au::new(0), -height));
|
position_ref.get().translate(&Point2D(Au::new(0), -height));
|
||||||
|
|
||||||
let ascent = height + bottom;
|
let ascent = height + bottom;
|
||||||
(height, Au::new(0), ascent)
|
(height, Au::new(0), ascent)
|
||||||
|
@ -818,7 +806,7 @@ impl Flow for InlineFlow {
|
||||||
bottommost = bottom_from_base;
|
bottommost = bottom_from_base;
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_box.position.mutate().ptr.origin.y = line.bounds.origin.y + offset;
|
cur_box.position.borrow_mut().get().origin.y = line.bounds.origin.y + offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the distance from baseline to the top of the biggest box with 'bottom'
|
// Calculate the distance from baseline to the top of the biggest box with 'bottom'
|
||||||
|
@ -847,7 +835,7 @@ impl Flow for InlineFlow {
|
||||||
_ => baseline_offset,
|
_ => baseline_offset,
|
||||||
};
|
};
|
||||||
|
|
||||||
cur_box.position.mutate().ptr.origin.y = cur_box.position.get().origin.y +
|
cur_box.position.borrow_mut().get().origin.y = cur_box.position.get().origin.y +
|
||||||
adjust_offset;
|
adjust_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ use layout::flow::{Flow, ImmutableFlowUtils, MutableFlowUtils, PreorderFlowTrave
|
||||||
use layout::flow::{PostorderFlowTraversal};
|
use layout::flow::{PostorderFlowTraversal};
|
||||||
use layout::flow;
|
use layout::flow;
|
||||||
use layout::incremental::{RestyleDamage};
|
use layout::incremental::{RestyleDamage};
|
||||||
use layout::util::{LayoutData, LayoutDataAccess, OpaqueNode};
|
use layout::util::{LayoutDataAccess, OpaqueNode, LayoutDataWrapper};
|
||||||
use layout::wrapper::LayoutNode;
|
use layout::wrapper::LayoutNode;
|
||||||
|
|
||||||
use extra::arc::{Arc, RWArc, MutexArc};
|
use extra::arc::{Arc, RWArc, MutexArc};
|
||||||
|
@ -34,7 +34,7 @@ use script::dom::element::{HTMLBodyElementTypeId, HTMLHtmlElementTypeId};
|
||||||
use script::layout_interface::{AddStylesheetMsg, ContentBoxQuery};
|
use script::layout_interface::{AddStylesheetMsg, ContentBoxQuery};
|
||||||
use script::layout_interface::{ContentBoxesQuery, ContentBoxesResponse, ExitNowMsg, LayoutQuery};
|
use script::layout_interface::{ContentBoxesQuery, ContentBoxesResponse, ExitNowMsg, LayoutQuery};
|
||||||
use script::layout_interface::{HitTestQuery, ContentBoxResponse, HitTestResponse};
|
use script::layout_interface::{HitTestQuery, ContentBoxResponse, HitTestResponse};
|
||||||
use script::layout_interface::{ContentChangedDocumentDamage, Msg, PrepareToExitMsg};
|
use script::layout_interface::{ContentChangedDocumentDamage, LayoutChan, Msg, PrepareToExitMsg};
|
||||||
use script::layout_interface::{QueryMsg, ReapLayoutDataMsg, Reflow, ReflowDocumentDamage};
|
use script::layout_interface::{QueryMsg, ReapLayoutDataMsg, Reflow, ReflowDocumentDamage};
|
||||||
use script::layout_interface::{ReflowForDisplay, ReflowMsg};
|
use script::layout_interface::{ReflowForDisplay, ReflowMsg};
|
||||||
use script::script_task::{ReflowCompleteMsg, ScriptChan, SendEventMsg};
|
use script::script_task::{ReflowCompleteMsg, ScriptChan, SendEventMsg};
|
||||||
|
@ -46,20 +46,22 @@ use servo_util::time::{ProfilerChan, profile};
|
||||||
use servo_util::time;
|
use servo_util::time;
|
||||||
use std::cast::transmute;
|
use std::cast::transmute;
|
||||||
use std::cast;
|
use std::cast;
|
||||||
use std::cell::Cell;
|
use std::cell::RefCell;
|
||||||
use std::comm::Port;
|
use std::comm::Port;
|
||||||
use std::task;
|
|
||||||
use std::util;
|
use std::util;
|
||||||
use style::{AuthorOrigin, Stylesheet, Stylist};
|
use style::{AuthorOrigin, Stylesheet, Stylist};
|
||||||
|
|
||||||
/// Information needed by the layout task.
|
/// Information needed by the layout task.
|
||||||
struct LayoutTask {
|
pub struct LayoutTask {
|
||||||
/// The ID of the pipeline that we belong to.
|
/// The ID of the pipeline that we belong to.
|
||||||
id: PipelineId,
|
id: PipelineId,
|
||||||
|
|
||||||
/// The port on which we receive messages.
|
/// The port on which we receive messages.
|
||||||
port: Port<Msg>,
|
port: Port<Msg>,
|
||||||
|
|
||||||
|
//// The channel to send messages to ourself.
|
||||||
|
chan: LayoutChan,
|
||||||
|
|
||||||
/// The channel on which messages can be sent to the constellation.
|
/// The channel on which messages can be sent to the constellation.
|
||||||
constellation_chan: ConstellationChan,
|
constellation_chan: ConstellationChan,
|
||||||
|
|
||||||
|
@ -132,9 +134,9 @@ impl PreorderFlowTraversal for PropagateDamageTraversal {
|
||||||
|
|
||||||
/// The bubble-widths traversal, the first part of layout computation. This computes preferred
|
/// The bubble-widths traversal, the first part of layout computation. This computes preferred
|
||||||
/// and intrinsic widths and bubbles them up the tree.
|
/// and intrinsic widths and bubbles them up the tree.
|
||||||
struct BubbleWidthsTraversal<'self>(&'self mut LayoutContext);
|
struct BubbleWidthsTraversal<'a>(&'a mut LayoutContext);
|
||||||
|
|
||||||
impl<'self> PostorderFlowTraversal for BubbleWidthsTraversal<'self> {
|
impl<'a> PostorderFlowTraversal for BubbleWidthsTraversal<'a> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn process(&mut self, flow: &mut Flow) -> bool {
|
fn process(&mut self, flow: &mut Flow) -> bool {
|
||||||
flow.bubble_widths(**self);
|
flow.bubble_widths(**self);
|
||||||
|
@ -151,9 +153,9 @@ impl<'self> PostorderFlowTraversal for BubbleWidthsTraversal<'self> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The assign-widths traversal. In Gecko this corresponds to `Reflow`.
|
/// The assign-widths traversal. In Gecko this corresponds to `Reflow`.
|
||||||
struct AssignWidthsTraversal<'self>(&'self mut LayoutContext);
|
struct AssignWidthsTraversal<'a>(&'a mut LayoutContext);
|
||||||
|
|
||||||
impl<'self> PreorderFlowTraversal for AssignWidthsTraversal<'self> {
|
impl<'a> PreorderFlowTraversal for AssignWidthsTraversal<'a> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn process(&mut self, flow: &mut Flow) -> bool {
|
fn process(&mut self, flow: &mut Flow) -> bool {
|
||||||
flow.assign_widths(**self);
|
flow.assign_widths(**self);
|
||||||
|
@ -164,9 +166,9 @@ impl<'self> PreorderFlowTraversal for AssignWidthsTraversal<'self> {
|
||||||
/// The assign-heights-and-store-overflow traversal, the last (and most expensive) part of layout
|
/// The assign-heights-and-store-overflow traversal, the last (and most expensive) part of layout
|
||||||
/// computation. Determines the final heights for all layout objects, computes positions, and
|
/// computation. Determines the final heights for all layout objects, computes positions, and
|
||||||
/// computes overflow regions. In Gecko this corresponds to `FinishAndStoreOverflow`.
|
/// computes overflow regions. In Gecko this corresponds to `FinishAndStoreOverflow`.
|
||||||
struct AssignHeightsAndStoreOverflowTraversal<'self>(&'self mut LayoutContext);
|
struct AssignHeightsAndStoreOverflowTraversal<'a>(&'a mut LayoutContext);
|
||||||
|
|
||||||
impl<'self> PostorderFlowTraversal for AssignHeightsAndStoreOverflowTraversal<'self> {
|
impl<'a> PostorderFlowTraversal for AssignHeightsAndStoreOverflowTraversal<'a> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn process(&mut self, flow: &mut Flow) -> bool {
|
fn process(&mut self, flow: &mut Flow) -> bool {
|
||||||
flow.assign_height(**self);
|
flow.assign_height(**self);
|
||||||
|
@ -186,10 +188,10 @@ struct LayoutImageResponder {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ImageResponder for LayoutImageResponder {
|
impl ImageResponder for LayoutImageResponder {
|
||||||
fn respond(&self) -> ~fn(ImageResponseMsg) {
|
fn respond(&self) -> proc(ImageResponseMsg) {
|
||||||
let id = self.id.clone();
|
let id = self.id.clone();
|
||||||
let script_chan = self.script_chan.clone();
|
let script_chan = self.script_chan.clone();
|
||||||
let f: ~fn(ImageResponseMsg) = |_| {
|
let f: proc(ImageResponseMsg) = proc(_) {
|
||||||
script_chan.send(SendEventMsg(id.clone(), ReflowEvent))
|
script_chan.send(SendEventMsg(id.clone(), ReflowEvent))
|
||||||
};
|
};
|
||||||
f
|
f
|
||||||
|
@ -200,6 +202,7 @@ impl LayoutTask {
|
||||||
/// Spawns a new layout task.
|
/// Spawns a new layout task.
|
||||||
pub fn create(id: PipelineId,
|
pub fn create(id: PipelineId,
|
||||||
port: Port<Msg>,
|
port: Port<Msg>,
|
||||||
|
chan: LayoutChan,
|
||||||
constellation_chan: ConstellationChan,
|
constellation_chan: ConstellationChan,
|
||||||
script_chan: ScriptChan,
|
script_chan: ScriptChan,
|
||||||
render_chan: RenderChan<OpaqueNode>,
|
render_chan: RenderChan<OpaqueNode>,
|
||||||
|
@ -207,11 +210,11 @@ impl LayoutTask {
|
||||||
opts: Opts,
|
opts: Opts,
|
||||||
profiler_chan: ProfilerChan,
|
profiler_chan: ProfilerChan,
|
||||||
shutdown_chan: Chan<()>) {
|
shutdown_chan: Chan<()>) {
|
||||||
spawn_with!(task::task(), [port, constellation_chan, script_chan,
|
spawn(proc() {
|
||||||
render_chan, img_cache_task, profiler_chan, shutdown_chan], {
|
{ // Ensures layout task is destroyed before we send shutdown message
|
||||||
{ // Ensures LayoutTask gets destroyed before we send the shutdown message
|
|
||||||
let mut layout = LayoutTask::new(id,
|
let mut layout = LayoutTask::new(id,
|
||||||
port,
|
port,
|
||||||
|
chan,
|
||||||
constellation_chan,
|
constellation_chan,
|
||||||
script_chan,
|
script_chan,
|
||||||
render_chan,
|
render_chan,
|
||||||
|
@ -220,7 +223,6 @@ impl LayoutTask {
|
||||||
profiler_chan);
|
profiler_chan);
|
||||||
layout.start();
|
layout.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
shutdown_chan.send(());
|
shutdown_chan.send(());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -228,6 +230,7 @@ impl LayoutTask {
|
||||||
/// Creates a new `LayoutTask` structure.
|
/// Creates a new `LayoutTask` structure.
|
||||||
fn new(id: PipelineId,
|
fn new(id: PipelineId,
|
||||||
port: Port<Msg>,
|
port: Port<Msg>,
|
||||||
|
chan: LayoutChan,
|
||||||
constellation_chan: ConstellationChan,
|
constellation_chan: ConstellationChan,
|
||||||
script_chan: ScriptChan,
|
script_chan: ScriptChan,
|
||||||
render_chan: RenderChan<OpaqueNode>,
|
render_chan: RenderChan<OpaqueNode>,
|
||||||
|
@ -239,6 +242,7 @@ impl LayoutTask {
|
||||||
LayoutTask {
|
LayoutTask {
|
||||||
id: id,
|
id: id,
|
||||||
port: port,
|
port: port,
|
||||||
|
chan: chan,
|
||||||
constellation_chan: constellation_chan,
|
constellation_chan: constellation_chan,
|
||||||
script_chan: script_chan,
|
script_chan: script_chan,
|
||||||
render_chan: render_chan,
|
render_chan: render_chan,
|
||||||
|
@ -281,17 +285,15 @@ impl LayoutTask {
|
||||||
match self.port.recv() {
|
match self.port.recv() {
|
||||||
AddStylesheetMsg(sheet) => self.handle_add_stylesheet(sheet),
|
AddStylesheetMsg(sheet) => self.handle_add_stylesheet(sheet),
|
||||||
ReflowMsg(data) => {
|
ReflowMsg(data) => {
|
||||||
let data = Cell::new(data);
|
profile(time::LayoutPerformCategory, self.profiler_chan.clone(), || {
|
||||||
|
self.handle_reflow(data);
|
||||||
do profile(time::LayoutPerformCategory, self.profiler_chan.clone()) {
|
});
|
||||||
self.handle_reflow(data.take());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
QueryMsg(query) => {
|
QueryMsg(query) => {
|
||||||
let query = Cell::new(query);
|
let mut query = Some(query);
|
||||||
do profile(time::LayoutQueryCategory, self.profiler_chan.clone()) {
|
profile(time::LayoutQueryCategory, self.profiler_chan.clone(), || {
|
||||||
self.handle_query(query.take());
|
self.handle_query(query.take_unwrap());
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
ReapLayoutDataMsg(dead_layout_data) => {
|
ReapLayoutDataMsg(dead_layout_data) => {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -340,16 +342,16 @@ impl LayoutTask {
|
||||||
/// Shuts down the layout task now. If there are any DOM nodes left, layout will now (safely)
|
/// Shuts down the layout task now. If there are any DOM nodes left, layout will now (safely)
|
||||||
/// crash.
|
/// crash.
|
||||||
fn exit_now(&mut self) {
|
fn exit_now(&mut self) {
|
||||||
let (response_port, response_chan) = stream();
|
let (response_port, response_chan) = Chan::new();
|
||||||
self.render_chan.send(render_task::ExitMsg(response_chan));
|
self.render_chan.send(render_task::ExitMsg(response_chan));
|
||||||
response_port.recv()
|
response_port.recv()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_add_stylesheet(&mut self, sheet: Stylesheet) {
|
fn handle_add_stylesheet(&mut self, sheet: Stylesheet) {
|
||||||
let sheet = Cell::new(sheet);
|
let mut sheet = Some(sheet);
|
||||||
do self.stylist.write |stylist| {
|
self.stylist.write(|stylist| {
|
||||||
stylist.add_stylesheet(sheet.take(), AuthorOrigin);
|
stylist.add_stylesheet(sheet.take_unwrap(), AuthorOrigin);
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds the flow tree.
|
/// Builds the flow tree.
|
||||||
|
@ -359,12 +361,13 @@ impl LayoutTask {
|
||||||
/// is intertwined with selector matching, making it difficult to compare directly. It is
|
/// is intertwined with selector matching, making it difficult to compare directly. It is
|
||||||
/// marked `#[inline(never)]` to aid benchmarking in sampling profilers.
|
/// marked `#[inline(never)]` to aid benchmarking in sampling profilers.
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn construct_flow_tree(&self, layout_context: &mut LayoutContext, node: LayoutNode) -> ~Flow: {
|
fn construct_flow_tree(&self, layout_context: &mut LayoutContext, node: LayoutNode) -> ~Flow {
|
||||||
node.traverse_postorder_mut(&mut FlowConstructor::init(layout_context));
|
node.traverse_postorder_mut(&mut FlowConstructor::init(layout_context));
|
||||||
|
|
||||||
let result = match *node.mutate_layout_data().ptr {
|
let mut layout_data_ref = node.mutate_layout_data();
|
||||||
|
let result = match *layout_data_ref.get() {
|
||||||
Some(ref mut layout_data) => {
|
Some(ref mut layout_data) => {
|
||||||
util::replace(&mut layout_data.flow_construction_result, NoConstructionResult)
|
util::replace(&mut layout_data.data.flow_construction_result, NoConstructionResult)
|
||||||
}
|
}
|
||||||
None => fail!("no layout data for root node"),
|
None => fail!("no layout data for root node"),
|
||||||
};
|
};
|
||||||
|
@ -436,18 +439,18 @@ impl LayoutTask {
|
||||||
// Initialize layout data for each node.
|
// Initialize layout data for each node.
|
||||||
//
|
//
|
||||||
// FIXME: This is inefficient. We don't need an entire traversal to do this!
|
// FIXME: This is inefficient. We don't need an entire traversal to do this!
|
||||||
do profile(time::LayoutAuxInitCategory, self.profiler_chan.clone()) {
|
profile(time::LayoutAuxInitCategory, self.profiler_chan.clone(), || {
|
||||||
node.initialize_style_for_subtree();
|
node.initialize_style_for_subtree(self.chan.clone());
|
||||||
}
|
});
|
||||||
|
|
||||||
// Perform CSS selector matching if necessary.
|
// Perform CSS selector matching if necessary.
|
||||||
match data.damage.level {
|
match data.damage.level {
|
||||||
ReflowDocumentDamage => {}
|
ReflowDocumentDamage => {}
|
||||||
_ => {
|
_ => {
|
||||||
do profile(time::LayoutSelectorMatchCategory, self.profiler_chan.clone()) {
|
profile(time::LayoutSelectorMatchCategory, self.profiler_chan.clone(), || {
|
||||||
node.match_subtree(self.stylist.clone());
|
node.match_subtree(self.stylist.clone());
|
||||||
node.cascade_subtree(None);
|
node.cascade_subtree(None);
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -464,25 +467,25 @@ impl LayoutTask {
|
||||||
|
|
||||||
// Perform the primary layout passes over the flow tree to compute the locations of all
|
// Perform the primary layout passes over the flow tree to compute the locations of all
|
||||||
// the boxes.
|
// the boxes.
|
||||||
do profile(time::LayoutMainCategory, self.profiler_chan.clone()) {
|
profile(time::LayoutMainCategory, self.profiler_chan.clone(), || {
|
||||||
self.solve_constraints(layout_root, &mut layout_ctx)
|
self.solve_constraints(layout_root, &mut layout_ctx)
|
||||||
}
|
});
|
||||||
|
|
||||||
debug!("layout: constraint solving done:");
|
debug!("layout: constraint solving done:");
|
||||||
debug!("{:?}", layout_root.dump());
|
debug!("{:?}", layout_root.dump());
|
||||||
|
|
||||||
// Build the display list if necessary, and send it to the renderer.
|
// Build the display list if necessary, and send it to the renderer.
|
||||||
if data.goal == ReflowForDisplay {
|
if data.goal == ReflowForDisplay {
|
||||||
do profile(time::LayoutDispListBuildCategory, self.profiler_chan.clone()) {
|
profile(time::LayoutDispListBuildCategory, self.profiler_chan.clone(), || {
|
||||||
let root_size = flow::base(layout_root).position.size;
|
let root_size = flow::base(layout_root).position.size;
|
||||||
let display_list = ~Cell::new(DisplayList::<OpaqueNode>::new());
|
let display_list = ~RefCell::new(DisplayList::<OpaqueNode>::new());
|
||||||
let dirty = flow::base(layout_root).position.clone();
|
let dirty = flow::base(layout_root).position.clone();
|
||||||
let display_list_builder = DisplayListBuilder {
|
let display_list_builder = DisplayListBuilder {
|
||||||
ctx: &layout_ctx,
|
ctx: &layout_ctx,
|
||||||
};
|
};
|
||||||
layout_root.build_display_list(&display_list_builder, &dirty, display_list);
|
layout_root.build_display_list(&display_list_builder, &dirty, display_list);
|
||||||
|
|
||||||
let display_list = Arc::new(display_list.take());
|
let display_list = Arc::new(display_list.unwrap());
|
||||||
|
|
||||||
let mut color = color::rgba(255.0, 255.0, 255.0, 255.0);
|
let mut color = color::rgba(255.0, 255.0, 255.0, 255.0);
|
||||||
|
|
||||||
|
@ -516,7 +519,7 @@ impl LayoutTask {
|
||||||
self.display_list = Some(display_list.clone());
|
self.display_list = Some(display_list.clone());
|
||||||
|
|
||||||
self.render_chan.send(RenderMsg(render_layer));
|
self.render_chan.send(RenderMsg(render_layer));
|
||||||
} // time(layout: display list building)
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tell script that we're done.
|
// Tell script that we're done.
|
||||||
|
@ -663,8 +666,9 @@ impl LayoutTask {
|
||||||
/// Handles a message to destroy layout data. Layout data must be destroyed on *this* task
|
/// Handles a message to destroy layout data. Layout data must be destroyed on *this* task
|
||||||
/// because it contains local managed pointers.
|
/// because it contains local managed pointers.
|
||||||
unsafe fn handle_reap_layout_data(&self, layout_data: LayoutDataRef) {
|
unsafe fn handle_reap_layout_data(&self, layout_data: LayoutDataRef) {
|
||||||
let ptr: &mut Option<~LayoutData> = cast::transmute(layout_data.borrow_unchecked());
|
let mut layout_data_ref = layout_data.borrow_mut();
|
||||||
*ptr = None
|
let _: Option<LayoutDataWrapper> = cast::transmute(
|
||||||
|
util::replace(layout_data_ref.get(), None));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
//! Text layout.
|
//! Text layout.
|
||||||
|
|
||||||
use layout::box::{Box, ScannedTextBox, ScannedTextBoxInfo, UnscannedTextBox};
|
use layout::box_::{Box, ScannedTextBox, ScannedTextBoxInfo, UnscannedTextBox};
|
||||||
use layout::context::LayoutContext;
|
use layout::context::LayoutContext;
|
||||||
use layout::flow::Flow;
|
use layout::flow::Flow;
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ use servo_util::range::Range;
|
||||||
use std::vec;
|
use std::vec;
|
||||||
|
|
||||||
/// A stack-allocated object for scanning an inline flow into `TextRun`-containing `TextBox`es.
|
/// A stack-allocated object for scanning an inline flow into `TextRun`-containing `TextBox`es.
|
||||||
struct TextRunScanner {
|
pub struct TextRunScanner {
|
||||||
clump: Range,
|
clump: Range,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,7 +123,7 @@ impl TextRunScanner {
|
||||||
// font group fonts. This is probably achieved by creating the font group above
|
// font group fonts. This is probably achieved by creating the font group above
|
||||||
// and then letting `FontGroup` decide which `Font` to stick into the text run.
|
// and then letting `FontGroup` decide which `Font` to stick into the text run.
|
||||||
let fontgroup = ctx.font_ctx.get_resolved_font_for_style(&font_style);
|
let fontgroup = ctx.font_ctx.get_resolved_font_for_style(&font_style);
|
||||||
let run = ~fontgroup.with_borrow(|fg| fg.create_textrun(transformed_text.clone(), decoration));
|
let run = ~fontgroup.borrow().with(|fg| fg.create_textrun(transformed_text.clone(), decoration));
|
||||||
|
|
||||||
debug!("TextRunScanner: pushing single text box in range: {} ({})",
|
debug!("TextRunScanner: pushing single text box in range: {} ({})",
|
||||||
self.clump,
|
self.clump,
|
||||||
|
@ -142,7 +142,7 @@ impl TextRunScanner {
|
||||||
|
|
||||||
// First, transform/compress text of all the nodes.
|
// First, transform/compress text of all the nodes.
|
||||||
let mut last_whitespace_in_clump = new_whitespace;
|
let mut last_whitespace_in_clump = new_whitespace;
|
||||||
let transformed_strs: ~[~str] = do vec::from_fn(self.clump.length()) |i| {
|
let transformed_strs: ~[~str] = vec::from_fn(self.clump.length(), |i| {
|
||||||
// TODO(#113): We should be passing the compression context between calls to
|
// TODO(#113): We should be passing the compression context between calls to
|
||||||
// `transform_text`, so that boxes starting and/or ending with whitespace can
|
// `transform_text`, so that boxes starting and/or ending with whitespace can
|
||||||
// be compressed correctly with respect to the text run.
|
// be compressed correctly with respect to the text run.
|
||||||
|
@ -157,7 +157,7 @@ impl TextRunScanner {
|
||||||
last_whitespace_in_clump);
|
last_whitespace_in_clump);
|
||||||
last_whitespace_in_clump = new_whitespace;
|
last_whitespace_in_clump = new_whitespace;
|
||||||
new_str
|
new_str
|
||||||
};
|
});
|
||||||
new_whitespace = last_whitespace_in_clump;
|
new_whitespace = last_whitespace_in_clump;
|
||||||
|
|
||||||
// Next, concatenate all of the transformed strings together, saving the new
|
// Next, concatenate all of the transformed strings together, saving the new
|
||||||
|
@ -186,8 +186,8 @@ impl TextRunScanner {
|
||||||
// sequence. If no clump takes ownership, however, it will leak.
|
// sequence. If no clump takes ownership, however, it will leak.
|
||||||
let clump = self.clump;
|
let clump = self.clump;
|
||||||
let run = if clump.length() != 0 && run_str.len() > 0 {
|
let run = if clump.length() != 0 && run_str.len() > 0 {
|
||||||
fontgroup.with_borrow( |fg| {
|
fontgroup.borrow().with(|fg| {
|
||||||
fg.fonts[0].with_mut_borrow( |font| {
|
fg.fonts[0].borrow().with_mut(|font| {
|
||||||
Some(Arc::new(~TextRun::new(font, run_str.clone(), decoration)))
|
Some(Arc::new(~TextRun::new(font, run_str.clone(), decoration)))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -216,14 +216,14 @@ impl TextRunScanner {
|
||||||
} // End of match.
|
} // End of match.
|
||||||
|
|
||||||
debug!("--- In boxes: ---");
|
debug!("--- In boxes: ---");
|
||||||
for (i, box) in in_boxes.iter().enumerate() {
|
for (i, box_) in in_boxes.iter().enumerate() {
|
||||||
debug!("{:u} --> {:s}", i, box.debug_str());
|
debug!("{:u} --> {:s}", i, box_.debug_str());
|
||||||
}
|
}
|
||||||
debug!("------------------");
|
debug!("------------------");
|
||||||
|
|
||||||
debug!("--- Out boxes: ---");
|
debug!("--- Out boxes: ---");
|
||||||
for (i, box) in out_boxes.iter().enumerate() {
|
for (i, box_) in out_boxes.iter().enumerate() {
|
||||||
debug!("{:u} --> {:s}", i, box.debug_str());
|
debug!("{:u} --> {:s}", i, box_.debug_str());
|
||||||
}
|
}
|
||||||
debug!("------------------");
|
debug!("------------------");
|
||||||
|
|
||||||
|
|
|
@ -2,15 +2,16 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use layout::box::Box;
|
use layout::box_::Box;
|
||||||
use layout::construct::{ConstructionResult, NoConstructionResult};
|
use layout::construct::{ConstructionResult, NoConstructionResult};
|
||||||
use layout::wrapper::LayoutNode;
|
use layout::wrapper::LayoutNode;
|
||||||
|
|
||||||
use extra::arc::Arc;
|
use extra::arc::Arc;
|
||||||
use script::dom::node::AbstractNode;
|
use script::dom::node::AbstractNode;
|
||||||
|
use script::layout_interface::LayoutChan;
|
||||||
use servo_util::range::Range;
|
use servo_util::range::Range;
|
||||||
use servo_util::slot::{MutSlotRef, SlotRef};
|
|
||||||
use std::cast;
|
use std::cast;
|
||||||
|
use std::cell::{Ref, RefMut};
|
||||||
use std::iter::Enumerate;
|
use std::iter::Enumerate;
|
||||||
use std::libc::uintptr_t;
|
use std::libc::uintptr_t;
|
||||||
use std::vec::VecIterator;
|
use std::vec::VecIterator;
|
||||||
|
@ -31,7 +32,7 @@ impl NodeRange {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ElementMapping {
|
pub struct ElementMapping {
|
||||||
priv entries: ~[NodeRange],
|
priv entries: ~[NodeRange],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +47,7 @@ impl ElementMapping {
|
||||||
self.entries.push(NodeRange::new(node, range))
|
self.entries.push(NodeRange::new(node, range))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn each(&self, callback: &fn(nr: &NodeRange) -> bool) -> bool {
|
pub fn each(&self, callback: |nr: &NodeRange| -> bool) -> bool {
|
||||||
for nr in self.entries.iter() {
|
for nr in self.entries.iter() {
|
||||||
if !callback(nr) {
|
if !callback(nr) {
|
||||||
break
|
break
|
||||||
|
@ -63,14 +64,14 @@ impl ElementMapping {
|
||||||
let entries = &mut self.entries;
|
let entries = &mut self.entries;
|
||||||
|
|
||||||
debug!("--- Old boxes: ---");
|
debug!("--- Old boxes: ---");
|
||||||
for (i, box) in old_boxes.iter().enumerate() {
|
for (i, box_) in old_boxes.iter().enumerate() {
|
||||||
debug!("{:u} --> {:s}", i, box.debug_str());
|
debug!("{:u} --> {:s}", i, box_.debug_str());
|
||||||
}
|
}
|
||||||
debug!("------------------");
|
debug!("------------------");
|
||||||
|
|
||||||
debug!("--- New boxes: ---");
|
debug!("--- New boxes: ---");
|
||||||
for (i, box) in new_boxes.iter().enumerate() {
|
for (i, box_) in new_boxes.iter().enumerate() {
|
||||||
debug!("{:u} --> {:s}", i, box.debug_str());
|
debug!("{:u} --> {:s}", i, box_.debug_str());
|
||||||
}
|
}
|
||||||
debug!("------------------");
|
debug!("------------------");
|
||||||
|
|
||||||
|
@ -125,7 +126,7 @@ impl ElementMapping {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Data that layout associates with a node.
|
/// Data that layout associates with a node.
|
||||||
pub struct LayoutData {
|
pub struct PrivateLayoutData {
|
||||||
/// The results of CSS matching for this node.
|
/// The results of CSS matching for this node.
|
||||||
before_applicable_declarations: ~[Arc<~[PropertyDeclaration]>],
|
before_applicable_declarations: ~[Arc<~[PropertyDeclaration]>],
|
||||||
|
|
||||||
|
@ -148,10 +149,10 @@ pub struct LayoutData {
|
||||||
flow_construction_result: ConstructionResult,
|
flow_construction_result: ConstructionResult,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LayoutData {
|
impl PrivateLayoutData {
|
||||||
/// Creates new layout data.
|
/// Creates new layout data.
|
||||||
pub fn new() -> LayoutData {
|
pub fn new() -> PrivateLayoutData {
|
||||||
LayoutData {
|
PrivateLayoutData {
|
||||||
applicable_declarations: ~[],
|
applicable_declarations: ~[],
|
||||||
before_applicable_declarations: ~[],
|
before_applicable_declarations: ~[],
|
||||||
after_applicable_declarations: ~[],
|
after_applicable_declarations: ~[],
|
||||||
|
@ -164,35 +165,35 @@ impl LayoutData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct LayoutDataWrapper {
|
||||||
|
chan: Option<LayoutChan>,
|
||||||
|
data: ~PrivateLayoutData,
|
||||||
|
}
|
||||||
|
|
||||||
/// A trait that allows access to the layout data of a DOM node.
|
/// A trait that allows access to the layout data of a DOM node.
|
||||||
pub trait LayoutDataAccess {
|
pub trait LayoutDataAccess {
|
||||||
/// Borrows the layout data without checks.
|
/// Borrows the layout data without checks.
|
||||||
///
|
///
|
||||||
/// FIXME(pcwalton): Make safe.
|
/// FIXME(pcwalton): Make safe.
|
||||||
unsafe fn borrow_layout_data_unchecked<'a>(&'a self) -> &'a Option<~LayoutData>;
|
// unsafe fn borrow_layout_data_unchecked<'a>(&'a self) -> &'a Option<~LayoutData>;
|
||||||
/// Borrows the layout data immutably. Fails on a conflicting borrow.
|
/// Borrows the layout data immutably. Fails on a conflicting borrow.
|
||||||
fn borrow_layout_data<'a>(&'a self) -> SlotRef<'a,Option<~LayoutData>>;
|
fn borrow_layout_data<'a>(&'a self) -> Ref<'a,Option<LayoutDataWrapper>>;
|
||||||
/// Borrows the layout data mutably. Fails on a conflicting borrow.
|
/// Borrows the layout data mutably. Fails on a conflicting borrow.
|
||||||
fn mutate_layout_data<'a>(&'a self) -> MutSlotRef<'a,Option<~LayoutData>>;
|
fn mutate_layout_data<'a>(&'a self) -> RefMut<'a,Option<LayoutDataWrapper>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> LayoutDataAccess for LayoutNode<'self> {
|
impl<'ln> LayoutDataAccess for LayoutNode<'ln> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn borrow_layout_data_unchecked<'a>(&'a self) -> &'a Option<~LayoutData> {
|
fn borrow_layout_data<'a>(&'a self) -> Ref<'a,Option<LayoutDataWrapper>> {
|
||||||
cast::transmute(self.get().layout_data.borrow_unchecked())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn borrow_layout_data<'a>(&'a self) -> SlotRef<'a,Option<~LayoutData>> {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
cast::transmute(self.get().layout_data.borrow())
|
cast::transmute(self.get().layout_data.borrow())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn mutate_layout_data<'a>(&'a self) -> MutSlotRef<'a,Option<~LayoutData>> {
|
fn mutate_layout_data<'a>(&'a self) -> RefMut<'a,Option<LayoutDataWrapper>> {
|
||||||
unsafe {
|
unsafe {
|
||||||
cast::transmute(self.get().layout_data.mutate())
|
cast::transmute(self.get().layout_data.borrow_mut())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,17 +29,17 @@ use style::{PropertyDeclarationBlock, TElement, TNode};
|
||||||
/// A wrapper so that layout can access only the methods that it should have access to. Layout must
|
/// A wrapper so that layout can access only the methods that it should have access to. Layout must
|
||||||
/// only ever see these and must never see instances of `AbstractNode`.
|
/// only ever see these and must never see instances of `AbstractNode`.
|
||||||
#[deriving(Clone, Eq)]
|
#[deriving(Clone, Eq)]
|
||||||
pub struct LayoutNode<'self> {
|
pub struct LayoutNode<'a> {
|
||||||
/// The wrapped node.
|
/// The wrapped node.
|
||||||
priv node: AbstractNode,
|
priv node: AbstractNode,
|
||||||
|
|
||||||
/// Being chained to a value prevents `LayoutNode`s from escaping.
|
/// Being chained to a value prevents `LayoutNode`s from escaping.
|
||||||
priv chain: &'self (),
|
priv chain: &'a (),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> LayoutNode<'self> {
|
impl<'ln> LayoutNode<'ln> {
|
||||||
/// Creates a new layout node, scoped to the given closure.
|
/// Creates a new layout node, scoped to the given closure.
|
||||||
pub unsafe fn with_layout_node<R>(node: AbstractNode, f: &fn<'a>(LayoutNode<'a>) -> R) -> R {
|
pub unsafe fn with_layout_node<R>(node: AbstractNode, f: <'a> |LayoutNode<'a>| -> R) -> R {
|
||||||
let heavy_iron_ball = ();
|
let heavy_iron_ball = ();
|
||||||
f(LayoutNode {
|
f(LayoutNode {
|
||||||
node: node,
|
node: node,
|
||||||
|
@ -48,7 +48,7 @@ impl<'self> LayoutNode<'self> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new layout node with the same lifetime as this layout node.
|
/// Creates a new layout node with the same lifetime as this layout node.
|
||||||
unsafe fn new_with_this_lifetime(&self, node: AbstractNode) -> LayoutNode<'self> {
|
unsafe fn new_with_this_lifetime(&self, node: AbstractNode) -> LayoutNode<'ln> {
|
||||||
LayoutNode {
|
LayoutNode {
|
||||||
node: node,
|
node: node,
|
||||||
chain: self.chain,
|
chain: self.chain,
|
||||||
|
@ -62,14 +62,14 @@ impl<'self> LayoutNode<'self> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the first child of this node.
|
/// Returns the first child of this node.
|
||||||
pub fn first_child(&self) -> Option<LayoutNode<'self>> {
|
pub fn first_child(&self) -> Option<LayoutNode<'ln>> {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.node.first_child().map(|node| self.new_with_this_lifetime(node))
|
self.node.first_child().map(|node| self.new_with_this_lifetime(node))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the first child of this node.
|
/// Returns the first child of this node.
|
||||||
pub fn last_child(&self) -> Option<LayoutNode<'self>> {
|
pub fn last_child(&self) -> Option<LayoutNode<'ln>> {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.node.last_child().map(|node| self.new_with_this_lifetime(node))
|
self.node.last_child().map(|node| self.new_with_this_lifetime(node))
|
||||||
}
|
}
|
||||||
|
@ -78,14 +78,14 @@ impl<'self> LayoutNode<'self> {
|
||||||
/// Iterates over this node and all its descendants, in preorder.
|
/// Iterates over this node and all its descendants, in preorder.
|
||||||
///
|
///
|
||||||
/// FIXME(pcwalton): Terribly inefficient. We should use parallelism.
|
/// FIXME(pcwalton): Terribly inefficient. We should use parallelism.
|
||||||
pub fn traverse_preorder(&self) -> LayoutTreeIterator<'self> {
|
pub fn traverse_preorder(&self) -> LayoutTreeIterator<'ln> {
|
||||||
let mut nodes = ~[];
|
let mut nodes = ~[];
|
||||||
gather_layout_nodes(self, &mut nodes, false);
|
gather_layout_nodes(self, &mut nodes, false);
|
||||||
LayoutTreeIterator::new(nodes)
|
LayoutTreeIterator::new(nodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator over this node's children.
|
/// Returns an iterator over this node's children.
|
||||||
pub fn children(&self) -> LayoutNodeChildrenIterator<'self> {
|
pub fn children(&self) -> LayoutNodeChildrenIterator<'ln> {
|
||||||
LayoutNodeChildrenIterator {
|
LayoutNodeChildrenIterator {
|
||||||
current_node: self.first_child(),
|
current_node: self.first_child(),
|
||||||
}
|
}
|
||||||
|
@ -110,7 +110,7 @@ impl<'self> LayoutNode<'self> {
|
||||||
/// Downcasts this node to an image element and calls the given closure.
|
/// Downcasts this node to an image element and calls the given closure.
|
||||||
///
|
///
|
||||||
/// FIXME(pcwalton): RAII.
|
/// FIXME(pcwalton): RAII.
|
||||||
unsafe fn with_image_element<R>(self, f: &fn(&HTMLImageElement) -> R) -> R {
|
unsafe fn with_image_element<R>(self, f: |&HTMLImageElement| -> R) -> R {
|
||||||
if !self.node.is_image_element() {
|
if !self.node.is_image_element() {
|
||||||
fail!(~"node is not an image element");
|
fail!(~"node is not an image element");
|
||||||
}
|
}
|
||||||
|
@ -131,7 +131,7 @@ impl<'self> LayoutNode<'self> {
|
||||||
/// Downcasts this node to an iframe element and calls the given closure.
|
/// Downcasts this node to an iframe element and calls the given closure.
|
||||||
///
|
///
|
||||||
/// FIXME(pcwalton): RAII.
|
/// FIXME(pcwalton): RAII.
|
||||||
unsafe fn with_iframe_element<R>(self, f: &fn(&HTMLIFrameElement) -> R) -> R {
|
unsafe fn with_iframe_element<R>(self, f: |&HTMLIFrameElement| -> R) -> R {
|
||||||
if !self.node.is_iframe_element() {
|
if !self.node.is_iframe_element() {
|
||||||
fail!(~"node is not an iframe element");
|
fail!(~"node is not an iframe element");
|
||||||
}
|
}
|
||||||
|
@ -164,7 +164,7 @@ impl<'self> LayoutNode<'self> {
|
||||||
/// Downcasts this node to a text node and calls the given closure.
|
/// Downcasts this node to a text node and calls the given closure.
|
||||||
///
|
///
|
||||||
/// FIXME(pcwalton): RAII.
|
/// FIXME(pcwalton): RAII.
|
||||||
unsafe fn with_text<R>(self, f: &fn(&Text) -> R) -> R {
|
unsafe fn with_text<R>(self, f: |&Text| -> R) -> R {
|
||||||
self.node.with_imm_text(f)
|
self.node.with_imm_text(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,20 +228,20 @@ impl<'self> LayoutNode<'self> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> TNode<LayoutElement<'self>> for LayoutNode<'self> {
|
impl<'ln> TNode<LayoutElement<'ln>> for LayoutNode<'ln> {
|
||||||
fn parent_node(&self) -> Option<LayoutNode<'self>> {
|
fn parent_node(&self) -> Option<LayoutNode<'ln>> {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.node.node().parent_node.map(|node| self.new_with_this_lifetime(node))
|
self.node.node().parent_node.map(|node| self.new_with_this_lifetime(node))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prev_sibling(&self) -> Option<LayoutNode<'self>> {
|
fn prev_sibling(&self) -> Option<LayoutNode<'ln>> {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.node.node().prev_sibling.map(|node| self.new_with_this_lifetime(node))
|
self.node.node().prev_sibling.map(|node| self.new_with_this_lifetime(node))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_sibling(&self) -> Option<LayoutNode<'self>> {
|
fn next_sibling(&self) -> Option<LayoutNode<'ln>> {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.node.node().next_sibling.map(|node| self.new_with_this_lifetime(node))
|
self.node.node().next_sibling.map(|node| self.new_with_this_lifetime(node))
|
||||||
}
|
}
|
||||||
|
@ -249,21 +249,21 @@ impl<'self> TNode<LayoutElement<'self>> for LayoutNode<'self> {
|
||||||
|
|
||||||
fn is_element(&self) -> bool {
|
fn is_element(&self) -> bool {
|
||||||
match self.node.type_id() {
|
match self.node.type_id() {
|
||||||
ElementNodeTypeId(*) => true,
|
ElementNodeTypeId(..) => true,
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_document(&self) -> bool {
|
fn is_document(&self) -> bool {
|
||||||
match self.node.type_id() {
|
match self.node.type_id() {
|
||||||
DocumentNodeTypeId(*) => true,
|
DocumentNodeTypeId(..) => true,
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If this is an element, accesses the element data. Fails if this is not an element node.
|
/// If this is an element, accesses the element data. Fails if this is not an element node.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn with_element<R>(&self, f: &fn(&LayoutElement<'self>) -> R) -> R {
|
fn with_element<R>(&self, f: |&LayoutElement<'ln>| -> R) -> R {
|
||||||
self.node.with_imm_element(|element| {
|
self.node.with_imm_element(|element| {
|
||||||
// FIXME(pcwalton): Workaround until Rust gets multiple lifetime parameters on
|
// FIXME(pcwalton): Workaround until Rust gets multiple lifetime parameters on
|
||||||
// implementations.
|
// implementations.
|
||||||
|
@ -276,16 +276,16 @@ impl<'self> TNode<LayoutElement<'self>> for LayoutNode<'self> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LayoutNodeChildrenIterator<'self> {
|
pub struct LayoutNodeChildrenIterator<'a> {
|
||||||
priv current_node: Option<LayoutNode<'self>>,
|
priv current_node: Option<LayoutNode<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> Iterator<LayoutNode<'self>> for LayoutNodeChildrenIterator<'self> {
|
impl<'a> Iterator<LayoutNode<'a>> for LayoutNodeChildrenIterator<'a> {
|
||||||
fn next(&mut self) -> Option<LayoutNode<'self>> {
|
fn next(&mut self) -> Option<LayoutNode<'a>> {
|
||||||
let node = self.current_node;
|
let node = self.current_node;
|
||||||
self.current_node = do self.current_node.and_then |node| {
|
self.current_node = self.current_node.and_then(|node| {
|
||||||
node.next_sibling()
|
node.next_sibling()
|
||||||
};
|
});
|
||||||
node
|
node
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -294,13 +294,13 @@ impl<'self> Iterator<LayoutNode<'self>> for LayoutNodeChildrenIterator<'self> {
|
||||||
// Easy for preorder; harder for postorder.
|
// Easy for preorder; harder for postorder.
|
||||||
//
|
//
|
||||||
// FIXME(pcwalton): Parallelism! Eventually this should just be nuked.
|
// FIXME(pcwalton): Parallelism! Eventually this should just be nuked.
|
||||||
pub struct LayoutTreeIterator<'self> {
|
pub struct LayoutTreeIterator<'a> {
|
||||||
priv nodes: ~[LayoutNode<'self>],
|
priv nodes: ~[LayoutNode<'a>],
|
||||||
priv index: uint,
|
priv index: uint,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> LayoutTreeIterator<'self> {
|
impl<'a> LayoutTreeIterator<'a> {
|
||||||
fn new(nodes: ~[LayoutNode<'self>]) -> LayoutTreeIterator<'self> {
|
fn new(nodes: ~[LayoutNode<'a>]) -> LayoutTreeIterator<'a> {
|
||||||
LayoutTreeIterator {
|
LayoutTreeIterator {
|
||||||
nodes: nodes,
|
nodes: nodes,
|
||||||
index: 0,
|
index: 0,
|
||||||
|
@ -308,8 +308,8 @@ impl<'self> LayoutTreeIterator<'self> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> Iterator<LayoutNode<'self>> for LayoutTreeIterator<'self> {
|
impl<'a> Iterator<LayoutNode<'a>> for LayoutTreeIterator<'a> {
|
||||||
fn next(&mut self) -> Option<LayoutNode<'self>> {
|
fn next(&mut self) -> Option<LayoutNode<'a>> {
|
||||||
if self.index >= self.nodes.len() {
|
if self.index >= self.nodes.len() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
@ -360,17 +360,17 @@ pub trait PostorderNodeMutTraversal {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A wrapper around elements that ensures layout can only ever access safe properties.
|
/// A wrapper around elements that ensures layout can only ever access safe properties.
|
||||||
pub struct LayoutElement<'self> {
|
pub struct LayoutElement<'le> {
|
||||||
priv element: &'self Element,
|
priv element: &'le Element,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> LayoutElement<'self> {
|
impl<'le> LayoutElement<'le> {
|
||||||
pub fn style_attribute(&self) -> &'self Option<PropertyDeclarationBlock> {
|
pub fn style_attribute(&self) -> &'le Option<PropertyDeclarationBlock> {
|
||||||
&self.element.style_attribute
|
&self.element.style_attribute
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> TElement for LayoutElement<'self> {
|
impl<'le> TElement for LayoutElement<'le> {
|
||||||
fn get_local_name<'a>(&'a self) -> &'a str {
|
fn get_local_name<'a>(&'a self) -> &'a str {
|
||||||
self.element.tag_name.as_slice()
|
self.element.tag_name.as_slice()
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,26 +2,10 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
#[macro_escape];
|
#[macro_escape];
|
||||||
macro_rules! special_stream(
|
|
||||||
($Chan:ident) => (
|
|
||||||
{
|
|
||||||
let (port, chan) = stream::();
|
|
||||||
(port, $Chan::new(chan))
|
|
||||||
}
|
|
||||||
);
|
|
||||||
)
|
|
||||||
|
|
||||||
// Spawn a task, capturing the listed variables in a way that avoids the
|
// Spawn a task, capturing the listed variables in a way that avoids the
|
||||||
// move-from-closure error. This is sugar around the function spawn_with,
|
// move-from-closure error. This is sugar around the function spawn_with,
|
||||||
// taking care of building a tuple and a lambda.
|
// taking care of building a tuple and a lambda.
|
||||||
//
|
|
||||||
// FIXME: Once cross-crate macros work, there are a few places outside of
|
|
||||||
// the main crate which could benefit from this macro.
|
|
||||||
macro_rules! spawn_with(
|
|
||||||
($task:expr, [ $($var:ident),+ ], $body:block) => (
|
|
||||||
do ($task).spawn_with(( $($var),+ , () )) |( $($var),+ , () )| $body
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
macro_rules! bitfield(
|
macro_rules! bitfield(
|
||||||
($bitfieldname:ident, $getter:ident, $setter:ident, $value:expr) => (
|
($bitfieldname:ident, $getter:ident, $setter:ident, $value:expr) => (
|
||||||
|
|
|
@ -15,12 +15,10 @@ use script::layout_interface::LayoutChan;
|
||||||
use script::script_task::LoadMsg;
|
use script::script_task::LoadMsg;
|
||||||
use script::script_task::{AttachLayoutMsg, NewLayoutInfo, ScriptTask, ScriptChan};
|
use script::script_task::{AttachLayoutMsg, NewLayoutInfo, ScriptTask, ScriptChan};
|
||||||
use script::script_task;
|
use script::script_task;
|
||||||
use servo_msg::constellation_msg::{ConstellationChan, FailureMsg, PipelineId, SubpageId};
|
use servo_msg::constellation_msg::{ConstellationChan, PipelineId, SubpageId};
|
||||||
use servo_net::image_cache_task::ImageCacheTask;
|
use servo_net::image_cache_task::ImageCacheTask;
|
||||||
use servo_net::resource_task::ResourceTask;
|
use servo_net::resource_task::ResourceTask;
|
||||||
use servo_util::time::ProfilerChan;
|
use servo_util::time::ProfilerChan;
|
||||||
use std::task;
|
|
||||||
use std::comm;
|
|
||||||
|
|
||||||
/// A uniquely-identifiable pipeline of script task, layout task, and render task.
|
/// A uniquely-identifiable pipeline of script task, layout task, and render task.
|
||||||
pub struct Pipeline {
|
pub struct Pipeline {
|
||||||
|
@ -55,10 +53,10 @@ impl Pipeline {
|
||||||
opts: Opts,
|
opts: Opts,
|
||||||
script_pipeline: &Pipeline)
|
script_pipeline: &Pipeline)
|
||||||
-> Pipeline {
|
-> Pipeline {
|
||||||
let (layout_port, layout_chan) = special_stream!(LayoutChan);
|
let (layout_port, layout_chan) = LayoutChan::new();
|
||||||
let (render_port, render_chan) = special_stream!(RenderChan);
|
let (render_port, render_chan) = RenderChan::new();
|
||||||
let (render_shutdown_port, render_shutdown_chan) = comm::stream();
|
let (render_shutdown_port, render_shutdown_chan) = Chan::new();
|
||||||
let (layout_shutdown_port, layout_shutdown_chan) = comm::stream();
|
let (layout_shutdown_port, layout_shutdown_chan) = Chan::new();
|
||||||
|
|
||||||
RenderTask::create(id,
|
RenderTask::create(id,
|
||||||
render_port,
|
render_port,
|
||||||
|
@ -70,6 +68,7 @@ impl Pipeline {
|
||||||
|
|
||||||
LayoutTask::create(id,
|
LayoutTask::create(id,
|
||||||
layout_port,
|
layout_port,
|
||||||
|
layout_chan.clone(),
|
||||||
constellation_chan,
|
constellation_chan,
|
||||||
script_pipeline.script_chan.clone(),
|
script_pipeline.script_chan.clone(),
|
||||||
render_chan.clone(),
|
render_chan.clone(),
|
||||||
|
@ -105,11 +104,11 @@ impl Pipeline {
|
||||||
window_size: Size2D<uint>,
|
window_size: Size2D<uint>,
|
||||||
opts: Opts)
|
opts: Opts)
|
||||||
-> Pipeline {
|
-> Pipeline {
|
||||||
let (script_port, script_chan) = special_stream!(ScriptChan);
|
let (script_port, script_chan) = ScriptChan::new();
|
||||||
let (layout_port, layout_chan) = special_stream!(LayoutChan);
|
let (layout_port, layout_chan) = LayoutChan::new();
|
||||||
let (render_port, render_chan) = special_stream!(RenderChan);
|
let (render_port, render_chan) = RenderChan::new();
|
||||||
let (render_shutdown_port, render_shutdown_chan) = comm::stream();
|
let (render_shutdown_port, render_shutdown_chan) = Chan::new();
|
||||||
let (layout_shutdown_port, layout_shutdown_chan) = comm::stream();
|
let (layout_shutdown_port, layout_shutdown_chan) = Chan::new();
|
||||||
let pipeline = Pipeline::new(id,
|
let pipeline = Pipeline::new(id,
|
||||||
subpage_id,
|
subpage_id,
|
||||||
script_chan.clone(),
|
script_chan.clone(),
|
||||||
|
@ -118,65 +117,36 @@ impl Pipeline {
|
||||||
layout_shutdown_port,
|
layout_shutdown_port,
|
||||||
render_shutdown_port);
|
render_shutdown_port);
|
||||||
|
|
||||||
// Wrap task creation within a supervised task so that failure will
|
// FIXME(#1434): add back failure supervision
|
||||||
// only tear down those tasks instead of ours.
|
|
||||||
let hard_fail = opts.hard_fail;
|
|
||||||
let failure_chan = constellation_chan.clone();
|
|
||||||
let mut supervised_task = task::task();
|
|
||||||
let task_port = supervised_task.future_result();
|
|
||||||
supervised_task.supervised();
|
|
||||||
|
|
||||||
spawn_with!(supervised_task, [
|
ScriptTask::create(id,
|
||||||
script_port,
|
compositor_chan.clone(),
|
||||||
resource_task,
|
layout_chan.clone(),
|
||||||
render_port,
|
script_port,
|
||||||
layout_port,
|
script_chan.clone(),
|
||||||
constellation_chan,
|
constellation_chan.clone(),
|
||||||
image_cache_task,
|
resource_task,
|
||||||
profiler_chan,
|
image_cache_task.clone(),
|
||||||
layout_shutdown_chan,
|
window_size);
|
||||||
render_shutdown_chan
|
|
||||||
], {
|
|
||||||
ScriptTask::create(id,
|
|
||||||
compositor_chan.clone(),
|
|
||||||
layout_chan.clone(),
|
|
||||||
script_port,
|
|
||||||
script_chan.clone(),
|
|
||||||
constellation_chan.clone(),
|
|
||||||
resource_task,
|
|
||||||
image_cache_task.clone(),
|
|
||||||
window_size);
|
|
||||||
|
|
||||||
RenderTask::create(id,
|
RenderTask::create(id,
|
||||||
render_port,
|
render_port,
|
||||||
compositor_chan.clone(),
|
compositor_chan.clone(),
|
||||||
constellation_chan.clone(),
|
constellation_chan.clone(),
|
||||||
opts.clone(),
|
opts.clone(),
|
||||||
profiler_chan.clone(),
|
profiler_chan.clone(),
|
||||||
render_shutdown_chan);
|
render_shutdown_chan);
|
||||||
|
|
||||||
LayoutTask::create(id,
|
LayoutTask::create(id,
|
||||||
layout_port,
|
layout_port,
|
||||||
constellation_chan,
|
layout_chan.clone(),
|
||||||
script_chan.clone(),
|
constellation_chan,
|
||||||
render_chan.clone(),
|
script_chan.clone(),
|
||||||
image_cache_task,
|
render_chan.clone(),
|
||||||
opts.clone(),
|
image_cache_task,
|
||||||
profiler_chan,
|
opts.clone(),
|
||||||
layout_shutdown_chan);
|
profiler_chan,
|
||||||
});
|
layout_shutdown_chan);
|
||||||
|
|
||||||
spawn_with!(task::task(), [failure_chan], {
|
|
||||||
match task_port.recv() {
|
|
||||||
Ok(*) => (),
|
|
||||||
Err(*) => {
|
|
||||||
if hard_fail {
|
|
||||||
fail!("Pipeline failed in hard-fail mode");
|
|
||||||
}
|
|
||||||
failure_chan.send(FailureMsg(id, subpage_id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
pipeline
|
pipeline
|
||||||
}
|
}
|
||||||
|
@ -215,9 +185,9 @@ impl Pipeline {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reload(&mut self) {
|
pub fn reload(&mut self) {
|
||||||
do self.url.clone().map() |url| {
|
self.url.clone().map(|url| {
|
||||||
self.load(url);
|
self.load(url);
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exit(&self) {
|
pub fn exit(&self) {
|
||||||
|
@ -226,8 +196,8 @@ impl Pipeline {
|
||||||
|
|
||||||
// Wait until all slave tasks have terminated and run destructors
|
// Wait until all slave tasks have terminated and run destructors
|
||||||
// NOTE: We don't wait for script task as we don't always own it
|
// NOTE: We don't wait for script task as we don't always own it
|
||||||
self.render_shutdown_port.try_recv();
|
self.render_shutdown_port.recv_opt();
|
||||||
self.layout_shutdown_port.try_recv();
|
self.layout_shutdown_port.recv_opt();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_sendable(&self) -> CompositionPipeline {
|
pub fn to_sendable(&self) -> CompositionPipeline {
|
||||||
|
|
|
@ -30,9 +30,7 @@ impl ApplicationMethods for Application {
|
||||||
fn new() -> Application {
|
fn new() -> Application {
|
||||||
// Per GLFW docs it's safe to set the error callback before calling
|
// Per GLFW docs it's safe to set the error callback before calling
|
||||||
// glfwInit(), and this way we notice errors from init too.
|
// glfwInit(), and this way we notice errors from init too.
|
||||||
do glfw::set_error_callback |_error_code, description| {
|
glfw::set_error_callback(~glfw::LogErrorHandler);
|
||||||
error!("GLFW error: {:s}", description);
|
|
||||||
};
|
|
||||||
glfw::init();
|
glfw::init();
|
||||||
Application
|
Application
|
||||||
}
|
}
|
||||||
|
@ -45,6 +43,38 @@ impl Drop for Application {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! glfw_callback(
|
||||||
|
(
|
||||||
|
$callback:path ($($arg:ident: $arg_ty:ty),*) $block:expr
|
||||||
|
) => ({
|
||||||
|
struct GlfwCallback;
|
||||||
|
impl $callback for GlfwCallback {
|
||||||
|
fn call(&self $(, $arg: $arg_ty)*) {
|
||||||
|
$block
|
||||||
|
}
|
||||||
|
}
|
||||||
|
~GlfwCallback
|
||||||
|
});
|
||||||
|
|
||||||
|
(
|
||||||
|
[$($state:ident: $state_ty:ty),*],
|
||||||
|
$callback:path ($($arg:ident: $arg_ty:ty),*) $block:expr
|
||||||
|
) => ({
|
||||||
|
struct GlfwCallback {
|
||||||
|
$($state: $state_ty,)*
|
||||||
|
}
|
||||||
|
impl $callback for GlfwCallback {
|
||||||
|
fn call(&self $(, $arg: $arg_ty)*) {
|
||||||
|
$block
|
||||||
|
}
|
||||||
|
}
|
||||||
|
~GlfwCallback {
|
||||||
|
$($state: $state,)*
|
||||||
|
}
|
||||||
|
});
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
/// The type of a window.
|
/// The type of a window.
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
glfw_window: glfw::Window,
|
glfw_window: glfw::Window,
|
||||||
|
@ -90,43 +120,50 @@ impl WindowMethods<Application> for Window {
|
||||||
install_local_window(window);
|
install_local_window(window);
|
||||||
|
|
||||||
// Register event handlers.
|
// Register event handlers.
|
||||||
do window.glfw_window.set_framebuffer_size_callback |_win, width, height| {
|
window.glfw_window.set_framebuffer_size_callback(
|
||||||
local_window().event_queue.push(ResizeWindowEvent(width as uint, height as uint))
|
glfw_callback!(glfw::FramebufferSizeCallback(_win: &glfw::Window, width: i32, height: i32) {
|
||||||
}
|
local_window().event_queue.push(ResizeWindowEvent(width as uint, height as uint));
|
||||||
do window.glfw_window.set_refresh_callback |_win| {
|
}));
|
||||||
local_window().event_queue.push(RefreshWindowEvent)
|
window.glfw_window.set_refresh_callback(
|
||||||
}
|
glfw_callback!(glfw::WindowRefreshCallback(_win: &glfw::Window) {
|
||||||
do window.glfw_window.set_key_callback |_win, key, _scancode, action, mods| {
|
local_window().event_queue.push(RefreshWindowEvent);
|
||||||
if action == glfw::Press {
|
}));
|
||||||
local_window().handle_key(key, mods)
|
window.glfw_window.set_key_callback(
|
||||||
}
|
glfw_callback!(glfw::KeyCallback(_win: &glfw::Window, key: glfw::Key, _scancode: c_int,
|
||||||
}
|
action: glfw::Action, mods: glfw::Modifiers) {
|
||||||
do window.glfw_window.set_mouse_button_callback |win, button, action, _mods| {
|
if action == glfw::Press {
|
||||||
let (x, y) = win.get_cursor_pos();
|
local_window().handle_key(key, mods)
|
||||||
//handle hidpi displays, since GLFW returns non-hi-def coordinates.
|
}
|
||||||
let (backing_size, _) = win.get_framebuffer_size();
|
}));
|
||||||
let (window_size, _) = win.get_size();
|
window.glfw_window.set_mouse_button_callback(
|
||||||
let hidpi = (backing_size as f32) / (window_size as f32);
|
glfw_callback!(glfw::MouseButtonCallback(win: &glfw::Window, button: glfw::MouseButton,
|
||||||
let x = x as f32 * hidpi;
|
action: glfw::Action, _mods: glfw::Modifiers) {
|
||||||
let y = y as f32 * hidpi;
|
let (x, y) = win.get_cursor_pos();
|
||||||
if button == glfw::MouseButtonLeft || button == glfw::MouseButtonRight {
|
//handle hidpi displays, since GLFW returns non-hi-def coordinates.
|
||||||
local_window().handle_mouse(button, action, x as i32, y as i32);
|
let (backing_size, _) = win.get_framebuffer_size();
|
||||||
}
|
let (window_size, _) = win.get_size();
|
||||||
}
|
let hidpi = (backing_size as f32) / (window_size as f32);
|
||||||
do window.glfw_window.set_scroll_callback |win, x_offset, y_offset| {
|
let x = x as f32 * hidpi;
|
||||||
let dx = (x_offset as f32) * 30.0;
|
let y = y as f32 * hidpi;
|
||||||
let dy = (y_offset as f32) * 30.0;
|
if button == glfw::MouseButtonLeft || button == glfw::MouseButtonRight {
|
||||||
|
local_window().handle_mouse(button, action, x as i32, y as i32);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
window.glfw_window.set_scroll_callback(
|
||||||
|
glfw_callback!(glfw::ScrollCallback(win: &glfw::Window, xpos: f64, ypos: f64) {
|
||||||
|
let dx = (xpos as f32) * 30.0;
|
||||||
|
let dy = (ypos as f32) * 30.0;
|
||||||
|
|
||||||
let (x, y) = win.get_cursor_pos();
|
let (x, y) = win.get_cursor_pos();
|
||||||
//handle hidpi displays, since GLFW returns non-hi-def coordinates.
|
//handle hidpi displays, since GLFW returns non-hi-def coordinates.
|
||||||
let (backing_size, _) = win.get_framebuffer_size();
|
let (backing_size, _) = win.get_framebuffer_size();
|
||||||
let (window_size, _) = win.get_size();
|
let (window_size, _) = win.get_size();
|
||||||
let hidpi = (backing_size as f32) / (window_size as f32);
|
let hidpi = (backing_size as f32) / (window_size as f32);
|
||||||
let x = x as f32 * hidpi;
|
let x = x as f32 * hidpi;
|
||||||
let y = y as f32 * hidpi;
|
let y = y as f32 * hidpi;
|
||||||
|
|
||||||
local_window().event_queue.push(ScrollWindowEvent(Point2D(dx, dy), Point2D(x as i32, y as i32)));
|
local_window().event_queue.push(ScrollWindowEvent(Point2D(dx, dy), Point2D(x as i32, y as i32)));
|
||||||
}
|
}));
|
||||||
|
|
||||||
window
|
window
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,22 +7,22 @@
|
||||||
use windowing::{ApplicationMethods, WindowEvent, WindowMethods};
|
use windowing::{ApplicationMethods, WindowEvent, WindowMethods};
|
||||||
use windowing::{IdleWindowEvent, ResizeWindowEvent, LoadUrlWindowEvent, MouseWindowEventClass};
|
use windowing::{IdleWindowEvent, ResizeWindowEvent, LoadUrlWindowEvent, MouseWindowEventClass};
|
||||||
use windowing::{ScrollWindowEvent, ZoomWindowEvent, NavigationWindowEvent, FinishedWindowEvent};
|
use windowing::{ScrollWindowEvent, ZoomWindowEvent, NavigationWindowEvent, FinishedWindowEvent};
|
||||||
use windowing::{QuitWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEvent, MouseWindowMouseUpEvent};
|
use windowing::{MouseWindowClickEvent, MouseWindowMouseDownEvent, MouseWindowMouseUpEvent};
|
||||||
use windowing::{Forward, Back};
|
use windowing::{Forward, Back};
|
||||||
|
|
||||||
use alert::{Alert, AlertMethods};
|
use alert::{Alert, AlertMethods};
|
||||||
use std::libc::c_int;
|
use std::libc::{c_int, c_uchar};
|
||||||
use std::local_data;
|
use std::local_data;
|
||||||
use geom::point::Point2D;
|
use geom::point::Point2D;
|
||||||
use geom::size::Size2D;
|
use geom::size::Size2D;
|
||||||
use servo_msg::compositor_msg::{IdleRenderState, RenderState, RenderingRenderState};
|
use servo_msg::compositor_msg::{IdleRenderState, RenderState, RenderingRenderState};
|
||||||
use servo_msg::compositor_msg::{FinishedLoading, Blank, Loading, PerformingLayout, ReadyState};
|
use servo_msg::compositor_msg::{FinishedLoading, Blank, ReadyState};
|
||||||
|
|
||||||
use glut::glut::{ACTIVE_CTRL, ACTIVE_SHIFT, DOUBLE, HAVE_PRECISE_MOUSE_WHEEL, WindowHeight};
|
use glut::glut::{ACTIVE_SHIFT, DOUBLE, WindowHeight};
|
||||||
use glut::glut::WindowWidth;
|
use glut::glut::WindowWidth;
|
||||||
use glut::glut;
|
use glut::glut;
|
||||||
|
|
||||||
static THROBBER: [char, ..8] = [ '⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷' ];
|
// static THROBBER: [char, ..8] = [ '⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷' ];
|
||||||
|
|
||||||
/// A structure responsible for setting up and tearing down the entire windowing system.
|
/// A structure responsible for setting up and tearing down the entire windowing system.
|
||||||
pub struct Application;
|
pub struct Application;
|
||||||
|
@ -85,31 +85,47 @@ impl WindowMethods<Application> for Window {
|
||||||
// Register event handlers.
|
// Register event handlers.
|
||||||
|
|
||||||
//Added dummy display callback to freeglut. According to freeglut ref, we should register some kind of display callback after freeglut 3.0.
|
//Added dummy display callback to freeglut. According to freeglut ref, we should register some kind of display callback after freeglut 3.0.
|
||||||
do glut::display_func || {
|
|
||||||
debug!("GLUT display func registered");
|
struct DisplayCallbackState;
|
||||||
}
|
impl glut::DisplayCallback for DisplayCallbackState {
|
||||||
do glut::reshape_func(window.glut_window) |width, height| {
|
fn call(&self) {
|
||||||
local_window().event_queue.push(ResizeWindowEvent(width as uint, height as uint))
|
debug!("GLUT display func registgered");
|
||||||
}
|
|
||||||
do glut::keyboard_func |key, _, _| {
|
|
||||||
local_window().handle_key(key)
|
|
||||||
}
|
|
||||||
do glut::mouse_func |button, state, x, y| {
|
|
||||||
if button < 3 {
|
|
||||||
local_window().handle_mouse(button, state, x, y);
|
|
||||||
}
|
}
|
||||||
else {
|
}
|
||||||
match button {
|
glut::display_func(~DisplayCallbackState);
|
||||||
3 => {
|
struct ReshapeCallbackState;
|
||||||
local_window().event_queue.push(ScrollWindowEvent(Point2D(0.0, 5.0 as f32), Point2D(0.0 as i32, 5.0 as i32)));
|
impl glut::ReshapeCallback for ReshapeCallbackState {
|
||||||
},
|
fn call(&self, width: c_int, height: c_int) {
|
||||||
4 => {
|
local_window().event_queue.push(ResizeWindowEvent(width as uint, height as uint))
|
||||||
local_window().event_queue.push(ScrollWindowEvent(Point2D(0.0, -5.0 as f32), Point2D(0.0 as i32, -5.0 as i32)));
|
}
|
||||||
},
|
}
|
||||||
_ => {}
|
glut::reshape_func(glut_window, ~ReshapeCallbackState);
|
||||||
|
struct KeyboardCallbackState;
|
||||||
|
impl glut::KeyboardCallback for KeyboardCallbackState {
|
||||||
|
fn call(&self, key: c_uchar, _x: c_int, _y: c_int) {
|
||||||
|
local_window().handle_key(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
glut::keyboard_func(~KeyboardCallbackState);
|
||||||
|
struct MouseCallbackState;
|
||||||
|
impl glut::MouseCallback for MouseCallbackState {
|
||||||
|
fn call(&self, button: c_int, state: c_int, x: c_int, y: c_int) {
|
||||||
|
if button < 3 {
|
||||||
|
local_window().handle_mouse(button, state, x, y);
|
||||||
|
} else {
|
||||||
|
match button {
|
||||||
|
3 => {
|
||||||
|
local_window().event_queue.push(ScrollWindowEvent(Point2D(0.0, 5.0 as f32), Point2D(0.0 as i32, 5.0 as i32)));
|
||||||
|
},
|
||||||
|
4 => {
|
||||||
|
local_window().event_queue.push(ScrollWindowEvent(Point2D(0.0, -5.0 as f32), Point2D(0.0 as i32, -5.0 as i32)));
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
glut::mouse_func(~MouseCallbackState);
|
||||||
|
|
||||||
window
|
window
|
||||||
}
|
}
|
||||||
|
@ -165,28 +181,28 @@ impl WindowMethods<Application> for Window {
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
/// Helper function to set the window title in accordance with the ready state.
|
/// Helper function to set the window title in accordance with the ready state.
|
||||||
fn update_window_title(&self) {
|
// fn update_window_title(&self) {
|
||||||
let throbber = THROBBER[self.throbber_frame];
|
// let throbber = THROBBER[self.throbber_frame];
|
||||||
match self.ready_state {
|
// match self.ready_state {
|
||||||
Blank => {
|
// Blank => {
|
||||||
glut::set_window_title(self.glut_window, "Blank")
|
// glut::set_window_title(self.glut_window, "Blank")
|
||||||
}
|
// }
|
||||||
Loading => {
|
// Loading => {
|
||||||
glut::set_window_title(self.glut_window, format!("{:c} Loading . Servo", throbber))
|
// glut::set_window_title(self.glut_window, format!("{:c} Loading . Servo", throbber))
|
||||||
}
|
// }
|
||||||
PerformingLayout => {
|
// PerformingLayout => {
|
||||||
glut::set_window_title(self.glut_window, format!("{:c} Performing Layout . Servo", throbber))
|
// glut::set_window_title(self.glut_window, format!("{:c} Performing Layout . Servo", throbber))
|
||||||
}
|
// }
|
||||||
FinishedLoading => {
|
// FinishedLoading => {
|
||||||
match self.render_state {
|
// match self.render_state {
|
||||||
RenderingRenderState => {
|
// RenderingRenderState => {
|
||||||
glut::set_window_title(self.glut_window, format!("{:c} Rendering . Servo", throbber))
|
// glut::set_window_title(self.glut_window, format!("{:c} Rendering . Servo", throbber))
|
||||||
}
|
// }
|
||||||
IdleRenderState => glut::set_window_title(self.glut_window, "Servo"),
|
// IdleRenderState => glut::set_window_title(self.glut_window, "Servo"),
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// Helper function to handle keyboard events.
|
/// Helper function to handle keyboard events.
|
||||||
fn handle_key(&self, key: u8) {
|
fn handle_key(&self, key: u8) {
|
||||||
|
|
|
@ -2,21 +2,16 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#[link(name = "servo",
|
#[crate_id = "github.com/mozilla/servo"];
|
||||||
vers = "0.1",
|
|
||||||
uuid = "637ffc98-9058-471d-9de7-abfc49ef0549",
|
|
||||||
url = "http://servo.org/")];
|
|
||||||
|
|
||||||
#[comment = "The Servo Parallel Browser Project"];
|
#[comment = "The Servo Parallel Browser Project"];
|
||||||
#[license = "MPL"];
|
#[license = "MPL"];
|
||||||
#[crate_type = "lib"];
|
|
||||||
|
|
||||||
#[feature(globs, macro_rules, managed_boxes)];
|
#[feature(globs, macro_rules, managed_boxes)];
|
||||||
|
|
||||||
extern mod alert;
|
extern mod alert;
|
||||||
extern mod azure;
|
extern mod azure;
|
||||||
extern mod geom;
|
extern mod geom;
|
||||||
extern mod gfx (name = "gfx");
|
extern mod gfx;
|
||||||
#[cfg(not(target_os="android"))]
|
#[cfg(not(target_os="android"))]
|
||||||
extern mod glfw;
|
extern mod glfw;
|
||||||
#[cfg(target_os="android")]
|
#[cfg(target_os="android")]
|
||||||
|
@ -26,39 +21,50 @@ extern mod layers;
|
||||||
extern mod opengles;
|
extern mod opengles;
|
||||||
extern mod png;
|
extern mod png;
|
||||||
extern mod script;
|
extern mod script;
|
||||||
extern mod servo_net (name = "net");
|
extern mod servo_net = "net";
|
||||||
extern mod servo_msg (name = "msg");
|
extern mod servo_msg = "msg";
|
||||||
extern mod servo_util (name = "util");
|
extern mod servo_util = "util";
|
||||||
extern mod style;
|
extern mod style;
|
||||||
extern mod sharegl;
|
extern mod sharegl;
|
||||||
extern mod stb_image;
|
extern mod stb_image;
|
||||||
|
|
||||||
extern mod extra;
|
extern mod extra;
|
||||||
|
extern mod green;
|
||||||
|
extern mod native;
|
||||||
|
|
||||||
#[cfg(target_os="macos")]
|
#[cfg(target_os="macos")]
|
||||||
extern mod core_graphics;
|
extern mod core_graphics;
|
||||||
#[cfg(target_os="macos")]
|
#[cfg(target_os="macos")]
|
||||||
extern mod core_text;
|
extern mod core_text;
|
||||||
|
|
||||||
|
#[cfg(not(test))]
|
||||||
use compositing::{CompositorChan, CompositorTask};
|
use compositing::{CompositorChan, CompositorTask};
|
||||||
|
#[cfg(not(test))]
|
||||||
use constellation::Constellation;
|
use constellation::Constellation;
|
||||||
use servo_msg::constellation_msg::{ConstellationChan, InitLoadUrlMsg};
|
#[cfg(not(test))]
|
||||||
|
use servo_msg::constellation_msg::InitLoadUrlMsg;
|
||||||
|
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
use gfx::opts;
|
use gfx::opts;
|
||||||
|
|
||||||
|
#[cfg(not(test))]
|
||||||
use servo_net::image_cache_task::ImageCacheTask;
|
use servo_net::image_cache_task::ImageCacheTask;
|
||||||
|
#[cfg(not(test))]
|
||||||
use servo_net::resource_task::ResourceTask;
|
use servo_net::resource_task::ResourceTask;
|
||||||
use servo_util::time::{Profiler, ProfilerChan};
|
#[cfg(not(test))]
|
||||||
|
use servo_util::time::Profiler;
|
||||||
|
|
||||||
pub use gfx::opts::Opts;
|
pub use gfx::opts::Opts;
|
||||||
pub use gfx::text;
|
pub use gfx::text;
|
||||||
pub use servo_util::url::make_url;
|
pub use servo_util::url::make_url;
|
||||||
use std::comm;
|
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
use std::os;
|
use std::os;
|
||||||
#[cfg(not(test), target_os="android")]
|
#[cfg(not(test), target_os="android")]
|
||||||
use std::str;
|
use std::str;
|
||||||
use std::task::spawn_with;
|
#[cfg(not(test))]
|
||||||
|
use std::task::TaskOpts;
|
||||||
|
|
||||||
|
|
||||||
#[path="compositing/compositor_task.rs"]
|
#[path="compositing/compositor_task.rs"]
|
||||||
pub mod compositing;
|
pub mod compositing;
|
||||||
|
@ -78,7 +84,7 @@ pub mod pipeline;
|
||||||
|
|
||||||
pub mod layout {
|
pub mod layout {
|
||||||
pub mod block;
|
pub mod block;
|
||||||
pub mod box;
|
pub mod box_;
|
||||||
pub mod construct;
|
pub mod construct;
|
||||||
pub mod context;
|
pub mod context;
|
||||||
pub mod display_list_builder;
|
pub mod display_list_builder;
|
||||||
|
@ -106,15 +112,15 @@ pub mod util;
|
||||||
#[cfg(not(test), target_os="macos")]
|
#[cfg(not(test), target_os="macos")]
|
||||||
#[start]
|
#[start]
|
||||||
fn start(argc: int, argv: **u8) -> int {
|
fn start(argc: int, argv: **u8) -> int {
|
||||||
do std::rt::start_on_main_thread(argc, argv) {
|
native::start(argc, argv, proc() {
|
||||||
run(opts::from_cmdline_args(os::args()))
|
run(opts::from_cmdline_args(os::args()))
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(test), target_os="android")]
|
#[cfg(not(test), target_os="android")]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn android_start(argc: int, argv: **u8) -> int {
|
pub extern "C" fn android_start(argc: int, argv: **u8) -> int {
|
||||||
do std::rt::start_on_main_thread(argc, argv) {
|
native::start(argc, argv, proc() {
|
||||||
let mut args:~[~str] = ~[];
|
let mut args:~[~str] = ~[];
|
||||||
for i in range(0u, argc as uint) {
|
for i in range(0u, argc as uint) {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -122,53 +128,51 @@ pub extern "C" fn android_start(argc: int, argv: **u8) -> int {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
run(opts::from_cmdline_args(args))
|
run(opts::from_cmdline_args(args))
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(test))]
|
||||||
fn run(opts: Opts) {
|
fn run(opts: Opts) {
|
||||||
let (exit_response_from_constellation, exit_chan) = comm::stream();
|
let mut pool = green::SchedPool::new(green::PoolConfig::new());
|
||||||
let (profiler_port, profiler_chan) = special_stream!(ProfilerChan);
|
|
||||||
let (compositor_port, compositor_chan) = special_stream!(CompositorChan);
|
|
||||||
let (constellation_port, constellation_chan) = special_stream!(ConstellationChan);
|
|
||||||
|
|
||||||
Profiler::create(profiler_port, profiler_chan.clone(), opts.profiler_period);
|
let (exit_response_from_constellation, exit_chan) = Chan::new();
|
||||||
|
let (compositor_port, compositor_chan) = CompositorChan::new();
|
||||||
|
let profiler_chan = Profiler::create(opts.profiler_period);
|
||||||
|
|
||||||
do spawn_with((constellation_port,
|
let opts_clone = opts.clone();
|
||||||
constellation_chan.clone(),
|
let profiler_chan_clone = profiler_chan.clone();
|
||||||
profiler_chan.clone(),
|
|
||||||
compositor_chan,
|
|
||||||
opts.clone()))
|
|
||||||
|(constellation_port,
|
|
||||||
constellation_chan,
|
|
||||||
profiler_chan,
|
|
||||||
compositor_chan,
|
|
||||||
opts)| {
|
|
||||||
let opts = &opts;
|
|
||||||
|
|
||||||
|
let (result_port, result_chan) = Chan::new();
|
||||||
|
pool.spawn(TaskOpts::new(), proc() {
|
||||||
|
let opts = &opts_clone;
|
||||||
// Create a Servo instance.
|
// Create a Servo instance.
|
||||||
let resource_task = ResourceTask();
|
let resource_task = ResourceTask();
|
||||||
let image_cache_task = ImageCacheTask(resource_task.clone());
|
let image_cache_task = ImageCacheTask(resource_task.clone());
|
||||||
Constellation::start(constellation_port,
|
let constellation_chan = Constellation::start(compositor_chan,
|
||||||
constellation_chan.clone(),
|
opts,
|
||||||
compositor_chan,
|
resource_task,
|
||||||
opts,
|
image_cache_task,
|
||||||
resource_task,
|
profiler_chan_clone);
|
||||||
image_cache_task,
|
|
||||||
profiler_chan.clone());
|
// Send the constallation Chan as the result
|
||||||
|
result_chan.send(constellation_chan.clone());
|
||||||
|
|
||||||
// Send the URL command to the constellation.
|
// Send the URL command to the constellation.
|
||||||
for filename in opts.urls.iter() {
|
for filename in opts.urls.iter() {
|
||||||
constellation_chan.send(InitLoadUrlMsg(make_url(filename.clone(), None)))
|
constellation_chan.send(InitLoadUrlMsg(make_url(filename.clone(), None)))
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
|
let constellation_chan = result_port.recv();
|
||||||
|
|
||||||
debug!("preparing to enter main loop");
|
debug!("preparing to enter main loop");
|
||||||
CompositorTask::create(opts,
|
CompositorTask::create(opts,
|
||||||
compositor_port,
|
compositor_port,
|
||||||
constellation_chan.clone(),
|
constellation_chan,
|
||||||
profiler_chan,
|
profiler_chan,
|
||||||
exit_chan,
|
exit_chan,
|
||||||
exit_response_from_constellation);
|
exit_response_from_constellation);
|
||||||
|
|
||||||
|
pool.shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,26 +2,20 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use std::cell::Cell;
|
pub fn spawn_listener<A: Send>(f: proc(Port<A>)) -> Chan<A> {
|
||||||
use std::comm;
|
let (setup_po, setup_ch) = Chan::new();
|
||||||
use std::comm::{Chan, Port};
|
spawn(proc() {
|
||||||
use std::task;
|
let (po, ch) = Chan::new();
|
||||||
|
|
||||||
pub fn spawn_listener<A: Send>(f: ~fn(Port<A>)) -> Chan<A> {
|
|
||||||
let (setup_po, setup_ch) = comm::stream();
|
|
||||||
do task::spawn {
|
|
||||||
let (po, ch) = comm::stream();
|
|
||||||
setup_ch.send(ch);
|
setup_ch.send(ch);
|
||||||
f(po);
|
f(po);
|
||||||
}
|
});
|
||||||
setup_po.recv()
|
setup_po.recv()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spawn_conversation<A: Send, B: Send>(f: ~fn(Port<A>, Chan<B>)) -> (Port<B>, Chan<A>) {
|
pub fn spawn_conversation<A: Send, B: Send>(f: proc(Port<A>, Chan<B>)) -> (Port<B>, Chan<A>) {
|
||||||
let (from_child, to_parent) = comm::stream();
|
let (from_child, to_parent) = Chan::new();
|
||||||
let to_parent = Cell::new(to_parent);
|
|
||||||
let to_child = do spawn_listener |from_parent| {
|
let to_child = do spawn_listener |from_parent| {
|
||||||
f(from_parent, to_parent.take())
|
f(from_parent, to_parent)
|
||||||
};
|
};
|
||||||
(from_child, to_child)
|
(from_child, to_child)
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,9 @@ use std::comm::{Chan, SharedChan};
|
||||||
pub struct ConstellationChan(SharedChan<Msg>);
|
pub struct ConstellationChan(SharedChan<Msg>);
|
||||||
|
|
||||||
impl ConstellationChan {
|
impl ConstellationChan {
|
||||||
pub fn new(chan: Chan<Msg>) -> ConstellationChan {
|
pub fn new() -> (Port<Msg>, ConstellationChan) {
|
||||||
ConstellationChan(SharedChan::new(chan))
|
let (port, chan) = SharedChan::new();
|
||||||
|
(port, ConstellationChan(chan))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,5 +54,6 @@ pub enum NavigationDirection {
|
||||||
|
|
||||||
#[deriving(Clone, Eq, IterBytes)]
|
#[deriving(Clone, Eq, IterBytes)]
|
||||||
pub struct PipelineId(uint);
|
pub struct PipelineId(uint);
|
||||||
|
|
||||||
#[deriving(Clone, Eq, IterBytes)]
|
#[deriving(Clone, Eq, IterBytes)]
|
||||||
pub struct SubpageId(uint);
|
pub struct SubpageId(uint);
|
||||||
|
|
|
@ -2,10 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#[link(name = "msg",
|
#[crate_id = "github.com/mozilla/servo#msg:0.1"];
|
||||||
vers = "0.1",
|
|
||||||
uuid = "4c6054e4-2a7b-4fae-b0c8-6d04416b2bf2",
|
|
||||||
url = "http://servo.org/")];
|
|
||||||
#[crate_type = "lib"];
|
#[crate_type = "lib"];
|
||||||
|
|
||||||
extern mod azure;
|
extern mod azure;
|
||||||
|
|
|
@ -11,7 +11,7 @@ use http::headers::test_utils::from_stream_with_str;
|
||||||
use http::headers::content_type::MediaType;
|
use http::headers::content_type::MediaType;
|
||||||
|
|
||||||
pub fn factory() -> LoaderTask {
|
pub fn factory() -> LoaderTask {
|
||||||
|url, start_chan| {
|
proc(url, start_chan) {
|
||||||
// NB: we don't spawn a new task.
|
// NB: we don't spawn a new task.
|
||||||
// Hypothesis: data URLs are too small for parallel base64 etc. to be worth it.
|
// Hypothesis: data URLs are too small for parallel base64 etc. to be worth it.
|
||||||
// Should be tested at some point.
|
// Should be tested at some point.
|
||||||
|
@ -25,7 +25,7 @@ fn load(url: Url, start_chan: Chan<LoadResponse>) {
|
||||||
let mut metadata = Metadata::default(url.clone());
|
let mut metadata = Metadata::default(url.clone());
|
||||||
|
|
||||||
// Split out content type and data.
|
// Split out content type and data.
|
||||||
let parts: ~[&str] = url.path.splitn_iter(',', 1).to_owned_vec();
|
let parts: ~[&str] = url.path.splitn(',', 1).to_owned_vec();
|
||||||
if parts.len() != 2 {
|
if parts.len() != 2 {
|
||||||
start_sending(start_chan, metadata).send(Done(Err(())));
|
start_sending(start_chan, metadata).send(Done(Err(())));
|
||||||
return;
|
return;
|
||||||
|
@ -49,7 +49,7 @@ fn load(url: Url, start_chan: Chan<LoadResponse>) {
|
||||||
|
|
||||||
if is_base64 {
|
if is_base64 {
|
||||||
match parts[1].from_base64() {
|
match parts[1].from_base64() {
|
||||||
Err(*) => {
|
Err(..) => {
|
||||||
progress_chan.send(Done(Err(())));
|
progress_chan.send(Done(Err(())));
|
||||||
}
|
}
|
||||||
Ok(data) => {
|
Ok(data) => {
|
||||||
|
@ -71,9 +71,8 @@ fn assert_parse(url: &'static str,
|
||||||
charset: Option<~str>,
|
charset: Option<~str>,
|
||||||
data: Option<~[u8]>) {
|
data: Option<~[u8]>) {
|
||||||
use std::from_str::FromStr;
|
use std::from_str::FromStr;
|
||||||
use std::comm;
|
|
||||||
|
|
||||||
let (start_port, start_chan) = comm::stream();
|
let (start_port, start_chan) = Chan::new();
|
||||||
load(FromStr::from_str(url).unwrap(), start_chan);
|
load(FromStr::from_str(url).unwrap(), start_chan);
|
||||||
|
|
||||||
let response = start_port.recv();
|
let response = start_port.recv();
|
||||||
|
|
|
@ -5,45 +5,44 @@
|
||||||
use resource_task::{ProgressMsg, Metadata, Payload, Done, LoaderTask, start_sending};
|
use resource_task::{ProgressMsg, Metadata, Payload, Done, LoaderTask, start_sending};
|
||||||
use servo_util::io::result;
|
use servo_util::io::result;
|
||||||
|
|
||||||
use std::comm::Chan;
|
use std::io;
|
||||||
use std::rt::io::file;
|
use std::io::File;
|
||||||
use std::rt::io::{FileStream, Reader, EndOfFile, Open, Read, ignore_io_error};
|
|
||||||
use std::task;
|
|
||||||
|
|
||||||
static READ_SIZE: uint = 1024;
|
static READ_SIZE: uint = 1024;
|
||||||
|
|
||||||
fn read_all(reader: &mut FileStream, progress_chan: &Chan<ProgressMsg>)
|
fn read_all(reader: &mut io::Stream, progress_chan: &SharedChan<ProgressMsg>)
|
||||||
-> Result<(), ()> {
|
-> Result<(), ()> {
|
||||||
loop {
|
loop {
|
||||||
match (do result {
|
match (result(|| {
|
||||||
let data = reader.read_bytes(READ_SIZE);
|
let data = reader.read_bytes(READ_SIZE);
|
||||||
progress_chan.send(Payload(data));
|
progress_chan.send(Payload(data));
|
||||||
}) {
|
})) {
|
||||||
Ok(()) => (),
|
Ok(()) => (),
|
||||||
Err(e) => match e.kind {
|
Err(e) => match e.kind {
|
||||||
EndOfFile => return Ok(()),
|
io::EndOfFile => return Ok(()),
|
||||||
_ => return Err(()),
|
_ => return Err(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn factory() -> LoaderTask {
|
pub fn factory() -> LoaderTask {
|
||||||
let f: LoaderTask = |url, start_chan| {
|
let f: LoaderTask = proc(url, start_chan) {
|
||||||
assert!("file" == url.scheme);
|
assert!("file" == url.scheme);
|
||||||
let progress_chan = start_sending(start_chan, Metadata::default(url.clone()));
|
let progress_chan = start_sending(start_chan, Metadata::default(url.clone()));
|
||||||
do task::spawn {
|
spawn(proc() {
|
||||||
// ignore_io_error causes us to get None instead of a task failure.
|
// ignore_io_error causes us to get None instead of a task failure.
|
||||||
match ignore_io_error(|| file::open(&url.path.as_slice(), Open, Read)) {
|
let _guard = io::ignore_io_error();
|
||||||
|
match File::open_mode(&Path::new(url.path), io::Open, io::Read) {
|
||||||
Some(ref mut reader) => {
|
Some(ref mut reader) => {
|
||||||
let res = read_all(reader, &progress_chan);
|
let res = read_all(reader as &mut io::Stream, &progress_chan);
|
||||||
progress_chan.send(Done(res));
|
progress_chan.send(Done(res));
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
progress_chan.send(Done(Err(())));
|
progress_chan.send(Done(Err(())));
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
});
|
||||||
};
|
};
|
||||||
f
|
f
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,19 +4,16 @@
|
||||||
|
|
||||||
use resource_task::{Metadata, Payload, Done, LoadResponse, LoaderTask, start_sending};
|
use resource_task::{Metadata, Payload, Done, LoadResponse, LoaderTask, start_sending};
|
||||||
|
|
||||||
use std::cell::Cell;
|
|
||||||
use std::vec;
|
use std::vec;
|
||||||
use extra::url::Url;
|
use extra::url::Url;
|
||||||
use http::client::RequestWriter;
|
use http::client::RequestWriter;
|
||||||
use http::method::Get;
|
use http::method::Get;
|
||||||
use http::headers::HeaderEnum;
|
use http::headers::HeaderEnum;
|
||||||
use std::rt::io::Reader;
|
use std::io::Reader;
|
||||||
|
|
||||||
pub fn factory() -> LoaderTask {
|
pub fn factory() -> LoaderTask {
|
||||||
let f: LoaderTask = |url, start_chan| {
|
let f: LoaderTask = proc(url, start_chan) {
|
||||||
let url = Cell::new(url);
|
spawn(proc() load(url, start_chan))
|
||||||
let start_chan = Cell::new(start_chan);
|
|
||||||
spawn(|| load(url.take(), start_chan.take()))
|
|
||||||
};
|
};
|
||||||
f
|
f
|
||||||
}
|
}
|
||||||
|
@ -63,10 +60,10 @@ fn load(mut url: Url, start_chan: Chan<LoadResponse>) {
|
||||||
loop {
|
loop {
|
||||||
let mut buf = vec::with_capacity(1024);
|
let mut buf = vec::with_capacity(1024);
|
||||||
|
|
||||||
unsafe { vec::raw::set_len(&mut buf, 1024) };
|
unsafe { buf.set_len(1024); }
|
||||||
match response.read(buf) {
|
match response.read(buf) {
|
||||||
Some(len) => {
|
Some(len) => {
|
||||||
unsafe { vec::raw::set_len(&mut buf, len) };
|
unsafe { buf.set_len(len); }
|
||||||
progress_chan.send(Payload(buf));
|
progress_chan.send(Payload(buf));
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
|
|
@ -64,12 +64,12 @@ impl ImageHolder {
|
||||||
/// Query and update the current image size.
|
/// Query and update the current image size.
|
||||||
pub fn get_size(&mut self) -> Option<Size2D<int>> {
|
pub fn get_size(&mut self) -> Option<Size2D<int>> {
|
||||||
debug!("get_size() {}", self.url.to_str());
|
debug!("get_size() {}", self.url.to_str());
|
||||||
do self.get_image().map |img| {
|
self.get_image().map(|img| {
|
||||||
let img_ref = img.get();
|
let img_ref = img.get();
|
||||||
self.cached_size = Size2D(img_ref.width as int,
|
self.cached_size = Size2D(img_ref.width as int,
|
||||||
img_ref.height as int);
|
img_ref.height as int);
|
||||||
self.cached_size.clone()
|
self.cached_size.clone()
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_image(&mut self) -> Option<Arc<~Image>> {
|
pub fn get_image(&mut self) -> Option<Arc<~Image>> {
|
||||||
|
|
|
@ -7,8 +7,7 @@ use resource_task;
|
||||||
use resource_task::ResourceTask;
|
use resource_task::ResourceTask;
|
||||||
use servo_util::url::{UrlMap, url_map};
|
use servo_util::url::{UrlMap, url_map};
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::comm::{Chan, Port, SharedChan};
|
||||||
use std::comm::{Chan, Port, SharedChan, stream};
|
|
||||||
use std::task::spawn;
|
use std::task::spawn;
|
||||||
use std::to_str::ToStr;
|
use std::to_str::ToStr;
|
||||||
use std::util::replace;
|
use std::util::replace;
|
||||||
|
@ -24,7 +23,7 @@ pub enum Msg {
|
||||||
// FIXME: We can probably get rid of this Cell now
|
// FIXME: We can probably get rid of this Cell now
|
||||||
// FIXME: make this priv after visibility rules change
|
// FIXME: make this priv after visibility rules change
|
||||||
/// Used be the prefetch tasks to post back image binaries
|
/// Used be the prefetch tasks to post back image binaries
|
||||||
StorePrefetchedImageData(Url, Result<Cell<~[u8]>, ()>),
|
StorePrefetchedImageData(Url, Result<~[u8], ()>),
|
||||||
|
|
||||||
/// Tell the cache to decode an image. Must be posted before GetImage/WaitForImage
|
/// Tell the cache to decode an image. Must be posted before GetImage/WaitForImage
|
||||||
Decode(Url),
|
Decode(Url),
|
||||||
|
@ -40,12 +39,16 @@ pub enum Msg {
|
||||||
/// Wait for an image to become available (or fail to load).
|
/// Wait for an image to become available (or fail to load).
|
||||||
WaitForImage(Url, Chan<ImageResponseMsg>),
|
WaitForImage(Url, Chan<ImageResponseMsg>),
|
||||||
|
|
||||||
/// For testing
|
|
||||||
// FIXME: make this priv after visibility rules change
|
|
||||||
OnMsg(~fn(msg: &Msg)),
|
|
||||||
|
|
||||||
/// Clients must wait for a response before shutting down the ResourceTask
|
/// Clients must wait for a response before shutting down the ResourceTask
|
||||||
Exit(Chan<()>),
|
Exit(Chan<()>),
|
||||||
|
|
||||||
|
/// For testing
|
||||||
|
// FIXME: make this priv after visibility rules change
|
||||||
|
WaitForStore(Chan<()>),
|
||||||
|
|
||||||
|
/// For testing
|
||||||
|
// FIXME: make this priv after visibility rules change
|
||||||
|
WaitForStorePrefetched(Chan<()>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone)]
|
||||||
|
@ -59,11 +62,11 @@ impl Eq for ImageResponseMsg {
|
||||||
fn eq(&self, other: &ImageResponseMsg) -> bool {
|
fn eq(&self, other: &ImageResponseMsg) -> bool {
|
||||||
// FIXME: Bad copies
|
// FIXME: Bad copies
|
||||||
match (self.clone(), other.clone()) {
|
match (self.clone(), other.clone()) {
|
||||||
(ImageReady(*), ImageReady(*)) => fail!(~"unimplemented comparison"),
|
(ImageReady(..), ImageReady(..)) => fail!(~"unimplemented comparison"),
|
||||||
(ImageNotReady, ImageNotReady) => true,
|
(ImageNotReady, ImageNotReady) => true,
|
||||||
(ImageFailed, ImageFailed) => true,
|
(ImageFailed, ImageFailed) => true,
|
||||||
|
|
||||||
(ImageReady(*), _) | (ImageNotReady, _) | (ImageFailed, _) => false
|
(ImageReady(..), _) | (ImageNotReady, _) | (ImageFailed, _) => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,49 +75,39 @@ impl Eq for ImageResponseMsg {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type ImageCacheTask = SharedChan<Msg>;
|
#[deriving(Clone)]
|
||||||
|
pub struct ImageCacheTask {
|
||||||
type DecoderFactory = ~fn() -> ~fn(&[u8]) -> Option<Image>;
|
chan: SharedChan<Msg>,
|
||||||
|
|
||||||
pub fn ImageCacheTask(resource_task: ResourceTask) -> ImageCacheTask {
|
|
||||||
ImageCacheTask_(resource_task, default_decoder_factory)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ImageCacheTask_(resource_task: ResourceTask, decoder_factory: DecoderFactory)
|
type DecoderFactory = fn() -> proc(&[u8]) -> Option<Image>;
|
||||||
-> ImageCacheTask {
|
|
||||||
// FIXME: Doing some dancing to avoid copying decoder_factory, our test
|
|
||||||
// version of which contains an uncopyable type which rust will currently
|
|
||||||
// copy unsoundly
|
|
||||||
let decoder_factory_cell = Cell::new(decoder_factory);
|
|
||||||
|
|
||||||
let (port, chan) = stream();
|
pub fn ImageCacheTask(resource_task: ResourceTask) -> ImageCacheTask {
|
||||||
let chan = SharedChan::new(chan);
|
let (port, chan) = SharedChan::new();
|
||||||
let port_cell = Cell::new(port);
|
let chan_clone = chan.clone();
|
||||||
let chan_cell = Cell::new(chan.clone());
|
|
||||||
|
|
||||||
do spawn {
|
spawn(proc() {
|
||||||
let mut cache = ImageCache {
|
let mut cache = ImageCache {
|
||||||
resource_task: resource_task.clone(),
|
resource_task: resource_task.clone(),
|
||||||
decoder_factory: decoder_factory_cell.take(),
|
port: port,
|
||||||
port: port_cell.take(),
|
chan: chan_clone,
|
||||||
chan: chan_cell.take(),
|
|
||||||
state_map: url_map(),
|
state_map: url_map(),
|
||||||
wait_map: url_map(),
|
wait_map: url_map(),
|
||||||
need_exit: None
|
need_exit: None
|
||||||
};
|
};
|
||||||
cache.run();
|
cache.run();
|
||||||
}
|
});
|
||||||
|
|
||||||
chan
|
ImageCacheTask {
|
||||||
|
chan: chan,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: make this priv after visibility rules change
|
// FIXME: make this priv after visibility rules change
|
||||||
pub fn SyncImageCacheTask(resource_task: ResourceTask) -> ImageCacheTask {
|
pub fn SyncImageCacheTask(resource_task: ResourceTask) -> ImageCacheTask {
|
||||||
let (port, chan) = stream();
|
let (port, chan) = SharedChan::new();
|
||||||
let port_cell = Cell::new(port);
|
|
||||||
|
|
||||||
do spawn {
|
spawn(proc() {
|
||||||
let port = port_cell.take();
|
|
||||||
let inner_cache = ImageCacheTask(resource_task.clone());
|
let inner_cache = ImageCacheTask(resource_task.clone());
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
@ -131,16 +124,16 @@ pub fn SyncImageCacheTask(resource_task: ResourceTask) -> ImageCacheTask {
|
||||||
msg => inner_cache.send(msg)
|
msg => inner_cache.send(msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
SharedChan::new(chan)
|
ImageCacheTask {
|
||||||
|
chan: chan,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ImageCache {
|
struct ImageCache {
|
||||||
/// A handle to the resource task for fetching the image binaries
|
/// A handle to the resource task for fetching the image binaries
|
||||||
resource_task: ResourceTask,
|
resource_task: ResourceTask,
|
||||||
/// Creates image decoders
|
|
||||||
decoder_factory: DecoderFactory,
|
|
||||||
/// The port on which we'll receive client requests
|
/// The port on which we'll receive client requests
|
||||||
port: Port<Msg>,
|
port: Port<Msg>,
|
||||||
/// A copy of the shared chan to give to child tasks
|
/// A copy of the shared chan to give to child tasks
|
||||||
|
@ -156,7 +149,7 @@ struct ImageCache {
|
||||||
enum ImageState {
|
enum ImageState {
|
||||||
Init,
|
Init,
|
||||||
Prefetching(AfterPrefetch),
|
Prefetching(AfterPrefetch),
|
||||||
Prefetched(Cell<~[u8]>),
|
Prefetched(~[u8]),
|
||||||
Decoding,
|
Decoding,
|
||||||
Decoded(Arc<~Image>),
|
Decoded(Arc<~Image>),
|
||||||
Failed
|
Failed
|
||||||
|
@ -170,29 +163,39 @@ enum AfterPrefetch {
|
||||||
|
|
||||||
impl ImageCache {
|
impl ImageCache {
|
||||||
pub fn run(&mut self) {
|
pub fn run(&mut self) {
|
||||||
let mut msg_handlers: ~[~fn(msg: &Msg)] = ~[];
|
let mut store_chan: Option<Chan<()>> = None;
|
||||||
|
let mut store_prefetched_chan: Option<Chan<()>> = None;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let msg = self.port.recv();
|
let msg = self.port.recv();
|
||||||
|
|
||||||
for handler in msg_handlers.iter() {
|
|
||||||
(*handler)(&msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
debug!("image_cache_task: received: {:?}", msg);
|
debug!("image_cache_task: received: {:?}", msg);
|
||||||
|
|
||||||
match msg {
|
match msg {
|
||||||
Prefetch(url) => self.prefetch(url),
|
Prefetch(url) => self.prefetch(url),
|
||||||
StorePrefetchedImageData(url, data) => {
|
StorePrefetchedImageData(url, data) => {
|
||||||
|
store_prefetched_chan.map(|chan| {
|
||||||
|
chan.send(());
|
||||||
|
});
|
||||||
|
store_prefetched_chan = None;
|
||||||
|
|
||||||
self.store_prefetched_image_data(url, data);
|
self.store_prefetched_image_data(url, data);
|
||||||
}
|
}
|
||||||
Decode(url) => self.decode(url),
|
Decode(url) => self.decode(url),
|
||||||
StoreImage(url, image) => self.store_image(url, image),
|
StoreImage(url, image) => {
|
||||||
|
store_chan.map(|chan| {
|
||||||
|
chan.send(());
|
||||||
|
});
|
||||||
|
store_chan = None;
|
||||||
|
|
||||||
|
self.store_image(url, image)
|
||||||
|
}
|
||||||
GetImage(url, response) => self.get_image(url, response),
|
GetImage(url, response) => self.get_image(url, response),
|
||||||
WaitForImage(url, response) => {
|
WaitForImage(url, response) => {
|
||||||
self.wait_for_image(url, response)
|
self.wait_for_image(url, response)
|
||||||
}
|
}
|
||||||
OnMsg(handler) => msg_handlers.push(handler),
|
WaitForStore(chan) => store_chan = Some(chan),
|
||||||
|
WaitForStorePrefetched(chan) => store_prefetched_chan = Some(chan),
|
||||||
Exit(response) => {
|
Exit(response) => {
|
||||||
assert!(self.need_exit.is_none());
|
assert!(self.need_exit.is_none());
|
||||||
self.need_exit = Some(response);
|
self.need_exit = Some(response);
|
||||||
|
@ -208,10 +211,10 @@ impl ImageCache {
|
||||||
let mut can_exit = true;
|
let mut can_exit = true;
|
||||||
for (_, state) in self.state_map.iter() {
|
for (_, state) in self.state_map.iter() {
|
||||||
match *state {
|
match *state {
|
||||||
Prefetching(*) => can_exit = false,
|
Prefetching(..) => can_exit = false,
|
||||||
Decoding => can_exit = false,
|
Decoding => can_exit = false,
|
||||||
|
|
||||||
Init | Prefetched(*) | Decoded(*) | Failed => ()
|
Init | Prefetched(..) | Decoded(..) | Failed => ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,45 +246,44 @@ impl ImageCache {
|
||||||
Init => {
|
Init => {
|
||||||
let to_cache = self.chan.clone();
|
let to_cache = self.chan.clone();
|
||||||
let resource_task = self.resource_task.clone();
|
let resource_task = self.resource_task.clone();
|
||||||
let url_cell = Cell::new(url.clone());
|
let url_clone = url.clone();
|
||||||
|
|
||||||
do spawn {
|
spawn(proc() {
|
||||||
let url = url_cell.take();
|
let url = url_clone;
|
||||||
debug!("image_cache_task: started fetch for {:s}", url.to_str());
|
debug!("image_cache_task: started fetch for {:s}", url.to_str());
|
||||||
|
|
||||||
let image = load_image_data(url.clone(), resource_task.clone());
|
let image = load_image_data(url.clone(), resource_task.clone());
|
||||||
|
|
||||||
let result = if image.is_ok() {
|
let result = if image.is_ok() {
|
||||||
Ok(Cell::new(image.unwrap()))
|
Ok(image.unwrap())
|
||||||
} else {
|
} else {
|
||||||
Err(())
|
Err(())
|
||||||
};
|
};
|
||||||
to_cache.send(StorePrefetchedImageData(url.clone(), result));
|
to_cache.send(StorePrefetchedImageData(url.clone(), result));
|
||||||
debug!("image_cache_task: ended fetch for {:s}", (url.clone()).to_str());
|
debug!("image_cache_task: ended fetch for {:s}", (url.clone()).to_str());
|
||||||
}
|
});
|
||||||
|
|
||||||
self.set_state(url, Prefetching(DoNotDecode));
|
self.set_state(url, Prefetching(DoNotDecode));
|
||||||
}
|
}
|
||||||
|
|
||||||
Prefetching(*) | Prefetched(*) | Decoding | Decoded(*) | Failed => {
|
Prefetching(..) | Prefetched(..) | Decoding | Decoded(..) | Failed => {
|
||||||
// We've already begun working on this image
|
// We've already begun working on this image
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn store_prefetched_image_data(&mut self, url: Url, data: Result<Cell<~[u8]>, ()>) {
|
fn store_prefetched_image_data(&mut self, url: Url, data: Result<~[u8], ()>) {
|
||||||
match self.get_state(url.clone()) {
|
match self.get_state(url.clone()) {
|
||||||
Prefetching(next_step) => {
|
Prefetching(next_step) => {
|
||||||
match data {
|
match data {
|
||||||
Ok(data_cell) => {
|
Ok(data) => {
|
||||||
let data = data_cell.take();
|
self.set_state(url.clone(), Prefetched(data));
|
||||||
self.set_state(url.clone(), Prefetched(Cell::new(data)));
|
|
||||||
match next_step {
|
match next_step {
|
||||||
DoDecode => self.decode(url),
|
DoDecode => self.decode(url),
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(*) => {
|
Err(..) => {
|
||||||
self.set_state(url.clone(), Failed);
|
self.set_state(url.clone(), Failed);
|
||||||
self.purge_waiters(url, || ImageFailed);
|
self.purge_waiters(url, || ImageFailed);
|
||||||
}
|
}
|
||||||
|
@ -289,9 +291,9 @@ impl ImageCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
Init
|
Init
|
||||||
| Prefetched(*)
|
| Prefetched(..)
|
||||||
| Decoding
|
| Decoding
|
||||||
| Decoded(*)
|
| Decoded(..)
|
||||||
| Failed => {
|
| Failed => {
|
||||||
fail!(~"wrong state for storing prefetched image")
|
fail!(~"wrong state for storing prefetched image")
|
||||||
}
|
}
|
||||||
|
@ -311,18 +313,14 @@ impl ImageCache {
|
||||||
// We don't have the data yet, but the decode request is queued up
|
// We don't have the data yet, but the decode request is queued up
|
||||||
}
|
}
|
||||||
|
|
||||||
Prefetched(data_cell) => {
|
Prefetched(data) => {
|
||||||
assert!(!data_cell.is_empty());
|
|
||||||
|
|
||||||
let data = data_cell.take();
|
|
||||||
let to_cache = self.chan.clone();
|
let to_cache = self.chan.clone();
|
||||||
let url_cell = Cell::new(url.clone());
|
let url_clone = url.clone();
|
||||||
let decode = (self.decoder_factory)();
|
|
||||||
|
|
||||||
do spawn {
|
spawn(proc() {
|
||||||
let url = url_cell.take();
|
let url = url_clone;
|
||||||
debug!("image_cache_task: started image decode for {:s}", url.to_str());
|
debug!("image_cache_task: started image decode for {:s}", url.to_str());
|
||||||
let image = decode(data);
|
let image = load_from_memory(data);
|
||||||
let image = if image.is_some() {
|
let image = if image.is_some() {
|
||||||
Some(Arc::new(~image.unwrap()))
|
Some(Arc::new(~image.unwrap()))
|
||||||
} else {
|
} else {
|
||||||
|
@ -330,12 +328,12 @@ impl ImageCache {
|
||||||
};
|
};
|
||||||
to_cache.send(StoreImage(url.clone(), image));
|
to_cache.send(StoreImage(url.clone(), image));
|
||||||
debug!("image_cache_task: ended image decode for {:s}", url.to_str());
|
debug!("image_cache_task: ended image decode for {:s}", url.to_str());
|
||||||
}
|
});
|
||||||
|
|
||||||
self.set_state(url, Decoding);
|
self.set_state(url, Decoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
Decoding | Decoded(*) | Failed => {
|
Decoding | Decoded(..) | Failed => {
|
||||||
// We've already begun decoding
|
// We've already begun decoding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -358,9 +356,9 @@ impl ImageCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
Init
|
Init
|
||||||
| Prefetching(*)
|
| Prefetching(..)
|
||||||
| Prefetched(*)
|
| Prefetched(..)
|
||||||
| Decoded(*)
|
| Decoded(..)
|
||||||
| Failed => {
|
| Failed => {
|
||||||
fail!(~"incorrect state in store_image")
|
fail!(~"incorrect state in store_image")
|
||||||
}
|
}
|
||||||
|
@ -368,7 +366,7 @@ impl ImageCache {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn purge_waiters(&mut self, url: Url, f: &fn() -> ImageResponseMsg) {
|
fn purge_waiters(&mut self, url: Url, f: || -> ImageResponseMsg) {
|
||||||
match self.wait_map.pop(&url) {
|
match self.wait_map.pop(&url) {
|
||||||
Some(waiters) => {
|
Some(waiters) => {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -387,7 +385,7 @@ impl ImageCache {
|
||||||
match self.get_state(url.clone()) {
|
match self.get_state(url.clone()) {
|
||||||
Init => fail!(~"request for image before prefetch"),
|
Init => fail!(~"request for image before prefetch"),
|
||||||
Prefetching(DoDecode) => response.send(ImageNotReady),
|
Prefetching(DoDecode) => response.send(ImageNotReady),
|
||||||
Prefetching(DoNotDecode) | Prefetched(*) => fail!(~"request for image before decode"),
|
Prefetching(DoNotDecode) | Prefetched(..) => fail!(~"request for image before decode"),
|
||||||
Decoding => response.send(ImageNotReady),
|
Decoding => response.send(ImageNotReady),
|
||||||
Decoded(image) => response.send(ImageReady(image.clone())),
|
Decoded(image) => response.send(ImageReady(image.clone())),
|
||||||
Failed => response.send(ImageFailed),
|
Failed => response.send(ImageFailed),
|
||||||
|
@ -398,16 +396,16 @@ impl ImageCache {
|
||||||
match self.get_state(url.clone()) {
|
match self.get_state(url.clone()) {
|
||||||
Init => fail!(~"request for image before prefetch"),
|
Init => fail!(~"request for image before prefetch"),
|
||||||
|
|
||||||
Prefetching(DoNotDecode) | Prefetched(*) => fail!(~"request for image before decode"),
|
Prefetching(DoNotDecode) | Prefetched(..) => fail!(~"request for image before decode"),
|
||||||
|
|
||||||
Prefetching(DoDecode) | Decoding => {
|
Prefetching(DoDecode) | Decoding => {
|
||||||
// We don't have this image yet
|
// We don't have this image yet
|
||||||
if self.wait_map.contains_key(&url) {
|
if self.wait_map.contains_key(&url) {
|
||||||
let waiters = self.wait_map.find_mut(&url).unwrap();
|
let waiters = self.wait_map.find_mut(&url).unwrap();
|
||||||
|
let mut response = Some(response);
|
||||||
unsafe {
|
unsafe {
|
||||||
let res = Cell::new(response);
|
waiters.unsafe_access(|waiters| {
|
||||||
waiters.unsafe_access( |waiters| {
|
waiters.push(response.take().unwrap());
|
||||||
waiters.push(res.take());
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -434,14 +432,34 @@ trait ImageCacheTaskClient {
|
||||||
|
|
||||||
impl ImageCacheTaskClient for ImageCacheTask {
|
impl ImageCacheTaskClient for ImageCacheTask {
|
||||||
fn exit(&self) {
|
fn exit(&self) {
|
||||||
let (response_port, response_chan) = stream();
|
let (response_port, response_chan) = Chan::new();
|
||||||
self.send(Exit(response_chan));
|
self.send(Exit(response_chan));
|
||||||
response_port.recv();
|
response_port.recv();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ImageCacheTask {
|
||||||
|
pub fn send(&self, msg: Msg) {
|
||||||
|
self.chan.send(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
fn wait_for_store(&self) -> Port<()> {
|
||||||
|
let (port, chan) = Chan::new();
|
||||||
|
self.send(WaitForStore(chan));
|
||||||
|
port
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
fn wait_for_store_prefetched(&self) -> Port<()> {
|
||||||
|
let (port, chan) = Chan::new();
|
||||||
|
self.send(WaitForStorePrefetched(chan));
|
||||||
|
port
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn load_image_data(url: Url, resource_task: ResourceTask) -> Result<~[u8], ()> {
|
fn load_image_data(url: Url, resource_task: ResourceTask) -> Result<~[u8], ()> {
|
||||||
let (response_port, response_chan) = stream();
|
let (response_port, response_chan) = Chan::new();
|
||||||
resource_task.send(resource_task::Load(url, response_chan));
|
resource_task.send(resource_task::Load(url, response_chan));
|
||||||
|
|
||||||
let mut image_data = ~[];
|
let mut image_data = ~[];
|
||||||
|
@ -452,38 +470,29 @@ fn load_image_data(url: Url, resource_task: ResourceTask) -> Result<~[u8], ()> {
|
||||||
resource_task::Payload(data) => {
|
resource_task::Payload(data) => {
|
||||||
image_data.push_all(data);
|
image_data.push_all(data);
|
||||||
}
|
}
|
||||||
resource_task::Done(result::Ok(*)) => {
|
resource_task::Done(result::Ok(..)) => {
|
||||||
return Ok(image_data);
|
return Ok(image_data);
|
||||||
}
|
}
|
||||||
resource_task::Done(result::Err(*)) => {
|
resource_task::Done(result::Err(..)) => {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_decoder_factory() -> ~fn(&[u8]) -> Option<Image> {
|
|
||||||
let foo: ~fn(&[u8]) -> Option<Image> = |data: &[u8]| { load_from_memory(data) };
|
|
||||||
foo
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use std::comm;
|
|
||||||
use std::comm::{Port, SharedChan};
|
|
||||||
use std::result;
|
|
||||||
use std::cell::Cell;
|
|
||||||
|
|
||||||
use resource_task;
|
use resource_task;
|
||||||
use resource_task::{ResourceTask, Metadata, start_sending};
|
use resource_task::{ResourceTask, Metadata, start_sending};
|
||||||
use image::base::{Image, test_image_bin, load_from_memory};
|
use image::base::test_image_bin;
|
||||||
use util::spawn_listener;
|
use util::spawn_listener;
|
||||||
use servo_util::url::make_url;
|
use servo_util::url::make_url;
|
||||||
|
|
||||||
fn mock_resource_task(on_load: ~fn(resource: Chan<resource_task::ProgressMsg>)) -> ResourceTask {
|
fn mock_resource_task(on_load: proc(resource: SharedChan<resource_task::ProgressMsg>)) -> ResourceTask {
|
||||||
let chan = do spawn_listener |port: Port<resource_task::ControlMsg>| {
|
spawn_listener(proc(port: Port<resource_task::ControlMsg>) {
|
||||||
loop {
|
loop {
|
||||||
match port.recv() {
|
match port.recv() {
|
||||||
resource_task::Load(_, response) => {
|
resource_task::Load(_, response) => {
|
||||||
|
@ -493,13 +502,12 @@ mod tests {
|
||||||
resource_task::Exit => break
|
resource_task::Exit => break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
})
|
||||||
SharedChan::new(chan)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_exit_on_request() {
|
fn should_exit_on_request() {
|
||||||
let mock_resource_task = mock_resource_task(|_response| () );
|
let mock_resource_task = mock_resource_task(proc(_response) {});
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
||||||
let _url = make_url(~"file", None);
|
let _url = make_url(~"file", None);
|
||||||
|
@ -511,24 +519,24 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
#[should_fail]
|
#[should_fail]
|
||||||
fn should_fail_if_unprefetched_image_is_requested() {
|
fn should_fail_if_unprefetched_image_is_requested() {
|
||||||
let mock_resource_task = mock_resource_task(|_response| () );
|
let mock_resource_task = mock_resource_task(proc(_response) {});
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
||||||
let url = make_url(~"file", None);
|
let url = make_url(~"file", None);
|
||||||
|
|
||||||
let (port, chan) = stream();
|
let (port, chan) = Chan::new();
|
||||||
image_cache_task.send(GetImage(url, chan));
|
image_cache_task.send(GetImage(url, chan));
|
||||||
port.recv();
|
port.recv();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_request_url_from_resource_task_on_prefetch() {
|
fn should_request_url_from_resource_task_on_prefetch() {
|
||||||
let (url_requested, url_requested_chan) = comm::stream();
|
let (url_requested, url_requested_chan) = Chan::new();
|
||||||
|
|
||||||
let mock_resource_task = do mock_resource_task |response| {
|
let mock_resource_task = mock_resource_task(proc(response) {
|
||||||
url_requested_chan.send(());
|
url_requested_chan.send(());
|
||||||
response.send(resource_task::Done(result::Ok(())));
|
response.send(resource_task::Done(Ok(())));
|
||||||
};
|
});
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
||||||
let url = make_url(~"file", None);
|
let url = make_url(~"file", None);
|
||||||
|
@ -539,47 +547,14 @@ mod tests {
|
||||||
mock_resource_task.send(resource_task::Exit);
|
mock_resource_task.send(resource_task::Exit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_fail]
|
|
||||||
fn should_fail_if_requesting_decode_of_an_unprefetched_image() {
|
|
||||||
let mock_resource_task = mock_resource_task(|_response| () );
|
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
|
||||||
let url = make_url(~"file", None);
|
|
||||||
|
|
||||||
image_cache_task.send(Decode(url));
|
|
||||||
image_cache_task.exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_fail]
|
|
||||||
fn should_fail_if_requesting_image_before_requesting_decode() {
|
|
||||||
let mock_resource_task = do mock_resource_task |response| {
|
|
||||||
response.send(resource_task::Done(result::Ok(())));
|
|
||||||
};
|
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
|
||||||
let url = make_url(~"file", None);
|
|
||||||
|
|
||||||
image_cache_task.send(Prefetch(url.clone()));
|
|
||||||
// no decode message
|
|
||||||
|
|
||||||
let (_port, chan) = stream();
|
|
||||||
image_cache_task.send(GetImage(url, chan));
|
|
||||||
|
|
||||||
image_cache_task.exit();
|
|
||||||
mock_resource_task.send(resource_task::Exit);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_not_request_url_from_resource_task_on_multiple_prefetches() {
|
fn should_not_request_url_from_resource_task_on_multiple_prefetches() {
|
||||||
let (url_requested, url_requested_chan) = comm::stream();
|
let (url_requested, url_requested_chan) = Chan::new();
|
||||||
|
|
||||||
let mock_resource_task = do mock_resource_task |response| {
|
let mock_resource_task = mock_resource_task(proc(response) {
|
||||||
url_requested_chan.send(());
|
url_requested_chan.send(());
|
||||||
response.send(resource_task::Done(result::Ok(())));
|
response.send(resource_task::Done(Ok(())));
|
||||||
};
|
});
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
||||||
let url = make_url(~"file", None);
|
let url = make_url(~"file", None);
|
||||||
|
@ -589,27 +564,27 @@ mod tests {
|
||||||
url_requested.recv();
|
url_requested.recv();
|
||||||
image_cache_task.exit();
|
image_cache_task.exit();
|
||||||
mock_resource_task.send(resource_task::Exit);
|
mock_resource_task.send(resource_task::Exit);
|
||||||
assert!(!url_requested.peek())
|
assert!(url_requested.try_recv().is_none())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_return_image_not_ready_if_data_has_not_arrived() {
|
fn should_return_image_not_ready_if_data_has_not_arrived() {
|
||||||
let (wait_port, wait_chan) = comm::stream();
|
let (wait_port, wait_chan) = Chan::new();
|
||||||
|
|
||||||
let mock_resource_task = do mock_resource_task |response| {
|
let mock_resource_task = mock_resource_task(proc(response) {
|
||||||
// Don't send the data until after the client requests
|
// Don't send the data until after the client requests
|
||||||
// the image
|
// the image
|
||||||
wait_port.recv();
|
wait_port.recv();
|
||||||
response.send(resource_task::Payload(test_image_bin()));
|
response.send(resource_task::Payload(test_image_bin()));
|
||||||
response.send(resource_task::Done(result::Ok(())));
|
response.send(resource_task::Done(Ok(())));
|
||||||
};
|
});
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
||||||
let url = make_url(~"file", None);
|
let url = make_url(~"file", None);
|
||||||
|
|
||||||
image_cache_task.send(Prefetch(url.clone()));
|
image_cache_task.send(Prefetch(url.clone()));
|
||||||
image_cache_task.send(Decode(url.clone()));
|
image_cache_task.send(Decode(url.clone()));
|
||||||
let (response_port, response_chan) = stream();
|
let (response_port, response_chan) = Chan::new();
|
||||||
image_cache_task.send(GetImage(url, response_chan));
|
image_cache_task.send(GetImage(url, response_chan));
|
||||||
assert!(response_port.recv() == ImageNotReady);
|
assert!(response_port.recv() == ImageNotReady);
|
||||||
wait_chan.send(());
|
wait_chan.send(());
|
||||||
|
@ -619,30 +594,23 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_return_decoded_image_data_if_data_has_arrived() {
|
fn should_return_decoded_image_data_if_data_has_arrived() {
|
||||||
let mock_resource_task = do mock_resource_task |response| {
|
let mock_resource_task = mock_resource_task(proc(response) {
|
||||||
response.send(resource_task::Payload(test_image_bin()));
|
response.send(resource_task::Payload(test_image_bin()));
|
||||||
response.send(resource_task::Done(result::Ok(())));
|
response.send(resource_task::Done(Ok(())));
|
||||||
};
|
});
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
||||||
let url = make_url(~"file", None);
|
let url = make_url(~"file", None);
|
||||||
|
|
||||||
let (wait_for_image, wait_for_image_chan) = comm::stream();
|
let join_port = image_cache_task.wait_for_store();
|
||||||
|
|
||||||
image_cache_task.send(OnMsg(|msg| {
|
|
||||||
match *msg {
|
|
||||||
StoreImage(*) => wait_for_image_chan.send(()),
|
|
||||||
_ => ()
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
image_cache_task.send(Prefetch(url.clone()));
|
image_cache_task.send(Prefetch(url.clone()));
|
||||||
image_cache_task.send(Decode(url.clone()));
|
image_cache_task.send(Decode(url.clone()));
|
||||||
|
|
||||||
// Wait until our mock resource task has sent the image to the image cache
|
// Wait until our mock resource task has sent the image to the image cache
|
||||||
wait_for_image.recv();
|
join_port.recv();
|
||||||
|
|
||||||
let (response_port, response_chan) = stream();
|
let (response_port, response_chan) = Chan::new();
|
||||||
image_cache_task.send(GetImage(url, response_chan));
|
image_cache_task.send(GetImage(url, response_chan));
|
||||||
match response_port.recv() {
|
match response_port.recv() {
|
||||||
ImageReady(_) => (),
|
ImageReady(_) => (),
|
||||||
|
@ -655,31 +623,24 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_return_decoded_image_data_for_multiple_requests() {
|
fn should_return_decoded_image_data_for_multiple_requests() {
|
||||||
let mock_resource_task = do mock_resource_task |response| {
|
let mock_resource_task = mock_resource_task(proc(response) {
|
||||||
response.send(resource_task::Payload(test_image_bin()));
|
response.send(resource_task::Payload(test_image_bin()));
|
||||||
response.send(resource_task::Done(result::Ok(())));
|
response.send(resource_task::Done(Ok(())));
|
||||||
};
|
});
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
||||||
let url = make_url(~"file", None);
|
let url = make_url(~"file", None);
|
||||||
|
|
||||||
let (wait_for_image, wait_for_image_chan) = comm::stream();
|
let join_port = image_cache_task.wait_for_store();
|
||||||
|
|
||||||
image_cache_task.send(OnMsg(|msg| {
|
|
||||||
match *msg {
|
|
||||||
StoreImage(*) => wait_for_image_chan.send(()),
|
|
||||||
_ => ()
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
image_cache_task.send(Prefetch(url.clone()));
|
image_cache_task.send(Prefetch(url.clone()));
|
||||||
image_cache_task.send(Decode(url.clone()));
|
image_cache_task.send(Decode(url.clone()));
|
||||||
|
|
||||||
// Wait until our mock resource task has sent the image to the image cache
|
// Wait until our mock resource task has sent the image to the image cache
|
||||||
wait_for_image.recv();
|
join_port.recv();
|
||||||
|
|
||||||
for _ in range(0,2) {
|
for _ in range(0,2) {
|
||||||
let (response_port, response_chan) = stream();
|
let (response_port, response_chan) = Chan::new();
|
||||||
image_cache_task.send(GetImage(url.clone(), response_chan));
|
image_cache_task.send(GetImage(url.clone(), response_chan));
|
||||||
match response_port.recv() {
|
match response_port.recv() {
|
||||||
ImageReady(_) => (),
|
ImageReady(_) => (),
|
||||||
|
@ -693,17 +654,17 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_not_request_image_from_resource_task_if_image_is_already_available() {
|
fn should_not_request_image_from_resource_task_if_image_is_already_available() {
|
||||||
let (image_bin_sent, image_bin_sent_chan) = comm::stream();
|
let (image_bin_sent, image_bin_sent_chan) = Chan::new();
|
||||||
|
|
||||||
let (resource_task_exited, resource_task_exited_chan) = comm::stream();
|
let (resource_task_exited, resource_task_exited_chan) = Chan::new();
|
||||||
|
|
||||||
let mock_resource_task = do spawn_listener |port: comm::Port<resource_task::ControlMsg>| {
|
let mock_resource_task = spawn_listener(proc(port: Port<resource_task::ControlMsg>) {
|
||||||
loop {
|
loop {
|
||||||
match port.recv() {
|
match port.recv() {
|
||||||
resource_task::Load(_, response) => {
|
resource_task::Load(_, response) => {
|
||||||
let chan = start_sending(response, Metadata::default(make_url(~"file:///fake", None)));
|
let chan = start_sending(response, Metadata::default(make_url(~"file:///fake", None)));
|
||||||
chan.send(resource_task::Payload(test_image_bin()));
|
chan.send(resource_task::Payload(test_image_bin()));
|
||||||
chan.send(resource_task::Done(result::Ok(())));
|
chan.send(resource_task::Done(Ok(())));
|
||||||
image_bin_sent_chan.send(());
|
image_bin_sent_chan.send(());
|
||||||
}
|
}
|
||||||
resource_task::Exit => {
|
resource_task::Exit => {
|
||||||
|
@ -712,8 +673,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
let mock_resource_task = SharedChan::new(mock_resource_task);
|
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
||||||
let url = make_url(~"file", None);
|
let url = make_url(~"file", None);
|
||||||
|
@ -732,22 +692,22 @@ mod tests {
|
||||||
|
|
||||||
// Our resource task should not have received another request for the image
|
// Our resource task should not have received another request for the image
|
||||||
// because it's already cached
|
// because it's already cached
|
||||||
assert!(!image_bin_sent.peek());
|
assert!(image_bin_sent.try_recv().is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_not_request_image_from_resource_task_if_image_fetch_already_failed() {
|
fn should_not_request_image_from_resource_task_if_image_fetch_already_failed() {
|
||||||
let (image_bin_sent, image_bin_sent_chan) = comm::stream();
|
let (image_bin_sent, image_bin_sent_chan) = Chan::new();
|
||||||
|
|
||||||
let (resource_task_exited, resource_task_exited_chan) = comm::stream();
|
let (resource_task_exited, resource_task_exited_chan) = Chan::new();
|
||||||
|
|
||||||
let mock_resource_task = do spawn_listener |port: comm::Port<resource_task::ControlMsg>| {
|
let mock_resource_task = spawn_listener(proc(port: Port<resource_task::ControlMsg>) {
|
||||||
loop {
|
loop {
|
||||||
match port.recv() {
|
match port.recv() {
|
||||||
resource_task::Load(_, response) => {
|
resource_task::Load(_, response) => {
|
||||||
let chan = start_sending(response, Metadata::default(make_url(~"file:///fake", None)));
|
let chan = start_sending(response, Metadata::default(make_url(~"file:///fake", None)));
|
||||||
chan.send(resource_task::Payload(test_image_bin()));
|
chan.send(resource_task::Payload(test_image_bin()));
|
||||||
chan.send(resource_task::Done(result::Err(())));
|
chan.send(resource_task::Done(Err(())));
|
||||||
image_bin_sent_chan.send(());
|
image_bin_sent_chan.send(());
|
||||||
}
|
}
|
||||||
resource_task::Exit => {
|
resource_task::Exit => {
|
||||||
|
@ -756,8 +716,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
let mock_resource_task = SharedChan::new(mock_resource_task);
|
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
||||||
let url = make_url(~"file", None);
|
let url = make_url(~"file", None);
|
||||||
|
@ -778,36 +737,29 @@ mod tests {
|
||||||
|
|
||||||
// Our resource task should not have received another request for the image
|
// Our resource task should not have received another request for the image
|
||||||
// because it's already cached
|
// because it's already cached
|
||||||
assert!(!image_bin_sent.peek());
|
assert!(image_bin_sent.try_recv().is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_return_failed_if_image_bin_cannot_be_fetched() {
|
fn should_return_failed_if_image_bin_cannot_be_fetched() {
|
||||||
let mock_resource_task = do mock_resource_task |response| {
|
let mock_resource_task = mock_resource_task(proc(response) {
|
||||||
response.send(resource_task::Payload(test_image_bin()));
|
response.send(resource_task::Payload(test_image_bin()));
|
||||||
// ERROR fetching image
|
// ERROR fetching image
|
||||||
response.send(resource_task::Done(result::Err(())));
|
response.send(resource_task::Done(Err(())));
|
||||||
};
|
});
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
||||||
let url = make_url(~"file", None);
|
let url = make_url(~"file", None);
|
||||||
|
|
||||||
let (wait_for_prefetech, wait_for_prefetech_chan) = comm::stream();
|
let join_port = image_cache_task.wait_for_store_prefetched();
|
||||||
|
|
||||||
image_cache_task.send(OnMsg(|msg| {
|
|
||||||
match *msg {
|
|
||||||
StorePrefetchedImageData(*) => wait_for_prefetech_chan.send(()),
|
|
||||||
_ => ()
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
image_cache_task.send(Prefetch(url.clone()));
|
image_cache_task.send(Prefetch(url.clone()));
|
||||||
image_cache_task.send(Decode(url.clone()));
|
image_cache_task.send(Decode(url.clone()));
|
||||||
|
|
||||||
// Wait until our mock resource task has sent the image to the image cache
|
// Wait until our mock resource task has sent the image to the image cache
|
||||||
wait_for_prefetech.recv();
|
join_port.recv();
|
||||||
|
|
||||||
let (response_port, response_chan) = stream();
|
let (response_port, response_chan) = Chan::new();
|
||||||
image_cache_task.send(GetImage(url, response_chan));
|
image_cache_task.send(GetImage(url, response_chan));
|
||||||
match response_port.recv() {
|
match response_port.recv() {
|
||||||
ImageFailed => (),
|
ImageFailed => (),
|
||||||
|
@ -820,31 +772,24 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_return_failed_for_multiple_get_image_requests_if_image_bin_cannot_be_fetched() {
|
fn should_return_failed_for_multiple_get_image_requests_if_image_bin_cannot_be_fetched() {
|
||||||
let mock_resource_task = do mock_resource_task |response | {
|
let mock_resource_task = mock_resource_task(proc(response) {
|
||||||
response.send(resource_task::Payload(test_image_bin()));
|
response.send(resource_task::Payload(test_image_bin()));
|
||||||
// ERROR fetching image
|
// ERROR fetching image
|
||||||
response.send(resource_task::Done(result::Err(())));
|
response.send(resource_task::Done(Err(())));
|
||||||
};
|
});
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
||||||
let url = make_url(~"file", None);
|
let url = make_url(~"file", None);
|
||||||
|
|
||||||
let (wait_for_prefetech, wait_for_prefetech_chan) = comm::stream();
|
let join_port = image_cache_task.wait_for_store_prefetched();
|
||||||
|
|
||||||
image_cache_task.send(OnMsg(|msg| {
|
|
||||||
match *msg {
|
|
||||||
StorePrefetchedImageData(*) => wait_for_prefetech_chan.send(()),
|
|
||||||
_ => ()
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
image_cache_task.send(Prefetch(url.clone()));
|
image_cache_task.send(Prefetch(url.clone()));
|
||||||
image_cache_task.send(Decode(url.clone()));
|
image_cache_task.send(Decode(url.clone()));
|
||||||
|
|
||||||
// Wait until our mock resource task has sent the image to the image cache
|
// Wait until our mock resource task has sent the image to the image cache
|
||||||
wait_for_prefetech.recv();
|
join_port.recv();
|
||||||
|
|
||||||
let (response_port, response_chan) = stream();
|
let (response_port, response_chan) = Chan::new();
|
||||||
image_cache_task.send(GetImage(url.clone(), response_chan));
|
image_cache_task.send(GetImage(url.clone(), response_chan));
|
||||||
match response_port.recv() {
|
match response_port.recv() {
|
||||||
ImageFailed => (),
|
ImageFailed => (),
|
||||||
|
@ -852,7 +797,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
// And ask again, we should get the same response
|
// And ask again, we should get the same response
|
||||||
let (response_port, response_chan) = stream();
|
let (response_port, response_chan) = Chan::new();
|
||||||
image_cache_task.send(GetImage(url, response_chan));
|
image_cache_task.send(GetImage(url, response_chan));
|
||||||
match response_port.recv() {
|
match response_port.recv() {
|
||||||
ImageFailed => (),
|
ImageFailed => (),
|
||||||
|
@ -863,87 +808,27 @@ mod tests {
|
||||||
mock_resource_task.send(resource_task::Exit);
|
mock_resource_task.send(resource_task::Exit);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn should_return_not_ready_if_image_is_still_decoding() {
|
|
||||||
let (wait_to_decode_port, wait_to_decode_chan) = comm::stream();
|
|
||||||
|
|
||||||
let mock_resource_task = do mock_resource_task |response| {
|
|
||||||
response.send(resource_task::Payload(test_image_bin()));
|
|
||||||
response.send(resource_task::Done(result::Ok(())));
|
|
||||||
};
|
|
||||||
|
|
||||||
let wait_to_decode_port_cell = Cell::new(wait_to_decode_port);
|
|
||||||
let decoder_factory: ~fn:Send() -> ~fn:Send(&[u8]) -> Option<Image> = || {
|
|
||||||
let wait_to_decode_port = wait_to_decode_port_cell.take();
|
|
||||||
|data: &[u8]| {
|
|
||||||
// Don't decode until after the client requests the image
|
|
||||||
wait_to_decode_port.recv();
|
|
||||||
load_from_memory(data)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask_(mock_resource_task.clone(), decoder_factory);
|
|
||||||
let url = make_url(~"file", None);
|
|
||||||
|
|
||||||
let (wait_for_prefetech, wait_for_prefetech_chan) = comm::stream();
|
|
||||||
|
|
||||||
image_cache_task.send(OnMsg(|msg| {
|
|
||||||
match *msg {
|
|
||||||
StorePrefetchedImageData(*) => wait_for_prefetech_chan.send(()),
|
|
||||||
_ => ()
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
image_cache_task.send(Prefetch(url.clone()));
|
|
||||||
image_cache_task.send(Decode(url.clone()));
|
|
||||||
|
|
||||||
// Wait until our mock resource task has sent the image to the image cache
|
|
||||||
wait_for_prefetech.recv();
|
|
||||||
|
|
||||||
// Make the request
|
|
||||||
let (response_port, response_chan) = stream();
|
|
||||||
image_cache_task.send(GetImage(url, response_chan));
|
|
||||||
|
|
||||||
match response_port.recv() {
|
|
||||||
ImageNotReady => (),
|
|
||||||
_ => fail!("bleh")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now decode
|
|
||||||
wait_to_decode_chan.send(());
|
|
||||||
|
|
||||||
image_cache_task.exit();
|
|
||||||
mock_resource_task.send(resource_task::Exit);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_return_failed_if_image_decode_fails() {
|
fn should_return_failed_if_image_decode_fails() {
|
||||||
let mock_resource_task = do mock_resource_task |response| {
|
let mock_resource_task = mock_resource_task(proc(response) {
|
||||||
// Bogus data
|
// Bogus data
|
||||||
response.send(resource_task::Payload(~[]));
|
response.send(resource_task::Payload(~[]));
|
||||||
response.send(resource_task::Done(result::Ok(())));
|
response.send(resource_task::Done(Ok(())));
|
||||||
};
|
});
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
||||||
let url = make_url(~"file", None);
|
let url = make_url(~"file", None);
|
||||||
|
|
||||||
let (wait_for_decode, wait_for_decode_chan) = comm::stream();
|
let join_port = image_cache_task.wait_for_store();
|
||||||
|
|
||||||
image_cache_task.send(OnMsg(|msg| {
|
|
||||||
match *msg {
|
|
||||||
StoreImage(*) => wait_for_decode_chan.send(()),
|
|
||||||
_ => ()
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
image_cache_task.send(Prefetch(url.clone()));
|
image_cache_task.send(Prefetch(url.clone()));
|
||||||
image_cache_task.send(Decode(url.clone()));
|
image_cache_task.send(Decode(url.clone()));
|
||||||
|
|
||||||
// Wait until our mock resource task has sent the image to the image cache
|
// Wait until our mock resource task has sent the image to the image cache
|
||||||
wait_for_decode.recv();
|
join_port.recv();
|
||||||
|
|
||||||
// Make the request
|
// Make the request
|
||||||
let (response_port, response_chan) = stream();
|
let (response_port, response_chan) = Chan::new();
|
||||||
image_cache_task.send(GetImage(url, response_chan));
|
image_cache_task.send(GetImage(url, response_chan));
|
||||||
|
|
||||||
match response_port.recv() {
|
match response_port.recv() {
|
||||||
|
@ -957,33 +842,26 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_return_image_on_wait_if_image_is_already_loaded() {
|
fn should_return_image_on_wait_if_image_is_already_loaded() {
|
||||||
let mock_resource_task = do mock_resource_task |response| {
|
let mock_resource_task = mock_resource_task(proc(response) {
|
||||||
response.send(resource_task::Payload(test_image_bin()));
|
response.send(resource_task::Payload(test_image_bin()));
|
||||||
response.send(resource_task::Done(result::Ok(())));
|
response.send(resource_task::Done(Ok(())));
|
||||||
};
|
});
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
||||||
let url = make_url(~"file", None);
|
let url = make_url(~"file", None);
|
||||||
|
|
||||||
let (wait_for_decode, wait_for_decode_chan) = comm::stream();
|
let join_port = image_cache_task.wait_for_store();
|
||||||
|
|
||||||
image_cache_task.send(OnMsg(|msg| {
|
|
||||||
match *msg {
|
|
||||||
StoreImage(*) => wait_for_decode_chan.send(()),
|
|
||||||
_ => ()
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
image_cache_task.send(Prefetch(url.clone()));
|
image_cache_task.send(Prefetch(url.clone()));
|
||||||
image_cache_task.send(Decode(url.clone()));
|
image_cache_task.send(Decode(url.clone()));
|
||||||
|
|
||||||
// Wait until our mock resource task has sent the image to the image cache
|
// Wait until our mock resource task has sent the image to the image cache
|
||||||
wait_for_decode.recv();
|
join_port.recv();
|
||||||
|
|
||||||
let (response_port, response_chan) = stream();
|
let (response_port, response_chan) = Chan::new();
|
||||||
image_cache_task.send(WaitForImage(url, response_chan));
|
image_cache_task.send(WaitForImage(url, response_chan));
|
||||||
match response_port.recv() {
|
match response_port.recv() {
|
||||||
ImageReady(*) => (),
|
ImageReady(..) => (),
|
||||||
_ => fail!("bleh")
|
_ => fail!("bleh")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -993,13 +871,13 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_return_image_on_wait_if_image_is_not_yet_loaded() {
|
fn should_return_image_on_wait_if_image_is_not_yet_loaded() {
|
||||||
let (wait_port, wait_chan) = comm::stream();
|
let (wait_port, wait_chan) = Chan::new();
|
||||||
|
|
||||||
let mock_resource_task = do mock_resource_task |response| {
|
let mock_resource_task = mock_resource_task(proc(response) {
|
||||||
wait_port.recv();
|
wait_port.recv();
|
||||||
response.send(resource_task::Payload(test_image_bin()));
|
response.send(resource_task::Payload(test_image_bin()));
|
||||||
response.send(resource_task::Done(result::Ok(())));
|
response.send(resource_task::Done(Ok(())));
|
||||||
};
|
});
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
||||||
let url = make_url(~"file", None);
|
let url = make_url(~"file", None);
|
||||||
|
@ -1007,13 +885,13 @@ mod tests {
|
||||||
image_cache_task.send(Prefetch(url.clone()));
|
image_cache_task.send(Prefetch(url.clone()));
|
||||||
image_cache_task.send(Decode(url.clone()));
|
image_cache_task.send(Decode(url.clone()));
|
||||||
|
|
||||||
let (response_port, response_chan) = stream();
|
let (response_port, response_chan) = Chan::new();
|
||||||
image_cache_task.send(WaitForImage(url, response_chan));
|
image_cache_task.send(WaitForImage(url, response_chan));
|
||||||
|
|
||||||
wait_chan.send(());
|
wait_chan.send(());
|
||||||
|
|
||||||
match response_port.recv() {
|
match response_port.recv() {
|
||||||
ImageReady(*) => (),
|
ImageReady(..) => (),
|
||||||
_ => fail!("bleh")
|
_ => fail!("bleh")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1023,13 +901,13 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_return_image_failed_on_wait_if_image_fails_to_load() {
|
fn should_return_image_failed_on_wait_if_image_fails_to_load() {
|
||||||
let (wait_port, wait_chan) = comm::stream();
|
let (wait_port, wait_chan) = Chan::new();
|
||||||
|
|
||||||
let mock_resource_task = do mock_resource_task |response| {
|
let mock_resource_task = mock_resource_task(proc(response) {
|
||||||
wait_port.recv();
|
wait_port.recv();
|
||||||
response.send(resource_task::Payload(test_image_bin()));
|
response.send(resource_task::Payload(test_image_bin()));
|
||||||
response.send(resource_task::Done(result::Err(())));
|
response.send(resource_task::Done(Err(())));
|
||||||
};
|
});
|
||||||
|
|
||||||
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
let image_cache_task = ImageCacheTask(mock_resource_task.clone());
|
||||||
let url = make_url(~"file", None);
|
let url = make_url(~"file", None);
|
||||||
|
@ -1037,7 +915,7 @@ mod tests {
|
||||||
image_cache_task.send(Prefetch(url.clone()));
|
image_cache_task.send(Prefetch(url.clone()));
|
||||||
image_cache_task.send(Decode(url.clone()));
|
image_cache_task.send(Decode(url.clone()));
|
||||||
|
|
||||||
let (response_port, response_chan) = stream();
|
let (response_port, response_chan) = Chan::new();
|
||||||
image_cache_task.send(WaitForImage(url, response_chan));
|
image_cache_task.send(WaitForImage(url, response_chan));
|
||||||
|
|
||||||
wait_chan.send(());
|
wait_chan.send(());
|
||||||
|
@ -1053,10 +931,10 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sync_cache_should_wait_for_images() {
|
fn sync_cache_should_wait_for_images() {
|
||||||
let mock_resource_task = do mock_resource_task |response| {
|
let mock_resource_task = mock_resource_task(proc(response) {
|
||||||
response.send(resource_task::Payload(test_image_bin()));
|
response.send(resource_task::Payload(test_image_bin()));
|
||||||
response.send(resource_task::Done(result::Ok(())));
|
response.send(resource_task::Done(Ok(())));
|
||||||
};
|
});
|
||||||
|
|
||||||
let image_cache_task = SyncImageCacheTask(mock_resource_task.clone());
|
let image_cache_task = SyncImageCacheTask(mock_resource_task.clone());
|
||||||
let url = make_url(~"file", None);
|
let url = make_url(~"file", None);
|
||||||
|
@ -1064,7 +942,7 @@ mod tests {
|
||||||
image_cache_task.send(Prefetch(url.clone()));
|
image_cache_task.send(Prefetch(url.clone()));
|
||||||
image_cache_task.send(Decode(url.clone()));
|
image_cache_task.send(Decode(url.clone()));
|
||||||
|
|
||||||
let (response_port, response_chan) = stream();
|
let (response_port, response_chan) = Chan::new();
|
||||||
image_cache_task.send(GetImage(url, response_chan));
|
image_cache_task.send(GetImage(url, response_chan));
|
||||||
match response_port.recv() {
|
match response_port.recv() {
|
||||||
ImageReady(_) => (),
|
ImageReady(_) => (),
|
||||||
|
|
|
@ -11,14 +11,13 @@ multiple times and thus triggering reflows multiple times.
|
||||||
use image_cache_task::{Decode, GetImage, ImageCacheTask, ImageFailed, ImageNotReady, ImageReady};
|
use image_cache_task::{Decode, GetImage, ImageCacheTask, ImageFailed, ImageNotReady, ImageReady};
|
||||||
use image_cache_task::{ImageResponseMsg, Prefetch, WaitForImage};
|
use image_cache_task::{ImageResponseMsg, Prefetch, WaitForImage};
|
||||||
|
|
||||||
use std::comm;
|
|
||||||
use std::comm::Port;
|
use std::comm::Port;
|
||||||
use std::task;
|
use std::task;
|
||||||
use servo_util::url::{UrlMap, url_map};
|
use servo_util::url::{UrlMap, url_map};
|
||||||
use extra::url::Url;
|
use extra::url::Url;
|
||||||
|
|
||||||
pub trait ImageResponder {
|
pub trait ImageResponder {
|
||||||
fn respond(&self) -> ~fn(ImageResponseMsg);
|
fn respond(&self) -> proc(ImageResponseMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn LocalImageCache(image_cache_task: ImageCacheTask) -> LocalImageCache {
|
pub fn LocalImageCache(image_cache_task: ImageCacheTask) -> LocalImageCache {
|
||||||
|
@ -90,13 +89,13 @@ impl LocalImageCache {
|
||||||
|
|
||||||
match state.last_response {
|
match state.last_response {
|
||||||
ImageReady(ref image) => {
|
ImageReady(ref image) => {
|
||||||
let (port, chan) = comm::stream();
|
let (port, chan) = Chan::new();
|
||||||
chan.send(ImageReady(image.clone()));
|
chan.send(ImageReady(image.clone()));
|
||||||
return port;
|
return port;
|
||||||
}
|
}
|
||||||
ImageNotReady => {
|
ImageNotReady => {
|
||||||
if last_round == self.round_number {
|
if last_round == self.round_number {
|
||||||
let (port, chan) = comm::stream();
|
let (port, chan) = Chan::new();
|
||||||
chan.send(ImageNotReady);
|
chan.send(ImageNotReady);
|
||||||
return port;
|
return port;
|
||||||
} else {
|
} else {
|
||||||
|
@ -105,14 +104,14 @@ impl LocalImageCache {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImageFailed => {
|
ImageFailed => {
|
||||||
let (port, chan) = comm::stream();
|
let (port, chan) = Chan::new();
|
||||||
chan.send(ImageFailed);
|
chan.send(ImageFailed);
|
||||||
return port;
|
return port;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (response_port, response_chan) = comm::stream();
|
let (response_port, response_chan) = Chan::new();
|
||||||
self.image_cache_task.send(GetImage((*url).clone(), response_chan));
|
self.image_cache_task.send(GetImage((*url).clone(), response_chan));
|
||||||
|
|
||||||
let response = response_port.recv();
|
let response = response_port.recv();
|
||||||
|
@ -128,7 +127,7 @@ impl LocalImageCache {
|
||||||
let on_image_available = self.on_image_available.as_ref().unwrap().respond();
|
let on_image_available = self.on_image_available.as_ref().unwrap().respond();
|
||||||
let url = (*url).clone();
|
let url = (*url).clone();
|
||||||
do task::spawn {
|
do task::spawn {
|
||||||
let (response_port, response_chan) = comm::stream();
|
let (response_port, response_chan) = Chan::new();
|
||||||
image_cache_task.send(WaitForImage(url.clone(), response_chan));
|
image_cache_task.send(WaitForImage(url.clone(), response_chan));
|
||||||
on_image_available(response_port.recv());
|
on_image_available(response_port.recv());
|
||||||
}
|
}
|
||||||
|
@ -144,7 +143,7 @@ impl LocalImageCache {
|
||||||
};
|
};
|
||||||
self.get_state(url).last_response = response_copy;
|
self.get_state(url).last_response = response_copy;
|
||||||
|
|
||||||
let (port, chan) = comm::stream();
|
let (port, chan) = Chan::new();
|
||||||
chan.send(response);
|
chan.send(response);
|
||||||
return port;
|
return port;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,17 +2,14 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#[link(name = "net",
|
#[crate_id = "github.com/mozilla/servo#net:0.1"];
|
||||||
vers = "0.1",
|
|
||||||
uuid = "69c2b7b7-0d7d-4514-a48a-0eed61476039",
|
|
||||||
url = "http://servo.org/")];
|
|
||||||
#[crate_type = "lib"];
|
#[crate_type = "lib"];
|
||||||
|
|
||||||
#[feature(globs, managed_boxes)];
|
#[feature(globs, managed_boxes)];
|
||||||
|
|
||||||
extern mod geom;
|
extern mod geom;
|
||||||
extern mod http;
|
extern mod http;
|
||||||
extern mod servo_util (name = "util");
|
extern mod servo_util = "util";
|
||||||
extern mod stb_image;
|
extern mod stb_image;
|
||||||
extern mod extra;
|
extern mod extra;
|
||||||
extern mod png;
|
extern mod png;
|
||||||
|
|
|
@ -8,9 +8,7 @@ use file_loader;
|
||||||
use http_loader;
|
use http_loader;
|
||||||
use data_loader;
|
use data_loader;
|
||||||
|
|
||||||
use std::cell::Cell;
|
|
||||||
use std::comm::{Chan, Port, SharedChan};
|
use std::comm::{Chan, Port, SharedChan};
|
||||||
use std::comm;
|
|
||||||
use extra::url::Url;
|
use extra::url::Url;
|
||||||
use util::spawn_listener;
|
use util::spawn_listener;
|
||||||
use http::headers::content_type::MediaType;
|
use http::headers::content_type::MediaType;
|
||||||
|
@ -87,8 +85,8 @@ pub enum ProgressMsg {
|
||||||
|
|
||||||
/// For use by loaders in responding to a Load message.
|
/// For use by loaders in responding to a Load message.
|
||||||
pub fn start_sending(start_chan: Chan<LoadResponse>,
|
pub fn start_sending(start_chan: Chan<LoadResponse>,
|
||||||
metadata: Metadata) -> Chan<ProgressMsg> {
|
metadata: Metadata) -> SharedChan<ProgressMsg> {
|
||||||
let (progress_port, progress_chan) = comm::stream();
|
let (progress_port, progress_chan) = SharedChan::new();
|
||||||
start_chan.send(LoadResponse {
|
start_chan.send(LoadResponse {
|
||||||
metadata: metadata,
|
metadata: metadata,
|
||||||
progress_port: progress_port,
|
progress_port: progress_port,
|
||||||
|
@ -99,7 +97,7 @@ pub fn start_sending(start_chan: Chan<LoadResponse>,
|
||||||
/// Convenience function for synchronously loading a whole resource.
|
/// Convenience function for synchronously loading a whole resource.
|
||||||
pub fn load_whole_resource(resource_task: &ResourceTask, url: Url)
|
pub fn load_whole_resource(resource_task: &ResourceTask, url: Url)
|
||||||
-> Result<(Metadata, ~[u8]), ()> {
|
-> Result<(Metadata, ~[u8]), ()> {
|
||||||
let (start_port, start_chan) = comm::stream();
|
let (start_port, start_chan) = Chan::new();
|
||||||
resource_task.send(Load(url, start_chan));
|
resource_task.send(Load(url, start_chan));
|
||||||
let response = start_port.recv();
|
let response = start_port.recv();
|
||||||
|
|
||||||
|
@ -116,7 +114,7 @@ pub fn load_whole_resource(resource_task: &ResourceTask, url: Url)
|
||||||
/// Handle to a resource task
|
/// Handle to a resource task
|
||||||
pub type ResourceTask = SharedChan<ControlMsg>;
|
pub type ResourceTask = SharedChan<ControlMsg>;
|
||||||
|
|
||||||
pub type LoaderTask = ~fn(url: Url, Chan<LoadResponse>);
|
pub type LoaderTask = proc(url: Url, Chan<LoadResponse>);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Creates a task to load a specific resource
|
Creates a task to load a specific resource
|
||||||
|
@ -137,12 +135,11 @@ pub fn ResourceTask() -> ResourceTask {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_resource_task_with_loaders(loaders: ~[(~str, LoaderTaskFactory)]) -> ResourceTask {
|
fn create_resource_task_with_loaders(loaders: ~[(~str, LoaderTaskFactory)]) -> ResourceTask {
|
||||||
let loaders_cell = Cell::new(loaders);
|
let chan = spawn_listener(proc(from_client) {
|
||||||
let chan = do spawn_listener |from_client| {
|
|
||||||
// TODO: change copy to move once we can move out of closures
|
// TODO: change copy to move once we can move out of closures
|
||||||
ResourceManager(from_client, loaders_cell.take()).start()
|
ResourceManager(from_client, loaders).start()
|
||||||
};
|
});
|
||||||
SharedChan::new(chan)
|
chan
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ResourceManager {
|
pub struct ResourceManager {
|
||||||
|
@ -211,7 +208,7 @@ fn test_exit() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bad_scheme() {
|
fn test_bad_scheme() {
|
||||||
let resource_task = ResourceTask();
|
let resource_task = ResourceTask();
|
||||||
let (start, start_chan) = comm::stream();
|
let (start, start_chan) = Chan::new();
|
||||||
resource_task.send(Load(FromStr::from_str("bogus://whatever").unwrap(), start_chan));
|
resource_task.send(Load(FromStr::from_str("bogus://whatever").unwrap(), start_chan));
|
||||||
let response = start.recv();
|
let response = start.recv();
|
||||||
match response.progress_port.recv() {
|
match response.progress_port.recv() {
|
||||||
|
@ -226,7 +223,7 @@ static snicklefritz_payload: [u8, ..3] = [1, 2, 3];
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
fn snicklefritz_loader_factory() -> LoaderTask {
|
fn snicklefritz_loader_factory() -> LoaderTask {
|
||||||
let f: LoaderTask = |url: Url, start_chan: Chan<LoadResponse>| {
|
let f: LoaderTask = proc(url: Url, start_chan: Chan<LoadResponse>) {
|
||||||
let progress_chan = start_sending(start_chan, Metadata::default(url));
|
let progress_chan = start_sending(start_chan, Metadata::default(url));
|
||||||
progress_chan.send(Payload(snicklefritz_payload.into_owned()));
|
progress_chan.send(Payload(snicklefritz_payload.into_owned()));
|
||||||
progress_chan.send(Done(Ok(())));
|
progress_chan.send(Done(Ok(())));
|
||||||
|
@ -238,7 +235,7 @@ fn snicklefritz_loader_factory() -> LoaderTask {
|
||||||
fn should_delegate_to_scheme_loader() {
|
fn should_delegate_to_scheme_loader() {
|
||||||
let loader_factories = ~[(~"snicklefritz", snicklefritz_loader_factory)];
|
let loader_factories = ~[(~"snicklefritz", snicklefritz_loader_factory)];
|
||||||
let resource_task = create_resource_task_with_loaders(loader_factories);
|
let resource_task = create_resource_task_with_loaders(loader_factories);
|
||||||
let (start, start_chan) = comm::stream();
|
let (start, start_chan) = Chan::new();
|
||||||
resource_task.send(Load(FromStr::from_str("snicklefritz://heya").unwrap(), start_chan));
|
resource_task.send(Load(FromStr::from_str("snicklefritz://heya").unwrap(), start_chan));
|
||||||
|
|
||||||
let response = start.recv();
|
let response = start.recv();
|
||||||
|
|
|
@ -2,14 +2,13 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use std::comm;
|
|
||||||
use std::comm::{Chan, Port};
|
use std::comm::{Chan, Port};
|
||||||
use std::task;
|
use std::task;
|
||||||
|
|
||||||
pub fn spawn_listener<A: Send>(f: ~fn(Port<A>)) -> Chan<A> {
|
pub fn spawn_listener<A: Send>(f: proc(Port<A>)) -> SharedChan<A> {
|
||||||
let (setup_port, setup_chan) = comm::stream();
|
let (setup_port, setup_chan) = Chan::new();
|
||||||
do task::spawn {
|
do task::spawn {
|
||||||
let (port, chan) = comm::stream();
|
let (port, chan) = SharedChan::new();
|
||||||
setup_chan.send(chan);
|
setup_chan.send(chan);
|
||||||
f(port);
|
f(port);
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,6 @@ impl CallbackInterface {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn GetCallableProperty(&self, cx: *JSContext, name: *libc::c_char, callable: &mut JSVal) -> bool {
|
pub fn GetCallableProperty(&self, cx: *JSContext, name: *libc::c_char, callable: &mut JSVal) -> bool {
|
||||||
unsafe {
|
unsafe {
|
||||||
if JS_GetProperty(cx, self.callback, name, &*callable) == 0 {
|
if JS_GetProperty(cx, self.callback, name, &*callable) == 0 {
|
||||||
|
@ -65,7 +64,6 @@ pub fn GetJSObjectFromCallback<T: CallbackContainer>(callback: &T) -> *JSObject
|
||||||
callback.callback()
|
callback.callback()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn WrapCallThisObject<T: 'static + CallbackContainer + Reflectable>(cx: *JSContext,
|
pub fn WrapCallThisObject<T: 'static + CallbackContainer + Reflectable>(cx: *JSContext,
|
||||||
_scope: *JSObject,
|
_scope: *JSObject,
|
||||||
p: @mut T) -> *JSObject {
|
p: @mut T) -> *JSObject {
|
||||||
|
|
|
@ -1091,7 +1091,7 @@ for (uint32_t i = 0; i < length; ++i) {
|
||||||
return handleDefault(
|
return handleDefault(
|
||||||
conversionCode,
|
conversionCode,
|
||||||
("static data: [u8, ..%s] = [ %s ];\n"
|
("static data: [u8, ..%s] = [ %s ];\n"
|
||||||
"%s = str::from_utf8(data)" %
|
"%s = str::from_utf8(data).to_owned()" %
|
||||||
(len(defaultValue.value) + 1,
|
(len(defaultValue.value) + 1,
|
||||||
", ".join(["'" + char + "' as u8" for char in defaultValue.value] + ["0"]),
|
", ".join(["'" + char + "' as u8" for char in defaultValue.value] + ["0"]),
|
||||||
varName)))
|
varName)))
|
||||||
|
@ -2173,7 +2173,7 @@ class CGImports(CGWrapper):
|
||||||
# Allow unreachable_code because we use 'break' in a way that sometimes produces
|
# Allow unreachable_code because we use 'break' in a way that sometimes produces
|
||||||
# two 'break's in a row. See for example CallbackMember.getArgConversions.
|
# two 'break's in a row. See for example CallbackMember.getArgConversions.
|
||||||
return '\n'.join([
|
return '\n'.join([
|
||||||
'#[allow(unreachable_code,non_uppercase_statics,unused_imports,unused_variable,unused_unsafe,unused_mut,dead_assignment)];',
|
'#[allow(unreachable_code,non_uppercase_statics,unused_imports,unused_variable,unused_unsafe,unused_mut,dead_assignment,dead_code)];',
|
||||||
''.join('use %s;\n' % i for i in imports),
|
''.join('use %s;\n' % i for i in imports),
|
||||||
''])
|
''])
|
||||||
CGWrapper.__init__(self, child,
|
CGWrapper.__init__(self, child,
|
||||||
|
@ -2454,16 +2454,14 @@ class CGAbstractMethod(CGThing):
|
||||||
def _decorators(self):
|
def _decorators(self):
|
||||||
decorators = []
|
decorators = []
|
||||||
if self.alwaysInline:
|
if self.alwaysInline:
|
||||||
# FIXME Rust #8801 #[inline(always)] and #[fixed_stack_segment] not compatible
|
decorators.append('#[inline(always)]')
|
||||||
# decorators.append('#[inline(always)]')
|
|
||||||
pass
|
|
||||||
elif self.inline:
|
elif self.inline:
|
||||||
#decorators.append('inline')
|
#decorators.append('inline')
|
||||||
pass
|
pass
|
||||||
if self.extern:
|
if self.extern:
|
||||||
decorators.append('extern')
|
decorators.append('extern')
|
||||||
if not self.extern:
|
if not self.extern:
|
||||||
decorators.append('#[fixed_stack_segment]')
|
pass
|
||||||
if self.static:
|
if self.static:
|
||||||
#decorators.append('static')
|
#decorators.append('static')
|
||||||
pass
|
pass
|
||||||
|
@ -3522,6 +3520,7 @@ class CGEnum(CGThing):
|
||||||
|
|
||||||
def define(self):
|
def define(self):
|
||||||
return """
|
return """
|
||||||
|
#[repr(uint)]
|
||||||
pub enum valuelist {
|
pub enum valuelist {
|
||||||
%s
|
%s
|
||||||
}
|
}
|
||||||
|
@ -3576,7 +3575,7 @@ class ClassMethod(ClassItem):
|
||||||
ClassItem.__init__(self, name, visibility)
|
ClassItem.__init__(self, name, visibility)
|
||||||
|
|
||||||
def getDecorators(self, declaring):
|
def getDecorators(self, declaring):
|
||||||
decorators = ['#[fixed_stack_segment]']
|
decorators = []
|
||||||
if self.inline:
|
if self.inline:
|
||||||
decorators.append('inline')
|
decorators.append('inline')
|
||||||
if declaring:
|
if declaring:
|
||||||
|
@ -4150,8 +4149,8 @@ class CGProxyUnwrap(CGAbstractMethod):
|
||||||
obj = js::UnwrapObject(obj);
|
obj = js::UnwrapObject(obj);
|
||||||
}*/
|
}*/
|
||||||
//MOZ_ASSERT(IsProxy(obj));
|
//MOZ_ASSERT(IsProxy(obj));
|
||||||
let box: *Box<%s> = cast::transmute(RUST_JSVAL_TO_PRIVATE(GetProxyPrivate(obj)));
|
let box_: *Box<%s> = cast::transmute(RUST_JSVAL_TO_PRIVATE(GetProxyPrivate(obj)));
|
||||||
return ptr::to_unsafe_ptr(&(*box).data);""" % (self.descriptor.concreteType)
|
return ptr::to_unsafe_ptr(&(*box_).data);""" % (self.descriptor.concreteType)
|
||||||
|
|
||||||
class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod):
|
class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod):
|
||||||
def __init__(self, descriptor):
|
def __init__(self, descriptor):
|
||||||
|
@ -4443,9 +4442,9 @@ class CGDOMJSProxyHandler_obj_toString(CGAbstractExternMethod):
|
||||||
JSString* jsresult;
|
JSString* jsresult;
|
||||||
return xpc_qsStringToJsstring(cx, result, &jsresult) ? jsresult : NULL;"""
|
return xpc_qsStringToJsstring(cx, result, &jsresult) ? jsresult : NULL;"""
|
||||||
|
|
||||||
return """ do "%s".to_c_str().with_ref |s| {
|
return """ "%s".to_c_str().with_ref(|s| {
|
||||||
_obj_toString(cx, s)
|
_obj_toString(cx, s)
|
||||||
}""" % self.descriptor.name
|
})""" % self.descriptor.name
|
||||||
|
|
||||||
def definition_body(self):
|
def definition_body(self):
|
||||||
return self.getBody()
|
return self.getBody()
|
||||||
|
@ -4907,7 +4906,6 @@ class CGDictionary(CGThing):
|
||||||
" return true;\n"
|
" return true;\n"
|
||||||
" }\n"
|
" }\n"
|
||||||
"\n" if not self.workers else "") +
|
"\n" if not self.workers else "") +
|
||||||
" #[fixed_stack_segment]\n" +
|
|
||||||
" pub fn Init(&mut self, cx: *JSContext, val: JSVal) -> JSBool {\n"
|
" pub fn Init(&mut self, cx: *JSContext, val: JSVal) -> JSBool {\n"
|
||||||
" unsafe {\n" +
|
" unsafe {\n" +
|
||||||
# NOTE: jsids are per-runtime, so don't use them in workers
|
# NOTE: jsids are per-runtime, so don't use them in workers
|
||||||
|
|
|
@ -13,14 +13,12 @@ pub trait JSValConvertible {
|
||||||
|
|
||||||
|
|
||||||
impl JSValConvertible for i64 {
|
impl JSValConvertible for i64 {
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn to_jsval(&self) -> JSVal {
|
fn to_jsval(&self) -> JSVal {
|
||||||
unsafe {
|
unsafe {
|
||||||
RUST_DOUBLE_TO_JSVAL(*self as f64)
|
RUST_DOUBLE_TO_JSVAL(*self as f64)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn from_jsval(val: JSVal) -> Option<i64> {
|
fn from_jsval(val: JSVal) -> Option<i64> {
|
||||||
unsafe {
|
unsafe {
|
||||||
Some(RUST_JSVAL_TO_DOUBLE(val) as i64)
|
Some(RUST_JSVAL_TO_DOUBLE(val) as i64)
|
||||||
|
@ -29,14 +27,12 @@ impl JSValConvertible for i64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JSValConvertible for u32 {
|
impl JSValConvertible for u32 {
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn to_jsval(&self) -> JSVal {
|
fn to_jsval(&self) -> JSVal {
|
||||||
unsafe {
|
unsafe {
|
||||||
RUST_UINT_TO_JSVAL(*self)
|
RUST_UINT_TO_JSVAL(*self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn from_jsval(val: JSVal) -> Option<u32> {
|
fn from_jsval(val: JSVal) -> Option<u32> {
|
||||||
unsafe {
|
unsafe {
|
||||||
Some(RUST_JSVAL_TO_INT(val) as u32)
|
Some(RUST_JSVAL_TO_INT(val) as u32)
|
||||||
|
@ -45,14 +41,12 @@ impl JSValConvertible for u32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JSValConvertible for i32 {
|
impl JSValConvertible for i32 {
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn to_jsval(&self) -> JSVal {
|
fn to_jsval(&self) -> JSVal {
|
||||||
unsafe {
|
unsafe {
|
||||||
RUST_UINT_TO_JSVAL(*self as u32)
|
RUST_UINT_TO_JSVAL(*self as u32)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn from_jsval(val: JSVal) -> Option<i32> {
|
fn from_jsval(val: JSVal) -> Option<i32> {
|
||||||
unsafe {
|
unsafe {
|
||||||
Some(RUST_JSVAL_TO_INT(val) as i32)
|
Some(RUST_JSVAL_TO_INT(val) as i32)
|
||||||
|
@ -61,14 +55,12 @@ impl JSValConvertible for i32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JSValConvertible for u16 {
|
impl JSValConvertible for u16 {
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn to_jsval(&self) -> JSVal {
|
fn to_jsval(&self) -> JSVal {
|
||||||
unsafe {
|
unsafe {
|
||||||
RUST_UINT_TO_JSVAL(*self as u32)
|
RUST_UINT_TO_JSVAL(*self as u32)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn from_jsval(val: JSVal) -> Option<u16> {
|
fn from_jsval(val: JSVal) -> Option<u16> {
|
||||||
unsafe {
|
unsafe {
|
||||||
Some(RUST_JSVAL_TO_INT(val) as u16)
|
Some(RUST_JSVAL_TO_INT(val) as u16)
|
||||||
|
@ -97,14 +89,12 @@ impl JSValConvertible for bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JSValConvertible for f32 {
|
impl JSValConvertible for f32 {
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn to_jsval(&self) -> JSVal {
|
fn to_jsval(&self) -> JSVal {
|
||||||
unsafe {
|
unsafe {
|
||||||
RUST_DOUBLE_TO_JSVAL(*self as f64)
|
RUST_DOUBLE_TO_JSVAL(*self as f64)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn from_jsval(val: JSVal) -> Option<f32> {
|
fn from_jsval(val: JSVal) -> Option<f32> {
|
||||||
unsafe {
|
unsafe {
|
||||||
Some(RUST_JSVAL_TO_DOUBLE(val) as f32)
|
Some(RUST_JSVAL_TO_DOUBLE(val) as f32)
|
||||||
|
@ -113,14 +103,12 @@ impl JSValConvertible for f32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JSValConvertible for f64 {
|
impl JSValConvertible for f64 {
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn to_jsval(&self) -> JSVal {
|
fn to_jsval(&self) -> JSVal {
|
||||||
unsafe {
|
unsafe {
|
||||||
RUST_DOUBLE_TO_JSVAL(*self as f64)
|
RUST_DOUBLE_TO_JSVAL(*self as f64)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn from_jsval(val: JSVal) -> Option<f64> {
|
fn from_jsval(val: JSVal) -> Option<f64> {
|
||||||
unsafe {
|
unsafe {
|
||||||
Some(RUST_JSVAL_TO_DOUBLE(val) as f64)
|
Some(RUST_JSVAL_TO_DOUBLE(val) as f64)
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use dom::bindings::utils::{Reflectable, Reflector, Traceable};
|
use dom::bindings::utils::{Reflectable, Reflector, Traceable, trace_reflector};
|
||||||
use dom::types::*;
|
use dom::types::*;
|
||||||
use dom::node::AbstractNode;
|
use dom::node::AbstractNode;
|
||||||
|
|
||||||
|
@ -23,7 +23,6 @@ impl Reflectable for AbstractNode {
|
||||||
|
|
||||||
impl Traceable for Node {
|
impl Traceable for Node {
|
||||||
fn trace(&self, tracer: *mut JSTracer) {
|
fn trace(&self, tracer: *mut JSTracer) {
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn trace_node(tracer: *mut JSTracer, node: Option<AbstractNode>, name: &str) {
|
fn trace_node(tracer: *mut JSTracer, node: Option<AbstractNode>, name: &str) {
|
||||||
if node.is_none() {
|
if node.is_none() {
|
||||||
return;
|
return;
|
||||||
|
@ -35,10 +34,10 @@ impl Traceable for Node {
|
||||||
unsafe {
|
unsafe {
|
||||||
(*tracer).debugPrinter = ptr::null();
|
(*tracer).debugPrinter = ptr::null();
|
||||||
(*tracer).debugPrintIndex = -1;
|
(*tracer).debugPrintIndex = -1;
|
||||||
do name.to_c_str().with_ref |name| {
|
name.to_c_str().with_ref(|name| {
|
||||||
(*tracer).debugPrintArg = name as *libc::c_void;
|
(*tracer).debugPrintArg = name as *libc::c_void;
|
||||||
JS_CallTracer(cast::transmute(tracer), obj, JSTRACE_OBJECT as u32);
|
JS_CallTracer(cast::transmute(tracer), obj, JSTRACE_OBJECT as u32);
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
debug!("tracing {:p}?:", self.reflector().get_jsobject());
|
debug!("tracing {:p}?:", self.reflector().get_jsobject());
|
||||||
|
@ -47,5 +46,7 @@ impl Traceable for Node {
|
||||||
trace_node(tracer, self.last_child, "last child");
|
trace_node(tracer, self.last_child, "last child");
|
||||||
trace_node(tracer, self.next_sibling, "next sibling");
|
trace_node(tracer, self.next_sibling, "next sibling");
|
||||||
trace_node(tracer, self.prev_sibling, "prev sibling");
|
trace_node(tracer, self.prev_sibling, "prev sibling");
|
||||||
|
let owner_doc = self.owner_doc();
|
||||||
|
trace_reflector(tracer, "document", owner_doc.reflector());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,6 @@ pub extern fn getPropertyDescriptor(cx: *JSContext, proxy: *JSObject, id: jsid,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn defineProperty_(cx: *JSContext, proxy: *JSObject, id: jsid,
|
pub fn defineProperty_(cx: *JSContext, proxy: *JSObject, id: jsid,
|
||||||
desc: *JSPropertyDescriptor) -> JSBool {
|
desc: *JSPropertyDescriptor) -> JSBool {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -72,7 +71,6 @@ pub extern fn defineProperty(cx: *JSContext, proxy: *JSObject, id: jsid,
|
||||||
defineProperty_(cx, proxy, id, desc)
|
defineProperty_(cx, proxy, id, desc)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn _obj_toString(cx: *JSContext, className: *libc::c_char) -> *JSString {
|
pub fn _obj_toString(cx: *JSContext, className: *libc::c_char) -> *JSString {
|
||||||
unsafe {
|
unsafe {
|
||||||
let name = str::raw::from_c_str(className);
|
let name = str::raw::from_c_str(className);
|
||||||
|
@ -83,7 +81,7 @@ pub fn _obj_toString(cx: *JSContext, className: *libc::c_char) -> *JSString {
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = ~"[object " + name + "]";
|
let result = ~"[object " + name + "]";
|
||||||
for (i, c) in result.iter().enumerate() {
|
for (i, c) in result.chars().enumerate() {
|
||||||
*chars.offset(i as int) = c as jschar;
|
*chars.offset(i as int) = c as jschar;
|
||||||
}
|
}
|
||||||
*chars.offset(nchars as int) = 0;
|
*chars.offset(nchars as int) = 0;
|
||||||
|
@ -95,7 +93,6 @@ pub fn _obj_toString(cx: *JSContext, className: *libc::c_char) -> *JSString {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn GetExpandoObject(obj: *JSObject) -> *JSObject {
|
pub fn GetExpandoObject(obj: *JSObject) -> *JSObject {
|
||||||
unsafe {
|
unsafe {
|
||||||
assert!(is_dom_proxy(obj));
|
assert!(is_dom_proxy(obj));
|
||||||
|
@ -108,7 +105,6 @@ pub fn GetExpandoObject(obj: *JSObject) -> *JSObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn EnsureExpandoObject(cx: *JSContext, obj: *JSObject) -> *JSObject {
|
pub fn EnsureExpandoObject(cx: *JSContext, obj: *JSObject) -> *JSObject {
|
||||||
unsafe {
|
unsafe {
|
||||||
assert!(is_dom_proxy(obj));
|
assert!(is_dom_proxy(obj));
|
||||||
|
|
|
@ -29,7 +29,7 @@ use js::jsapi::{JS_NewUCStringCopyN, JS_DefineFunctions, JS_DefineProperty};
|
||||||
use js::jsapi::{JS_ValueToString, JS_GetReservedSlot, JS_SetReservedSlot};
|
use js::jsapi::{JS_ValueToString, JS_GetReservedSlot, JS_SetReservedSlot};
|
||||||
use js::jsapi::{JSContext, JSObject, JSBool, jsid, JSClass, JSNative, JSTracer};
|
use js::jsapi::{JSContext, JSObject, JSBool, jsid, JSClass, JSNative, JSTracer};
|
||||||
use js::jsapi::{JSFunctionSpec, JSPropertySpec, JSVal, JSPropertyDescriptor};
|
use js::jsapi::{JSFunctionSpec, JSPropertySpec, JSVal, JSPropertyDescriptor};
|
||||||
use js::jsapi::{JSPropertyOp, JSStrictPropertyOp, JS_NewGlobalObject, JS_InitStandardClasses};
|
use js::jsapi::{JS_NewGlobalObject, JS_InitStandardClasses};
|
||||||
use js::jsapi::{JSString, JS_CallTracer, JSTRACE_OBJECT};
|
use js::jsapi::{JSString, JS_CallTracer, JSTRACE_OBJECT};
|
||||||
use js::jsapi::{JS_IsExceptionPending};
|
use js::jsapi::{JS_IsExceptionPending};
|
||||||
use js::jsfriendapi::bindgen::JS_NewObjectWithUniqueType;
|
use js::jsfriendapi::bindgen::JS_NewObjectWithUniqueType;
|
||||||
|
@ -47,22 +47,18 @@ mod jsval {
|
||||||
use js::glue::{RUST_JSVAL_IS_STRING, RUST_JSVAL_TO_STRING};
|
use js::glue::{RUST_JSVAL_IS_STRING, RUST_JSVAL_TO_STRING};
|
||||||
use js::jsapi::{JSVal, JSString};
|
use js::jsapi::{JSVal, JSString};
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn is_null(v: JSVal) -> bool {
|
pub fn is_null(v: JSVal) -> bool {
|
||||||
unsafe { RUST_JSVAL_IS_NULL(v) == 1 }
|
unsafe { RUST_JSVAL_IS_NULL(v) == 1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn is_undefined(v: JSVal) -> bool {
|
pub fn is_undefined(v: JSVal) -> bool {
|
||||||
unsafe { RUST_JSVAL_IS_VOID(v) == 1 }
|
unsafe { RUST_JSVAL_IS_VOID(v) == 1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn is_string(v: JSVal) -> bool {
|
pub fn is_string(v: JSVal) -> bool {
|
||||||
unsafe { RUST_JSVAL_IS_STRING(v) == 1 }
|
unsafe { RUST_JSVAL_IS_STRING(v) == 1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub unsafe fn to_string(v: JSVal) -> *JSString {
|
pub unsafe fn to_string(v: JSVal) -> *JSString {
|
||||||
RUST_JSVAL_TO_STRING(v)
|
RUST_JSVAL_TO_STRING(v)
|
||||||
}
|
}
|
||||||
|
@ -149,7 +145,6 @@ fn is_dom_class(clasp: *JSClass) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn is_dom_proxy(obj: *JSObject) -> bool {
|
pub fn is_dom_proxy(obj: *JSObject) -> bool {
|
||||||
unsafe {
|
unsafe {
|
||||||
(js_IsObjectProxyClass(obj) || js_IsFunctionProxyClass(obj)) &&
|
(js_IsObjectProxyClass(obj) || js_IsFunctionProxyClass(obj)) &&
|
||||||
|
@ -157,7 +152,6 @@ pub fn is_dom_proxy(obj: *JSObject) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub unsafe fn dom_object_slot(obj: *JSObject) -> u32 {
|
pub unsafe fn dom_object_slot(obj: *JSObject) -> u32 {
|
||||||
let clasp = JS_GetClass(obj);
|
let clasp = JS_GetClass(obj);
|
||||||
if is_dom_class(clasp) {
|
if is_dom_class(clasp) {
|
||||||
|
@ -168,14 +162,12 @@ pub unsafe fn dom_object_slot(obj: *JSObject) -> u32 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub unsafe fn unwrap<T>(obj: *JSObject) -> T {
|
pub unsafe fn unwrap<T>(obj: *JSObject) -> T {
|
||||||
let slot = dom_object_slot(obj);
|
let slot = dom_object_slot(obj);
|
||||||
let val = JS_GetReservedSlot(obj, slot);
|
let val = JS_GetReservedSlot(obj, slot);
|
||||||
cast::transmute(RUST_JSVAL_TO_PRIVATE(val))
|
cast::transmute(RUST_JSVAL_TO_PRIVATE(val))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub unsafe fn get_dom_class(obj: *JSObject) -> Result<DOMClass, ()> {
|
pub unsafe fn get_dom_class(obj: *JSObject) -> Result<DOMClass, ()> {
|
||||||
let clasp = JS_GetClass(obj);
|
let clasp = JS_GetClass(obj);
|
||||||
if is_dom_class(clasp) {
|
if is_dom_class(clasp) {
|
||||||
|
@ -194,7 +186,7 @@ pub unsafe fn get_dom_class(obj: *JSObject) -> Result<DOMClass, ()> {
|
||||||
|
|
||||||
pub fn unwrap_object<T>(obj: *JSObject, proto_id: PrototypeList::id::ID, proto_depth: uint) -> Result<T, ()> {
|
pub fn unwrap_object<T>(obj: *JSObject, proto_id: PrototypeList::id::ID, proto_depth: uint) -> Result<T, ()> {
|
||||||
unsafe {
|
unsafe {
|
||||||
do get_dom_class(obj).and_then |dom_class| {
|
get_dom_class(obj).and_then(|dom_class| {
|
||||||
if dom_class.interface_chain[proto_depth] == proto_id {
|
if dom_class.interface_chain[proto_depth] == proto_id {
|
||||||
debug!("good prototype");
|
debug!("good prototype");
|
||||||
Ok(unwrap(obj))
|
Ok(unwrap(obj))
|
||||||
|
@ -202,11 +194,10 @@ pub fn unwrap_object<T>(obj: *JSObject, proto_id: PrototypeList::id::ID, proto_d
|
||||||
debug!("bad prototype");
|
debug!("bad prototype");
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn unwrap_value<T>(val: *JSVal, proto_id: PrototypeList::id::ID, proto_depth: uint) -> Result<T, ()> {
|
pub fn unwrap_value<T>(val: *JSVal, proto_id: PrototypeList::id::ID, proto_depth: uint) -> Result<T, ()> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let obj = RUST_JSVAL_TO_OBJECT(*val);
|
let obj = RUST_JSVAL_TO_OBJECT(*val);
|
||||||
|
@ -216,22 +207,19 @@ pub fn unwrap_value<T>(val: *JSVal, proto_id: PrototypeList::id::ID, proto_depth
|
||||||
|
|
||||||
pub unsafe fn squirrel_away<T>(x: @mut T) -> *Box<T> {
|
pub unsafe fn squirrel_away<T>(x: @mut T) -> *Box<T> {
|
||||||
let y: *Box<T> = cast::transmute(x);
|
let y: *Box<T> = cast::transmute(x);
|
||||||
cast::forget(x);
|
|
||||||
y
|
y
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn jsstring_to_str(cx: *JSContext, s: *JSString) -> ~str {
|
pub fn jsstring_to_str(cx: *JSContext, s: *JSString) -> ~str {
|
||||||
unsafe {
|
unsafe {
|
||||||
let length = 0;
|
let length = 0;
|
||||||
let chars = JS_GetStringCharsAndLength(cx, s, &length);
|
let chars = JS_GetStringCharsAndLength(cx, s, &length);
|
||||||
do vec::raw::buf_as_slice(chars, length as uint) |char_vec| {
|
vec::raw::buf_as_slice(chars, length as uint, |char_vec| {
|
||||||
str::from_utf16(char_vec)
|
str::from_utf16(char_vec)
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn jsid_to_str(cx: *JSContext, id: jsid) -> ~str {
|
pub fn jsid_to_str(cx: *JSContext, id: jsid) -> ~str {
|
||||||
unsafe {
|
unsafe {
|
||||||
assert!(RUST_JSID_IS_STRING(id) != 0);
|
assert!(RUST_JSID_IS_STRING(id) != 0);
|
||||||
|
@ -245,7 +233,6 @@ pub enum StringificationBehavior {
|
||||||
Empty,
|
Empty,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn jsval_to_str(cx: *JSContext, v: JSVal,
|
pub fn jsval_to_str(cx: *JSContext, v: JSVal,
|
||||||
nullBehavior: StringificationBehavior) -> Result<~str, ()> {
|
nullBehavior: StringificationBehavior) -> Result<~str, ()> {
|
||||||
if jsval::is_null(v) && nullBehavior == Empty {
|
if jsval::is_null(v) && nullBehavior == Empty {
|
||||||
|
@ -261,7 +248,6 @@ pub fn jsval_to_str(cx: *JSContext, v: JSVal,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn jsval_to_domstring(cx: *JSContext, v: JSVal) -> Result<Option<DOMString>, ()> {
|
pub fn jsval_to_domstring(cx: *JSContext, v: JSVal) -> Result<Option<DOMString>, ()> {
|
||||||
if jsval::is_null(v) || jsval::is_undefined(v) {
|
if jsval::is_null(v) || jsval::is_undefined(v) {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
|
@ -276,20 +262,17 @@ pub fn jsval_to_domstring(cx: *JSContext, v: JSVal) -> Result<Option<DOMString>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub unsafe fn str_to_jsval(cx: *JSContext, string: DOMString) -> JSVal {
|
pub unsafe fn str_to_jsval(cx: *JSContext, string: DOMString) -> JSVal {
|
||||||
do string.to_utf16().as_imm_buf |buf, len| {
|
let string_utf16 = string.to_utf16();
|
||||||
let jsstr = JS_NewUCStringCopyN(cx, buf, len as libc::size_t);
|
let jsstr = JS_NewUCStringCopyN(cx, string_utf16.as_ptr(), string_utf16.len() as libc::size_t);
|
||||||
if jsstr.is_null() {
|
if jsstr.is_null() {
|
||||||
// FIXME: is there something else we should do on failure?
|
// FIXME: is there something else we should do on failure?
|
||||||
JSVAL_NULL
|
JSVAL_NULL
|
||||||
} else {
|
} else {
|
||||||
RUST_STRING_TO_JSVAL(jsstr)
|
RUST_STRING_TO_JSVAL(jsstr)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub unsafe fn domstring_to_jsval(cx: *JSContext, string: Option<DOMString>) -> JSVal {
|
pub unsafe fn domstring_to_jsval(cx: *JSContext, string: Option<DOMString>) -> JSVal {
|
||||||
match string {
|
match string {
|
||||||
None => JSVAL_NULL,
|
None => JSVAL_NULL,
|
||||||
|
@ -313,7 +296,7 @@ pub static DOM_PROTOTYPE_SLOT: u32 = js::JSCLASS_GLOBAL_SLOT_COUNT;
|
||||||
// NOTE: This is baked into the Ion JIT as 0 in codegen for LGetDOMProperty and
|
// NOTE: This is baked into the Ion JIT as 0 in codegen for LGetDOMProperty and
|
||||||
// LSetDOMProperty. Those constants need to be changed accordingly if this value
|
// LSetDOMProperty. Those constants need to be changed accordingly if this value
|
||||||
// changes.
|
// changes.
|
||||||
static JSCLASS_DOM_GLOBAL: u32 = js::JSCLASS_USERBIT1;
|
pub static JSCLASS_DOM_GLOBAL: u32 = js::JSCLASS_USERBIT1;
|
||||||
|
|
||||||
pub struct NativeProperties {
|
pub struct NativeProperties {
|
||||||
staticMethods: *JSFunctionSpec,
|
staticMethods: *JSFunctionSpec,
|
||||||
|
@ -379,7 +362,6 @@ pub struct DOMJSClass {
|
||||||
dom_class: DOMClass
|
dom_class: DOMClass
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn GetProtoOrIfaceArray(global: *JSObject) -> **JSObject {
|
pub fn GetProtoOrIfaceArray(global: *JSObject) -> **JSObject {
|
||||||
unsafe {
|
unsafe {
|
||||||
/*assert ((*JS_GetClass(global)).flags & JSCLASS_DOM_GLOBAL) != 0;*/
|
/*assert ((*JS_GetClass(global)).flags & JSCLASS_DOM_GLOBAL) != 0;*/
|
||||||
|
@ -387,7 +369,6 @@ pub fn GetProtoOrIfaceArray(global: *JSObject) -> **JSObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn CreateInterfaceObjects2(cx: *JSContext, global: *JSObject, receiver: *JSObject,
|
pub fn CreateInterfaceObjects2(cx: *JSContext, global: *JSObject, receiver: *JSObject,
|
||||||
protoProto: *JSObject, protoClass: *JSClass,
|
protoProto: *JSObject, protoClass: *JSClass,
|
||||||
constructorClass: *JSClass, constructor: Option<JSNative>,
|
constructorClass: *JSClass, constructor: Option<JSNative>,
|
||||||
|
@ -415,11 +396,11 @@ pub fn CreateInterfaceObjects2(cx: *JSContext, global: *JSObject, receiver: *JSO
|
||||||
|
|
||||||
let mut interface = ptr::null();
|
let mut interface = ptr::null();
|
||||||
if constructorClass.is_not_null() || constructor.is_some() {
|
if constructorClass.is_not_null() || constructor.is_some() {
|
||||||
interface = do name.to_c_str().with_ref |s| {
|
interface = name.to_c_str().with_ref(|s| {
|
||||||
CreateInterfaceObject(cx, global, receiver, constructorClass,
|
CreateInterfaceObject(cx, global, receiver, constructorClass,
|
||||||
constructor, ctorNargs, proto,
|
constructor, ctorNargs, proto,
|
||||||
staticMethods, constants, s)
|
staticMethods, constants, s)
|
||||||
};
|
});
|
||||||
if interface.is_null() {
|
if interface.is_null() {
|
||||||
return ptr::null();
|
return ptr::null();
|
||||||
}
|
}
|
||||||
|
@ -432,7 +413,6 @@ pub fn CreateInterfaceObjects2(cx: *JSContext, global: *JSObject, receiver: *JSO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn CreateInterfaceObject(cx: *JSContext, global: *JSObject, receiver: *JSObject,
|
fn CreateInterfaceObject(cx: *JSContext, global: *JSObject, receiver: *JSObject,
|
||||||
constructorClass: *JSClass, constructorNative: Option<JSNative>,
|
constructorClass: *JSClass, constructorNative: Option<JSNative>,
|
||||||
ctorNargs: u32, proto: *JSObject,
|
ctorNargs: u32, proto: *JSObject,
|
||||||
|
@ -467,11 +447,11 @@ fn CreateInterfaceObject(cx: *JSContext, global: *JSObject, receiver: *JSObject,
|
||||||
}
|
}
|
||||||
|
|
||||||
if constructorClass.is_not_null() {
|
if constructorClass.is_not_null() {
|
||||||
let toString = do "toString".to_c_str().with_ref |s| {
|
let toString = "toString".to_c_str().with_ref(|s| {
|
||||||
DefineFunctionWithReserved(cx, constructor, s,
|
DefineFunctionWithReserved(cx, constructor, s,
|
||||||
InterfaceObjectToString,
|
InterfaceObjectToString,
|
||||||
0, 0)
|
0, 0)
|
||||||
};
|
});
|
||||||
if toString.is_null() {
|
if toString.is_null() {
|
||||||
return ptr::null();
|
return ptr::null();
|
||||||
}
|
}
|
||||||
|
@ -511,7 +491,6 @@ fn CreateInterfaceObject(cx: *JSContext, global: *JSObject, receiver: *JSObject,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn DefineConstants(cx: *JSContext, obj: *JSObject, constants: *ConstantSpec) -> bool {
|
fn DefineConstants(cx: *JSContext, obj: *JSObject, constants: *ConstantSpec) -> bool {
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
loop {
|
loop {
|
||||||
|
@ -541,21 +520,18 @@ fn DefineConstants(cx: *JSContext, obj: *JSObject, constants: *ConstantSpec) ->
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn DefineMethods(cx: *JSContext, obj: *JSObject, methods: *JSFunctionSpec) -> bool {
|
fn DefineMethods(cx: *JSContext, obj: *JSObject, methods: *JSFunctionSpec) -> bool {
|
||||||
unsafe {
|
unsafe {
|
||||||
JS_DefineFunctions(cx, obj, methods) != 0
|
JS_DefineFunctions(cx, obj, methods) != 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn DefineProperties(cx: *JSContext, obj: *JSObject, properties: *JSPropertySpec) -> bool {
|
fn DefineProperties(cx: *JSContext, obj: *JSObject, properties: *JSPropertySpec) -> bool {
|
||||||
unsafe {
|
unsafe {
|
||||||
JS_DefineProperties(cx, obj, properties) != 0
|
JS_DefineProperties(cx, obj, properties) != 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn CreateInterfacePrototypeObject(cx: *JSContext, global: *JSObject,
|
fn CreateInterfacePrototypeObject(cx: *JSContext, global: *JSObject,
|
||||||
parentProto: *JSObject, protoClass: *JSClass,
|
parentProto: *JSObject, protoClass: *JSClass,
|
||||||
methods: *JSFunctionSpec,
|
methods: *JSFunctionSpec,
|
||||||
|
@ -592,17 +568,16 @@ pub trait Traceable {
|
||||||
fn trace(&self, trc: *mut JSTracer);
|
fn trace(&self, trc: *mut JSTracer);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn trace_reflector(tracer: *mut JSTracer, description: &str, reflector: &Reflector) {
|
pub fn trace_reflector(tracer: *mut JSTracer, description: &str, reflector: &Reflector) {
|
||||||
unsafe {
|
unsafe {
|
||||||
do description.to_c_str().with_ref |name| {
|
description.to_c_str().with_ref(|name| {
|
||||||
(*tracer).debugPrinter = ptr::null();
|
(*tracer).debugPrinter = ptr::null();
|
||||||
(*tracer).debugPrintIndex = -1;
|
(*tracer).debugPrintIndex = -1;
|
||||||
(*tracer).debugPrintArg = name as *libc::c_void;
|
(*tracer).debugPrintArg = name as *libc::c_void;
|
||||||
debug!("tracing {:s}", description);
|
debug!("tracing {:s}", description);
|
||||||
JS_CallTracer(tracer as *JSTracer, reflector.get_jsobject(),
|
JS_CallTracer(tracer as *JSTracer, reflector.get_jsobject(),
|
||||||
JSTRACE_OBJECT as u32);
|
JSTRACE_OBJECT as u32);
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -610,13 +585,12 @@ pub fn trace_option<T: Reflectable>(tracer: *mut JSTracer, description: &str, op
|
||||||
option.map(|some| trace_reflector(tracer, description, some.reflector()));
|
option.map(|some| trace_reflector(tracer, description, some.reflector()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn initialize_global(global: *JSObject) {
|
pub fn initialize_global(global: *JSObject) {
|
||||||
let protoArray = @mut ([0 as *JSObject, ..PrototypeList::id::_ID_Count as uint]);
|
let protoArray = @mut ([0 as *JSObject, ..PrototypeList::id::_ID_Count as uint]);
|
||||||
unsafe {
|
unsafe {
|
||||||
//XXXjdm we should be storing the box pointer instead of the inner
|
//XXXjdm we should be storing the box pointer instead of the inner
|
||||||
let box = squirrel_away(protoArray);
|
let box_ = squirrel_away(protoArray);
|
||||||
let inner = ptr::to_unsafe_ptr(&(*box).data);
|
let inner = ptr::to_unsafe_ptr(&(*box_).data);
|
||||||
JS_SetReservedSlot(global,
|
JS_SetReservedSlot(global,
|
||||||
DOM_PROTOTYPE_SLOT,
|
DOM_PROTOTYPE_SLOT,
|
||||||
RUST_PRIVATE_TO_JSVAL(inner as *libc::c_void));
|
RUST_PRIVATE_TO_JSVAL(inner as *libc::c_void));
|
||||||
|
@ -668,7 +642,6 @@ impl Reflector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn GetReflector(cx: *JSContext, reflector: &Reflector,
|
pub fn GetReflector(cx: *JSContext, reflector: &Reflector,
|
||||||
vp: *mut JSVal) -> JSBool {
|
vp: *mut JSVal) -> JSBool {
|
||||||
let obj = reflector.get_jsobject();
|
let obj = reflector.get_jsobject();
|
||||||
|
@ -679,7 +652,6 @@ pub fn GetReflector(cx: *JSContext, reflector: &Reflector,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn GetPropertyOnPrototype(cx: *JSContext, proxy: *JSObject, id: jsid, found: *mut bool,
|
pub fn GetPropertyOnPrototype(cx: *JSContext, proxy: *JSObject, id: jsid, found: *mut bool,
|
||||||
vp: *JSVal) -> bool {
|
vp: *JSVal) -> bool {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -703,7 +675,6 @@ pub fn GetPropertyOnPrototype(cx: *JSContext, proxy: *JSObject, id: jsid, found:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn GetArrayIndexFromId(_cx: *JSContext, id: jsid) -> Option<u32> {
|
pub fn GetArrayIndexFromId(_cx: *JSContext, id: jsid) -> Option<u32> {
|
||||||
unsafe {
|
unsafe {
|
||||||
if RUST_JSID_IS_INT(id) != 0 {
|
if RUST_JSID_IS_INT(id) != 0 {
|
||||||
|
@ -727,7 +698,6 @@ pub fn GetArrayIndexFromId(_cx: *JSContext, id: jsid) -> Option<u32> {
|
||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn XrayResolveProperty(cx: *JSContext,
|
pub fn XrayResolveProperty(cx: *JSContext,
|
||||||
wrapper: *JSObject,
|
wrapper: *JSObject,
|
||||||
id: jsid,
|
id: jsid,
|
||||||
|
@ -754,7 +724,7 @@ pub fn XrayResolveProperty(cx: *JSContext,
|
||||||
|
|
||||||
RUST_SET_JITINFO(fun, attr.getter.info);
|
RUST_SET_JITINFO(fun, attr.getter.info);
|
||||||
let funobj = JS_GetFunctionObject(fun);
|
let funobj = JS_GetFunctionObject(fun);
|
||||||
(*desc).getter = Some(funobj as JSPropertyOp);
|
(*desc).getter = Some(cast::transmute(funobj));
|
||||||
(*desc).attrs |= JSPROP_GETTER;
|
(*desc).attrs |= JSPROP_GETTER;
|
||||||
if attr.setter.op.is_some() {
|
if attr.setter.op.is_some() {
|
||||||
let fun = JS_NewFunction(cx, attr.setter.op, 1, 0, global, ptr::null());
|
let fun = JS_NewFunction(cx, attr.setter.op, 1, 0, global, ptr::null());
|
||||||
|
@ -764,7 +734,7 @@ pub fn XrayResolveProperty(cx: *JSContext,
|
||||||
|
|
||||||
RUST_SET_JITINFO(fun, attr.setter.info);
|
RUST_SET_JITINFO(fun, attr.setter.info);
|
||||||
let funobj = JS_GetFunctionObject(fun);
|
let funobj = JS_GetFunctionObject(fun);
|
||||||
(*desc).setter = Some(funobj as JSStrictPropertyOp);
|
(*desc).setter = Some(cast::transmute(funobj));
|
||||||
(*desc).attrs |= JSPROP_SETTER;
|
(*desc).attrs |= JSPROP_SETTER;
|
||||||
} else {
|
} else {
|
||||||
(*desc).setter = None;
|
(*desc).setter = None;
|
||||||
|
@ -777,7 +747,6 @@ pub fn XrayResolveProperty(cx: *JSContext,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn InternJSString(cx: *JSContext, chars: *libc::c_char) -> Option<jsid> {
|
fn InternJSString(cx: *JSContext, chars: *libc::c_char) -> Option<jsid> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let s = JS_InternString(cx, chars);
|
let s = JS_InternString(cx, chars);
|
||||||
|
@ -824,7 +793,6 @@ pub struct EnumEntry {
|
||||||
length: uint
|
length: uint
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn FindEnumStringIndex(cx: *JSContext,
|
pub fn FindEnumStringIndex(cx: *JSContext,
|
||||||
v: JSVal,
|
v: JSVal,
|
||||||
values: &[EnumEntry]) -> Result<uint, ()> {
|
values: &[EnumEntry]) -> Result<uint, ()> {
|
||||||
|
@ -865,14 +833,12 @@ pub fn HasPropertyOnPrototype(cx: *JSContext, proxy: *JSObject, id: jsid) -> boo
|
||||||
return !GetPropertyOnPrototype(cx, proxy, id, &mut found, ptr::null()) || found;
|
return !GetPropertyOnPrototype(cx, proxy, id, &mut found, ptr::null()) || found;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn IsConvertibleToCallbackInterface(cx: *JSContext, obj: *JSObject) -> bool {
|
pub fn IsConvertibleToCallbackInterface(cx: *JSContext, obj: *JSObject) -> bool {
|
||||||
unsafe {
|
unsafe {
|
||||||
JS_ObjectIsDate(cx, obj) == 0 && JS_ObjectIsRegExp(cx, obj) == 0
|
JS_ObjectIsDate(cx, obj) == 0 && JS_ObjectIsRegExp(cx, obj) == 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn CreateDOMGlobal(cx: *JSContext, class: *JSClass) -> *JSObject {
|
pub fn CreateDOMGlobal(cx: *JSContext, class: *JSClass) -> *JSObject {
|
||||||
unsafe {
|
unsafe {
|
||||||
let obj = JS_NewGlobalObject(cx, class, ptr::null());
|
let obj = JS_NewGlobalObject(cx, class, ptr::null());
|
||||||
|
@ -886,7 +852,6 @@ pub fn CreateDOMGlobal(cx: *JSContext, class: *JSClass) -> *JSObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the global object of the realm that the given JS object was created in.
|
/// Returns the global object of the realm that the given JS object was created in.
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn global_object_for_js_object(obj: *JSObject) -> *Box<window::Window> {
|
fn global_object_for_js_object(obj: *JSObject) -> *Box<window::Window> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let global = GetGlobalForObjectCrossCompartment(obj);
|
let global = GetGlobalForObjectCrossCompartment(obj);
|
||||||
|
@ -900,7 +865,6 @@ fn global_object_for_js_object(obj: *JSObject) -> *Box<window::Window> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn cx_for_dom_reflector(obj: *JSObject) -> *JSContext {
|
fn cx_for_dom_reflector(obj: *JSObject) -> *JSContext {
|
||||||
unsafe {
|
unsafe {
|
||||||
let win = global_object_for_js_object(obj);
|
let win = global_object_for_js_object(obj);
|
||||||
|
@ -912,7 +876,6 @@ fn cx_for_dom_reflector(obj: *JSObject) -> *JSContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the global object of the realm that the given DOM object was created in.
|
/// Returns the global object of the realm that the given DOM object was created in.
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn global_object_for_dom_object<T: Reflectable>(obj: &mut T) -> *Box<window::Window> {
|
pub fn global_object_for_dom_object<T: Reflectable>(obj: &mut T) -> *Box<window::Window> {
|
||||||
global_object_for_js_object(obj.reflector().get_jsobject())
|
global_object_for_js_object(obj.reflector().get_jsobject())
|
||||||
}
|
}
|
||||||
|
@ -921,7 +884,6 @@ pub fn cx_for_dom_object<T: Reflectable>(obj: &mut T) -> *JSContext {
|
||||||
cx_for_dom_reflector(obj.reflector().get_jsobject())
|
cx_for_dom_reflector(obj.reflector().get_jsobject())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn throw_method_failed_with_details<T>(cx: *JSContext,
|
pub fn throw_method_failed_with_details<T>(cx: *JSContext,
|
||||||
result: Result<T, Error>,
|
result: Result<T, Error>,
|
||||||
interface: &'static str,
|
interface: &'static str,
|
||||||
|
@ -929,9 +891,9 @@ pub fn throw_method_failed_with_details<T>(cx: *JSContext,
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
assert!(unsafe { JS_IsExceptionPending(cx) } == 0);
|
assert!(unsafe { JS_IsExceptionPending(cx) } == 0);
|
||||||
let message = format!("Method failed: {}.{}", interface, member);
|
let message = format!("Method failed: {}.{}", interface, member);
|
||||||
do message.with_c_str |string| {
|
message.with_c_str(|string| {
|
||||||
unsafe { ReportError(cx, string) };
|
unsafe { ReportError(cx, string) };
|
||||||
}
|
});
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -979,7 +941,7 @@ pub fn xml_name_type(name: &str) -> XMLName {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut iter = name.iter();
|
let mut iter = name.chars();
|
||||||
let mut non_qname_colons = false;
|
let mut non_qname_colons = false;
|
||||||
let mut seen_colon = false;
|
let mut seen_colon = false;
|
||||||
match iter.next() {
|
match iter.next() {
|
||||||
|
@ -994,7 +956,7 @@ pub fn xml_name_type(name: &str) -> XMLName {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for c in name.iter() {
|
for c in name.chars() {
|
||||||
if !is_valid_continuation(c) {
|
if !is_valid_continuation(c) {
|
||||||
return InvalidXMLName;
|
return InvalidXMLName;
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,17 +55,12 @@ impl AbstractDocument {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn transmute<T, R>(&self, f: &fn(&T) -> R) -> R {
|
unsafe fn transmute<T, R>(&self, f: |&T| -> R) -> R {
|
||||||
let box: *Box<T> = cast::transmute(self.document);
|
let box_: *Box<T> = cast::transmute(self.document);
|
||||||
f(&(*box).data)
|
f(&(*box_).data)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn transmute_mut<T, R>(&self, f: &fn(&mut T) -> R) -> R {
|
pub fn with_html<R>(&self, callback: |&HTMLDocument| -> R) -> R {
|
||||||
let box: *mut Box<T> = cast::transmute(self.document);
|
|
||||||
f(&mut (*box).data)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_html<R>(&self, callback: &fn(&HTMLDocument) -> R) -> R {
|
|
||||||
match self.document().doctype {
|
match self.document().doctype {
|
||||||
HTML => unsafe { self.transmute(callback) },
|
HTML => unsafe { self.transmute(callback) },
|
||||||
_ => fail!("attempt to downcast a non-HTMLDocument to HTMLDocument")
|
_ => fail!("attempt to downcast a non-HTMLDocument to HTMLDocument")
|
||||||
|
@ -105,9 +100,9 @@ impl Document {
|
||||||
let document = reflect_dom_object(document, window, wrap_fn);
|
let document = reflect_dom_object(document, window, wrap_fn);
|
||||||
assert!(document.reflector().get_jsobject().is_not_null());
|
assert!(document.reflector().get_jsobject().is_not_null());
|
||||||
|
|
||||||
// This surrenders memory management of the document!
|
// JS object now owns the Document, so transmute_copy is needed
|
||||||
let abstract = AbstractDocument {
|
let abstract = AbstractDocument {
|
||||||
document: unsafe { cast::transmute(document) }
|
document: unsafe { cast::transmute_copy(&document) }
|
||||||
};
|
};
|
||||||
abstract.mut_document().node.set_owner_doc(abstract);
|
abstract.mut_document().node.set_owner_doc(abstract);
|
||||||
abstract
|
abstract
|
||||||
|
@ -165,10 +160,6 @@ impl Document {
|
||||||
self.node.child_elements().next()
|
self.node.child_elements().next()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_cx(&self) -> *JSContext {
|
|
||||||
self.window.get_cx()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn GetElementsByTagName(&self, tag: DOMString) -> @mut HTMLCollection {
|
pub fn GetElementsByTagName(&self, tag: DOMString) -> @mut HTMLCollection {
|
||||||
self.createHTMLCollection(|elem| eq_slice(elem.tag_name, tag))
|
self.createHTMLCollection(|elem| eq_slice(elem.tag_name, tag))
|
||||||
}
|
}
|
||||||
|
@ -238,9 +229,9 @@ impl Document {
|
||||||
}
|
}
|
||||||
for child in node.children() {
|
for child in node.children() {
|
||||||
if child.is_text() {
|
if child.is_text() {
|
||||||
do child.with_imm_text() |text| {
|
child.with_imm_text(|text| {
|
||||||
title = title + text.element.Data();
|
title = title + text.element.Data();
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -249,7 +240,7 @@ impl Document {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let v: ~[&str] = title.word_iter().collect();
|
let v: ~[&str] = title.words().collect();
|
||||||
title = v.connect(" ");
|
title = v.connect(" ");
|
||||||
title = title.trim().to_owned();
|
title = title.trim().to_owned();
|
||||||
title
|
title
|
||||||
|
@ -295,12 +286,12 @@ impl Document {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_html_element(&self) -> Option<AbstractNode> {
|
fn get_html_element(&self) -> Option<AbstractNode> {
|
||||||
do self.GetDocumentElement().filtered |root| {
|
self.GetDocumentElement().filtered(|root| {
|
||||||
match root.type_id() {
|
match root.type_id() {
|
||||||
ElementNodeTypeId(HTMLHtmlElementTypeId) => true,
|
ElementNodeTypeId(HTMLHtmlElementTypeId) => true,
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// http://www.whatwg.org/specs/web-apps/current-work/#dom-document-head
|
// http://www.whatwg.org/specs/web-apps/current-work/#dom-document-head
|
||||||
|
@ -316,13 +307,13 @@ impl Document {
|
||||||
match self.get_html_element() {
|
match self.get_html_element() {
|
||||||
None => None,
|
None => None,
|
||||||
Some(root) => {
|
Some(root) => {
|
||||||
do root.children().find |child| {
|
root.children().find(|child| {
|
||||||
match child.type_id() {
|
match child.type_id() {
|
||||||
ElementNodeTypeId(HTMLBodyElementTypeId) |
|
ElementNodeTypeId(HTMLBodyElementTypeId) |
|
||||||
ElementNodeTypeId(HTMLFrameSetElementTypeId) => true,
|
ElementNodeTypeId(HTMLFrameSetElementTypeId) => true,
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -365,18 +356,18 @@ impl Document {
|
||||||
elem.get_attr(Null, "name").is_some() && eq_slice(elem.get_attr(Null, "name").unwrap(), name))
|
elem.get_attr(Null, "name").is_some() && eq_slice(elem.get_attr(Null, "name").unwrap(), name))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn createHTMLCollection(&self, callback: &fn(elem: &Element) -> bool) -> @mut HTMLCollection {
|
pub fn createHTMLCollection(&self, callback: |elem: &Element| -> bool) -> @mut HTMLCollection {
|
||||||
let mut elements = ~[];
|
let mut elements = ~[];
|
||||||
match self.GetDocumentElement() {
|
match self.GetDocumentElement() {
|
||||||
None => {},
|
None => {},
|
||||||
Some(root) => {
|
Some(root) => {
|
||||||
for child in root.traverse_preorder() {
|
for child in root.traverse_preorder() {
|
||||||
if child.is_element() {
|
if child.is_element() {
|
||||||
do child.with_imm_element |elem| {
|
child.with_imm_element(|elem| {
|
||||||
if callback(elem) {
|
if callback(elem) {
|
||||||
elements.push(child);
|
elements.push(child);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -435,25 +426,24 @@ impl Document {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn foreach_ided_elements(root: &AbstractNode, callback: &fn(&DOMString, &AbstractNode)) {
|
fn foreach_ided_elements(root: &AbstractNode, callback: |&DOMString, &AbstractNode|) {
|
||||||
for node in root.traverse_preorder() {
|
for node in root.traverse_preorder() {
|
||||||
if !node.is_element() {
|
if !node.is_element() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
do node.with_imm_element |element| {
|
node.with_imm_element(|element| {
|
||||||
match element.get_attr(Null, "id") {
|
match element.get_attr(Null, "id") {
|
||||||
Some(id) => {
|
Some(id) => {
|
||||||
callback(&id.to_str(), &node);
|
callback(&id.to_str(), &node);
|
||||||
}
|
}
|
||||||
None => ()
|
None => ()
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Traceable for Document {
|
impl Traceable for Document {
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn trace(&self, tracer: *mut JSTracer) {
|
fn trace(&self, tracer: *mut JSTracer) {
|
||||||
self.node.trace(tracer);
|
self.node.trace(tracer);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,6 @@ use layout_interface::{ContentBoxesResponse, ContentChangedDocumentDamage};
|
||||||
use layout_interface::{MatchSelectorsDocumentDamage};
|
use layout_interface::{MatchSelectorsDocumentDamage};
|
||||||
use style;
|
use style;
|
||||||
|
|
||||||
use std::comm;
|
|
||||||
use std::str::eq;
|
use std::str::eq;
|
||||||
use std::ascii::StrAsciiExt;
|
use std::ascii::StrAsciiExt;
|
||||||
|
|
||||||
|
@ -123,7 +122,7 @@ pub enum ElementTypeId {
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
impl<'self> Element {
|
impl Element {
|
||||||
pub fn new_inherited(type_id: ElementTypeId, tag_name: ~str, namespace: Namespace, document: AbstractDocument) -> Element {
|
pub fn new_inherited(type_id: ElementTypeId, tag_name: ~str, namespace: Namespace, document: AbstractDocument) -> Element {
|
||||||
Element {
|
Element {
|
||||||
node: Node::new_inherited(ElementNodeTypeId(type_id), document),
|
node: Node::new_inherited(ElementNodeTypeId(type_id), document),
|
||||||
|
@ -175,7 +174,7 @@ impl<'self> Element {
|
||||||
//FIXME: Throw for XML-invalid names
|
//FIXME: Throw for XML-invalid names
|
||||||
//FIXME: Throw for XMLNS-invalid names
|
//FIXME: Throw for XMLNS-invalid names
|
||||||
let (prefix, local_name) = if name.contains(":") {
|
let (prefix, local_name) = if name.contains(":") {
|
||||||
let parts: ~[&str] = name.splitn_iter(':', 1).collect();
|
let parts: ~[&str] = name.splitn(':', 1).collect();
|
||||||
(Some(parts[0].to_owned()), parts[1].to_owned())
|
(Some(parts[0].to_owned()), parts[1].to_owned())
|
||||||
} else {
|
} else {
|
||||||
(None, name.clone())
|
(None, name.clone())
|
||||||
|
@ -238,14 +237,14 @@ impl<'self> Element {
|
||||||
// This hardcoding is awful.
|
// This hardcoding is awful.
|
||||||
match abstract_self.type_id() {
|
match abstract_self.type_id() {
|
||||||
ElementNodeTypeId(HTMLImageElementTypeId) => {
|
ElementNodeTypeId(HTMLImageElementTypeId) => {
|
||||||
do abstract_self.with_mut_image_element |image| {
|
abstract_self.with_mut_image_element(|image| {
|
||||||
image.AfterSetAttr(local_name.clone(), value.clone());
|
image.AfterSetAttr(local_name.clone(), value.clone());
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
ElementNodeTypeId(HTMLIframeElementTypeId) => {
|
ElementNodeTypeId(HTMLIframeElementTypeId) => {
|
||||||
do abstract_self.with_mut_iframe_element |iframe| {
|
abstract_self.with_mut_iframe_element(|iframe| {
|
||||||
iframe.AfterSetAttr(local_name.clone(), value.clone());
|
iframe.AfterSetAttr(local_name.clone(), value.clone());
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
|
@ -390,18 +389,18 @@ impl Element {
|
||||||
let win = self.node.owner_doc().document().window;
|
let win = self.node.owner_doc().document().window;
|
||||||
let node = abstract_self;
|
let node = abstract_self;
|
||||||
assert!(node.is_element());
|
assert!(node.is_element());
|
||||||
let (port, chan) = comm::stream();
|
let (port, chan) = Chan::new();
|
||||||
let rects =
|
let rects =
|
||||||
match win.page.query_layout(ContentBoxesQuery(node, chan), port) {
|
match win.page.query_layout(ContentBoxesQuery(node, chan), port) {
|
||||||
ContentBoxesResponse(rects) => {
|
ContentBoxesResponse(rects) => {
|
||||||
do rects.map |r| {
|
rects.map(|r| {
|
||||||
ClientRect::new(
|
ClientRect::new(
|
||||||
win,
|
win,
|
||||||
r.origin.y,
|
r.origin.y,
|
||||||
r.origin.y + r.size.height,
|
r.origin.y + r.size.height,
|
||||||
r.origin.x,
|
r.origin.x,
|
||||||
r.origin.x + r.size.width)
|
r.origin.x + r.size.width)
|
||||||
}
|
})
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -412,7 +411,7 @@ impl Element {
|
||||||
let win = self.node.owner_doc().document().window;
|
let win = self.node.owner_doc().document().window;
|
||||||
let node = abstract_self;
|
let node = abstract_self;
|
||||||
assert!(node.is_element());
|
assert!(node.is_element());
|
||||||
let (port, chan) = comm::stream();
|
let (port, chan) = Chan::new();
|
||||||
match win.page.query_layout(ContentBoxQuery(node, chan), port) {
|
match win.page.query_layout(ContentBoxQuery(node, chan), port) {
|
||||||
ContentBoxResponse(rect) => {
|
ContentBoxResponse(rect) => {
|
||||||
ClientRect::new(
|
ClientRect::new(
|
||||||
|
|
|
@ -35,9 +35,9 @@ pub enum EventPhase {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractEvent {
|
impl AbstractEvent {
|
||||||
pub fn from_box(box: *mut Box<Event>) -> AbstractEvent {
|
pub fn from_box(box_: *mut Box<Event>) -> AbstractEvent {
|
||||||
AbstractEvent {
|
AbstractEvent {
|
||||||
event: box
|
event: box_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,15 +47,15 @@ impl AbstractEvent {
|
||||||
|
|
||||||
fn transmute<'a, T>(&'a self) -> &'a T {
|
fn transmute<'a, T>(&'a self) -> &'a T {
|
||||||
unsafe {
|
unsafe {
|
||||||
let box: *Box<T> = self.event as *Box<T>;
|
let box_: *Box<T> = self.event as *Box<T>;
|
||||||
&(*box).data
|
&(*box_).data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transmute_mut<'a, T>(&'a self) -> &'a mut T {
|
fn transmute_mut<'a, T>(&'a self) -> &'a mut T {
|
||||||
unsafe {
|
unsafe {
|
||||||
let box: *mut Box<T> = self.event as *mut Box<T>;
|
let box_: *mut Box<T> = self.event as *mut Box<T>;
|
||||||
&mut (*box).data
|
&mut (*box_).data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,9 +44,9 @@ pub struct AbstractEventTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractEventTarget {
|
impl AbstractEventTarget {
|
||||||
pub fn from_box<T>(box: *mut Box<T>) -> AbstractEventTarget {
|
pub fn from_box<T>(box_: *mut Box<T>) -> AbstractEventTarget {
|
||||||
AbstractEventTarget {
|
AbstractEventTarget {
|
||||||
eventtarget: box as *mut Box<EventTarget>
|
eventtarget: box_ as *mut Box<EventTarget>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,15 +86,15 @@ impl AbstractEventTarget {
|
||||||
|
|
||||||
fn transmute<'a, T>(&'a self) -> &'a T {
|
fn transmute<'a, T>(&'a self) -> &'a T {
|
||||||
unsafe {
|
unsafe {
|
||||||
let box: *Box<T> = self.eventtarget as *Box<T>;
|
let box_: *Box<T> = self.eventtarget as *Box<T>;
|
||||||
&(*box).data
|
&(*box_).data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transmute_mut<'a, T>(&'a mut self) -> &'a mut T {
|
fn transmute_mut<'a, T>(&'a mut self) -> &'a mut T {
|
||||||
unsafe {
|
unsafe {
|
||||||
let box: *mut Box<T> = self.eventtarget as *mut Box<T>;
|
let box_: *mut Box<T> = self.eventtarget as *mut Box<T>;
|
||||||
&mut (*box).data
|
&mut (*box_).data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,17 +127,17 @@ impl EventTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_listeners(&self, type_: &str) -> Option<~[EventListener]> {
|
pub fn get_listeners(&self, type_: &str) -> Option<~[EventListener]> {
|
||||||
do self.handlers.find_equiv(&type_).map |listeners| {
|
self.handlers.find_equiv(&type_).map(|listeners| {
|
||||||
listeners.iter().map(|entry| entry.listener).collect()
|
listeners.iter().map(|entry| entry.listener).collect()
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_listeners_for(&self, type_: &str, desired_phase: ListenerPhase)
|
pub fn get_listeners_for(&self, type_: &str, desired_phase: ListenerPhase)
|
||||||
-> Option<~[EventListener]> {
|
-> Option<~[EventListener]> {
|
||||||
do self.handlers.find_equiv(&type_).map |listeners| {
|
self.handlers.find_equiv(&type_).map(|listeners| {
|
||||||
let filtered = listeners.iter().filter(|entry| entry.phase == desired_phase);
|
let filtered = listeners.iter().filter(|entry| entry.phase == desired_phase);
|
||||||
filtered.map(|entry| entry.listener).collect()
|
filtered.map(|entry| entry.listener).collect()
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn AddEventListener(&mut self,
|
pub fn AddEventListener(&mut self,
|
||||||
|
|
|
@ -95,7 +95,7 @@ impl HTMLIFrameElement {
|
||||||
pub fn AfterSetAttr(&mut self, name: DOMString, value: DOMString) {
|
pub fn AfterSetAttr(&mut self, name: DOMString, value: DOMString) {
|
||||||
if "sandbox" == name {
|
if "sandbox" == name {
|
||||||
let mut modes = AllowNothing as u8;
|
let mut modes = AllowNothing as u8;
|
||||||
for word in value.split_iter(' ') {
|
for word in value.split(' ') {
|
||||||
// FIXME: Workaround for https://github.com/mozilla/rust/issues/10683
|
// FIXME: Workaround for https://github.com/mozilla/rust/issues/10683
|
||||||
let word_lower = word.to_ascii_lower();
|
let word_lower = word.to_ascii_lower();
|
||||||
modes |= match word_lower.as_slice() {
|
modes |= match word_lower.as_slice() {
|
||||||
|
|
|
@ -112,7 +112,7 @@ impl HTMLImageElement {
|
||||||
pub fn Width(&self, abstract_self: AbstractNode) -> u32 {
|
pub fn Width(&self, abstract_self: AbstractNode) -> u32 {
|
||||||
let node = &self.htmlelement.element.node;
|
let node = &self.htmlelement.element.node;
|
||||||
let page = node.owner_doc().document().window.page;
|
let page = node.owner_doc().document().window.page;
|
||||||
let (port, chan) = stream();
|
let (port, chan) = Chan::new();
|
||||||
match page.query_layout(ContentBoxQuery(abstract_self, chan), port) {
|
match page.query_layout(ContentBoxQuery(abstract_self, chan), port) {
|
||||||
ContentBoxResponse(rect) => {
|
ContentBoxResponse(rect) => {
|
||||||
to_px(rect.size.width) as u32
|
to_px(rect.size.width) as u32
|
||||||
|
@ -129,7 +129,7 @@ impl HTMLImageElement {
|
||||||
pub fn Height(&self, abstract_self: AbstractNode) -> u32 {
|
pub fn Height(&self, abstract_self: AbstractNode) -> u32 {
|
||||||
let node = &self.htmlelement.element.node;
|
let node = &self.htmlelement.element.node;
|
||||||
let page = node.owner_doc().document().window.page;
|
let page = node.owner_doc().document().window.page;
|
||||||
let (port, chan) = stream();
|
let (port, chan) = Chan::new();
|
||||||
match page.query_layout(ContentBoxQuery(abstract_self, chan), port) {
|
match page.query_layout(ContentBoxQuery(abstract_self, chan), port) {
|
||||||
ContentBoxResponse(rect) => {
|
ContentBoxResponse(rect) => {
|
||||||
to_px(rect.size.height) as u32
|
to_px(rect.size.height) as u32
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
|
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
|
||||||
use dom::bindings::utils::{DOMString, null_str_as_empty};
|
use dom::bindings::utils::{DOMString, null_str_as_empty};
|
||||||
use dom::bindings::utils::{ErrorResult, Fallible, NotFound, HierarchyRequest};
|
use dom::bindings::utils::{ErrorResult, Fallible, NotFound, HierarchyRequest};
|
||||||
use dom::bindings::utils;
|
|
||||||
use dom::characterdata::CharacterData;
|
use dom::characterdata::CharacterData;
|
||||||
use dom::document::{AbstractDocument, DocumentTypeId};
|
use dom::document::{AbstractDocument, DocumentTypeId};
|
||||||
use dom::documenttype::DocumentType;
|
use dom::documenttype::DocumentType;
|
||||||
|
@ -20,12 +19,15 @@ use dom::nodelist::{NodeList};
|
||||||
use dom::text::Text;
|
use dom::text::Text;
|
||||||
|
|
||||||
use js::jsapi::{JSObject, JSContext};
|
use js::jsapi::{JSObject, JSContext};
|
||||||
use servo_util::slot::{MutSlotRef, Slot, SlotRef};
|
|
||||||
use std::cast::transmute;
|
use layout_interface::{LayoutChan, ReapLayoutDataMsg};
|
||||||
|
|
||||||
use std::cast;
|
use std::cast;
|
||||||
use std::unstable::raw::Box;
|
use std::cast::transmute;
|
||||||
use std::util;
|
use std::cell::{RefCell, Ref, RefMut};
|
||||||
use std::iter::Filter;
|
use std::iter::Filter;
|
||||||
|
use std::util;
|
||||||
|
use std::unstable::raw::Box;
|
||||||
|
|
||||||
//
|
//
|
||||||
// The basic Node structure
|
// The basic Node structure
|
||||||
|
@ -37,7 +39,7 @@ use std::iter::Filter;
|
||||||
/// FIXME: This should be replaced with a trait once they can inherit from structs.
|
/// FIXME: This should be replaced with a trait once they can inherit from structs.
|
||||||
#[deriving(Eq)]
|
#[deriving(Eq)]
|
||||||
pub struct AbstractNode {
|
pub struct AbstractNode {
|
||||||
priv obj: *mut Box<Node>,
|
priv obj: *mut (),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An HTML node.
|
/// An HTML node.
|
||||||
|
@ -109,30 +111,43 @@ impl Drop for Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Encapsulates the abstract layout data.
|
/// Encapsulates the abstract layout data.
|
||||||
|
pub struct LayoutData {
|
||||||
|
priv chan: Option<LayoutChan>,
|
||||||
|
priv data: *(),
|
||||||
|
}
|
||||||
|
|
||||||
pub struct LayoutDataRef {
|
pub struct LayoutDataRef {
|
||||||
priv data: Slot<Option<*()>>,
|
data_cell: RefCell<Option<LayoutData>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LayoutDataRef {
|
impl LayoutDataRef {
|
||||||
#[inline]
|
pub fn new() -> LayoutDataRef {
|
||||||
pub fn init() -> LayoutDataRef {
|
|
||||||
LayoutDataRef {
|
LayoutDataRef {
|
||||||
data: Slot::init(None),
|
data_cell: RefCell::new(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new piece of layout data from a value.
|
|
||||||
#[inline]
|
|
||||||
pub unsafe fn from_data<T>(data: ~T) -> LayoutDataRef {
|
pub unsafe fn from_data<T>(data: ~T) -> LayoutDataRef {
|
||||||
LayoutDataRef {
|
LayoutDataRef {
|
||||||
data: Slot::init(Some(cast::transmute(data))),
|
data_cell: RefCell::new(Some(cast::transmute(data))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if this layout data is present or false otherwise.
|
/// Returns true if there is layout data present.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_present(&self) -> bool {
|
pub fn is_present(&self) -> bool {
|
||||||
self.data.get().is_some()
|
let data_ref = self.data_cell.borrow();
|
||||||
|
data_ref.get().is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Take the chan out of the layout data if it is present.
|
||||||
|
pub fn take_chan(&self) -> Option<LayoutChan> {
|
||||||
|
let mut data_ref = self.data_cell.borrow_mut();
|
||||||
|
let layout_data = data_ref.get();
|
||||||
|
match *layout_data {
|
||||||
|
None => None,
|
||||||
|
Some(..) => Some(layout_data.get_mut_ref().chan.take_unwrap()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Borrows the layout data immutably, *asserting that there are no mutators*. Bad things will
|
/// Borrows the layout data immutably, *asserting that there are no mutators*. Bad things will
|
||||||
|
@ -141,17 +156,15 @@ impl LayoutDataRef {
|
||||||
///
|
///
|
||||||
/// FIXME(pcwalton): Enforce this invariant via the type system. Will require traversal
|
/// FIXME(pcwalton): Enforce this invariant via the type system. Will require traversal
|
||||||
/// functions to be trusted, but c'est la vie.
|
/// functions to be trusted, but c'est la vie.
|
||||||
#[inline]
|
// #[inline]
|
||||||
pub unsafe fn borrow_unchecked<'a>(&'a self) -> &'a () {
|
// pub unsafe fn borrow_unchecked<'a>(&'a self) -> &'a () {
|
||||||
cast::transmute(self.data.borrow_unchecked())
|
// self.data.borrow_unchecked()
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// Borrows the layout data immutably. This function is *not* thread-safe.
|
/// Borrows the layout data immutably. This function is *not* thread-safe.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn borrow<'a>(&'a self) -> SlotRef<'a,()> {
|
pub fn borrow<'a>(&'a self) -> Ref<'a,Option<LayoutData>> {
|
||||||
unsafe {
|
self.data_cell.borrow()
|
||||||
cast::transmute(self.data.borrow())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Borrows the layout data mutably. This function is *not* thread-safe.
|
/// Borrows the layout data mutably. This function is *not* thread-safe.
|
||||||
|
@ -160,10 +173,8 @@ impl LayoutDataRef {
|
||||||
/// prevent CSS selector matching from mutably accessing nodes it's not supposed to and racing
|
/// prevent CSS selector matching from mutably accessing nodes it's not supposed to and racing
|
||||||
/// on it. This has already resulted in one bug!
|
/// on it. This has already resulted in one bug!
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn mutate<'a>(&'a self) -> MutSlotRef<'a,()> {
|
pub fn borrow_mut<'a>(&'a self) -> RefMut<'a,Option<LayoutData>> {
|
||||||
unsafe {
|
self.data_cell.borrow_mut()
|
||||||
cast::transmute(self.data.mutate())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,13 +204,15 @@ impl Clone for AbstractNode {
|
||||||
impl AbstractNode {
|
impl AbstractNode {
|
||||||
pub fn node<'a>(&'a self) -> &'a Node {
|
pub fn node<'a>(&'a self) -> &'a Node {
|
||||||
unsafe {
|
unsafe {
|
||||||
&(*self.obj).data
|
let box_: *mut Box<Node> = cast::transmute(self.obj);
|
||||||
|
&(*box_).data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mut_node<'a>(&'a self) -> &'a mut Node {
|
pub fn mut_node<'a>(&'a self) -> &'a mut Node {
|
||||||
unsafe {
|
unsafe {
|
||||||
&mut (*self.obj).data
|
let box_: *mut Box<Node> = cast::transmute(self.obj);
|
||||||
|
&mut (*box_).data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,20 +230,20 @@ impl AbstractNode {
|
||||||
|
|
||||||
pub fn is_element(&self) -> bool {
|
pub fn is_element(&self) -> bool {
|
||||||
match self.type_id() {
|
match self.type_id() {
|
||||||
ElementNodeTypeId(*) => true,
|
ElementNodeTypeId(..) => true,
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_document(&self) -> bool {
|
pub fn is_document(&self) -> bool {
|
||||||
match self.type_id() {
|
match self.type_id() {
|
||||||
DocumentNodeTypeId(*) => true,
|
DocumentNodeTypeId(..) => true,
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> AbstractNode {
|
impl<'a> AbstractNode {
|
||||||
// Unsafe accessors
|
// Unsafe accessors
|
||||||
|
|
||||||
pub unsafe fn as_cacheable_wrapper(&self) -> @mut Reflectable {
|
pub unsafe fn as_cacheable_wrapper(&self) -> @mut Reflectable {
|
||||||
|
@ -252,7 +265,7 @@ impl<'self> AbstractNode {
|
||||||
/// FIXME(pcwalton): Mark unsafe?
|
/// FIXME(pcwalton): Mark unsafe?
|
||||||
pub fn from_box<T>(ptr: *mut Box<T>) -> AbstractNode {
|
pub fn from_box<T>(ptr: *mut Box<T>) -> AbstractNode {
|
||||||
AbstractNode {
|
AbstractNode {
|
||||||
obj: ptr as *mut Box<Node>
|
obj: ptr as *mut ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,27 +304,27 @@ impl<'self> AbstractNode {
|
||||||
// Downcasting borrows
|
// Downcasting borrows
|
||||||
//
|
//
|
||||||
|
|
||||||
pub fn transmute<T, R>(self, f: &fn(&T) -> R) -> R {
|
pub fn transmute<'a, T, R>(self, f: |&'a T| -> R) -> R {
|
||||||
unsafe {
|
unsafe {
|
||||||
let node_box: *mut Box<Node> = transmute(self.obj);
|
let node_box: *mut Box<Node> = transmute(self.obj);
|
||||||
let node = &mut (*node_box).data;
|
let node = &mut (*node_box).data;
|
||||||
let old = node.abstract;
|
let old = node.abstract;
|
||||||
node.abstract = Some(self);
|
node.abstract = Some(self);
|
||||||
let box: *Box<T> = transmute(self.obj);
|
let box_: *Box<T> = transmute(self.obj);
|
||||||
let rv = f(&(*box).data);
|
let rv = f(&(*box_).data);
|
||||||
node.abstract = old;
|
node.abstract = old;
|
||||||
rv
|
rv
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn transmute_mut<T, R>(self, f: &fn(&mut T) -> R) -> R {
|
pub fn transmute_mut<T, R>(self, f: |&mut T| -> R) -> R {
|
||||||
unsafe {
|
unsafe {
|
||||||
let node_box: *mut Box<Node> = transmute(self.obj);
|
let node_box: *mut Box<Node> = transmute(self.obj);
|
||||||
let node = &mut (*node_box).data;
|
let node = &mut (*node_box).data;
|
||||||
let old = node.abstract;
|
let old = node.abstract;
|
||||||
node.abstract = Some(self);
|
node.abstract = Some(self);
|
||||||
let box: *Box<T> = transmute(self.obj);
|
let box_: *Box<T> = transmute(self.obj);
|
||||||
let rv = f(cast::transmute(&(*box).data));
|
let rv = f(cast::transmute(&(*box_).data));
|
||||||
node.abstract = old;
|
node.abstract = old;
|
||||||
rv
|
rv
|
||||||
}
|
}
|
||||||
|
@ -323,14 +336,14 @@ impl<'self> AbstractNode {
|
||||||
self.is_text() || self.is_comment()
|
self.is_text() || self.is_comment()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_imm_characterdata<R>(self, f: &fn(&CharacterData) -> R) -> R {
|
pub fn with_imm_characterdata<R>(self, f: |&CharacterData| -> R) -> R {
|
||||||
if !self.is_characterdata() {
|
if !self.is_characterdata() {
|
||||||
fail!(~"node is not characterdata");
|
fail!(~"node is not characterdata");
|
||||||
}
|
}
|
||||||
self.transmute(f)
|
self.transmute(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_mut_characterdata<R>(self, f: &fn(&mut CharacterData) -> R) -> R {
|
pub fn with_mut_characterdata<R>(self, f: |&mut CharacterData| -> R) -> R {
|
||||||
if !self.is_characterdata() {
|
if !self.is_characterdata() {
|
||||||
fail!(~"node is not characterdata");
|
fail!(~"node is not characterdata");
|
||||||
}
|
}
|
||||||
|
@ -341,14 +354,14 @@ impl<'self> AbstractNode {
|
||||||
self.type_id() == DoctypeNodeTypeId
|
self.type_id() == DoctypeNodeTypeId
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_imm_doctype<R>(self, f: &fn(&DocumentType) -> R) -> R {
|
pub fn with_imm_doctype<R>(self, f: |&DocumentType| -> R) -> R {
|
||||||
if !self.is_doctype() {
|
if !self.is_doctype() {
|
||||||
fail!(~"node is not doctype");
|
fail!(~"node is not doctype");
|
||||||
}
|
}
|
||||||
self.transmute(f)
|
self.transmute(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_mut_doctype<R>(self, f: &fn(&mut DocumentType) -> R) -> R {
|
pub fn with_mut_doctype<R>(self, f: |&mut DocumentType| -> R) -> R {
|
||||||
if !self.is_doctype() {
|
if !self.is_doctype() {
|
||||||
fail!(~"node is not doctype");
|
fail!(~"node is not doctype");
|
||||||
}
|
}
|
||||||
|
@ -375,14 +388,14 @@ impl<'self> AbstractNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_imm_text<R>(self, f: &fn(&Text) -> R) -> R {
|
pub fn with_imm_text<R>(self, f: |&Text| -> R) -> R {
|
||||||
if !self.is_text() {
|
if !self.is_text() {
|
||||||
fail!(~"node is not text");
|
fail!(~"node is not text");
|
||||||
}
|
}
|
||||||
self.transmute(f)
|
self.transmute(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_mut_text<R>(self, f: &fn(&mut Text) -> R) -> R {
|
pub fn with_mut_text<R>(self, f: |&mut Text| -> R) -> R {
|
||||||
if !self.is_text() {
|
if !self.is_text() {
|
||||||
fail!(~"node is not text");
|
fail!(~"node is not text");
|
||||||
}
|
}
|
||||||
|
@ -390,7 +403,7 @@ impl<'self> AbstractNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: This should be doing dynamic borrow checking for safety.
|
// FIXME: This should be doing dynamic borrow checking for safety.
|
||||||
pub fn with_imm_element<R>(self, f: &fn(&Element) -> R) -> R {
|
pub fn with_imm_element<R>(self, f: |&Element| -> R) -> R {
|
||||||
if !self.is_element() {
|
if !self.is_element() {
|
||||||
fail!(~"node is not an element");
|
fail!(~"node is not an element");
|
||||||
}
|
}
|
||||||
|
@ -398,7 +411,7 @@ impl<'self> AbstractNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: This should be doing dynamic borrow checking for safety.
|
// FIXME: This should be doing dynamic borrow checking for safety.
|
||||||
pub fn as_mut_element<R>(self, f: &fn(&mut Element) -> R) -> R {
|
pub fn as_mut_element<R>(self, f: |&mut Element| -> R) -> R {
|
||||||
if !self.is_element() {
|
if !self.is_element() {
|
||||||
fail!(~"node is not an element");
|
fail!(~"node is not an element");
|
||||||
}
|
}
|
||||||
|
@ -413,7 +426,7 @@ impl<'self> AbstractNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_mut_image_element<R>(self, f: &fn(&mut HTMLImageElement) -> R) -> R {
|
pub fn with_mut_image_element<R>(self, f: |&mut HTMLImageElement| -> R) -> R {
|
||||||
if !self.is_image_element() {
|
if !self.is_image_element() {
|
||||||
fail!(~"node is not an image element");
|
fail!(~"node is not an image element");
|
||||||
}
|
}
|
||||||
|
@ -424,7 +437,7 @@ impl<'self> AbstractNode {
|
||||||
self.type_id() == ElementNodeTypeId(HTMLIframeElementTypeId)
|
self.type_id() == ElementNodeTypeId(HTMLIframeElementTypeId)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_mut_iframe_element<R>(self, f: &fn(&mut HTMLIFrameElement) -> R) -> R {
|
pub fn with_mut_iframe_element<R>(self, f: |&mut HTMLIFrameElement| -> R) -> R {
|
||||||
if !self.is_iframe_element() {
|
if !self.is_iframe_element() {
|
||||||
fail!(~"node is not an iframe element");
|
fail!(~"node is not an iframe element");
|
||||||
}
|
}
|
||||||
|
@ -440,12 +453,12 @@ impl<'self> AbstractNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn raw_object(self) -> *mut Box<Node> {
|
pub unsafe fn raw_object(self) -> *mut Box<Node> {
|
||||||
self.obj
|
cast::transmute(self.obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_raw(raw: *mut Box<Node>) -> AbstractNode {
|
pub fn from_raw(raw: *mut Box<Node>) -> AbstractNode {
|
||||||
AbstractNode {
|
AbstractNode {
|
||||||
obj: raw
|
obj: raw as *mut ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -479,10 +492,6 @@ impl<'self> AbstractNode {
|
||||||
// Convenience accessors
|
// Convenience accessors
|
||||||
//
|
//
|
||||||
|
|
||||||
fn is_leaf(&self) -> bool {
|
|
||||||
self.first_child().is_none()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn children(&self) -> AbstractNodeChildrenIterator {
|
pub fn children(&self) -> AbstractNodeChildrenIterator {
|
||||||
self.node().children()
|
self.node().children()
|
||||||
}
|
}
|
||||||
|
@ -610,35 +619,6 @@ impl AbstractNode {
|
||||||
child_node.set_next_sibling(None);
|
child_node.set_next_sibling(None);
|
||||||
child_node.set_parent_node(None);
|
child_node.set_parent_node(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Low-level pointer stitching wrappers
|
|
||||||
//
|
|
||||||
|
|
||||||
fn set_parent_node(&self, new_parent_node: Option<AbstractNode>) {
|
|
||||||
let node = self.mut_node();
|
|
||||||
node.set_parent_node(new_parent_node)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_first_child(&self, new_first_child: Option<AbstractNode>) {
|
|
||||||
let node = self.mut_node();
|
|
||||||
node.set_first_child(new_first_child)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_last_child(&self, new_last_child: Option<AbstractNode>) {
|
|
||||||
let node = self.mut_node();
|
|
||||||
node.set_last_child(new_last_child)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_prev_sibling(&self, new_prev_sibling: Option<AbstractNode>) {
|
|
||||||
let node = self.mut_node();
|
|
||||||
node.set_prev_sibling(new_prev_sibling)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_next_sibling(&self, new_next_sibling: Option<AbstractNode>) {
|
|
||||||
let node = self.mut_node();
|
|
||||||
node.set_next_sibling(new_next_sibling)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -652,9 +632,9 @@ pub struct AbstractNodeChildrenIterator {
|
||||||
impl Iterator<AbstractNode> for AbstractNodeChildrenIterator {
|
impl Iterator<AbstractNode> for AbstractNodeChildrenIterator {
|
||||||
fn next(&mut self) -> Option<AbstractNode> {
|
fn next(&mut self) -> Option<AbstractNode> {
|
||||||
let node = self.current_node;
|
let node = self.current_node;
|
||||||
self.current_node = do self.current_node.and_then |node| {
|
self.current_node = self.current_node.and_then(|node| {
|
||||||
node.next_sibling()
|
node.next_sibling()
|
||||||
};
|
});
|
||||||
node
|
node
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -766,9 +746,9 @@ impl Node {
|
||||||
assert!(node.reflector().get_jsobject().is_null());
|
assert!(node.reflector().get_jsobject().is_null());
|
||||||
let node = reflect_dom_object(node, document.document().window, wrap_fn);
|
let node = reflect_dom_object(node, document.document().window, wrap_fn);
|
||||||
assert!(node.reflector().get_jsobject().is_not_null());
|
assert!(node.reflector().get_jsobject().is_not_null());
|
||||||
// This surrenders memory management of the node!
|
// JS owns the node now, so transmute_copy to not increase the refcount
|
||||||
AbstractNode {
|
AbstractNode {
|
||||||
obj: unsafe { transmute(node) },
|
obj: unsafe { cast::transmute_copy(&node) },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -798,16 +778,19 @@ impl Node {
|
||||||
|
|
||||||
flags: NodeFlags::new(type_id),
|
flags: NodeFlags::new(type_id),
|
||||||
|
|
||||||
layout_data: LayoutDataRef::init(),
|
layout_data: LayoutDataRef::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sends layout data, if any, back to the script task to be destroyed.
|
/// Sends layout data, if any, back to the script task to be destroyed.
|
||||||
pub unsafe fn reap_layout_data(&mut self) {
|
pub unsafe fn reap_layout_data(&mut self) {
|
||||||
if self.layout_data.is_present() {
|
if self.layout_data.is_present() {
|
||||||
let layout_data = util::replace(&mut self.layout_data, LayoutDataRef::init());
|
let layout_data = util::replace(&mut self.layout_data, LayoutDataRef::new());
|
||||||
let js_window = utils::global_object_for_dom_object(self);
|
let layout_chan = layout_data.take_chan();
|
||||||
(*js_window).data.page.reap_dead_layout_data(layout_data)
|
match layout_chan {
|
||||||
|
None => {}
|
||||||
|
Some(chan) => chan.send(ReapLayoutDataMsg(layout_data)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -825,17 +808,17 @@ impl Node {
|
||||||
|
|
||||||
pub fn NodeName(&self, abstract_self: AbstractNode) -> DOMString {
|
pub fn NodeName(&self, abstract_self: AbstractNode) -> DOMString {
|
||||||
match self.type_id {
|
match self.type_id {
|
||||||
ElementNodeTypeId(*) => {
|
ElementNodeTypeId(..) => {
|
||||||
do abstract_self.with_imm_element |element| {
|
abstract_self.with_imm_element(|element| {
|
||||||
element.TagName()
|
element.TagName()
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
CommentNodeTypeId => ~"#comment",
|
CommentNodeTypeId => ~"#comment",
|
||||||
TextNodeTypeId => ~"#text",
|
TextNodeTypeId => ~"#text",
|
||||||
DoctypeNodeTypeId => {
|
DoctypeNodeTypeId => {
|
||||||
do abstract_self.with_imm_doctype |doctype| {
|
abstract_self.with_imm_doctype(|doctype| {
|
||||||
doctype.name.clone()
|
doctype.name.clone()
|
||||||
}
|
})
|
||||||
},
|
},
|
||||||
DocumentFragmentNodeTypeId => ~"#document-fragment",
|
DocumentFragmentNodeTypeId => ~"#document-fragment",
|
||||||
DocumentNodeTypeId(_) => ~"#document"
|
DocumentNodeTypeId(_) => ~"#document"
|
||||||
|
@ -848,7 +831,7 @@ impl Node {
|
||||||
|
|
||||||
pub fn GetOwnerDocument(&self) -> Option<AbstractDocument> {
|
pub fn GetOwnerDocument(&self) -> Option<AbstractDocument> {
|
||||||
match self.type_id {
|
match self.type_id {
|
||||||
ElementNodeTypeId(*) |
|
ElementNodeTypeId(..) |
|
||||||
CommentNodeTypeId |
|
CommentNodeTypeId |
|
||||||
TextNodeTypeId |
|
TextNodeTypeId |
|
||||||
DoctypeNodeTypeId |
|
DoctypeNodeTypeId |
|
||||||
|
@ -889,9 +872,9 @@ impl Node {
|
||||||
match self.type_id {
|
match self.type_id {
|
||||||
// ProcessingInstruction
|
// ProcessingInstruction
|
||||||
CommentNodeTypeId | TextNodeTypeId => {
|
CommentNodeTypeId | TextNodeTypeId => {
|
||||||
do abstract_self.with_imm_characterdata() |characterdata| {
|
abstract_self.with_imm_characterdata(|characterdata| {
|
||||||
Some(characterdata.Data())
|
Some(characterdata.Data())
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
None
|
None
|
||||||
|
@ -906,21 +889,21 @@ impl Node {
|
||||||
|
|
||||||
pub fn GetTextContent(&self, abstract_self: AbstractNode) -> Option<DOMString> {
|
pub fn GetTextContent(&self, abstract_self: AbstractNode) -> Option<DOMString> {
|
||||||
match self.type_id {
|
match self.type_id {
|
||||||
DocumentFragmentNodeTypeId | ElementNodeTypeId(*) => {
|
DocumentFragmentNodeTypeId | ElementNodeTypeId(..) => {
|
||||||
let mut content = ~"";
|
let mut content = ~"";
|
||||||
for node in abstract_self.traverse_preorder() {
|
for node in abstract_self.traverse_preorder() {
|
||||||
if node.is_text() {
|
if node.is_text() {
|
||||||
do node.with_imm_text() |text| {
|
node.with_imm_text(|text| {
|
||||||
content = content + text.element.Data();
|
content = content + text.element.Data();
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(content)
|
Some(content)
|
||||||
}
|
}
|
||||||
CommentNodeTypeId | TextNodeTypeId => {
|
CommentNodeTypeId | TextNodeTypeId => {
|
||||||
do abstract_self.with_imm_characterdata() |characterdata| {
|
abstract_self.with_imm_characterdata(|characterdata| {
|
||||||
Some(characterdata.Data())
|
Some(characterdata.Data())
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
DoctypeNodeTypeId | DocumentNodeTypeId(_) => {
|
DoctypeNodeTypeId | DocumentNodeTypeId(_) => {
|
||||||
None
|
None
|
||||||
|
@ -968,9 +951,9 @@ impl Node {
|
||||||
|
|
||||||
// Step 1.
|
// Step 1.
|
||||||
match parent.type_id() {
|
match parent.type_id() {
|
||||||
DocumentNodeTypeId(*) |
|
DocumentNodeTypeId(..) |
|
||||||
DocumentFragmentNodeTypeId |
|
DocumentFragmentNodeTypeId |
|
||||||
ElementNodeTypeId(*) => (),
|
ElementNodeTypeId(..) => (),
|
||||||
_ => {
|
_ => {
|
||||||
return Err(HierarchyRequest);
|
return Err(HierarchyRequest);
|
||||||
},
|
},
|
||||||
|
@ -999,7 +982,7 @@ impl Node {
|
||||||
TextNodeTypeId |
|
TextNodeTypeId |
|
||||||
// ProcessingInstructionNodeTypeId |
|
// ProcessingInstructionNodeTypeId |
|
||||||
CommentNodeTypeId => (),
|
CommentNodeTypeId => (),
|
||||||
DocumentNodeTypeId(*) => return Err(HierarchyRequest),
|
DocumentNodeTypeId(..) => return Err(HierarchyRequest),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 5.
|
// Step 5.
|
||||||
|
@ -1241,7 +1224,7 @@ impl Node {
|
||||||
-> ErrorResult {
|
-> ErrorResult {
|
||||||
let value = null_str_as_empty(&value);
|
let value = null_str_as_empty(&value);
|
||||||
match self.type_id {
|
match self.type_id {
|
||||||
DocumentFragmentNodeTypeId | ElementNodeTypeId(*) => {
|
DocumentFragmentNodeTypeId | ElementNodeTypeId(..) => {
|
||||||
// Step 1-2.
|
// Step 1-2.
|
||||||
let node = if value.len() == 0 {
|
let node = if value.len() == 0 {
|
||||||
None
|
None
|
||||||
|
@ -1255,13 +1238,13 @@ impl Node {
|
||||||
CommentNodeTypeId | TextNodeTypeId => {
|
CommentNodeTypeId | TextNodeTypeId => {
|
||||||
self.wait_until_safe_to_modify_dom();
|
self.wait_until_safe_to_modify_dom();
|
||||||
|
|
||||||
do abstract_self.with_mut_characterdata() |characterdata| {
|
abstract_self.with_mut_characterdata(|characterdata| {
|
||||||
characterdata.data = value.clone();
|
characterdata.data = value.clone();
|
||||||
|
|
||||||
// Notify the document that the content of this node is different
|
// Notify the document that the content of this node is different
|
||||||
let document = self.owner_doc();
|
let document = self.owner_doc();
|
||||||
document.document().content_changed();
|
document.document().content_changed();
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
DoctypeNodeTypeId | DocumentNodeTypeId(_) => {}
|
DoctypeNodeTypeId | DocumentNodeTypeId(_) => {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,19 +18,17 @@ use servo_msg::compositor_msg::ScriptListener;
|
||||||
use servo_net::image_cache_task::ImageCacheTask;
|
use servo_net::image_cache_task::ImageCacheTask;
|
||||||
|
|
||||||
use js::glue::*;
|
use js::glue::*;
|
||||||
use js::jsapi::{JSObject, JSContext, JS_DefineProperty};
|
use js::jsapi::{JSObject, JSContext, JS_DefineProperty, JSTracer, JSVal};
|
||||||
use js::jsapi::{JSPropertyOp, JSStrictPropertyOp, JSTracer};
|
|
||||||
use js::{JSVAL_NULL, JSPROP_ENUMERATE};
|
use js::{JSVAL_NULL, JSPROP_ENUMERATE};
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cast;
|
||||||
use std::comm;
|
|
||||||
use std::comm::SharedChan;
|
use std::comm::SharedChan;
|
||||||
|
use std::comm::Select;
|
||||||
use std::hashmap::HashSet;
|
use std::hashmap::HashSet;
|
||||||
|
use std::io::timer::Timer;
|
||||||
|
use std::num;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::int;
|
use std::to_bytes::Cb;
|
||||||
use std::rt::io::timer::Timer;
|
|
||||||
use std::task::spawn_with;
|
|
||||||
use js::jsapi::JSVal;
|
|
||||||
|
|
||||||
pub enum TimerControlMsg {
|
pub enum TimerControlMsg {
|
||||||
TimerMessage_Fire(~TimerData),
|
TimerMessage_Fire(~TimerData),
|
||||||
|
@ -38,6 +36,29 @@ pub enum TimerControlMsg {
|
||||||
TimerMessage_TriggerExit //XXXjdm this is just a quick hack to talk to the script task
|
TimerMessage_TriggerExit //XXXjdm this is just a quick hack to talk to the script task
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct TimerHandle {
|
||||||
|
handle: i32,
|
||||||
|
cancel_chan: Option<Chan<()>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IterBytes for TimerHandle {
|
||||||
|
fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool {
|
||||||
|
self.handle.iter_bytes(lsb0, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for TimerHandle {
|
||||||
|
fn eq(&self, other: &TimerHandle) -> bool {
|
||||||
|
self.handle == other.handle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TimerHandle {
|
||||||
|
fn cancel(&self) {
|
||||||
|
self.cancel_chan.as_ref().map(|chan| chan.send(()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
eventtarget: EventTarget,
|
eventtarget: EventTarget,
|
||||||
page: @mut Page,
|
page: @mut Page,
|
||||||
|
@ -47,7 +68,7 @@ pub struct Window {
|
||||||
location: Option<@mut Location>,
|
location: Option<@mut Location>,
|
||||||
navigator: Option<@mut Navigator>,
|
navigator: Option<@mut Navigator>,
|
||||||
image_cache_task: ImageCacheTask,
|
image_cache_task: ImageCacheTask,
|
||||||
active_timers: ~HashSet<i32>,
|
active_timers: ~HashSet<TimerHandle>,
|
||||||
next_timer_handle: i32,
|
next_timer_handle: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,6 +82,9 @@ impl Window {
|
||||||
impl Drop for Window {
|
impl Drop for Window {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.timer_chan.send(TimerMessage_Close);
|
self.timer_chan.send(TimerMessage_Close);
|
||||||
|
for handle in self.active_timers.iter() {
|
||||||
|
handle.cancel();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,29 +184,40 @@ impl Reflectable for Window {
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
pub fn SetTimeout(&mut self, _cx: *JSContext, callback: JSVal, timeout: i32) -> i32 {
|
pub fn SetTimeout(&mut self, _cx: *JSContext, callback: JSVal, timeout: i32) -> i32 {
|
||||||
let timeout = int::max(0, timeout) as u64;
|
let timeout = num::max(0, timeout) as u64;
|
||||||
let handle = self.next_timer_handle;
|
let handle = self.next_timer_handle;
|
||||||
self.next_timer_handle += 1;
|
self.next_timer_handle += 1;
|
||||||
|
|
||||||
// Post a delayed message to the per-window timer task; it will dispatch it
|
// Post a delayed message to the per-window timer task; it will dispatch it
|
||||||
// to the relevant script handler that will deal with it.
|
// to the relevant script handler that will deal with it.
|
||||||
let tm = Cell::new(Timer::new().unwrap());
|
let tm = Timer::new().unwrap();
|
||||||
|
let (cancel_port, cancel_chan) = Chan::new();
|
||||||
let chan = self.timer_chan.clone();
|
let chan = self.timer_chan.clone();
|
||||||
do spawn {
|
spawn(proc() {
|
||||||
let mut tm = tm.take();
|
let mut tm = tm;
|
||||||
tm.sleep(timeout);
|
let mut timeout_port = tm.oneshot(timeout);
|
||||||
chan.send(TimerMessage_Fire(~TimerData {
|
let mut cancel_port = cancel_port;
|
||||||
handle: handle,
|
|
||||||
funval: callback,
|
let select = Select::new();
|
||||||
args: ~[]
|
let timeout_handle = select.add(&mut timeout_port);
|
||||||
}));
|
let _cancel_handle = select.add(&mut cancel_port);
|
||||||
}
|
let id = select.wait();
|
||||||
self.active_timers.insert(handle);
|
if id == timeout_handle.id {
|
||||||
|
chan.send(TimerMessage_Fire(~TimerData {
|
||||||
|
handle: handle,
|
||||||
|
funval: callback,
|
||||||
|
args: ~[],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
self.active_timers.insert(TimerHandle { handle: handle, cancel_chan: Some(cancel_chan) });
|
||||||
handle
|
handle
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ClearTimeout(&mut self, handle: i32) {
|
pub fn ClearTimeout(&mut self, handle: i32) {
|
||||||
self.active_timers.remove(&handle);
|
// FIXME(#1477): active_timers should be a HashMap and this should
|
||||||
|
// cancel the removed timer.
|
||||||
|
self.active_timers.remove(&TimerHandle { handle: handle, cancel_chan: None });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn damage_and_reflow(&self, damage: DocumentDamageLevel) {
|
pub fn damage_and_reflow(&self, damage: DocumentDamageLevel) {
|
||||||
|
@ -199,7 +234,6 @@ impl Window {
|
||||||
self.page.join_layout();
|
self.page.join_layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn new(cx: *JSContext,
|
pub fn new(cx: *JSContext,
|
||||||
page: @mut Page,
|
page: @mut Page,
|
||||||
script_chan: ScriptChan,
|
script_chan: ScriptChan,
|
||||||
|
@ -212,9 +246,9 @@ impl Window {
|
||||||
script_chan: script_chan.clone(),
|
script_chan: script_chan.clone(),
|
||||||
compositor: compositor,
|
compositor: compositor,
|
||||||
timer_chan: {
|
timer_chan: {
|
||||||
let (timer_port, timer_chan) = comm::stream::<TimerControlMsg>();
|
let (timer_port, timer_chan): (Port<TimerControlMsg>, SharedChan<TimerControlMsg>) = SharedChan::new();
|
||||||
let id = page.id.clone();
|
let id = page.id.clone();
|
||||||
do spawn_with(script_chan) |script_chan| {
|
spawn(proc() {
|
||||||
loop {
|
loop {
|
||||||
match timer_port.recv() {
|
match timer_port.recv() {
|
||||||
TimerMessage_Close => break,
|
TimerMessage_Close => break,
|
||||||
|
@ -222,8 +256,8 @@ impl Window {
|
||||||
TimerMessage_TriggerExit => script_chan.send(ExitWindowMsg(id)),
|
TimerMessage_TriggerExit => script_chan.send(ExitWindowMsg(id)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
SharedChan::new(timer_chan)
|
timer_chan
|
||||||
},
|
},
|
||||||
location: None,
|
location: None,
|
||||||
navigator: None,
|
navigator: None,
|
||||||
|
@ -236,13 +270,13 @@ impl Window {
|
||||||
unsafe {
|
unsafe {
|
||||||
let fn_names = ["window","self"];
|
let fn_names = ["window","self"];
|
||||||
for str in fn_names.iter() {
|
for str in fn_names.iter() {
|
||||||
do (*str).to_c_str().with_ref |name| {
|
(*str).to_c_str().with_ref(|name| {
|
||||||
JS_DefineProperty(cx, global, name,
|
JS_DefineProperty(cx, global, name,
|
||||||
RUST_OBJECT_TO_JSVAL(global),
|
RUST_OBJECT_TO_JSVAL(global),
|
||||||
Some(GetJSClassHookStubPointer(PROPERTY_STUB) as JSPropertyOp),
|
Some(cast::transmute(GetJSClassHookStubPointer(PROPERTY_STUB))),
|
||||||
Some(GetJSClassHookStubPointer(STRICT_PROPERTY_STUB) as JSStrictPropertyOp),
|
Some(cast::transmute(GetJSClassHookStubPointer(STRICT_PROPERTY_STUB))),
|
||||||
JSPROP_ENUMERATE);
|
JSPROP_ENUMERATE);
|
||||||
}
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,10 +4,7 @@
|
||||||
|
|
||||||
/// Some little helpers for hooking up the HTML parser with the CSS parser.
|
/// Some little helpers for hooking up the HTML parser with the CSS parser.
|
||||||
|
|
||||||
use std::cell::Cell;
|
|
||||||
use std::comm;
|
|
||||||
use std::comm::Port;
|
use std::comm::Port;
|
||||||
use std::task;
|
|
||||||
use encoding::EncodingRef;
|
use encoding::EncodingRef;
|
||||||
use encoding::all::UTF_8;
|
use encoding::all::UTF_8;
|
||||||
use style::Stylesheet;
|
use style::Stylesheet;
|
||||||
|
@ -23,25 +20,22 @@ pub enum StylesheetProvenance {
|
||||||
pub fn spawn_css_parser(provenance: StylesheetProvenance,
|
pub fn spawn_css_parser(provenance: StylesheetProvenance,
|
||||||
resource_task: ResourceTask)
|
resource_task: ResourceTask)
|
||||||
-> Port<Stylesheet> {
|
-> Port<Stylesheet> {
|
||||||
let (result_port, result_chan) = comm::stream();
|
let (result_port, result_chan) = Chan::new();
|
||||||
|
|
||||||
// TODO: Get the actual value. http://dev.w3.org/csswg/css-syntax/#environment-encoding
|
// TODO: Get the actual value. http://dev.w3.org/csswg/css-syntax/#environment-encoding
|
||||||
let environment_encoding = UTF_8 as EncodingRef;
|
let environment_encoding = UTF_8 as EncodingRef;
|
||||||
|
|
||||||
let provenance_cell = Cell::new(provenance);
|
spawn(proc() {
|
||||||
do task::spawn {
|
|
||||||
// TODO: CSS parsing should take a base URL.
|
// TODO: CSS parsing should take a base URL.
|
||||||
let _url = do provenance_cell.with_ref |p| {
|
let _url = match provenance {
|
||||||
match *p {
|
UrlProvenance(ref the_url) => (*the_url).clone(),
|
||||||
UrlProvenance(ref the_url) => (*the_url).clone(),
|
InlineProvenance(ref the_url, _) => (*the_url).clone()
|
||||||
InlineProvenance(ref the_url, _) => (*the_url).clone()
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let sheet = match provenance_cell.take() {
|
let sheet = match provenance {
|
||||||
UrlProvenance(url) => {
|
UrlProvenance(url) => {
|
||||||
debug!("cssparse: loading style sheet at {:s}", url.to_str());
|
debug!("cssparse: loading style sheet at {:s}", url.to_str());
|
||||||
let (input_port, input_chan) = comm::stream();
|
let (input_port, input_chan) = Chan::new();
|
||||||
resource_task.send(Load(url, input_chan));
|
resource_task.send(Load(url, input_chan));
|
||||||
let LoadResponse { metadata: metadata, progress_port: progress_port }
|
let LoadResponse { metadata: metadata, progress_port: progress_port }
|
||||||
= input_port.recv();
|
= input_port.recv();
|
||||||
|
@ -56,7 +50,7 @@ pub fn spawn_css_parser(provenance: StylesheetProvenance,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
result_chan.send(sheet);
|
result_chan.send(sheet);
|
||||||
}
|
});
|
||||||
|
|
||||||
return result_port;
|
return result_port;
|
||||||
}
|
}
|
||||||
|
@ -69,7 +63,7 @@ impl Iterator<~[u8]> for ProgressMsgPortIterator {
|
||||||
fn next(&mut self) -> Option<~[u8]> {
|
fn next(&mut self) -> Option<~[u8]> {
|
||||||
match self.progress_port.recv() {
|
match self.progress_port.recv() {
|
||||||
Payload(data) => Some(data),
|
Payload(data) => Some(data),
|
||||||
Done(*) => None
|
Done(..) => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,9 +22,8 @@ use servo_net::image_cache_task::ImageCacheTask;
|
||||||
use servo_net::resource_task::{Load, Payload, Done, ResourceTask, load_whole_resource};
|
use servo_net::resource_task::{Load, Payload, Done, ResourceTask, load_whole_resource};
|
||||||
use servo_util::url::make_url;
|
use servo_util::url::make_url;
|
||||||
use std::cast;
|
use std::cast;
|
||||||
use std::cell::Cell;
|
use std::cell::RefCell;
|
||||||
use std::comm::{Port, SharedChan};
|
use std::comm::{Port, SharedChan};
|
||||||
use std::comm;
|
|
||||||
use std::from_str::FromStr;
|
use std::from_str::FromStr;
|
||||||
use std::str::eq_slice;
|
use std::str::eq_slice;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
@ -107,11 +106,11 @@ fn css_link_listener(to_parent: SharedChan<HtmlDiscoveryMessage>,
|
||||||
let mut result_vec = ~[];
|
let mut result_vec = ~[];
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match from_parent.recv() {
|
match from_parent.recv_opt() {
|
||||||
CSSTaskNewFile(provenance) => {
|
Some(CSSTaskNewFile(provenance)) => {
|
||||||
result_vec.push(spawn_css_parser(provenance, resource_task.clone()));
|
result_vec.push(spawn_css_parser(provenance, resource_task.clone()));
|
||||||
}
|
}
|
||||||
CSSTaskExit => {
|
Some(CSSTaskExit) | None => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,7 +119,7 @@ fn css_link_listener(to_parent: SharedChan<HtmlDiscoveryMessage>,
|
||||||
// Send the sheets back in order
|
// Send the sheets back in order
|
||||||
// FIXME: Shouldn't wait until after we've recieved CSSTaskExit to start sending these
|
// FIXME: Shouldn't wait until after we've recieved CSSTaskExit to start sending these
|
||||||
for port in result_vec.iter() {
|
for port in result_vec.iter() {
|
||||||
to_parent.send(HtmlDiscoveredStyle(port.recv()));
|
to_parent.try_send(HtmlDiscoveredStyle(port.recv()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,30 +129,30 @@ fn js_script_listener(to_parent: SharedChan<HtmlDiscoveryMessage>,
|
||||||
let mut result_vec = ~[];
|
let mut result_vec = ~[];
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match from_parent.recv() {
|
match from_parent.recv_opt() {
|
||||||
JSTaskNewFile(url) => {
|
Some(JSTaskNewFile(url)) => {
|
||||||
match load_whole_resource(&resource_task, url.clone()) {
|
match load_whole_resource(&resource_task, url.clone()) {
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
error!("error loading script {:s}", url.to_str());
|
error!("error loading script {:s}", url.to_str());
|
||||||
}
|
}
|
||||||
Ok((metadata, bytes)) => {
|
Ok((metadata, bytes)) => {
|
||||||
result_vec.push(JSFile {
|
result_vec.push(JSFile {
|
||||||
data: str::from_utf8(bytes),
|
data: str::from_utf8(bytes).to_owned(),
|
||||||
url: metadata.final_url,
|
url: metadata.final_url,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
JSTaskNewInlineScript(data, url) => {
|
Some(JSTaskNewInlineScript(data, url)) => {
|
||||||
result_vec.push(JSFile { data: data, url: url });
|
result_vec.push(JSFile { data: data, url: url });
|
||||||
}
|
}
|
||||||
JSTaskExit => {
|
Some(JSTaskExit) | None => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
to_parent.send(HtmlDiscoveredScript(result_vec));
|
to_parent.try_send(HtmlDiscoveredScript(result_vec));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Silly macros to handle constructing DOM nodes. This produces bad code and should be optimized
|
// Silly macros to handle constructing DOM nodes. This produces bad code and should be optimized
|
||||||
|
@ -253,30 +252,23 @@ pub fn parse_html(cx: *JSContext,
|
||||||
// Spawn a CSS parser to receive links to CSS style sheets.
|
// Spawn a CSS parser to receive links to CSS style sheets.
|
||||||
let resource_task2 = resource_task.clone();
|
let resource_task2 = resource_task.clone();
|
||||||
|
|
||||||
let (discovery_port, discovery_chan) = comm::stream();
|
let (discovery_port, discovery_chan) = SharedChan::new();
|
||||||
let discovery_chan = SharedChan::new(discovery_chan);
|
let stylesheet_chan = discovery_chan.clone();
|
||||||
|
let (css_msg_port, css_chan) = SharedChan::new();
|
||||||
let stylesheet_chan = Cell::new(discovery_chan.clone());
|
spawn(proc() {
|
||||||
let (css_msg_port, css_msg_chan) = comm::stream();
|
css_link_listener(stylesheet_chan, css_msg_port, resource_task2.clone());
|
||||||
let css_msg_port = Cell::new(css_msg_port);
|
});
|
||||||
do spawn {
|
|
||||||
css_link_listener(stylesheet_chan.take(), css_msg_port.take(), resource_task2.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
let css_chan = SharedChan::new(css_msg_chan);
|
|
||||||
|
|
||||||
// Spawn a JS parser to receive JavaScript.
|
// Spawn a JS parser to receive JavaScript.
|
||||||
let resource_task2 = resource_task.clone();
|
let resource_task2 = resource_task.clone();
|
||||||
let js_result_chan = Cell::new(discovery_chan.clone());
|
let js_result_chan = discovery_chan.clone();
|
||||||
let (js_msg_port, js_msg_chan) = comm::stream();
|
let (js_msg_port, js_chan) = SharedChan::new();
|
||||||
let js_msg_port = Cell::new(js_msg_port);
|
spawn(proc() {
|
||||||
do spawn {
|
js_script_listener(js_result_chan, js_msg_port, resource_task2.clone());
|
||||||
js_script_listener(js_result_chan.take(), js_msg_port.take(), resource_task2.clone());
|
});
|
||||||
}
|
|
||||||
let js_chan = SharedChan::new(js_msg_chan);
|
|
||||||
|
|
||||||
// Wait for the LoadResponse so that the parser knows the final URL.
|
// Wait for the LoadResponse so that the parser knows the final URL.
|
||||||
let (input_port, input_chan) = comm::stream();
|
let (input_port, input_chan) = Chan::new();
|
||||||
resource_task.send(Load(url.clone(), input_chan));
|
resource_task.send(Load(url.clone(), input_chan));
|
||||||
let load_response = input_port.recv();
|
let load_response = input_port.recv();
|
||||||
|
|
||||||
|
@ -305,9 +297,10 @@ pub fn parse_html(cx: *JSContext,
|
||||||
parser.enable_styling(true);
|
parser.enable_styling(true);
|
||||||
|
|
||||||
let (css_chan2, css_chan3, js_chan2) = (css_chan.clone(), css_chan.clone(), js_chan.clone());
|
let (css_chan2, css_chan3, js_chan2) = (css_chan.clone(), css_chan.clone(), js_chan.clone());
|
||||||
let next_subpage_id = Cell::new(next_subpage_id);
|
|
||||||
|
let next_subpage_id = RefCell::new(next_subpage_id);
|
||||||
parser.set_tree_handler(~hubbub::TreeHandler {
|
|
||||||
|
let tree_handler = hubbub::TreeHandler {
|
||||||
create_comment: |data: ~str| {
|
create_comment: |data: ~str| {
|
||||||
debug!("create comment");
|
debug!("create comment");
|
||||||
let comment = Comment::new(data, document);
|
let comment = Comment::new(data, document);
|
||||||
|
@ -333,19 +326,19 @@ pub fn parse_html(cx: *JSContext,
|
||||||
let node = build_element_from_tag(tag.name.clone(), document);
|
let node = build_element_from_tag(tag.name.clone(), document);
|
||||||
|
|
||||||
debug!("-- attach attrs");
|
debug!("-- attach attrs");
|
||||||
do node.as_mut_element |element| {
|
node.as_mut_element(|element| {
|
||||||
for attr in tag.attributes.iter() {
|
for attr in tag.attributes.iter() {
|
||||||
element.set_attr(node,
|
element.set_attr(node,
|
||||||
attr.name.clone(),
|
attr.name.clone(),
|
||||||
attr.value.clone());
|
attr.value.clone());
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
// Spawn additional parsing, network loads, etc. from tag and attrs
|
// Spawn additional parsing, network loads, etc. from tag and attrs
|
||||||
match node.type_id() {
|
match node.type_id() {
|
||||||
// Handle CSS style sheets from <link> elements
|
// Handle CSS style sheets from <link> elements
|
||||||
ElementNodeTypeId(HTMLLinkElementTypeId) => {
|
ElementNodeTypeId(HTMLLinkElementTypeId) => {
|
||||||
do node.with_imm_element |element| {
|
node.with_imm_element(|element| {
|
||||||
match (element.get_attr(Null, "rel"), element.get_attr(Null, "href")) {
|
match (element.get_attr(Null, "rel"), element.get_attr(Null, "href")) {
|
||||||
(Some(rel), Some(href)) => {
|
(Some(rel), Some(href)) => {
|
||||||
if "stylesheet" == rel {
|
if "stylesheet" == rel {
|
||||||
|
@ -356,13 +349,12 @@ pub fn parse_html(cx: *JSContext,
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ElementNodeTypeId(HTMLIframeElementTypeId) => {
|
ElementNodeTypeId(HTMLIframeElementTypeId) => {
|
||||||
let iframe_chan = Cell::new(discovery_chan.clone());
|
let iframe_chan = discovery_chan.clone();
|
||||||
do node.with_mut_iframe_element |iframe_element| {
|
node.with_mut_iframe_element(|iframe_element| {
|
||||||
let iframe_chan = iframe_chan.take();
|
|
||||||
let sandboxed = iframe_element.is_sandboxed();
|
let sandboxed = iframe_element.is_sandboxed();
|
||||||
let elem = &mut iframe_element.htmlelement.element;
|
let elem = &mut iframe_element.htmlelement.element;
|
||||||
let src_opt = elem.get_attr(Null, "src").map(|x| x.to_str());
|
let src_opt = elem.get_attr(Null, "src").map(|x| x.to_str());
|
||||||
|
@ -371,8 +363,8 @@ pub fn parse_html(cx: *JSContext,
|
||||||
iframe_element.frame = Some(iframe_url.clone());
|
iframe_element.frame = Some(iframe_url.clone());
|
||||||
|
|
||||||
// Subpage Id
|
// Subpage Id
|
||||||
let subpage_id = next_subpage_id.take();
|
let subpage_id = next_subpage_id.get();
|
||||||
next_subpage_id.put_back(SubpageId(*subpage_id + 1));
|
next_subpage_id.set(SubpageId(*subpage_id + 1));
|
||||||
|
|
||||||
// Pipeline Id
|
// Pipeline Id
|
||||||
let pipeline_id = {
|
let pipeline_id = {
|
||||||
|
@ -388,15 +380,15 @@ pub fn parse_html(cx: *JSContext,
|
||||||
subpage_id,
|
subpage_id,
|
||||||
sandboxed)));
|
sandboxed)));
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//FIXME: This should be taken care of by set_attr, but we don't have
|
//FIXME: This should be taken care of by set_attr, but we don't have
|
||||||
// access to a window so HTMLImageElement::AfterSetAttr bails.
|
// access to a window so HTMLImageElement::AfterSetAttr bails.
|
||||||
ElementNodeTypeId(HTMLImageElementTypeId) => {
|
ElementNodeTypeId(HTMLImageElementTypeId) => {
|
||||||
do node.with_mut_image_element |image_element| {
|
node.with_mut_image_element(|image_element| {
|
||||||
image_element.update_image(image_cache_task.clone(), Some(url2.clone()));
|
image_element.update_image(image_cache_task.clone(), Some(url2.clone()));
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -460,7 +452,7 @@ pub fn parse_html(cx: *JSContext,
|
||||||
complete_script: |script| {
|
complete_script: |script| {
|
||||||
unsafe {
|
unsafe {
|
||||||
let scriptnode: AbstractNode = NodeWrapping::from_hubbub_node(script);
|
let scriptnode: AbstractNode = NodeWrapping::from_hubbub_node(script);
|
||||||
do scriptnode.with_imm_element |script| {
|
scriptnode.with_imm_element(|script| {
|
||||||
match script.get_attr(Null, "src") {
|
match script.get_attr(Null, "src") {
|
||||||
Some(src) => {
|
Some(src) => {
|
||||||
debug!("found script: {:s}", src);
|
debug!("found script: {:s}", src);
|
||||||
|
@ -472,16 +464,16 @@ pub fn parse_html(cx: *JSContext,
|
||||||
debug!("iterating over children {:?}", scriptnode.first_child());
|
debug!("iterating over children {:?}", scriptnode.first_child());
|
||||||
for child in scriptnode.children() {
|
for child in scriptnode.children() {
|
||||||
debug!("child = {:?}", child);
|
debug!("child = {:?}", child);
|
||||||
do child.with_imm_text() |text| {
|
child.with_imm_text(|text| {
|
||||||
data.push(text.element.data.to_str()); // FIXME: Bad copy.
|
data.push(text.element.data.to_str()); // FIXME: Bad copy.
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("script data = {:?}", data);
|
debug!("script data = {:?}", data);
|
||||||
js_chan2.send(JSTaskNewInlineScript(data.concat(), url3.clone()));
|
js_chan2.send(JSTaskNewInlineScript(data.concat(), url3.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
debug!("complete script");
|
debug!("complete script");
|
||||||
},
|
},
|
||||||
|
@ -490,23 +482,22 @@ pub fn parse_html(cx: *JSContext,
|
||||||
unsafe {
|
unsafe {
|
||||||
let style: AbstractNode = NodeWrapping::from_hubbub_node(style);
|
let style: AbstractNode = NodeWrapping::from_hubbub_node(style);
|
||||||
let url = FromStr::from_str("http://example.com/"); // FIXME
|
let url = FromStr::from_str("http://example.com/"); // FIXME
|
||||||
let url_cell = Cell::new(url);
|
|
||||||
|
|
||||||
let mut data = ~[];
|
let mut data = ~[];
|
||||||
debug!("iterating over children {:?}", style.first_child());
|
debug!("iterating over children {:?}", style.first_child());
|
||||||
for child in style.children() {
|
for child in style.children() {
|
||||||
debug!("child = {:?}", child);
|
debug!("child = {:?}", child);
|
||||||
do child.with_imm_text() |text| {
|
child.with_imm_text(|text| {
|
||||||
data.push(text.element.data.to_str()); // FIXME: Bad copy.
|
data.push(text.element.data.to_str()); // FIXME: Bad copy.
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("style data = {:?}", data);
|
debug!("style data = {:?}", data);
|
||||||
let provenance = InlineProvenance(url_cell.take().unwrap(), data.concat());
|
let provenance = InlineProvenance(url.unwrap(), data.concat());
|
||||||
css_chan3.send(CSSTaskNewFile(provenance));
|
css_chan3.send(CSSTaskNewFile(provenance));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
};
|
||||||
|
parser.set_tree_handler(&tree_handler);
|
||||||
debug!("set tree handler");
|
debug!("set tree handler");
|
||||||
|
|
||||||
debug!("loaded page");
|
debug!("loaded page");
|
||||||
|
@ -516,10 +507,10 @@ pub fn parse_html(cx: *JSContext,
|
||||||
debug!("received data");
|
debug!("received data");
|
||||||
parser.parse_chunk(data);
|
parser.parse_chunk(data);
|
||||||
}
|
}
|
||||||
Done(Err(*)) => {
|
Done(Err(..)) => {
|
||||||
fail!("Failed to load page URL {:s}", url.to_str());
|
fail!("Failed to load page URL {:s}", url.to_str());
|
||||||
}
|
}
|
||||||
Done(*) => {
|
Done(..) => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,9 +122,11 @@ pub struct Reflow {
|
||||||
/// Encapsulates a channel to the layout task.
|
/// Encapsulates a channel to the layout task.
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone)]
|
||||||
pub struct LayoutChan(SharedChan<Msg>);
|
pub struct LayoutChan(SharedChan<Msg>);
|
||||||
|
|
||||||
impl LayoutChan {
|
impl LayoutChan {
|
||||||
pub fn new(chan: Chan<Msg>) -> LayoutChan {
|
pub fn new() -> (Port<Msg>, LayoutChan) {
|
||||||
LayoutChan(SharedChan::new(chan))
|
let (port, chan) = SharedChan::new();
|
||||||
|
(port, LayoutChan(chan))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,14 +2,11 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#[link(name = "script",
|
#[crate_id = "github.com/mozilla/servo#script:0.1"];
|
||||||
vers = "0.1",
|
#[crate_type = "lib"];
|
||||||
uuid = "536a45e2-b605-4ee0-b54c-466810f1ffc1",
|
|
||||||
url = "http://servo.org/")];
|
|
||||||
|
|
||||||
#[comment = "The Servo Parallel Browser Project"];
|
#[comment = "The Servo Parallel Browser Project"];
|
||||||
#[license = "MPL"];
|
#[license = "MPL"];
|
||||||
#[crate_type = "lib"];
|
|
||||||
|
|
||||||
#[feature(globs, macro_rules, struct_variant, managed_boxes)];
|
#[feature(globs, macro_rules, struct_variant, managed_boxes)];
|
||||||
|
|
||||||
|
@ -17,11 +14,12 @@ extern mod geom;
|
||||||
extern mod hubbub;
|
extern mod hubbub;
|
||||||
extern mod encoding;
|
extern mod encoding;
|
||||||
extern mod js;
|
extern mod js;
|
||||||
extern mod servo_net (name = "net");
|
extern mod servo_net = "net";
|
||||||
extern mod servo_util (name = "util");
|
extern mod servo_util = "util";
|
||||||
extern mod style;
|
extern mod style;
|
||||||
extern mod servo_msg (name = "msg");
|
extern mod servo_msg = "msg";
|
||||||
extern mod extra;
|
extern mod extra;
|
||||||
|
extern mod native;
|
||||||
|
|
||||||
// Macros
|
// Macros
|
||||||
mod macros;
|
mod macros;
|
||||||
|
|
|
@ -14,15 +14,15 @@ use dom::event::Event;
|
||||||
use dom::eventtarget::AbstractEventTarget;
|
use dom::eventtarget::AbstractEventTarget;
|
||||||
use dom::htmldocument::HTMLDocument;
|
use dom::htmldocument::HTMLDocument;
|
||||||
use dom::namespace::Null;
|
use dom::namespace::Null;
|
||||||
use dom::node::{AbstractNode, LayoutDataRef};
|
use dom::node::AbstractNode;
|
||||||
use dom::window::{TimerData, Window};
|
use dom::window::{TimerData, TimerHandle, Window};
|
||||||
use html::hubbub_html_parser::HtmlParserResult;
|
use html::hubbub_html_parser::HtmlParserResult;
|
||||||
use html::hubbub_html_parser::{HtmlDiscoveredStyle, HtmlDiscoveredIFrame, HtmlDiscoveredScript};
|
use html::hubbub_html_parser::{HtmlDiscoveredStyle, HtmlDiscoveredIFrame, HtmlDiscoveredScript};
|
||||||
use html::hubbub_html_parser;
|
use html::hubbub_html_parser;
|
||||||
use layout_interface::{AddStylesheetMsg, DocumentDamage};
|
use layout_interface::{AddStylesheetMsg, DocumentDamage};
|
||||||
use layout_interface::{ContentBoxQuery, ContentBoxResponse};
|
use layout_interface::{ContentBoxQuery, ContentBoxResponse};
|
||||||
use layout_interface::{DocumentDamageLevel, HitTestQuery, HitTestResponse, LayoutQuery};
|
use layout_interface::{DocumentDamageLevel, HitTestQuery, HitTestResponse, LayoutQuery};
|
||||||
use layout_interface::{LayoutChan, MatchSelectorsDocumentDamage, QueryMsg, ReapLayoutDataMsg};
|
use layout_interface::{LayoutChan, MatchSelectorsDocumentDamage, QueryMsg};
|
||||||
use layout_interface::{Reflow, ReflowDocumentDamage, ReflowForDisplay, ReflowGoal, ReflowMsg};
|
use layout_interface::{Reflow, ReflowDocumentDamage, ReflowForDisplay, ReflowGoal, ReflowMsg};
|
||||||
use layout_interface::ContentChangedDocumentDamage;
|
use layout_interface::ContentChangedDocumentDamage;
|
||||||
use layout_interface;
|
use layout_interface;
|
||||||
|
@ -46,12 +46,9 @@ use servo_net::image_cache_task::ImageCacheTask;
|
||||||
use servo_net::resource_task::ResourceTask;
|
use servo_net::resource_task::ResourceTask;
|
||||||
use servo_util::geometry::to_frac_px;
|
use servo_util::geometry::to_frac_px;
|
||||||
use servo_util::url::make_url;
|
use servo_util::url::make_url;
|
||||||
use std::cell::Cell;
|
|
||||||
use std::comm::{Port, SharedChan};
|
use std::comm::{Port, SharedChan};
|
||||||
use std::comm;
|
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::str::eq_slice;
|
use std::str::eq_slice;
|
||||||
use std::task::{spawn_sched, SingleThreaded};
|
|
||||||
use std::util::replace;
|
use std::util::replace;
|
||||||
|
|
||||||
/// Messages used to control the script task.
|
/// Messages used to control the script task.
|
||||||
|
@ -90,8 +87,9 @@ pub struct ScriptChan(SharedChan<ScriptMsg>);
|
||||||
|
|
||||||
impl ScriptChan {
|
impl ScriptChan {
|
||||||
/// Creates a new script chan.
|
/// Creates a new script chan.
|
||||||
pub fn new(chan: Chan<ScriptMsg>) -> ScriptChan {
|
pub fn new() -> (Port<ScriptMsg>, ScriptChan) {
|
||||||
ScriptChan(SharedChan::new(chan))
|
let (port, chan) = SharedChan::new();
|
||||||
|
(port, ScriptChan(chan))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,8 +138,8 @@ pub struct PageTree {
|
||||||
inner: ~[PageTree],
|
inner: ~[PageTree],
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PageTreeIterator<'self> {
|
pub struct PageTreeIterator<'a> {
|
||||||
priv stack: ~[&'self mut PageTree],
|
priv stack: ~[&'a mut PageTree],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PageTree {
|
impl PageTree {
|
||||||
|
@ -203,7 +201,7 @@ impl PageTree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> Iterator<@mut Page> for PageTreeIterator<'self> {
|
impl<'a> Iterator<@mut Page> for PageTreeIterator<'a> {
|
||||||
fn next(&mut self) -> Option<@mut Page> {
|
fn next(&mut self) -> Option<@mut Page> {
|
||||||
if !self.stack.is_empty() {
|
if !self.stack.is_empty() {
|
||||||
let next = self.stack.pop();
|
let next = self.stack.pop();
|
||||||
|
@ -254,12 +252,14 @@ impl Page {
|
||||||
let join_port = replace(&mut self.layout_join_port, None);
|
let join_port = replace(&mut self.layout_join_port, None);
|
||||||
match join_port {
|
match join_port {
|
||||||
Some(ref join_port) => {
|
Some(ref join_port) => {
|
||||||
if !join_port.peek() {
|
match join_port.try_recv() {
|
||||||
info!("script: waiting on layout");
|
None => {
|
||||||
|
info!("script: waiting on layout");
|
||||||
|
join_port.recv();
|
||||||
|
}
|
||||||
|
Some(_) => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
join_port.recv();
|
|
||||||
|
|
||||||
debug!("script: layout joined")
|
debug!("script: layout joined")
|
||||||
}
|
}
|
||||||
None => fail!(~"reader forked but no join port?"),
|
None => fail!(~"reader forked but no join port?"),
|
||||||
|
@ -307,7 +307,7 @@ impl Page {
|
||||||
compositor.set_ready_state(PerformingLayout);
|
compositor.set_ready_state(PerformingLayout);
|
||||||
|
|
||||||
// Layout will let us know when it's done.
|
// Layout will let us know when it's done.
|
||||||
let (join_port, join_chan) = comm::stream();
|
let (join_port, join_chan) = Chan::new();
|
||||||
self.layout_join_port = Some(join_port);
|
self.layout_join_port = Some(join_port);
|
||||||
|
|
||||||
self.last_reflow_id += 1;
|
self.last_reflow_id += 1;
|
||||||
|
@ -359,11 +359,6 @@ impl Page {
|
||||||
js_context: js_context,
|
js_context: js_context,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sends the given layout data back to the layout task to be destroyed.
|
|
||||||
pub unsafe fn reap_dead_layout_data(&self, layout_data: LayoutDataRef) {
|
|
||||||
self.layout_chan.send(ReapLayoutDataMsg(layout_data))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Information for one frame in the browsing context.
|
/// Information for one frame in the browsing context.
|
||||||
|
@ -412,7 +407,6 @@ pub struct ScriptTask {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the relevant page from the associated JS Context.
|
/// Returns the relevant page from the associated JS Context.
|
||||||
#[fixed_stack_segment]
|
|
||||||
pub fn page_from_context(js_context: *JSContext) -> *mut Page {
|
pub fn page_from_context(js_context: *JSContext) -> *mut Page {
|
||||||
unsafe {
|
unsafe {
|
||||||
JS_GetContextPrivate(js_context) as *mut Page
|
JS_GetContextPrivate(js_context) as *mut Page
|
||||||
|
@ -468,24 +462,7 @@ impl ScriptTask {
|
||||||
resource_task: ResourceTask,
|
resource_task: ResourceTask,
|
||||||
image_cache_task: ImageCacheTask,
|
image_cache_task: ImageCacheTask,
|
||||||
window_size: Size2D<uint>) {
|
window_size: Size2D<uint>) {
|
||||||
let parms = Cell::new((compositor,
|
spawn(proc() {
|
||||||
layout_chan,
|
|
||||||
port,
|
|
||||||
chan,
|
|
||||||
constellation_chan,
|
|
||||||
resource_task,
|
|
||||||
image_cache_task));
|
|
||||||
// Since SpiderMonkey is blocking it needs to run in its own thread.
|
|
||||||
// If we don't do this then we'll just end up with a bunch of SpiderMonkeys
|
|
||||||
// starving all the other tasks.
|
|
||||||
do spawn_sched(SingleThreaded) {
|
|
||||||
let (compositor,
|
|
||||||
layout_chan,
|
|
||||||
port,
|
|
||||||
chan,
|
|
||||||
constellation_chan,
|
|
||||||
resource_task,
|
|
||||||
image_cache_task) = parms.take();
|
|
||||||
let script_task = ScriptTask::new(id,
|
let script_task = ScriptTask::new(id,
|
||||||
@compositor as @ScriptListener,
|
@compositor as @ScriptListener,
|
||||||
layout_chan,
|
layout_chan,
|
||||||
|
@ -496,7 +473,7 @@ impl ScriptTask {
|
||||||
image_cache_task,
|
image_cache_task,
|
||||||
window_size);
|
window_size);
|
||||||
script_task.start();
|
script_task.start();
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle incoming control messages.
|
/// Handle incoming control messages.
|
||||||
|
@ -520,12 +497,13 @@ impl ScriptTask {
|
||||||
|
|
||||||
// Store new resizes, and gather all other events.
|
// Store new resizes, and gather all other events.
|
||||||
let mut sequential = ~[];
|
let mut sequential = ~[];
|
||||||
|
|
||||||
|
// Receive at least one message so we don't spinloop.
|
||||||
|
let mut event = self.port.recv();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// Receive at least one message so we don't spinloop.
|
|
||||||
let event = self.port.recv();
|
|
||||||
match event {
|
match event {
|
||||||
ResizeMsg(id, size) => {
|
ResizeMsg(id, size) => {
|
||||||
debug!("script got resize message");
|
|
||||||
let page = self.page_tree.find(id).expect("resize sent to nonexistent pipeline").page;
|
let page = self.page_tree.find(id).expect("resize sent to nonexistent pipeline").page;
|
||||||
page.resize_event = Some(size);
|
page.resize_event = Some(size);
|
||||||
}
|
}
|
||||||
|
@ -534,9 +512,9 @@ impl ScriptTask {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Break if there are no more messages.
|
match self.port.try_recv() {
|
||||||
if !self.port.peek() {
|
None => break,
|
||||||
break;
|
Some(ev) => event = ev,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -556,7 +534,7 @@ impl ScriptTask {
|
||||||
self.handle_exit_window_msg(id);
|
self.handle_exit_window_msg(id);
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
ResizeMsg(*) => fail!("should have handled ResizeMsg already"),
|
ResizeMsg(..) => fail!("should have handled ResizeMsg already"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -579,14 +557,14 @@ impl ScriptTask {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles a timer that fired.
|
/// Handles a timer that fired.
|
||||||
#[fixed_stack_segment]
|
|
||||||
fn handle_fire_timer_msg(&mut self, id: PipelineId, timer_data: ~TimerData) {
|
fn handle_fire_timer_msg(&mut self, id: PipelineId, timer_data: ~TimerData) {
|
||||||
let page = self.page_tree.find(id).expect("ScriptTask: received fire timer msg for a
|
let page = self.page_tree.find(id).expect("ScriptTask: received fire timer msg for a
|
||||||
pipeline ID not associated with this script task. This is a bug.").page;
|
pipeline ID not associated with this script task. This is a bug.").page;
|
||||||
let window = page.frame.expect("ScriptTask: Expect a timeout to have a document").window;
|
let window = page.frame.expect("ScriptTask: Expect a timeout to have a document").window;
|
||||||
if !window.active_timers.contains(&timer_data.handle) {
|
if !window.active_timers.contains(&TimerHandle { handle: timer_data.handle, cancel_chan: None }) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
window.active_timers.remove(&TimerHandle { handle: timer_data.handle, cancel_chan: None });
|
||||||
unsafe {
|
unsafe {
|
||||||
let this_value = if timer_data.args.len() > 0 {
|
let this_value = if timer_data.args.len() > 0 {
|
||||||
RUST_JSVAL_TO_OBJECT(timer_data.args[0])
|
RUST_JSVAL_TO_OBJECT(timer_data.args[0])
|
||||||
|
@ -711,7 +689,6 @@ impl ScriptTask {
|
||||||
//
|
//
|
||||||
// Note: We can parse the next document in parallel with any previous documents.
|
// Note: We can parse the next document in parallel with any previous documents.
|
||||||
let document = HTMLDocument::new(window);
|
let document = HTMLDocument::new(window);
|
||||||
|
|
||||||
let html_parsing_result = hubbub_html_parser::parse_html(cx.ptr,
|
let html_parsing_result = hubbub_html_parser::parse_html(cx.ptr,
|
||||||
document,
|
document,
|
||||||
url.clone(),
|
url.clone(),
|
||||||
|
@ -736,7 +713,7 @@ impl ScriptTask {
|
||||||
|
|
||||||
let mut js_scripts = None;
|
let mut js_scripts = None;
|
||||||
loop {
|
loop {
|
||||||
match discovery_port.try_recv() {
|
match discovery_port.recv_opt() {
|
||||||
Some(HtmlDiscoveredScript(scripts)) => {
|
Some(HtmlDiscoveredScript(scripts)) => {
|
||||||
assert!(js_scripts.is_none());
|
assert!(js_scripts.is_none());
|
||||||
js_scripts = Some(scripts);
|
js_scripts = Some(scripts);
|
||||||
|
@ -805,20 +782,20 @@ impl ScriptTask {
|
||||||
None => {
|
None => {
|
||||||
let doc_node = AbstractNode::from_document(document);
|
let doc_node = AbstractNode::from_document(document);
|
||||||
let mut anchors = doc_node.traverse_preorder().filter(|node| node.is_anchor_element());
|
let mut anchors = doc_node.traverse_preorder().filter(|node| node.is_anchor_element());
|
||||||
do anchors.find |node| {
|
anchors.find(|node| {
|
||||||
do node.with_imm_element |elem| {
|
node.with_imm_element(|elem| {
|
||||||
match elem.get_attr(Null, "name") {
|
match elem.get_attr(Null, "name") {
|
||||||
Some(name) => eq_slice(name, fragid),
|
Some(name) => eq_slice(name, fragid),
|
||||||
None => false
|
None => false
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scroll_fragment_point(&self, pipeline_id: PipelineId, page: &mut Page, node: AbstractNode) {
|
fn scroll_fragment_point(&self, pipeline_id: PipelineId, page: &mut Page, node: AbstractNode) {
|
||||||
let (port, chan) = comm::stream();
|
let (port, chan) = Chan::new();
|
||||||
match page.query_layout(ContentBoxQuery(node, chan), port) {
|
match page.query_layout(ContentBoxQuery(node, chan), port) {
|
||||||
ContentBoxResponse(rect) => {
|
ContentBoxResponse(rect) => {
|
||||||
let point = Point2D(to_frac_px(rect.origin.x).to_f32().unwrap(),
|
let point = Point2D(to_frac_px(rect.origin.x).to_f32().unwrap(),
|
||||||
|
@ -870,7 +847,7 @@ impl ScriptTask {
|
||||||
if root.is_none() {
|
if root.is_none() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let (port, chan) = comm::stream();
|
let (port, chan) = Chan::new();
|
||||||
match page.query_layout(HitTestQuery(root.unwrap(), point, chan), port) {
|
match page.query_layout(HitTestQuery(root.unwrap(), point, chan), port) {
|
||||||
Ok(node) => match node {
|
Ok(node) => match node {
|
||||||
HitTestResponse(node) => {
|
HitTestResponse(node) => {
|
||||||
|
@ -886,11 +863,11 @@ impl ScriptTask {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if node.is_element() {
|
if node.is_element() {
|
||||||
do node.with_imm_element |element| {
|
node.with_imm_element(|element| {
|
||||||
if "a" == element.tag_name {
|
if "a" == element.tag_name {
|
||||||
self.load_url_from_element(page, element)
|
self.load_url_from_element(page, element)
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -899,8 +876,8 @@ impl ScriptTask {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MouseDownEvent(*) => {}
|
MouseDownEvent(..) => {}
|
||||||
MouseUpEvent(*) => {}
|
MouseUpEvent(..) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -910,9 +887,9 @@ impl ScriptTask {
|
||||||
for href in attr.iter() {
|
for href in attr.iter() {
|
||||||
debug!("ScriptTask: clicked on link to {:s}", *href);
|
debug!("ScriptTask: clicked on link to {:s}", *href);
|
||||||
let click_frag = href.starts_with("#");
|
let click_frag = href.starts_with("#");
|
||||||
let current_url = do page.url.as_ref().map |&(ref url, _)| {
|
let current_url = page.url.as_ref().map(|&(ref url, _)| {
|
||||||
url.clone()
|
url.clone()
|
||||||
};
|
});
|
||||||
debug!("ScriptTask: current url is {:?}", current_url);
|
debug!("ScriptTask: current url is {:?}", current_url);
|
||||||
let url = make_url(href.to_owned(), current_url);
|
let url = make_url(href.to_owned(), current_url);
|
||||||
|
|
||||||
|
@ -933,29 +910,15 @@ fn shut_down_layout(page: @mut Page) {
|
||||||
page.join_layout();
|
page.join_layout();
|
||||||
|
|
||||||
// Tell the layout task to begin shutting down.
|
// Tell the layout task to begin shutting down.
|
||||||
let (response_port, response_chan) = comm::stream();
|
let (response_port, response_chan) = Chan::new();
|
||||||
page.layout_chan.send(layout_interface::PrepareToExitMsg(response_chan));
|
page.layout_chan.send(layout_interface::PrepareToExitMsg(response_chan));
|
||||||
response_port.recv();
|
response_port.recv();
|
||||||
|
|
||||||
// Destroy all nodes.
|
// Destroy all nodes. Setting frame and js_info to None will trigger our
|
||||||
//
|
// compartment to shutdown, run GC, etc.
|
||||||
// If there was a leak, the layout task will soon crash safely when it detects that local data
|
page.frame = None;
|
||||||
// is missing from its heap.
|
page.js_info = None;
|
||||||
//
|
|
||||||
// FIXME(pcwalton): *But*, for now, because we use `@mut` boxes to hold onto Nodes, if this
|
|
||||||
// didn't destroy all the nodes there will be an *exploitable* security vulnerability as the
|
|
||||||
// nodes try to access the destroyed JS context. We need to change this so that the only actor
|
|
||||||
// who can judge a JS object dead (and thus run its drop glue) is the JS engine itself; thus it
|
|
||||||
// will be impossible (absent a serious flaw in the JS engine) for the JS context to be dead
|
|
||||||
// before nodes are.
|
|
||||||
unsafe {
|
|
||||||
let document_node = AbstractNode::from_document(page.frame.as_ref().unwrap().document);
|
|
||||||
for node in document_node.traverse_preorder() {
|
|
||||||
node.mut_node().reap_layout_data()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Destroy the layout task. If there were node leaks, layout will now crash safely.
|
// Destroy the layout task. If there were node leaks, layout will now crash safely.
|
||||||
page.layout_chan.send(layout_interface::ExitNowMsg);
|
page.layout_chan.send(layout_interface::ExitNowMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,7 @@ pub mod specified {
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn parse(input: &ComponentValue) -> Option<Length> {
|
pub fn parse(input: &ComponentValue) -> Option<Length> {
|
||||||
Length::parse_internal(input, /* negative_ok = */ true)
|
Length::parse_internal(input, /* negative_ok = */ true)
|
||||||
}
|
}
|
||||||
|
@ -87,6 +88,7 @@ pub mod specified {
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[allow(dead_code)]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn parse(input: &ComponentValue) -> Option<LengthOrPercentage> {
|
pub fn parse(input: &ComponentValue) -> Option<LengthOrPercentage> {
|
||||||
LengthOrPercentage::parse_internal(input, /* negative_ok = */ true)
|
LengthOrPercentage::parse_internal(input, /* negative_ok = */ true)
|
||||||
|
@ -145,6 +147,7 @@ pub mod specified {
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[allow(dead_code)]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn parse(input: &ComponentValue) -> Option<LengthOrPercentageOrNone> {
|
pub fn parse(input: &ComponentValue) -> Option<LengthOrPercentageOrNone> {
|
||||||
LengthOrPercentageOrNone::parse_internal(input, /* negative_ok = */ true)
|
LengthOrPercentageOrNone::parse_internal(input, /* negative_ok = */ true)
|
||||||
|
|
|
@ -31,7 +31,7 @@ pub fn log_css_error(location: SourceLocation, message: &str) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn with_errors_silenced<T>(f: &fn() -> T) -> T {
|
pub fn with_errors_silenced<T>(f: || -> T) -> T {
|
||||||
local_data::set(silence_errors, ());
|
local_data::set(silence_errors, ());
|
||||||
let result = f();
|
let result = f();
|
||||||
local_data::pop(silence_errors);
|
local_data::pop(silence_errors);
|
||||||
|
|
|
@ -121,12 +121,12 @@ pub fn parse_media_query_list(input: &[ComponentValue]) -> MediaQueryList {
|
||||||
|
|
||||||
impl MediaQueryList {
|
impl MediaQueryList {
|
||||||
pub fn evaluate(&self, device: &Device) -> bool {
|
pub fn evaluate(&self, device: &Device) -> bool {
|
||||||
do self.media_queries.iter().any |mq| {
|
self.media_queries.iter().any(|mq| {
|
||||||
match mq.media_type {
|
match mq.media_type {
|
||||||
MediaType(media_type) => media_type == device.media_type,
|
MediaType(media_type) => media_type == device.media_type,
|
||||||
All => true,
|
All => true,
|
||||||
}
|
}
|
||||||
// TODO: match Level 3 expressions
|
// TODO: match Level 3 expressions
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ pub trait TNode<E:TElement> : Clone {
|
||||||
fn is_element(&self) -> bool;
|
fn is_element(&self) -> bool;
|
||||||
|
|
||||||
/// FIXME(pcwalton): This should not use the `with` pattern.
|
/// FIXME(pcwalton): This should not use the `with` pattern.
|
||||||
fn with_element<R>(&self, f: &fn(&E) -> R) -> R;
|
fn with_element<'a, R>(&self, f: |&E| -> R) -> R;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait TElement {
|
pub trait TElement {
|
||||||
|
|
|
@ -74,8 +74,8 @@ pub mod longhands {
|
||||||
pub fn parse_declared(input: &[ComponentValue])
|
pub fn parse_declared(input: &[ComponentValue])
|
||||||
-> Option<DeclaredValue<SpecifiedValue>> {
|
-> Option<DeclaredValue<SpecifiedValue>> {
|
||||||
match CSSWideKeyword::parse(input) {
|
match CSSWideKeyword::parse(input) {
|
||||||
Some(Left(keyword)) => Some(CSSWideKeyword(keyword)),
|
Some(Some(keyword)) => Some(CSSWideKeyword(keyword)),
|
||||||
Some(Right(Unset)) => Some(CSSWideKeyword(${
|
Some(None) => Some(CSSWideKeyword(${
|
||||||
"Inherit" if inherited else "Initial"})),
|
"Inherit" if inherited else "Initial"})),
|
||||||
None => parse_specified(input),
|
None => parse_specified(input),
|
||||||
}
|
}
|
||||||
|
@ -118,14 +118,14 @@ pub mod longhands {
|
||||||
${to_rust_ident(values.split()[0])}
|
${to_rust_ident(values.split()[0])}
|
||||||
}
|
}
|
||||||
pub fn from_component_value(v: &ComponentValue) -> Option<SpecifiedValue> {
|
pub fn from_component_value(v: &ComponentValue) -> Option<SpecifiedValue> {
|
||||||
do get_ident_lower(v).and_then |keyword| {
|
get_ident_lower(v).and_then(|keyword| {
|
||||||
match keyword.as_slice() {
|
match keyword.as_slice() {
|
||||||
% for value in values.split():
|
% for value in values.split():
|
||||||
"${value}" => Some(${to_rust_ident(value)}),
|
"${value}" => Some(${to_rust_ident(value)}),
|
||||||
% endfor
|
% endfor
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
</%self:single_component_value>
|
</%self:single_component_value>
|
||||||
</%def>
|
</%def>
|
||||||
|
@ -648,12 +648,12 @@ pub mod longhands {
|
||||||
/// <length> | <percentage>
|
/// <length> | <percentage>
|
||||||
/// TODO: support <absolute-size> and <relative-size>
|
/// TODO: support <absolute-size> and <relative-size>
|
||||||
pub fn from_component_value(input: &ComponentValue) -> Option<SpecifiedValue> {
|
pub fn from_component_value(input: &ComponentValue) -> Option<SpecifiedValue> {
|
||||||
do specified::LengthOrPercentage::parse_non_negative(input).map |value| {
|
specified::LengthOrPercentage::parse_non_negative(input).map(|value| {
|
||||||
match value {
|
match value {
|
||||||
specified::LP_Length(value) => value,
|
specified::LP_Length(value) => value,
|
||||||
specified::LP_Percentage(value) => specified::Em(value),
|
specified::LP_Percentage(value) => specified::Em(value),
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
</%self:single_component_value>
|
</%self:single_component_value>
|
||||||
|
|
||||||
|
@ -767,9 +767,9 @@ pub mod shorthands {
|
||||||
|
|
||||||
// TODO: other background-* properties
|
// TODO: other background-* properties
|
||||||
<%self:shorthand name="background" sub_properties="background-color">
|
<%self:shorthand name="background" sub_properties="background-color">
|
||||||
do one_component_value(input).and_then(specified::CSSColor::parse).map |color| {
|
one_component_value(input).and_then(specified::CSSColor::parse).map(|color| {
|
||||||
Longhands { background_color: Some(color) }
|
Longhands { background_color: Some(color) }
|
||||||
}
|
})
|
||||||
</%self:shorthand>
|
</%self:shorthand>
|
||||||
|
|
||||||
${four_sides_shorthand("margin", "margin-%s", "margin_top::from_component_value")}
|
${four_sides_shorthand("margin", "margin-%s", "margin_top::from_component_value")}
|
||||||
|
@ -818,13 +818,13 @@ pub mod shorthands {
|
||||||
'border-%s-%s' % (side, prop)
|
'border-%s-%s' % (side, prop)
|
||||||
for prop in ['color', 'style', 'width']
|
for prop in ['color', 'style', 'width']
|
||||||
)}">
|
)}">
|
||||||
do parse_border(input).map |(color, style, width)| {
|
parse_border(input).map(|(color, style, width)| {
|
||||||
Longhands {
|
Longhands {
|
||||||
% for prop in ["color", "style", "width"]:
|
% for prop in ["color", "style", "width"]:
|
||||||
${"border_%s_%s: %s," % (side, prop, prop)}
|
${"border_%s_%s: %s," % (side, prop, prop)}
|
||||||
% endfor
|
% endfor
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
</%self:shorthand>
|
</%self:shorthand>
|
||||||
% endfor
|
% endfor
|
||||||
|
|
||||||
|
@ -833,7 +833,7 @@ pub mod shorthands {
|
||||||
for side in ['top', 'right', 'bottom', 'left']
|
for side in ['top', 'right', 'bottom', 'left']
|
||||||
for prop in ['color', 'style', 'width']
|
for prop in ['color', 'style', 'width']
|
||||||
)}">
|
)}">
|
||||||
do parse_border(input).map |(color, style, width)| {
|
parse_border(input).map(|(color, style, width)| {
|
||||||
Longhands {
|
Longhands {
|
||||||
% for side in ["top", "right", "bottom", "left"]:
|
% for side in ["top", "right", "bottom", "left"]:
|
||||||
% for prop in ["color", "style", "width"]:
|
% for prop in ["color", "style", "width"]:
|
||||||
|
@ -841,7 +841,7 @@ pub mod shorthands {
|
||||||
% endfor
|
% endfor
|
||||||
% endfor
|
% endfor
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
</%self:shorthand>
|
</%self:shorthand>
|
||||||
|
|
||||||
<%self:shorthand name="font" sub_properties="font-style font-variant font-weight
|
<%self:shorthand name="font" sub_properties="font-style font-variant font-weight
|
||||||
|
@ -966,18 +966,16 @@ pub enum CSSWideKeyword {
|
||||||
Inherit,
|
Inherit,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Unset;
|
|
||||||
|
|
||||||
impl CSSWideKeyword {
|
impl CSSWideKeyword {
|
||||||
pub fn parse(input: &[ComponentValue]) -> Option<Either<CSSWideKeyword, Unset>> {
|
pub fn parse(input: &[ComponentValue]) -> Option<Option<CSSWideKeyword>> {
|
||||||
do one_component_value(input).and_then(get_ident_lower).and_then |keyword| {
|
one_component_value(input).and_then(get_ident_lower).and_then(|keyword| {
|
||||||
match keyword.as_slice() {
|
match keyword.as_slice() {
|
||||||
"initial" => Some(Left(Initial)),
|
"initial" => Some(Some(Initial)),
|
||||||
"inherit" => Some(Left(Inherit)),
|
"inherit" => Some(Some(Inherit)),
|
||||||
"unset" => Some(Right(Unset)),
|
"unset" => Some(None),
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1018,14 +1016,14 @@ impl PropertyDeclaration {
|
||||||
% endfor
|
% endfor
|
||||||
% for shorthand in SHORTHANDS:
|
% for shorthand in SHORTHANDS:
|
||||||
"${shorthand.name}" => match CSSWideKeyword::parse(value) {
|
"${shorthand.name}" => match CSSWideKeyword::parse(value) {
|
||||||
Some(Left(keyword)) => {
|
Some(Some(keyword)) => {
|
||||||
% for sub_property in shorthand.sub_properties:
|
% for sub_property in shorthand.sub_properties:
|
||||||
result_list.push(${sub_property.ident}_declaration(
|
result_list.push(${sub_property.ident}_declaration(
|
||||||
CSSWideKeyword(keyword)
|
CSSWideKeyword(keyword)
|
||||||
));
|
));
|
||||||
% endfor
|
% endfor
|
||||||
},
|
},
|
||||||
Some(Right(Unset)) => {
|
Some(None) => {
|
||||||
% for sub_property in shorthand.sub_properties:
|
% for sub_property in shorthand.sub_properties:
|
||||||
result_list.push(${sub_property.ident}_declaration(
|
result_list.push(${sub_property.ident}_declaration(
|
||||||
CSSWideKeyword(${
|
CSSWideKeyword(${
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use extra::arc::Arc;
|
use extra::arc::Arc;
|
||||||
use extra::sort::tim_sort;
|
|
||||||
use std::ascii::StrAsciiExt;
|
use std::ascii::StrAsciiExt;
|
||||||
use std::hashmap::HashMap;
|
use std::hashmap::HashMap;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
@ -86,11 +85,9 @@ impl SelectorMap {
|
||||||
|
|
||||||
match element.get_attr(None, "class") {
|
match element.get_attr(None, "class") {
|
||||||
Some(ref class_attr) => {
|
Some(ref class_attr) => {
|
||||||
for class in class_attr.split_iter(SELECTOR_WHITESPACE) {
|
for class in class_attr.split(SELECTOR_WHITESPACE) {
|
||||||
SelectorMap::get_matching_rules_from_hash(node,
|
SelectorMap::get_matching_rules_from_hash(
|
||||||
&self.class_hash,
|
node, &self.class_hash, class, matching_rules_list);
|
||||||
class,
|
|
||||||
matching_rules_list)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {}
|
None => {}
|
||||||
|
@ -108,7 +105,13 @@ impl SelectorMap {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Sort only the rules we just added.
|
// Sort only the rules we just added.
|
||||||
tim_sort(matching_rules_list.mut_slice_from(init_len));
|
matching_rules_list.mut_slice_from(init_len).sort_by(|a, b| {
|
||||||
|
if a < b {
|
||||||
|
Less
|
||||||
|
} else {
|
||||||
|
Greater
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_matching_rules_from_hash<E:TElement,
|
fn get_matching_rules_from_hash<E:TElement,
|
||||||
|
@ -292,11 +295,11 @@ impl Stylist {
|
||||||
);
|
);
|
||||||
|
|
||||||
let device = &Device { media_type: Screen }; // TODO, use Print when printing
|
let device = &Device { media_type: Screen }; // TODO, use Print when printing
|
||||||
do iter_style_rules(stylesheet.rules.as_slice(), device) |style_rule| {
|
iter_style_rules(stylesheet.rules.as_slice(), device, |style_rule| {
|
||||||
append!(normal);
|
append!(normal);
|
||||||
append!(important);
|
append!(important);
|
||||||
self.rules_source_order += 1;
|
self.rules_source_order += 1;
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the applicable CSS declarations for the given element. This corresponds to
|
/// Returns the applicable CSS declarations for the given element. This corresponds to
|
||||||
|
@ -344,7 +347,7 @@ impl Stylist {
|
||||||
let mut declaration_iter = matching_rules_list.move_iter().map(|rule| {
|
let mut declaration_iter = matching_rules_list.move_iter().map(|rule| {
|
||||||
let Rule {
|
let Rule {
|
||||||
declarations,
|
declarations,
|
||||||
_
|
..
|
||||||
} = rule;
|
} = rule;
|
||||||
declarations
|
declarations
|
||||||
});
|
});
|
||||||
|
@ -436,9 +439,9 @@ impl Ord for Rule {
|
||||||
|
|
||||||
fn matches_compound_selector<E:TElement,N:TNode<E>>(selector: &CompoundSelector, element: &N)
|
fn matches_compound_selector<E:TElement,N:TNode<E>>(selector: &CompoundSelector, element: &N)
|
||||||
-> bool {
|
-> bool {
|
||||||
if !do selector.simple_selectors.iter().all |simple_selector| {
|
if !selector.simple_selectors.iter().all(|simple_selector| {
|
||||||
matches_simple_selector(simple_selector, element)
|
matches_simple_selector(simple_selector, element)
|
||||||
} {
|
}) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
match selector.next {
|
match selector.next {
|
||||||
|
@ -479,77 +482,77 @@ fn matches_simple_selector<E:TElement,N:TNode<E>>(selector: &SimpleSelector, ele
|
||||||
// TODO: case-sensitivity depends on the document type
|
// TODO: case-sensitivity depends on the document type
|
||||||
// TODO: intern element names
|
// TODO: intern element names
|
||||||
LocalNameSelector(ref name) => {
|
LocalNameSelector(ref name) => {
|
||||||
do element.with_element |element: &E| {
|
element.with_element(|element: &E| {
|
||||||
element.get_local_name().eq_ignore_ascii_case(name.as_slice())
|
element.get_local_name().eq_ignore_ascii_case(name.as_slice())
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
NamespaceSelector(ref url) => {
|
NamespaceSelector(ref url) => {
|
||||||
do element.with_element |element: &E| {
|
element.with_element(|element: &E| {
|
||||||
element.get_namespace_url() == url.as_slice()
|
element.get_namespace_url() == url.as_slice()
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
// TODO: case-sensitivity depends on the document type and quirks mode
|
// TODO: case-sensitivity depends on the document type and quirks mode
|
||||||
// TODO: cache and intern IDs on elements.
|
// TODO: cache and intern IDs on elements.
|
||||||
IDSelector(ref id) => {
|
IDSelector(ref id) => {
|
||||||
do element.with_element |element: &E| {
|
element.with_element(|element: &E| {
|
||||||
match element.get_attr(None, "id") {
|
match element.get_attr(None, "id") {
|
||||||
Some(attr) => str::eq_slice(attr, *id),
|
Some(attr) => str::eq_slice(attr, *id),
|
||||||
None => false
|
None => false
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
// TODO: cache and intern classe names on elements.
|
// TODO: cache and intern classe names on elements.
|
||||||
ClassSelector(ref class) => {
|
ClassSelector(ref class) => {
|
||||||
do element.with_element |element: &E| {
|
element.with_element(|element: &E| {
|
||||||
match element.get_attr(None, "class") {
|
match element.get_attr(None, "class") {
|
||||||
None => false,
|
None => false,
|
||||||
// TODO: case-sensitivity depends on the document type and quirks mode
|
// TODO: case-sensitivity depends on the document type and quirks mode
|
||||||
Some(ref class_attr)
|
Some(ref class_attr)
|
||||||
=> class_attr.split_iter(SELECTOR_WHITESPACE).any(|c| c == class.as_slice()),
|
=> class_attr.split(SELECTOR_WHITESPACE).any(|c| c == class.as_slice()),
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
AttrExists(ref attr) => match_attribute(attr, element, |_| true),
|
AttrExists(ref attr) => match_attribute(attr, element, |_| true),
|
||||||
AttrEqual(ref attr, ref value) => match_attribute(attr, element, |v| v == value.as_slice()),
|
AttrEqual(ref attr, ref value) => match_attribute(attr, element, |v| v == value.as_slice()),
|
||||||
AttrIncludes(ref attr, ref value) => do match_attribute(attr, element) |attr_value| {
|
AttrIncludes(ref attr, ref value) => match_attribute(attr, element, |attr_value| {
|
||||||
attr_value.split_iter(SELECTOR_WHITESPACE).any(|v| v == value.as_slice())
|
attr_value.split(SELECTOR_WHITESPACE).any(|v| v == value.as_slice())
|
||||||
},
|
}),
|
||||||
AttrDashMatch(ref attr, ref value, ref dashing_value)
|
AttrDashMatch(ref attr, ref value, ref dashing_value)
|
||||||
=> do match_attribute(attr, element) |attr_value| {
|
=> match_attribute(attr, element, |attr_value| {
|
||||||
attr_value == value.as_slice() || attr_value.starts_with(dashing_value.as_slice())
|
attr_value == value.as_slice() || attr_value.starts_with(dashing_value.as_slice())
|
||||||
},
|
}),
|
||||||
AttrPrefixMatch(ref attr, ref value) => do match_attribute(attr, element) |attr_value| {
|
AttrPrefixMatch(ref attr, ref value) => match_attribute(attr, element, |attr_value| {
|
||||||
attr_value.starts_with(value.as_slice())
|
attr_value.starts_with(value.as_slice())
|
||||||
},
|
}),
|
||||||
AttrSubstringMatch(ref attr, ref value) => do match_attribute(attr, element) |attr_value| {
|
AttrSubstringMatch(ref attr, ref value) => match_attribute(attr, element, |attr_value| {
|
||||||
attr_value.contains(value.as_slice())
|
attr_value.contains(value.as_slice())
|
||||||
},
|
}),
|
||||||
AttrSuffixMatch(ref attr, ref value) => do match_attribute(attr, element) |attr_value| {
|
AttrSuffixMatch(ref attr, ref value) => match_attribute(attr, element, |attr_value| {
|
||||||
attr_value.ends_with(value.as_slice())
|
attr_value.ends_with(value.as_slice())
|
||||||
},
|
}),
|
||||||
|
|
||||||
|
|
||||||
AnyLink => {
|
AnyLink => {
|
||||||
do element.with_element |element: &E| {
|
element.with_element(|element: &E| {
|
||||||
element.get_link().is_some()
|
element.get_link().is_some()
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
Link => {
|
Link => {
|
||||||
do element.with_element |element: &E| {
|
element.with_element(|element: &E| {
|
||||||
match element.get_link() {
|
match element.get_link() {
|
||||||
Some(url) => !url_is_visited(url),
|
Some(url) => !url_is_visited(url),
|
||||||
None => false,
|
None => false,
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
Visited => {
|
Visited => {
|
||||||
do element.with_element |element: &E| {
|
element.with_element(|element: &E| {
|
||||||
match element.get_link() {
|
match element.get_link() {
|
||||||
Some(url) => url_is_visited(url),
|
Some(url) => url_is_visited(url),
|
||||||
None => false,
|
None => false,
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
FirstChild => matches_first_child(element),
|
FirstChild => matches_first_child(element),
|
||||||
|
@ -583,7 +586,8 @@ fn url_is_visited(_url: &str) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn matches_generic_nth_child<E:TElement,
|
fn matches_generic_nth_child<'a,
|
||||||
|
E:TElement,
|
||||||
N:TNode<E>>(
|
N:TNode<E>>(
|
||||||
element: &N,
|
element: &N,
|
||||||
a: i32,
|
a: i32,
|
||||||
|
@ -601,15 +605,6 @@ fn matches_generic_nth_child<E:TElement,
|
||||||
None => return false
|
None => return false
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut element_local_name = "";
|
|
||||||
let mut element_namespace = "";
|
|
||||||
if is_of_type {
|
|
||||||
do element.with_element |element: &E| {
|
|
||||||
element_local_name = element.get_local_name();
|
|
||||||
element_namespace = element.get_namespace_url();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut index = 1;
|
let mut index = 1;
|
||||||
loop {
|
loop {
|
||||||
if is_from_end {
|
if is_from_end {
|
||||||
|
@ -626,12 +621,14 @@ fn matches_generic_nth_child<E:TElement,
|
||||||
|
|
||||||
if node.is_element() {
|
if node.is_element() {
|
||||||
if is_of_type {
|
if is_of_type {
|
||||||
do node.with_element |node: &E| {
|
element.with_element(|element: &E| {
|
||||||
if element_local_name == node.get_local_name() &&
|
node.with_element(|node: &E| {
|
||||||
element_namespace == node.get_namespace_url() {
|
if element.get_local_name() == node.get_local_name() &&
|
||||||
index += 1;
|
element.get_namespace_url() == node.get_namespace_url() {
|
||||||
}
|
index += 1;
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
index += 1;
|
index += 1;
|
||||||
}
|
}
|
||||||
|
@ -704,18 +701,17 @@ fn match_attribute<E:TElement,
|
||||||
N:TNode<E>>(
|
N:TNode<E>>(
|
||||||
attr: &AttrSelector,
|
attr: &AttrSelector,
|
||||||
element: &N,
|
element: &N,
|
||||||
f: &fn(&str) -> bool)
|
f: |&str| -> bool)
|
||||||
-> bool {
|
-> bool {
|
||||||
do element.with_element |element: &E| {
|
element.with_element(|element: &E| {
|
||||||
// FIXME: avoid .clone() here? See #1367
|
// FIXME: avoid .clone() here? See #1367
|
||||||
match element.get_attr(attr.namespace.clone(), attr.name) {
|
match element.get_attr(attr.namespace.clone(), attr.name) {
|
||||||
None => false,
|
None => false,
|
||||||
Some(value) => f(value)
|
Some(value) => f(value)
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use extra::arc::Arc;
|
use extra::arc::Arc;
|
||||||
|
|
|
@ -27,9 +27,6 @@ pub struct Selector {
|
||||||
specificity: u32,
|
specificity: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static STYLE_ATTRIBUTE_SPECIFICITY: u32 = 1 << 31;
|
|
||||||
|
|
||||||
|
|
||||||
#[deriving(Eq, Clone)]
|
#[deriving(Eq, Clone)]
|
||||||
pub enum PseudoElement {
|
pub enum PseudoElement {
|
||||||
Before,
|
Before,
|
||||||
|
@ -203,19 +200,19 @@ fn compute_specificity(mut selector: &CompoundSelector,
|
||||||
specificity: &mut Specificity) {
|
specificity: &mut Specificity) {
|
||||||
for simple_selector in simple_selectors.iter() {
|
for simple_selector in simple_selectors.iter() {
|
||||||
match simple_selector {
|
match simple_selector {
|
||||||
&LocalNameSelector(*) => specificity.element_selectors += 1,
|
&LocalNameSelector(..) => specificity.element_selectors += 1,
|
||||||
&IDSelector(*) => specificity.id_selectors += 1,
|
&IDSelector(..) => specificity.id_selectors += 1,
|
||||||
&ClassSelector(*)
|
&ClassSelector(..)
|
||||||
| &AttrExists(*) | &AttrEqual(*) | &AttrIncludes(*) | &AttrDashMatch(*)
|
| &AttrExists(..) | &AttrEqual(..) | &AttrIncludes(..) | &AttrDashMatch(..)
|
||||||
| &AttrPrefixMatch(*) | &AttrSubstringMatch(*) | &AttrSuffixMatch(*)
|
| &AttrPrefixMatch(..) | &AttrSubstringMatch(..) | &AttrSuffixMatch(..)
|
||||||
| &AnyLink | &Link | &Visited
|
| &AnyLink | &Link | &Visited
|
||||||
| &FirstChild | &LastChild | &OnlyChild | &Root
|
| &FirstChild | &LastChild | &OnlyChild | &Root
|
||||||
// | &Empty | &Lang(*)
|
// | &Empty | &Lang(*)
|
||||||
| &NthChild(*) | &NthLastChild(*)
|
| &NthChild(..) | &NthLastChild(..)
|
||||||
| &NthOfType(*) | &NthLastOfType(*)
|
| &NthOfType(..) | &NthLastOfType(..)
|
||||||
| &FirstOfType | &LastOfType | &OnlyOfType
|
| &FirstOfType | &LastOfType | &OnlyOfType
|
||||||
=> specificity.class_like_selectors += 1,
|
=> specificity.class_like_selectors += 1,
|
||||||
&NamespaceSelector(*) => (),
|
&NamespaceSelector(..) => (),
|
||||||
&Negation(ref negated)
|
&Negation(ref negated)
|
||||||
=> simple_selectors_specificity(negated.as_slice(), specificity),
|
=> simple_selectors_specificity(negated.as_slice(), specificity),
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,21 +2,18 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#[link(name = "style",
|
#[crate_id = "github.com/mozilla/servo#style:0.1"];
|
||||||
vers = "0.1",
|
#[crate_type = "lib"];
|
||||||
uuid = "4a50ca00-3283-11e3-aa6e-0800200c9a66",
|
|
||||||
url = "http://servo.org/")];
|
|
||||||
|
|
||||||
#[comment = "The Servo Parallel Browser Project"];
|
#[comment = "The Servo Parallel Browser Project"];
|
||||||
#[license = "MPL"];
|
#[license = "MPL"];
|
||||||
#[crate_type = "lib"];
|
|
||||||
|
|
||||||
#[feature(globs, macro_rules, managed_boxes)];
|
#[feature(globs, macro_rules, managed_boxes)];
|
||||||
|
|
||||||
extern mod extra;
|
extern mod extra;
|
||||||
extern mod cssparser;
|
extern mod cssparser;
|
||||||
extern mod encoding;
|
extern mod encoding;
|
||||||
extern mod servo_util (name = "util");
|
extern mod servo_util = "util";
|
||||||
|
|
||||||
|
|
||||||
// Public API
|
// Public API
|
||||||
|
|
|
@ -151,7 +151,7 @@ pub fn parse_nested_at_rule(lower_name: &str, rule: AtRule,
|
||||||
|
|
||||||
|
|
||||||
pub fn iter_style_rules<'a>(rules: &[CSSRule], device: &media_queries::Device,
|
pub fn iter_style_rules<'a>(rules: &[CSSRule], device: &media_queries::Device,
|
||||||
callback: &fn(&StyleRule)) {
|
callback: |&StyleRule|) {
|
||||||
for rule in rules.iter() {
|
for rule in rules.iter() {
|
||||||
match *rule {
|
match *rule {
|
||||||
CSSStyleRule(ref rule) => callback(rule),
|
CSSStyleRule(ref rule) => callback(rule),
|
||||||
|
|
|
@ -7,7 +7,7 @@ use std::hashmap::HashMap;
|
||||||
pub trait Cache<K: Eq, V: Clone> {
|
pub trait Cache<K: Eq, V: Clone> {
|
||||||
fn insert(&mut self, key: K, value: V);
|
fn insert(&mut self, key: K, value: V);
|
||||||
fn find(&mut self, key: &K) -> Option<V>;
|
fn find(&mut self, key: &K) -> Option<V>;
|
||||||
fn find_or_create(&mut self, key: &K, blk: &fn(&K) -> V) -> V;
|
fn find_or_create(&mut self, key: &K, blk: |&K| -> V) -> V;
|
||||||
fn evict_all(&mut self);
|
fn evict_all(&mut self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ impl<K: Clone + Eq, V: Clone> Cache<K,V> for MonoCache<K,V> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_or_create(&mut self, key: &K, blk: &fn(&K) -> V) -> V {
|
fn find_or_create(&mut self, key: &K, blk: |&K| -> V) -> V {
|
||||||
match self.find(key) {
|
match self.find(key) {
|
||||||
Some(value) => value,
|
Some(value) => value,
|
||||||
None => {
|
None => {
|
||||||
|
@ -87,7 +87,7 @@ impl<K: Clone + Eq + Hash, V: Clone> Cache<K,V> for HashCache<K,V> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_or_create(&mut self, key: &K, blk: &fn(&K) -> V) -> V {
|
fn find_or_create(&mut self, key: &K, blk: |&K| -> V) -> V {
|
||||||
self.entries.find_or_insert_with(key.clone(), blk).clone()
|
self.entries.find_or_insert_with(key.clone(), blk).clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,7 +149,7 @@ impl<K: Clone + Eq, V: Clone> Cache<K,V> for LRUCache<K,V> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_or_create(&mut self, key: &K, blk: &fn(&K) -> V) -> V {
|
fn find_or_create(&mut self, key: &K, blk: |&K| -> V) -> V {
|
||||||
match self.entries.iter().position(|&(ref k, _)| *k == *key) {
|
match self.entries.iter().position(|&(ref k, _)| *k == *key) {
|
||||||
Some(pos) => self.touch(pos),
|
Some(pos) => self.touch(pos),
|
||||||
None => {
|
None => {
|
||||||
|
@ -191,7 +191,7 @@ fn test_lru_cache() {
|
||||||
assert!(cache.find(&4).is_some()); // (2, 4) (no change)
|
assert!(cache.find(&4).is_some()); // (2, 4) (no change)
|
||||||
|
|
||||||
// Test find_or_create.
|
// Test find_or_create.
|
||||||
do cache.find_or_create(&1) |_| { one }; // (4, 1)
|
cache.find_or_create(&1, |_| { one }); // (4, 1)
|
||||||
|
|
||||||
assert!(cache.find(&1).is_some()); // (4, 1) (no change)
|
assert!(cache.find(&1).is_some()); // (4, 1) (no change)
|
||||||
assert!(cache.find(&2).is_none()); // (4, 1) (no change)
|
assert!(cache.find(&2).is_none()); // (4, 1) (no change)
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use std::rt::io;
|
use std::io;
|
||||||
use std::rt::io::Writer;
|
use std::io::Writer;
|
||||||
use std::vec::raw::buf_as_slice;
|
use std::vec::raw::buf_as_slice;
|
||||||
use std::cast::transmute;
|
use std::cast::transmute;
|
||||||
use std::mem::size_of;
|
use std::mem::size_of;
|
||||||
|
|
|
@ -124,10 +124,6 @@ impl ToPrimitive for Au {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn box<T:Clone + Ord + Add<T,T> + Sub<T,T>>(x: T, y: T, w: T, h: T) -> Rect<T> {
|
|
||||||
Rect(Point2D(x, y), Size2D(w, h))
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Au {
|
impl Au {
|
||||||
/// FIXME(pcwalton): Workaround for lack of cross crate inlining of newtype structs!
|
/// FIXME(pcwalton): Workaround for lack of cross crate inlining of newtype structs!
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use std::rt::io::{io_error, IoError};
|
use std::io::{io_error, IoError};
|
||||||
|
|
||||||
/// Helper for catching an I/O error and wrapping it in a Result object. The
|
/// Helper for catching an I/O error and wrapping it in a Result object. The
|
||||||
/// return result will be the last I/O error that happened or the result of the
|
/// return result will be the last I/O error that happened or the result of the
|
||||||
|
@ -10,7 +10,7 @@ use std::rt::io::{io_error, IoError};
|
||||||
///
|
///
|
||||||
/// FIXME: This is a copy of std::rt::io::result which doesn't exist yet in our
|
/// FIXME: This is a copy of std::rt::io::result which doesn't exist yet in our
|
||||||
/// version of Rust. We should switch after the next Rust upgrade.
|
/// version of Rust. We should switch after the next Rust upgrade.
|
||||||
pub fn result<T>(cb: &fn() -> T) -> Result<T, IoError> {
|
pub fn result<T>(cb: || -> T) -> Result<T, IoError> {
|
||||||
let mut err = None;
|
let mut err = None;
|
||||||
let ret = io_error::cond.trap(|e| err = Some(e)).inside(cb);
|
let ret = io_error::cond.trap(|e| err = Some(e)).inside(cb);
|
||||||
match err {
|
match err {
|
||||||
|
|
|
@ -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.
|
//! Timing functions.
|
||||||
|
|
||||||
use extra::sort::tim_sort;
|
|
||||||
use extra::time::precise_time_ns;
|
use extra::time::precise_time_ns;
|
||||||
use extra::treemap::TreeMap;
|
use extra::treemap::TreeMap;
|
||||||
use std::comm::{Port, SendDeferred, SharedChan};
|
use std::comm::{Port, SharedChan};
|
||||||
use std::iter::AdditiveIterator;
|
use std::iter::AdditiveIterator;
|
||||||
use std::rt::io::timer::Timer;
|
|
||||||
use std::task::spawn_with;
|
|
||||||
|
// TODO: This code should be changed to use the commented code that uses timers
|
||||||
|
// directly, once native timers land in Rust.
|
||||||
|
extern {
|
||||||
|
pub fn usleep(secs: u64) -> u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Timer;
|
||||||
|
impl Timer {
|
||||||
|
pub fn sleep(ms: u64) {
|
||||||
|
//
|
||||||
|
// let mut timer = Timer::new().unwrap();
|
||||||
|
// timer.sleep(period);
|
||||||
|
unsafe { usleep((ms * 1000)); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// front-end representation of the profiler used to communicate with the profiler
|
// front-end representation of the profiler used to communicate with the profiler
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone)]
|
||||||
pub struct ProfilerChan(SharedChan<ProfilerMsg>);
|
pub struct ProfilerChan(SharedChan<ProfilerMsg>);
|
||||||
|
|
||||||
impl ProfilerChan {
|
impl ProfilerChan {
|
||||||
pub fn new(chan: Chan<ProfilerMsg>) -> ProfilerChan {
|
pub fn send(&self, msg: ProfilerMsg) {
|
||||||
ProfilerChan(SharedChan::new(chan))
|
(**self).send(msg);
|
||||||
}
|
|
||||||
|
|
||||||
pub fn send_deferred(&self, msg: ProfilerMsg) {
|
|
||||||
(**self).send_deferred(msg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,32 +111,35 @@ pub struct Profiler {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Profiler {
|
impl Profiler {
|
||||||
pub fn create(port: Port<ProfilerMsg>, chan: ProfilerChan, period: Option<f64>) {
|
pub fn create(period: Option<f64>) -> ProfilerChan {
|
||||||
|
let (port, chan) = SharedChan::new();
|
||||||
match period {
|
match period {
|
||||||
Some(period) => {
|
Some(period) => {
|
||||||
let period = (period * 1000f64) as u64;
|
let period = (period * 1000f64) as u64;
|
||||||
do spawn {
|
let chan = chan.clone();
|
||||||
let mut timer = Timer::new().unwrap();
|
spawn(proc() {
|
||||||
loop {
|
loop {
|
||||||
timer.sleep(period);
|
Timer::sleep(period);
|
||||||
if !chan.try_send(PrintMsg) {
|
if !chan.try_send(PrintMsg) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
// Spawn the profiler
|
// Spawn the profiler
|
||||||
do spawn_with(port) |port| {
|
spawn(proc() {
|
||||||
let mut profiler = Profiler::new(port);
|
let mut profiler = Profiler::new(port);
|
||||||
profiler.start();
|
profiler.start();
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
// no-op to handle profiler messages when the profiler is inactive
|
// no-op to handle profiler messages when the profiler is inactive
|
||||||
do spawn_with(port) |port| {
|
spawn(proc() {
|
||||||
while port.try_recv().is_some() {}
|
while port.recv_opt().is_some() {}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ProfilerChan(chan)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(port: Port<ProfilerMsg>) -> Profiler {
|
pub fn new(port: Port<ProfilerMsg>) -> Profiler {
|
||||||
|
@ -138,7 +152,7 @@ impl Profiler {
|
||||||
|
|
||||||
pub fn start(&mut self) {
|
pub fn start(&mut self) {
|
||||||
loop {
|
loop {
|
||||||
let msg = self.port.try_recv();
|
let msg = self.port.recv_opt();
|
||||||
match msg {
|
match msg {
|
||||||
Some (msg) => self.handle_msg(msg),
|
Some (msg) => self.handle_msg(msg),
|
||||||
None => break
|
None => break
|
||||||
|
@ -151,7 +165,7 @@ impl Profiler {
|
||||||
TimeMsg(category, t) => self.buckets.find_mut(&category).unwrap().push(t),
|
TimeMsg(category, t) => self.buckets.find_mut(&category).unwrap().push(t),
|
||||||
PrintMsg => match self.last_msg {
|
PrintMsg => match self.last_msg {
|
||||||
// only print if more data has arrived since the last printout
|
// only print if more data has arrived since the last printout
|
||||||
Some(TimeMsg(*)) => self.print_buckets(),
|
Some(TimeMsg(..)) => self.print_buckets(),
|
||||||
_ => ()
|
_ => ()
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -165,7 +179,13 @@ impl Profiler {
|
||||||
for (category, data) in self.buckets.iter() {
|
for (category, data) in self.buckets.iter() {
|
||||||
// FIXME(XXX): TreeMap currently lacks mut_iter()
|
// FIXME(XXX): TreeMap currently lacks mut_iter()
|
||||||
let mut data = data.clone();
|
let mut data = data.clone();
|
||||||
tim_sort(data);
|
data.sort_by(|a, b| {
|
||||||
|
if a < b {
|
||||||
|
Less
|
||||||
|
} else {
|
||||||
|
Greater
|
||||||
|
}
|
||||||
|
});
|
||||||
let data_len = data.len();
|
let data_len = data.len();
|
||||||
if data_len > 0 {
|
if data_len > 0 {
|
||||||
let (mean, median, &min, &max) =
|
let (mean, median, &min, &max) =
|
||||||
|
@ -184,17 +204,17 @@ impl Profiler {
|
||||||
|
|
||||||
pub fn profile<T>(category: ProfilerCategory,
|
pub fn profile<T>(category: ProfilerCategory,
|
||||||
profiler_chan: ProfilerChan,
|
profiler_chan: ProfilerChan,
|
||||||
callback: &fn() -> T)
|
callback: || -> T)
|
||||||
-> T {
|
-> T {
|
||||||
let start_time = precise_time_ns();
|
let start_time = precise_time_ns();
|
||||||
let val = callback();
|
let val = callback();
|
||||||
let end_time = precise_time_ns();
|
let end_time = precise_time_ns();
|
||||||
let ms = ((end_time - start_time) as f64 / 1000000f64);
|
let ms = ((end_time - start_time) as f64 / 1000000f64);
|
||||||
profiler_chan.send_deferred(TimeMsg(category, ms));
|
profiler_chan.send(TimeMsg(category, ms));
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn time<T>(msg: &str, callback: &fn() -> T) -> T{
|
pub fn time<T>(msg: &str, callback: || -> T) -> T{
|
||||||
let start_time = precise_time_ns();
|
let start_time = precise_time_ns();
|
||||||
let val = callback();
|
let val = callback();
|
||||||
let end_time = precise_time_ns();
|
let end_time = precise_time_ns();
|
||||||
|
|
|
@ -73,7 +73,7 @@ pub fn make_url(str_url: ~str, current_url: Option<Url>) -> Url {
|
||||||
// Drop whitespace within data: URLs, e.g. newlines within a base64
|
// Drop whitespace within data: URLs, e.g. newlines within a base64
|
||||||
// src="..." block. Whitespace intended as content should be
|
// src="..." block. Whitespace intended as content should be
|
||||||
// %-encoded or base64'd.
|
// %-encoded or base64'd.
|
||||||
str_url.iter().filter(|&c| !c.is_whitespace()).collect()
|
str_url.chars().filter(|&c| !c.is_whitespace()).collect()
|
||||||
},
|
},
|
||||||
_ => str_url
|
_ => str_url
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#[link(name = "util",
|
#[crate_id = "github.com/mozilla/servo#util:0.1"];
|
||||||
vers = "0.1",
|
|
||||||
uuid = "48421f49-17cf-41c5-a68e-ff669ff2ecd5",
|
|
||||||
url = "http://servo.org/")];
|
|
||||||
#[crate_type = "lib"];
|
#[crate_type = "lib"];
|
||||||
|
|
||||||
#[feature(macro_rules, managed_boxes)];
|
#[feature(macro_rules, managed_boxes)];
|
||||||
|
@ -16,7 +13,6 @@ extern mod geom;
|
||||||
pub mod cache;
|
pub mod cache;
|
||||||
pub mod geometry;
|
pub mod geometry;
|
||||||
pub mod range;
|
pub mod range;
|
||||||
pub mod slot;
|
|
||||||
pub mod time;
|
pub mod time;
|
||||||
pub mod url;
|
pub mod url;
|
||||||
pub mod vec;
|
pub mod vec;
|
||||||
|
|
|
@ -4,13 +4,13 @@
|
||||||
|
|
||||||
use std::cmp::{Ord, Eq};
|
use std::cmp::{Ord, Eq};
|
||||||
|
|
||||||
pub trait BinarySearchMethods<'self, T: Ord + Eq> {
|
pub trait BinarySearchMethods<'a, T: Ord + Eq> {
|
||||||
fn binary_search(&self, key: &T) -> Option<&'self T>;
|
fn binary_search(&self, key: &T) -> Option<&'a T>;
|
||||||
fn binary_search_index(&self, key: &T) -> Option<uint>;
|
fn binary_search_index(&self, key: &T) -> Option<uint>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self, T: Ord + Eq> BinarySearchMethods<'self, T> for &'self [T] {
|
impl<'a, T: Ord + Eq> BinarySearchMethods<'a, T> for &'a [T] {
|
||||||
fn binary_search(&self, key: &T) -> Option<&'self T> {
|
fn binary_search(&self, key: &T) -> Option<&'a T> {
|
||||||
self.binary_search_index(key).map(|i| &self[i])
|
self.binary_search_index(key).map(|i| &self[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,6 +39,7 @@ impl<'self, T: Ord + Eq> BinarySearchMethods<'self, T> for &'self [T] {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
fn test_find_all_elems<T: Eq + Ord>(arr: &[T]) {
|
fn test_find_all_elems<T: Eq + Ord>(arr: &[T]) {
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while i < arr.len() {
|
while i < arr.len() {
|
||||||
|
@ -47,6 +48,7 @@ fn test_find_all_elems<T: Eq + Ord>(arr: &[T]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
fn test_miss_all_elems<T: Eq + Ord>(arr: &[T], misses: &[T]) {
|
fn test_miss_all_elems<T: Eq + Ord>(arr: &[T], misses: &[T]) {
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while i < misses.len() {
|
while i < misses.len() {
|
||||||
|
@ -57,6 +59,7 @@ fn test_miss_all_elems<T: Eq + Ord>(arr: &[T], misses: &[T]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
fn test_match<T: Eq>(b: &T, a: Option<&T>) -> bool {
|
fn test_match<T: Eq>(b: &T, a: Option<&T>) -> bool {
|
||||||
match a {
|
match a {
|
||||||
None => false,
|
None => false,
|
||||||
|
@ -70,9 +73,8 @@ pub fn zip_copies<A: Clone, B: Clone>(avec: &[A], bvec: &[B]) -> ~[(A,B)] {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
fn should_find_all_elements() {
|
fn should_find_all_elements() {
|
||||||
#[test];
|
|
||||||
|
|
||||||
let arr_odd = [1, 2, 4, 6, 7, 8, 9];
|
let arr_odd = [1, 2, 4, 6, 7, 8, 9];
|
||||||
let arr_even = [1, 2, 5, 6, 7, 8, 9, 42];
|
let arr_even = [1, 2, 5, 6, 7, 8, 9, 42];
|
||||||
let arr_double = [1, 1, 2, 2, 6, 8, 22];
|
let arr_double = [1, 1, 2, 2, 6, 8, 22];
|
||||||
|
@ -88,9 +90,8 @@ fn should_find_all_elements() {
|
||||||
test_find_all_elems(arr_three);
|
test_find_all_elems(arr_three);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
fn should_not_find_missing_elements() {
|
fn should_not_find_missing_elements() {
|
||||||
#[test];
|
|
||||||
|
|
||||||
let arr_odd = [1, 2, 4, 6, 7, 8, 9];
|
let arr_odd = [1, 2, 4, 6, 7, 8, 9];
|
||||||
let arr_even = [1, 2, 5, 6, 7, 8, 9, 42];
|
let arr_even = [1, 2, 5, 6, 7, 8, 9, 42];
|
||||||
let arr_double = [1, 1, 2, 2, 6, 8, 22];
|
let arr_double = [1, 1, 2, 2, 6, 8, 22];
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit d0c6dd720f90e2e8f8d8a103754195096531b531
|
Subproject commit 3f9c99be6ab7f733ec38e6c566a9cfb441e8f47d
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue