diff options
78 files changed, 1282 insertions, 1076 deletions
diff --git a/Makefile.in b/Makefile.in index e96fac06955..de75507a6e1 100644 --- a/Makefile.in +++ b/Makefile.in @@ -30,7 +30,7 @@ B := $(CFG_BUILD_DIR) MKFILE_DEPS := config.stamp $(call rwildcard,$(S)mk/,*) CFG_GCCISH_CFLAGS += -DRUST_DEBUG -CFG_RUSTC_FLAGS = -D unused-imports +CFG_RUSTC_FLAGS += -D unused-imports ifdef CFG_DISABLE_OPTIMIZE $(info cfg: disabling rustc optimization (CFG_DISABLE_OPTIMIZE)) @@ -107,6 +107,12 @@ $(B)src/compiler/rust/rust-auto-clean-stamp: $(S)src/compiler/rust-auto-clean-tr rust: $(CFG_RUSTC) +# These arguments are automatically provided by the Rust compiler's build process to +# itself, so they must be specified later for our Rust modules. +ifeq ($(CFG_OSTYPE),linux-androideabi) + CFG_RUSTC_FLAGS += --target arm-linux-androideabi -C android-cross-path=$(CFG_ANDROID_CROSS_PATH) +endif + # Strip off submodule paths to determine "raw" submodule names. SUBMODULES=$(shell echo $(CFG_SUBMODULES) | perl -p -e 's![A-Za-z0-9_-]+/!!g') @@ -131,6 +137,8 @@ endif # their name already, while others don't. DONE_$(1) = $$(B)src/$$(PATH_$(1))/lib*.dummy DEPS_SUBMODULES += $$(PATH_$(1)) +DEPS_SUBMODULES += $$(PATH_$(1))/.libs +DEPS_SUBMODULES += $$(PATH_$(1))/src/.libs endef # these will get populated. @@ -157,7 +165,7 @@ endef define DEF_SUBMODULE_RULES ENV_RLDFLAGS_$(1) = -L $$(CFG_BUILD_HOME)workspace/lib/$$(CFG_TARGET_TRIPLES) -ENV_RLDFLAGS_$(1) += $$(foreach dep,$$(DEPS_$(1)),-L $$(B)src/$$(PATH_$$(dep))) +ENV_RLDFLAGS_$(1) += $$(foreach dep,$$(DEPS_$(1)),-L $$(B)src/$$(PATH_$$(dep)) -L $$(B)src/$$(PATH_$$(dep))/.libs -L $$(B)src/$$(PATH_$$(dep))/src/.libs) # variables that depend on dependency definitions from sub.mk! ENV_CFLAGS_$(1) = CFLAGS="$$(CFLAGS_$(1))" @@ -333,10 +341,17 @@ ifneq ($(CFG_OSTYPE),linux-androideabi) servo: $(DEPS_servo) @$(call E, compile: $@) $(Q)$(RUSTC) $(RFLAGS_servo) -o $@ $< + +libservo.dummy: $(DEPS_servo) + @$(call E, compile: $@) + $(Q)$(RUSTC) $(RFLAGS_servo) $< --crate-type dylib,rlib + touch libservo.dummy + else servo: $(DEPS_servo) @$(call E, compile: $@) - $(Q)$(RUSTC) $(RFLAGS_servo) -C gen-crate-map -o $@ $< --crate-type lib + $(Q)$(RUSTC) $(RFLAGS_servo) -C gen-crate-map $< -o libservo.so --crate-type dylib + touch servo endif # Darwin app packaging @@ -354,12 +369,11 @@ package: servo else ifeq ($(CFG_OSTYPE),linux-androideabi) package: servo mkdir -p sofile - -exec cp -f {} $(CFG_BUILD_HOME)sofile \; - find . ! \( \( -type d -path './sofile' -o -path './$(CFG_TARGET_TRIPLES)/src/compiler/rust' \) -prune \) -name '*.so' -type f | xargs cp -f -t $(CFG_BUILD_HOME)sofile - find $(CFG_RUST_HOME)/lib/rustc/$(CFG_TARGET_TRIPLES)/lib/ -name '*.so' -type f -size +1c | xargs cp -f -t $(CFG_BUILD_HOME)sofile + find . ! \( \( -type d -path './sofile' -o -path './$(CFG_TARGET_TRIPLES)/src/compiler/rust' \) -prune \) -name '*.so' -type f | xargs -I {} cp -f {} $(CFG_BUILD_HOME)sofile/ + find $(CFG_RUST_HOME)/lib/rustlib/$(CFG_TARGET_TRIPLES)/lib/ -name '*.so' -type f -size +1c | xargs -I {} cp -f {} $(CFG_BUILD_HOME)sofile/ cd $(S)src/platform/android/servo-android-glue && make with-libs cd $(CFG_BUILD_HOME) - cp $(S)src/platform/android/servo-android-glue/bin/ServoAndroid-debug.apk -t $(CFG_BUILD_HOME) + cp $(S)src/platform/android/servo-android-glue/bin/ServoAndroid-debug.apk $(CFG_BUILD_HOME) else diff --git a/configure b/configure index ad101f6201f..a460952b47a 100755 --- a/configure +++ b/configure @@ -385,7 +385,6 @@ case ${TARGET_OSTYPE} in probe CFG_RANLIB arm-linux-androideabi-ranlib export PATH=${OLD_PATH} - CFG_RUSTC_FLAGS="--target=${CFG_TARGET_TRIPLES} -C android-cross-path=${CFG_ANDROID_CROSS_PATH}" ;; *) CFG_PATH=$PATH diff --git a/src/components/gfx/buffer_map.rs b/src/components/gfx/buffer_map.rs index 4c9b8950d94..7980e16c421 100644 --- a/src/components/gfx/buffer_map.rs +++ b/src/components/gfx/buffer_map.rs @@ -83,6 +83,7 @@ impl<T: Tile> BufferMap<T> { // memory limit, no need to store this new buffer; just let it drop. if self.mem + new_buffer.get_mem() > self.max_mem && self.map.len() == 1 && self.map.contains_key(&new_key) { + new_buffer.destroy(graphics_context); return; } diff --git a/src/components/gfx/font.rs b/src/components/gfx/font.rs index 470e1bb49bb..b6a97837d90 100644 --- a/src/components/gfx/font.rs +++ b/src/components/gfx/font.rs @@ -453,72 +453,3 @@ impl Font { } } -/*fn should_destruct_on_fail_without_leaking() { - #[test]; - #[should_fail]; - - let fctx = @FontContext(); - let matcher = @FontMatcher(fctx); - let _font = matcher.get_test_font(); - fail; -} - -fn should_get_glyph_indexes() { - #[test]; - - let fctx = @FontContext(); - let matcher = @FontMatcher(fctx); - let font = matcher.get_test_font(); - let glyph_idx = font.glyph_index('w'); - assert!(glyph_idx == Some(40u as GlyphIndex)); -} - -fn should_get_glyph_advance() { - #[test]; - #[ignore]; - - let fctx = @FontContext(); - let matcher = @FontMatcher(fctx); - let font = matcher.get_test_font(); - let x = font.glyph_h_advance(40u as GlyphIndex); - assert!(x == 15f || x == 16f); -} - -// Testing thread safety -fn should_get_glyph_advance_stress() { - #[test]; - #[ignore]; - - let mut ports = ~[]; - - for iter::repeat(100) { - let (chan, port) = pipes::stream(); - ports += [@port]; - spawn_named("should_get_glyph_advance_stress") { - let fctx = @FontContext(); - let matcher = @FontMatcher(fctx); - let _font = matcher.get_test_font(); - let x = font.glyph_h_advance(40u as GlyphIndex); - assert!(x == 15f || x == 16f); - chan.send(()); - } - } - - for ports.each |port| { - port.recv(); - } -} - -fn should_be_able_to_create_instances_in_multiple_threads() { - #[test]; - - for iter::repeat(10u) { - do task::spawn { - let fctx = @FontContext(); - let matcher = @FontMatcher(fctx); - let _font = matcher.get_test_font(); - } - } -} - -*/ diff --git a/src/components/gfx/freetype_impl/font_context.rs b/src/components/gfx/freetype_impl/font_context.rs index 4ae11ea9ade..bffe06ceda2 100644 --- a/src/components/gfx/freetype_impl/font_context.rs +++ b/src/components/gfx/freetype_impl/font_context.rs @@ -2,6 +2,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use std::rc::Rc; + extern mod freetype; extern mod fontconfig; @@ -34,7 +36,7 @@ impl Drop for FreeTypeLibraryHandle { } pub struct FreeTypeFontContextHandle { - ctx: @FreeTypeLibraryHandle, + ctx: Rc<FreeTypeLibraryHandle>, } pub impl FreeTypeFontContextHandle { @@ -44,7 +46,7 @@ pub impl FreeTypeFontContextHandle { if !result.succeeded() { fail!(); } FreeTypeFontContextHandle { - ctx: @FreeTypeLibraryHandle { ctx: ctx }, + ctx: Rc::new(FreeTypeLibraryHandle { ctx: ctx }), } } } diff --git a/src/components/gfx/gfx.rs b/src/components/gfx/gfx.rs index de02ece7fbd..3635d5d3b61 100644 --- a/src/components/gfx/gfx.rs +++ b/src/components/gfx/gfx.rs @@ -4,8 +4,10 @@ #[crate_id = "github.com/mozilla/servo#gfx:0.1"]; #[crate_type = "lib"]; +#[crate_type = "dylib"]; +#[crate_type = "rlib"]; -#[feature(globs, managed_boxes, macro_rules, phase)]; +#[feature(globs, macro_rules, phase)]; #[feature(phase)]; #[phase(syntax, link)] diff --git a/src/components/gfx/platform/android/font.rs b/src/components/gfx/platform/android/font.rs index 46205f57ffb..ad6228c7533 100644 --- a/src/components/gfx/platform/android/font.rs +++ b/src/components/gfx/platform/android/font.rs @@ -76,7 +76,7 @@ impl FontHandleMethods for FontHandle { buf: ~[u8], style: &SpecifiedFontStyle) -> Result<FontHandle, ()> { - let ft_ctx: FT_Library = fctx.ctx.borrow().ctx; + let ft_ctx: FT_Library = fctx.ctx.ctx; if ft_ctx.is_null() { return Err(()); } let face_result = create_face_from_buffer(ft_ctx, buf.as_ptr(), buf.len(), style.pt_size); @@ -279,7 +279,7 @@ impl<'a> FontHandle { pub fn new_from_file(fctx: &FontContextHandle, file: &str, style: &SpecifiedFontStyle) -> Result<FontHandle, ()> { unsafe { - let ft_ctx: FT_Library = fctx.ctx.borrow().ctx; + let ft_ctx: FT_Library = fctx.ctx.ctx; if ft_ctx.is_null() { return Err(()); } let mut face: FT_Face = ptr::null(); @@ -306,7 +306,7 @@ impl<'a> FontHandle { pub fn new_from_file_unstyled(fctx: &FontContextHandle, file: ~str) -> Result<FontHandle, ()> { unsafe { - let ft_ctx: FT_Library = fctx.ctx.borrow().ctx; + let ft_ctx: FT_Library = fctx.ctx.ctx; if ft_ctx.is_null() { return Err(()); } let mut face: FT_Face = ptr::null(); diff --git a/src/components/gfx/platform/android/font_list.rs b/src/components/gfx/platform/android/font_list.rs index e372d891797..b245b74e4bd 100644 --- a/src/components/gfx/platform/android/font_list.rs +++ b/src/components/gfx/platform/android/font_list.rs @@ -25,7 +25,7 @@ use font_list::{FontEntry, FontFamily, FontFamilyMap}; use platform::font::FontHandle; use platform::font_context::FontContextHandle; -use collections::hashmap::HashMap; +use collections::HashMap; use std::libc; use std::libc::{c_int, c_char}; use std::ptr; diff --git a/src/components/main/compositing/compositor.rs b/src/components/main/compositing/compositor.rs index 9ae6520c38a..72e0ec80a98 100644 --- a/src/components/main/compositing/compositor.rs +++ b/src/components/main/compositing/compositor.rs @@ -354,16 +354,15 @@ impl IOCompositor { self.constellation_chan = new_constellation_chan; } - // FIXME(pcwalton): Take the pipeline ID into account. fn create_root_compositor_layer_if_necessary(&mut self, - _: PipelineId, + id: PipelineId, layer_id: LayerId, size: Size2D<f32>) { let (root_pipeline, root_layer_id) = match self.compositor_layer { - Some(ref compositor_layer) => { + Some(ref compositor_layer) if compositor_layer.pipeline.id == id => { (compositor_layer.pipeline.clone(), compositor_layer.id_of_first_child()) } - None => { + _ => { match self.root_pipeline { Some(ref root_pipeline) => (root_pipeline.clone(), LayerId::null()), None => fail!("Compositor: Received new layer without initialized pipeline"), @@ -395,6 +394,11 @@ impl IOCompositor { ContainerLayer::add_child_start(self.root_layer.clone(), ContainerLayerKind(new_layer.root_layer.clone())); + + // Release all tiles from the layer before dropping it. + for layer in self.compositor_layer.mut_iter() { + layer.clear_all_tiles(); + } self.compositor_layer = Some(new_layer); } diff --git a/src/components/main/compositing/compositor_layer.rs b/src/components/main/compositing/compositor_layer.rs index 678c8c03bd5..5b38b4f332f 100644 --- a/src/components/main/compositing/compositor_layer.rs +++ b/src/components/main/compositing/compositor_layer.rs @@ -879,7 +879,7 @@ impl CompositorLayer { } // Send back all tiles to renderer. - child.get_mut_ref().child.clear(); + child.get_mut_ref().child.clear_all_tiles(); self.build_layer_tree(graphics_context); true @@ -951,6 +951,15 @@ impl CompositorLayer { } } + /// Destroys tiles for this layer and all descendent layers, sending the buffers back to the + /// renderer to be destroyed or reused. + pub fn clear_all_tiles(&mut self) { + self.clear(); + for kid in self.children.mut_iter() { + kid.child.clear_all_tiles(); + } + } + /// Destroys all tiles of all layers, including children, *without* sending them back to the /// renderer. You must call this only when the render task is destined to be going down; /// otherwise, you will leak tiles. diff --git a/src/components/main/compositing/compositor_task.rs b/src/components/main/compositing/compositor_task.rs index f16beae7733..509c1481a0a 100644 --- a/src/components/main/compositing/compositor_task.rs +++ b/src/components/main/compositing/compositor_task.rs @@ -83,13 +83,6 @@ impl RenderListener for CompositorChan { self.chan.send(Paint(pipeline_id, layer_id, layer_buffer_set, epoch)) } - fn create_layer_group_for_pipeline(&self, id: PipelineId, page_size: Size2D<uint>) { - let Size2D { width, height } = page_size; - self.chan.send(CreateRootCompositorLayerIfNecessary(id, - LayerId::null(), - Size2D(width as f32, height as f32))) - } - fn initialize_layers_for_pipeline(&self, pipeline_id: PipelineId, metadata: ~[LayerMetadata], diff --git a/src/components/main/constellation.rs b/src/components/main/constellation.rs index 85fbc5eaf30..3832fac100c 100644 --- a/src/components/main/constellation.rs +++ b/src/components/main/constellation.rs @@ -52,7 +52,7 @@ pub struct Constellation { } /// Stores the Id of the outermost frame's pipeline, along with a vector of children frames -struct FrameTree { +pub struct FrameTree { pipeline: RefCell<Rc<Pipeline>>, parent: RefCell<Option<Rc<Pipeline>>>, children: RefCell<~[ChildFrameTree]>, @@ -74,7 +74,7 @@ impl Clone for FrameTree { } } -struct ChildFrameTree { +pub struct ChildFrameTree { frame_tree: Rc<FrameTree>, /// Clipping rect representing the size and position, in page coordinates, of the visible /// region of the child frame relative to the parent. @@ -176,14 +176,14 @@ impl Iterator<Rc<FrameTree>> for FrameTreeIterator { } /// Represents the portion of a page that is changing in navigating. -struct FrameChange { +pub struct FrameChange { before: Option<PipelineId>, after: Rc<FrameTree>, navigation_type: NavigationType, } /// Stores the Id's of the pipelines previous and next in the browser's history -struct NavigationContext { +pub struct NavigationContext { previous: ~[Rc<FrameTree>], next: ~[Rc<FrameTree>], current: Option<Rc<FrameTree>>, diff --git a/src/components/main/css/matching.rs b/src/components/main/css/matching.rs index cb60e0d9781..f84b4b53738 100644 --- a/src/components/main/css/matching.rs +++ b/src/components/main/css/matching.rs @@ -50,7 +50,7 @@ impl ApplicableDeclarations { } #[deriving(Clone)] -struct ApplicableDeclarationsCacheEntry { +pub struct ApplicableDeclarationsCacheEntry { declarations: SmallVec16<MatchedProperty>, } @@ -159,7 +159,7 @@ pub struct StyleSharingCandidateCache { } #[deriving(Clone)] -struct StyleSharingCandidate { +pub struct StyleSharingCandidate { style: Arc<ComputedValues>, parent_style: Arc<ComputedValues>, diff --git a/src/components/main/layout/block.rs b/src/components/main/layout/block.rs index b9f0e6fee55..7663a85a768 100644 --- a/src/components/main/layout/block.rs +++ b/src/components/main/layout/block.rs @@ -484,7 +484,7 @@ pub struct BlockFlow { base: BaseFlow, /// The associated box. - box_: Option<Box>, + box_: Box, /// TODO: is_root should be a bit field to conserve memory. /// Whether this block flow is the root flow. @@ -501,7 +501,7 @@ impl BlockFlow { pub fn from_node(constructor: &mut FlowConstructor, node: &ThreadSafeLayoutNode) -> BlockFlow { BlockFlow { base: BaseFlow::new((*node).clone()), - box_: Some(Box::new(constructor, node)), + box_: Box::new(constructor, node), is_root: false, static_y_offset: Au::new(0), float: None @@ -511,7 +511,7 @@ impl BlockFlow { pub fn from_node_and_box(node: &ThreadSafeLayoutNode, box_: Box) -> BlockFlow { BlockFlow { base: BaseFlow::new((*node).clone()), - box_: Some(box_), + box_: box_, is_root: false, static_y_offset: Au::new(0), float: None @@ -524,7 +524,7 @@ impl BlockFlow { -> BlockFlow { BlockFlow { base: BaseFlow::new((*node).clone()), - box_: Some(Box::new(constructor, node)), + box_: Box::new(constructor, node), is_root: false, static_y_offset: Au::new(0), float: Some(~FloatedBlockInfo::new(float_kind)) @@ -590,10 +590,7 @@ impl BlockFlow { /// Return this flow's box. pub fn box_<'a>(&'a mut self) -> &'a mut Box { - match self.box_ { - Some(ref mut box_) => box_, - None => fail!("BlockFlow: no principal box found") - } + &mut self.box_ } /// Return the static x offset from the appropriate Containing Block for this flow. @@ -694,22 +691,14 @@ impl BlockFlow { /// The only two types of replaced boxes currently are text boxes and /// image boxes. fn is_replaced_content(&self) -> bool { - match self.box_ { - Some(ref box_) => { - match box_.specific { - ScannedTextBox(_) | ImageBox(_) => true, - _ => false, - } - } - None => false, + match self.box_.specific { + ScannedTextBox(_) | ImageBox(_) => true, + _ => false, } } pub fn teardown(&mut self) { - for box_ in self.box_.iter() { - box_.teardown(); - } - self.box_ = None; + self.box_.teardown(); self.float = None; } @@ -791,11 +780,9 @@ impl BlockFlow { self.base.position.size.height = self.base.position.size.height + top_margin_value + bottom_margin_value; - for fragment in self.box_.iter() { - let mut position = fragment.border_box.get(); - position.size.height = position.size.height + top_margin_value + bottom_margin_value; - fragment.border_box.set(position); - } + let mut position = self.box_.border_box.get(); + position.size.height = position.size.height + top_margin_value + bottom_margin_value; + self.box_.border_box.set(position); } /// Assign height for current flow. @@ -819,9 +806,6 @@ impl BlockFlow { // Our current border-box position. let mut cur_y = Au(0); - // The sum of our top border and top padding. - let mut top_offset = Au(0); - // Absolute positioning establishes a block formatting context. Don't propagate floats // in or out. (But do propagate them between kids.) if inorder && self.is_absolutely_positioned() { @@ -832,20 +816,19 @@ impl BlockFlow { } let mut margin_collapse_info = MarginCollapseInfo::new(); - for fragment in self.box_.iter() { - self.base.floats.translate(Point2D(-fragment.left_offset(), Au(0))); - - top_offset = fragment.border.get().top + fragment.padding.get().top; - translate_including_floats(&mut cur_y, top_offset, inorder, &mut self.base.floats); - - let can_collapse_top_margin_with_kids = - margins_may_collapse == MarginsMayCollapse && - !self.is_absolutely_positioned() && - fragment.border.get().top == Au(0) && - fragment.padding.get().top == Au(0); - margin_collapse_info.initialize_top_margin(fragment, - can_collapse_top_margin_with_kids); - } + self.base.floats.translate(Point2D(-self.box_.left_offset(), Au(0))); + + // The sum of our top border and top padding. + let top_offset = self.box_.border.get().top + self.box_.padding.get().top; + translate_including_floats(&mut cur_y, top_offset, inorder, &mut self.base.floats); + + let can_collapse_top_margin_with_kids = + margins_may_collapse == MarginsMayCollapse && + !self.is_absolutely_positioned() && + self.box_.border.get().top == Au(0) && + self.box_.padding.get().top == Au(0); + margin_collapse_info.initialize_top_margin(&self.box_, + can_collapse_top_margin_with_kids); // At this point, cur_y is at the content edge of the flow's box. let mut floats = self.base.floats.clone(); @@ -954,19 +937,17 @@ impl BlockFlow { self.collect_static_y_offsets_from_kids(); // Add in our bottom margin and compute our collapsible margins. - for fragment in self.box_.iter() { - let can_collapse_bottom_margin_with_kids = - margins_may_collapse == MarginsMayCollapse && - !self.is_absolutely_positioned() && - fragment.border.get().bottom == Au(0) && - fragment.padding.get().bottom == Au(0); - let (collapsible_margins, delta) = - margin_collapse_info.finish_and_compute_collapsible_margins( - fragment, - can_collapse_bottom_margin_with_kids); - self.base.collapsible_margins = collapsible_margins; - translate_including_floats(&mut cur_y, delta, inorder, &mut floats); - } + let can_collapse_bottom_margin_with_kids = + margins_may_collapse == MarginsMayCollapse && + !self.is_absolutely_positioned() && + self.box_.border.get().bottom == Au(0) && + self.box_.padding.get().bottom == Au(0); + let (collapsible_margins, delta) = + margin_collapse_info.finish_and_compute_collapsible_margins( + &self.box_, + can_collapse_bottom_margin_with_kids); + self.base.collapsible_margins = collapsible_margins; + translate_including_floats(&mut cur_y, delta, inorder, &mut floats); // FIXME(#2003, pcwalton): The max is taken here so that you can scroll the page, but this // is not correct behavior according to CSS 2.1 § 10.5. Instead I think we should treat the @@ -989,41 +970,37 @@ impl BlockFlow { // Store the content height for use in calculating the absolute flow's dimensions // later. - for box_ in self.box_.iter() { - let mut temp_position = box_.border_box.get(); - temp_position.size.height = height; - box_.border_box.set(temp_position); - } + let mut temp_position = self.box_.border_box.get(); + temp_position.size.height = height; + self.box_.border_box.set(temp_position); return } - for fragment in self.box_.iter() { - let mut candidate_height_iterator = CandidateHeightIterator::new(fragment.style(), - None); - for (candidate_height, new_candidate_height) in candidate_height_iterator { - *new_candidate_height = match candidate_height { - Auto => height, - Specified(value) => value - } + let mut candidate_height_iterator = CandidateHeightIterator::new(self.box_.style(), + None); + for (candidate_height, new_candidate_height) in candidate_height_iterator { + *new_candidate_height = match candidate_height { + Auto => height, + Specified(value) => value } + } - // Adjust `cur_y` as necessary to account for the explicitly-specified height. - height = candidate_height_iterator.candidate_value; - let delta = height - (cur_y - top_offset); - translate_including_floats(&mut cur_y, delta, inorder, &mut floats); + // Adjust `cur_y` as necessary to account for the explicitly-specified height. + height = candidate_height_iterator.candidate_value; + let delta = height - (cur_y - top_offset); + translate_including_floats(&mut cur_y, delta, inorder, &mut floats); - // Compute content height and noncontent height. - let bottom_offset = fragment.border.get().bottom + fragment.padding.get().bottom; - translate_including_floats(&mut cur_y, bottom_offset, inorder, &mut floats); - - // Now that `cur_y` is at the bottom of the border box, compute the final border box - // position. - let mut border_box = fragment.border_box.get(); - border_box.size.height = cur_y; - border_box.origin.y = Au(0); - fragment.border_box.set(border_box); - self.base.position.size.height = cur_y; - } + // Compute content height and noncontent height. + let bottom_offset = self.box_.border.get().bottom + self.box_.padding.get().bottom; + translate_including_floats(&mut cur_y, bottom_offset, inorder, &mut floats); + + // Now that `cur_y` is at the bottom of the border box, compute the final border box + // position. + let mut border_box = self.box_.border_box.get(); + border_box.size.height = cur_y; + border_box.origin.y = Au(0); + self.box_.border_box.set(border_box); + self.base.position.size.height = cur_y; self.base.floats = floats.clone(); self.adjust_boxes_for_collapsed_margins_if_root(); @@ -1054,25 +1031,18 @@ impl BlockFlow { /// Therefore, assign_height_float was already called on this kid flow by /// the traversal function. So, the values used are well-defined. pub fn assign_height_float_inorder(&mut self) { - let mut height = Au(0); - let mut clearance = Au(0); - let mut full_noncontent_width = Au(0); - let mut margin_height = Au(0); - - for box_ in self.box_.iter() { - height = box_.border_box.get().size.height; - clearance = match box_.clear() { - None => Au(0), - Some(clear) => self.base.floats.clearance(clear), - }; - - let noncontent_width = box_.padding.get().left + box_.padding.get().right + - box_.border.get().left + box_.border.get().right; - - full_noncontent_width = noncontent_width + box_.margin.get().left + - box_.margin.get().right; - margin_height = box_.margin.get().top + box_.margin.get().bottom; - } + let height = self.box_.border_box.get().size.height; + let clearance = match self.box_.clear() { + None => Au(0), + Some(clear) => self.base.floats.clearance(clear), + }; + + let noncontent_width = self.box_.padding.get().left + self.box_.padding.get().right + + self.box_.border.get().left + self.box_.border.get().right; + + let full_noncontent_width = noncontent_width + self.box_.margin.get().left + + self.box_.margin.get().right; + let margin_height = self.box_.margin.get().top + self.box_.margin.get().bottom; let info = PlacementInfo { size: Size2D(self.base.position.size.width + full_noncontent_width, @@ -1112,12 +1082,9 @@ impl BlockFlow { drop(floats); } let mut cur_y = Au(0); - let mut top_offset = Au(0); - for box_ in self.box_.iter() { - top_offset = box_.margin.get().top + box_.border.get().top + box_.padding.get().top; - cur_y = cur_y + top_offset; - } + let top_offset = self.box_.margin.get().top + self.box_.border.get().top + self.box_.padding.get().top; + cur_y = cur_y + top_offset; // cur_y is now at the top content edge @@ -1131,18 +1098,17 @@ impl BlockFlow { let content_height = cur_y - top_offset; let mut noncontent_height; - let box_ = self.box_.as_ref().unwrap(); - let mut position = box_.border_box.get(); + let mut position = self.box_.border_box.get(); // The associated box is the border box of this flow. - position.origin.y = box_.margin.get().top; + position.origin.y = self.box_.margin.get().top; - noncontent_height = box_.padding.get().top + box_.padding.get().bottom + - box_.border.get().top + box_.border.get().bottom; + noncontent_height = self.box_.padding.get().top + self.box_.padding.get().bottom + + self.box_.border.get().top + self.box_.border.get().bottom; // Calculate content height, taking `min-height` and `max-height` into account. - let mut candidate_height_iterator = CandidateHeightIterator::new(box_.style(), None); + let mut candidate_height_iterator = CandidateHeightIterator::new(self.box_.style(), None); for (candidate_height, new_candidate_height) in candidate_height_iterator { *new_candidate_height = match candidate_height { Auto => content_height, @@ -1155,7 +1121,7 @@ impl BlockFlow { debug!("assign_height_float -- height: {}", content_height + noncontent_height); position.size.height = content_height + noncontent_height; - box_.border_box.set(position); + self.box_.border_box.set(position); } fn build_display_list_block_common(&mut self, @@ -1165,28 +1131,25 @@ impl BlockFlow { offset: Point2D<Au>, background_border_level: BackgroundAndBorderLevel) { let mut info = *info; - let mut rel_offset = Point2D(Au(0), Au(0)); - for fragment in self.box_.iter() { - rel_offset = fragment.relative_position(&info.relative_containing_block_size); - - // Add the box that starts the block context. - fragment.build_display_list(stacking_context, - builder, - &info, - self.base.abs_position + rel_offset + offset, - (&*self) as &Flow, - background_border_level); - - // For relatively-positioned descendants, the containing block formed by a block is - // just the content box. The containing block for absolutely-positioned descendants, - // on the other hand, only established if we are positioned. - info.relative_containing_block_size = fragment.content_box_size(); - if self.is_positioned() { - info.absolute_containing_block_position = - self.base.abs_position + - self.generated_cb_position() + - fragment.relative_position(&info.relative_containing_block_size) - } + let rel_offset = self.box_.relative_position(&info.relative_containing_block_size); + + // Add the box that starts the block context. + self.box_.build_display_list(stacking_context, + builder, + &info, + self.base.abs_position + rel_offset + offset, + (&*self) as &Flow, + background_border_level); + + // For relatively-positioned descendants, the containing block formed by a block is + // just the content box. The containing block for absolutely-positioned descendants, + // on the other hand, only established if we are positioned. + info.relative_containing_block_size = self.box_.content_box_size(); + if self.is_positioned() { + info.absolute_containing_block_position = + self.base.abs_position + + self.generated_cb_position() + + self.box_.relative_position(&info.relative_containing_block_size) } let this_position = self.base.abs_position; @@ -1268,40 +1231,54 @@ impl BlockFlow { let containing_block_height = self.containing_block_size(ctx.screen_size).height; let static_y_offset = self.static_y_offset; - for box_ in self.box_.iter() { - // This is the stored content height value from assign-height - let content_height = box_.border_box.get().size.height - box_.noncontent_height(); - - let style = box_.style(); - - // Non-auto margin-top and margin-bottom values have already been - // calculated during assign-width. - let margin = box_.margin.get(); - let margin_top = match MaybeAuto::from_style(style.Margin.get().margin_top, Au(0)) { - Auto => Auto, - _ => Specified(margin.top) - }; - let margin_bottom = match MaybeAuto::from_style(style.Margin.get().margin_bottom, Au(0)) { - Auto => Auto, - _ => Specified(margin.bottom) - }; - - let (top, bottom) = - (MaybeAuto::from_style(style.PositionOffsets.get().top, containing_block_height), - MaybeAuto::from_style(style.PositionOffsets.get().bottom, containing_block_height)); - let available_height = containing_block_height - box_.noncontent_height(); - - let mut solution = None; - if self.is_replaced_content() { - // Calculate used value of height just like we do for inline replaced elements. - // TODO: Pass in the containing block height when Box's - // assign-height can handle it correctly. - box_.assign_replaced_height_if_necessary(); - // TODO: Right now, this content height value includes the - // margin because of erroneous height calculation in Box_. - // Check this when that has been fixed. - let height_used_val = box_.border_box.get().size.height; - solution = Some(HeightConstraintSolution::solve_vertical_constraints_abs_replaced( + // This is the stored content height value from assign-height + let content_height = self.box_.border_box.get().size.height - self.box_.noncontent_height(); + + let style = self.box_.style(); + + // Non-auto margin-top and margin-bottom values have already been + // calculated during assign-width. + let margin = self.box_.margin.get(); + let margin_top = match MaybeAuto::from_style(style.Margin.get().margin_top, Au(0)) { + Auto => Auto, + _ => Specified(margin.top) + }; + let margin_bottom = match MaybeAuto::from_style(style.Margin.get().margin_bottom, Au(0)) { + Auto => Auto, + _ => Specified(margin.bottom) + }; + + let (top, bottom) = + (MaybeAuto::from_style(style.PositionOffsets.get().top, containing_block_height), + MaybeAuto::from_style(style.PositionOffsets.get().bottom, containing_block_height)); + let available_height = containing_block_height - self.box_.noncontent_height(); + + let mut solution = None; + if self.is_replaced_content() { + // Calculate used value of height just like we do for inline replaced elements. + // TODO: Pass in the containing block height when Box's + // assign-height can handle it correctly. + self.box_.assign_replaced_height_if_necessary(); + // TODO: Right now, this content height value includes the + // margin because of erroneous height calculation in Box_. + // Check this when that has been fixed. + let height_used_val = self.box_.border_box.get().size.height; + solution = Some(HeightConstraintSolution::solve_vertical_constraints_abs_replaced( + height_used_val, + margin_top, + margin_bottom, + top, + bottom, + content_height, + available_height, + static_y_offset)); + } else { + let mut candidate_height_iterator = + CandidateHeightIterator::new(style, Some(containing_block_height)); + + for (height_used_val, new_candidate_height) in candidate_height_iterator { + solution = + Some(HeightConstraintSolution::solve_vertical_constraints_abs_nonreplaced( height_used_val, margin_top, margin_bottom, @@ -1310,43 +1287,27 @@ impl BlockFlow { content_height, available_height, static_y_offset)); - } else { - let mut candidate_height_iterator = - CandidateHeightIterator::new(style, Some(containing_block_height)); - - for (height_used_val, new_candidate_height) in candidate_height_iterator { - solution = - Some(HeightConstraintSolution::solve_vertical_constraints_abs_nonreplaced( - height_used_val, - margin_top, - margin_bottom, - top, - bottom, - content_height, - available_height, - static_y_offset)); - - *new_candidate_height = solution.unwrap().height - } + + *new_candidate_height = solution.unwrap().height } + } - let solution = solution.unwrap(); + let solution = solution.unwrap(); - let mut margin = box_.margin.get(); - margin.top = solution.margin_top; - margin.bottom = solution.margin_bottom; - box_.margin.set(margin); + let mut margin = self.box_.margin.get(); + margin.top = solution.margin_top; + margin.bottom = solution.margin_bottom; + self.box_.margin.set(margin); - let mut position = box_.border_box.get(); - position.origin.y = Au(0); - // Border box height - let border_and_padding = box_.noncontent_height(); - position.size.height = solution.height + border_and_padding; - box_.border_box.set(position); + let mut position = self.box_.border_box.get(); + position.origin.y = Au(0); + // Border box height + let border_and_padding = self.box_.noncontent_height(); + position.size.height = solution.height + border_and_padding; + self.box_.border_box.set(position); - self.base.position.origin.y = solution.top + margin.top; - self.base.position.size.height = solution.height + border_and_padding; - } + self.base.position.origin.y = solution.top + margin.top; + self.base.position.size.height = solution.height + border_and_padding; } /// Add display items for Absolutely Positioned flow. @@ -1439,15 +1400,10 @@ impl BlockFlow { let kid_abs_cb_x_offset; if self.is_positioned() { - match self.box_ { - Some(ref box_) => { - // Pass yourself as a new Containing Block - // The static x offset for any immediate kid flows will be the - // left padding - kid_abs_cb_x_offset = box_.padding.get().left; - } - None => fail!("BlockFlow: no principal box found"), - } + // Pass yourself as a new Containing Block + // The static x offset for any immediate kid flows will be the + // left padding + kid_abs_cb_x_offset = self.box_.padding.get().left; } else { // For kids, the left margin edge will be at our left content edge. // The current static offset is at our left margin @@ -1565,20 +1521,18 @@ impl Flow for BlockFlow { } // Add in borders, padding, and margins. - for box_ in self.box_.iter() { - { - // Can compute border width here since it doesn't depend on anything. - box_.compute_borders(box_.style()) - } - - let box_intrinsic_widths = box_.intrinsic_widths(); - intrinsic_widths.minimum_width = geometry::max(intrinsic_widths.minimum_width, - box_intrinsic_widths.minimum_width); - intrinsic_widths.preferred_width = geometry::max(intrinsic_widths.preferred_width, - box_intrinsic_widths.preferred_width); - intrinsic_widths.surround_width = box_intrinsic_widths.surround_width + { + // Can compute border width here since it doesn't depend on anything. + self.box_.compute_borders(self.box_.style()) } + let box_intrinsic_widths = self.box_.intrinsic_widths(); + intrinsic_widths.minimum_width = geometry::max(intrinsic_widths.minimum_width, + box_intrinsic_widths.minimum_width); + intrinsic_widths.preferred_width = geometry::max(intrinsic_widths.preferred_width, + box_intrinsic_widths.preferred_width); + intrinsic_widths.surround_width = box_intrinsic_widths.surround_width; + self.base.intrinsic_widths = intrinsic_widths } @@ -1606,25 +1560,21 @@ impl Flow for BlockFlow { // The position was set to the containing block by the flow's parent. let containing_block_width = self.base.position.size.width; - let mut left_content_edge = Au::new(0); - let mut content_width = containing_block_width; self.set_containing_width_if_float(containing_block_width); self.compute_used_width(ctx, containing_block_width); - for box_ in self.box_.iter() { - // Assign `clear` now so that the assign-heights pass will have the correct value for - // it. - self.base.clear = box_.style().Box.get().clear; - - // Move in from the left border edge - left_content_edge = box_.border_box.get().origin.x - + box_.padding.get().left + box_.border.get().left; - let padding_and_borders = box_.padding.get().left + box_.padding.get().right + - box_.border.get().left + box_.border.get().right; - content_width = box_.border_box.get().size.width - padding_and_borders; - } + // Assign `clear` now so that the assign-heights pass will have the correct value for + // it. + self.base.clear = self.box_.style().Box.get().clear; + + // Move in from the left border edge + let left_content_edge = self.box_.border_box.get().origin.x + + self.box_.padding.get().left + self.box_.border.get().left; + let padding_and_borders = self.box_.padding.get().left + self.box_.padding.get().right + + self.box_.border.get().left + self.box_.border.get().right; + let content_width = self.box_.border_box.get().size.width - padding_and_borders; if self.is_float() { self.base.position.size.width = content_width; @@ -1649,9 +1599,7 @@ impl Flow for BlockFlow { fn assign_height(&mut self, ctx: &mut LayoutContext) { // Assign height for box if it is an image box. - for box_ in self.box_.iter() { - box_.assign_replaced_height_if_necessary(); - } + self.box_.assign_replaced_height_if_necessary(); if self.is_float() { debug!("assign_height_float: assigning height for float"); @@ -1689,12 +1637,7 @@ impl Flow for BlockFlow { /// The 'position' property of this flow. fn positioning(&self) -> position::T { - match self.box_ { - Some(ref box_) => { - box_.style.get().Box.get().position - } - None => fail!("BlockFlow does not have a box_") - } + self.box_.style.get().Box.get().position } /// Return true if this is the root of an Absolute flow tree. @@ -1708,34 +1651,20 @@ impl Flow for BlockFlow { /// /// For Blocks, this will be the padding box. fn generated_cb_size(&self) -> Size2D<Au> { - match self.box_ { - Some(ref box_) => { - box_.padding_box_size() - } - None => fail!("Containing Block must have a box") - } + self.box_.padding_box_size() } /// Return position of the CB generated by this flow from the start of this flow. fn generated_cb_position(&self) -> Point2D<Au> { - match self.box_ { - Some(ref box_) => { - // Border box y coordinate + border top - box_.border_box.get().origin + Point2D(box_.border.get().left, box_.border.get().top)} - None => fail!("Containing Block must have a box") - } + // Border box y coordinate + border top + self.box_.border_box.get().origin + Point2D(self.box_.border.get().left, self.box_.border.get().top) } fn layer_id(&self, fragment_index: uint) -> LayerId { // FIXME(#2010, pcwalton): This is a hack and is totally bogus in the presence of pseudo- // elements. But until we have incremental reflow we can't do better--we recreate the flow // for every DOM node so otherwise we nuke layers on every reflow. - match self.box_ { - Some(ref box_) => { - LayerId(box_.node.id(), fragment_index) - } - None => fail!("can't make a layer ID for a flow with no box"), - } + LayerId(self.box_.node.id(), fragment_index) } fn debug_str(&self) -> ~str { @@ -1746,10 +1675,7 @@ impl Flow for BlockFlow { } else { ~"BlockFlow: " }; - txt.append(match self.box_ { - Some(ref rb) => rb.debug_str(), - None => ~"", - }) + txt.append(self.box_.debug_str()) } fn is_absolute_containing_block(&self) -> bool { @@ -1841,35 +1767,32 @@ pub trait WidthAndMarginsComputer { -> WidthConstraintInput { let containing_block_width = self.containing_block_width(block, parent_flow_width, ctx); let computed_width = self.initial_computed_width(block, parent_flow_width, ctx); - for box_ in block.box_.iter() { - let style = box_.style(); - - // The text alignment of a block flow is the text alignment of its box's style. - block.base.flags_info.flags.set_text_align(style.InheritedText.get().text_align); - - box_.compute_padding(style, containing_block_width); - - // We calculate and set margin-top and margin-bottom here - // because CSS 2.1 defines % on this wrt CB *width*. - box_.compute_margin_top_bottom(containing_block_width); - - let (margin_left, margin_right) = - (MaybeAuto::from_style(style.Margin.get().margin_left, containing_block_width), - MaybeAuto::from_style(style.Margin.get().margin_right, containing_block_width)); - - let (left, right) = - (MaybeAuto::from_style(style.PositionOffsets.get().left, containing_block_width), - MaybeAuto::from_style(style.PositionOffsets.get().right, containing_block_width)); - let available_width = containing_block_width - box_.noncontent_width(); - return WidthConstraintInput::new(computed_width, - margin_left, - margin_right, - left, - right, - available_width, - block.static_x_offset()); - } - fail!("Block doesn't have a principal box") + let style = block.box_.style(); + + // The text alignment of a block flow is the text alignment of its box's style. + block.base.flags_info.flags.set_text_align(style.InheritedText.get().text_align); + + block.box_.compute_padding(style, containing_block_width); + + // We calculate and set margin-top and margin-bottom here + // because CSS 2.1 defines % on this wrt CB *width*. + block.box_.compute_margin_top_bottom(containing_block_width); + + let (margin_left, margin_right) = + (MaybeAuto::from_style(style.Margin.get().margin_left, containing_block_width), + MaybeAuto::from_style(style.Margin.get().margin_right, containing_block_width)); + + let (left, right) = + (MaybeAuto::from_style(style.PositionOffsets.get().left, containing_block_width), + MaybeAuto::from_style(style.PositionOffsets.get().right, containing_block_width)); + let available_width = containing_block_width - block.box_.noncontent_width(); + return WidthConstraintInput::new(computed_width, + margin_left, + margin_right, + left, + right, + available_width, + block.static_x_offset()); } /// Set the used values for width and margins got from the relevant constraint equation. diff --git a/src/components/main/layout/construct.rs b/src/components/main/layout/construct.rs index 398f915197b..bf5ed0673d0 100644 --- a/src/components/main/layout/construct.rs +++ b/src/components/main/layout/construct.rs @@ -98,7 +98,7 @@ impl ConstructionResult { /// Represents the output of flow construction for a DOM node that has not yet resulted in a /// complete flow. Construction items bubble up the tree until they find a `Flow` to be /// attached to. -enum ConstructionItem { +pub enum ConstructionItem { /// Inline boxes and associated {ib} splits that have not yet found flows. InlineBoxesConstructionItem(InlineBoxesConstructionResult), /// Potentially ignorable whitespace. @@ -124,7 +124,7 @@ impl ConstructionItem { } /// Represents inline boxes and {ib} splits that are bubbling up from an inline. -struct InlineBoxesConstructionResult { +pub struct InlineBoxesConstructionResult { /// Any {ib} splits that we're bubbling up. /// /// TODO(pcwalton): Small vector optimization. @@ -159,7 +159,7 @@ struct InlineBoxesConstructionResult { /// }),~[ /// C /// ]) -struct InlineBlockSplit { +pub struct InlineBlockSplit { /// The inline boxes that precede the flow. /// /// TODO(pcwalton): Small vector optimization. @@ -558,6 +558,9 @@ impl<'a> FlowConstructor<'a> { // Concatenate all the boxes of our kids, creating {ib} splits as necessary. for kid in node.children() { + if kid.get_element_type() != Normal { + self.process(&kid); + } match kid.swap_out_construction_result() { NoConstructionResult => {} FlowConstructionResult(flow, kid_abs_descendants) => { diff --git a/src/components/main/layout/context.rs b/src/components/main/layout/context.rs index 1b13470ed30..512e71aca7a 100644 --- a/src/components/main/layout/context.rs +++ b/src/components/main/layout/context.rs @@ -9,6 +9,7 @@ use css::matching::{ApplicableDeclarationsCache, StyleSharingCandidateCache}; use geom::size::Size2D; use gfx::display_list::OpaqueNode; use gfx::font_context::{FontContext, FontContextInfo}; +#[cfg(not(target_os="android"))] use green::task::GreenTask; use script::layout_interface::LayoutChan; use servo_msg::constellation_msg::ConstellationChan; @@ -16,25 +17,44 @@ use servo_net::local_image_cache::LocalImageCache; use servo_util::geometry::Au; use servo_util::opts::Opts; use std::cast; +#[cfg(not(target_os="android"))] use std::ptr; +#[cfg(not(target_os="android"))] use std::rt::Runtime; +#[cfg(not(target_os="android"))] use std::rt::local::Local; +#[cfg(not(target_os="android"))] use std::rt::task::Task; use style::{ComputedValues, Stylist}; use sync::{Arc, MutexArc}; use url::Url; +#[cfg(target_os="android")] +use std::local_data; + +#[cfg(not(target_os="android"))] #[thread_local] static mut FONT_CONTEXT: *mut FontContext = 0 as *mut FontContext; +#[cfg(target_os="android")] +local_data_key!(font_context: *mut FontContext) + +#[cfg(not(target_os="android"))] #[thread_local] static mut APPLICABLE_DECLARATIONS_CACHE: *mut ApplicableDeclarationsCache = 0 as *mut ApplicableDeclarationsCache; +#[cfg(target_os="android")] +local_data_key!(applicable_declarations_cache: *mut ApplicableDeclarationsCache) + +#[cfg(not(target_os="android"))] #[thread_local] static mut STYLE_SHARING_CANDIDATE_CACHE: *mut StyleSharingCandidateCache = 0 as *mut StyleSharingCandidateCache; +#[cfg(target_os="android")] +local_data_key!(style_sharing_candidate_cache: *mut StyleSharingCandidateCache) + /// Data shared by all layout workers. #[deriving(Clone)] pub struct LayoutContext { @@ -71,6 +91,7 @@ pub struct LayoutContext { opts: Opts, } +#[cfg(not(target_os="android"))] impl LayoutContext { pub fn font_context<'a>(&'a mut self) -> &'a mut FontContext { // Sanity check. @@ -139,3 +160,57 @@ impl LayoutContext { } } + +// On Android, we don't have the __tls_* functions emitted by rustc, so we +// need to use the slower local_data functions. +// Making matters worse, the local_data functions are very particular about +// enforcing the lifetimes associated with objects that they hold onto, +// which causes us some trouble we work around as below. +#[cfg(target_os="android")] +impl LayoutContext { + pub fn font_context<'a>(&'a mut self) -> &'a mut FontContext { + unsafe { + let opt = local_data::pop(font_context); + let mut context; + match opt { + Some(c) => context = cast::transmute(c), + None => { + context = cast::transmute(~FontContext::new(self.font_context_info.clone())) + } + } + local_data::set(font_context, context); + cast::transmute(context) + } + } + + pub fn applicable_declarations_cache<'a>(&'a self) -> &'a mut ApplicableDeclarationsCache { + unsafe { + let opt = local_data::pop(applicable_declarations_cache); + let mut cache; + match opt { + Some(c) => cache = cast::transmute(c), + None => { + cache = cast::transmute(~ApplicableDeclarationsCache::new()); + } + } + local_data::set(applicable_declarations_cache, cache); + cast::transmute(cache) + } + } + + pub fn style_sharing_candidate_cache<'a>(&'a self) -> &'a mut StyleSharingCandidateCache { + unsafe { + let opt = local_data::pop(style_sharing_candidate_cache); + let mut cache; + match opt { + Some(c) => cache = cast::transmute(c), + None => { + cache = cast::transmute(~StyleSharingCandidateCache::new()); + } + } + local_data::set(style_sharing_candidate_cache, cache); + cast::transmute(cache) + } + } +} + diff --git a/src/components/main/layout/flow.rs b/src/components/main/layout/flow.rs index 2fd6b310d86..96db9770a5d 100644 --- a/src/components/main/layout/flow.rs +++ b/src/components/main/layout/flow.rs @@ -718,9 +718,9 @@ impl Descendants { pub type AbsDescendants = Descendants; -type DescendantIter<'a> = MutItems<'a, Rawlink>; +pub type DescendantIter<'a> = MutItems<'a, Rawlink>; -type DescendantOffsetIter<'a> = Zip<MutItems<'a, Rawlink>, MutItems<'a, Au>>; +pub type DescendantOffsetIter<'a> = Zip<MutItems<'a, Rawlink>, MutItems<'a, Au>>; /// Data common to all flows. pub struct BaseFlow { @@ -805,23 +805,6 @@ impl Drop for BaseFlow { } } -pub struct BoxIterator { - priv boxes: ~[@Box], - priv index: uint, -} - -impl Iterator<@Box> for BoxIterator { - fn next(&mut self) -> Option<@Box> { - if self.index >= self.boxes.len() { - None - } else { - let v = self.boxes[self.index].clone(); - self.index += 1; - Some(v) - } - } -} - impl BaseFlow { #[inline] pub fn new(node: ThreadSafeLayoutNode) -> BaseFlow { diff --git a/src/components/main/layout/inline.rs b/src/components/main/layout/inline.rs index 940d2b50d95..a504031b69b 100644 --- a/src/components/main/layout/inline.rs +++ b/src/components/main/layout/inline.rs @@ -50,7 +50,7 @@ use style::computed_values::{text_align, vertical_align, white_space}; /// with a float or a horizontal wall of the containing block. The top /// left corner of the green zone is the same as that of the line, but /// the green zone can be taller and wider than the line itself. -struct LineBox { +pub struct LineBox { range: Range, bounds: Rect<Au>, green_zone: Size2D<Au> diff --git a/src/components/main/layout/model.rs b/src/components/main/layout/model.rs index 098e238a252..fac209ac770 100644 --- a/src/components/main/layout/model.rs +++ b/src/components/main/layout/model.rs @@ -231,7 +231,7 @@ impl MarginCollapseInfo { } } -enum MarginCollapseState { +pub enum MarginCollapseState { AccumulatingCollapsibleTopMargin, AccumulatingMarginIn, } diff --git a/src/components/main/layout/table.rs b/src/components/main/layout/table.rs index 1a8b38975ba..679a944a333 100644 --- a/src/components/main/layout/table.rs +++ b/src/components/main/layout/table.rs @@ -241,9 +241,7 @@ impl Flow for TableFlow { let child_base = flow::mut_base(kid); num_floats = num_floats + child_base.num_floats; } - for box_ in self.block_flow.box_.iter() { - box_.compute_borders(box_.style()); - } + self.block_flow.box_.compute_borders(self.block_flow.box_.style()); self.block_flow.base.num_floats = num_floats; self.block_flow.base.intrinsic_widths.minimum_width = min_width; self.block_flow.base.intrinsic_widths.preferred_width = geometry::max(min_width, pref_width); @@ -256,8 +254,6 @@ impl Flow for TableFlow { // The position was set to the containing block by the flow's parent. let containing_block_width = self.block_flow.base.position.size.width; - let mut left_content_edge = Au::new(0); - let mut content_width = containing_block_width; let mut num_unspecified_widths = 0; let mut total_column_width = Au::new(0); @@ -272,12 +268,10 @@ impl Flow for TableFlow { let width_computer = InternalTable; width_computer.compute_used_width(&mut self.block_flow, ctx, containing_block_width); - for box_ in self.block_flow.box_.iter() { - left_content_edge = box_.padding.get().left + box_.border.get().left; - let padding_and_borders = box_.padding.get().left + box_.padding.get().right + - box_.border.get().left + box_.border.get().right; - content_width = box_.border_box.get().size.width - padding_and_borders; - } + let left_content_edge = self.block_flow.box_.padding.get().left + self.block_flow.box_.border.get().left; + let padding_and_borders = self.block_flow.box_.padding.get().left + self.block_flow.box_.padding.get().right + + self.block_flow.box_.border.get().left + self.block_flow.box_.border.get().right; + let content_width = self.block_flow.box_.border_box.get().size.width - padding_and_borders; match self.table_layout { FixedLayout => { @@ -319,10 +313,7 @@ impl Flow for TableFlow { fn debug_str(&self) -> ~str { let txt = ~"TableFlow: "; - txt.append(match self.block_flow.box_ { - Some(ref rb) => rb.debug_str(), - None => ~"", - }) + txt.append(self.block_flow.box_.debug_str()) } } diff --git a/src/components/main/layout/table_caption.rs b/src/components/main/layout/table_caption.rs index 7aecbe22fb5..2b55ad95e30 100644 --- a/src/components/main/layout/table_caption.rs +++ b/src/components/main/layout/table_caption.rs @@ -78,9 +78,6 @@ impl Flow for TableCaptionFlow { fn debug_str(&self) -> ~str { let txt = ~"TableCaptionFlow: "; - txt.append(match self.block_flow.box_ { - Some(ref rb) => rb.debug_str(), - None => ~"", - }) + txt.append(self.block_flow.box_.debug_str()) } } diff --git a/src/components/main/layout/table_cell.rs b/src/components/main/layout/table_cell.rs index d6e88b629fe..6f6da339d55 100644 --- a/src/components/main/layout/table_cell.rs +++ b/src/components/main/layout/table_cell.rs @@ -35,7 +35,7 @@ impl TableCellFlow { self.block_flow.teardown() } - pub fn box_<'a>(&'a mut self) -> &'a Option<Box>{ + pub fn box_<'a>(&'a mut self) -> &'a Box { &self.block_flow.box_ } @@ -77,17 +77,15 @@ impl Flow for TableCellFlow { /// Minimum/preferred widths set by this function are used in automatic table layout calculation. fn bubble_widths(&mut self, ctx: &mut LayoutContext) { self.block_flow.bubble_widths(ctx); - for box_ in self.block_flow.box_.iter() { - let specified_width = MaybeAuto::from_style(box_.style().Box.get().width, - Au::new(0)).specified_or_zero(); - if self.block_flow.base.intrinsic_widths.minimum_width < specified_width { - self.block_flow.base.intrinsic_widths.minimum_width = specified_width; - } - if self.block_flow.base.intrinsic_widths.preferred_width < - self.block_flow.base.intrinsic_widths.minimum_width { - self.block_flow.base.intrinsic_widths.preferred_width = - self.block_flow.base.intrinsic_widths.minimum_width; - } + let specified_width = MaybeAuto::from_style(self.block_flow.box_.style().Box.get().width, + Au::new(0)).specified_or_zero(); + if self.block_flow.base.intrinsic_widths.minimum_width < specified_width { + self.block_flow.base.intrinsic_widths.minimum_width = specified_width; + } + if self.block_flow.base.intrinsic_widths.preferred_width < + self.block_flow.base.intrinsic_widths.minimum_width { + self.block_flow.base.intrinsic_widths.preferred_width = + self.block_flow.base.intrinsic_widths.minimum_width; } } @@ -98,18 +96,14 @@ impl Flow for TableCellFlow { // The position was set to the column width by the parent flow, table row flow. let containing_block_width = self.block_flow.base.position.size.width; - let mut left_content_edge = Au::new(0); - let mut content_width = containing_block_width; let width_computer = InternalTable; width_computer.compute_used_width(&mut self.block_flow, ctx, containing_block_width); - for box_ in self.block_flow.box_.iter() { - left_content_edge = box_.border_box.get().origin.x + box_.padding.get().left + box_.border.get().left; - let padding_and_borders = box_.padding.get().left + box_.padding.get().right + - box_.border.get().left + box_.border.get().right; - content_width = box_.border_box.get().size.width - padding_and_borders; - } + let left_content_edge = self.block_flow.box_.border_box.get().origin.x + self.block_flow.box_.padding.get().left + self.block_flow.box_.border.get().left; + let padding_and_borders = self.block_flow.box_.padding.get().left + self.block_flow.box_.padding.get().right + + self.block_flow.box_.border.get().left + self.block_flow.box_.border.get().right; + let content_width = self.block_flow.box_.border_box.get().size.width - padding_and_borders; self.block_flow.propagate_assigned_width_to_children(left_content_edge, content_width, None); } @@ -130,10 +124,7 @@ impl Flow for TableCellFlow { fn debug_str(&self) -> ~str { let txt = ~"TableCellFlow: "; - txt.append(match self.block_flow.box_ { - Some(ref rb) => rb.debug_str(), - None => ~"", - }) + txt.append(self.block_flow.box_.debug_str()) } } diff --git a/src/components/main/layout/table_row.rs b/src/components/main/layout/table_row.rs index d0b251d08de..f4319fabee3 100644 --- a/src/components/main/layout/table_row.rs +++ b/src/components/main/layout/table_row.rs @@ -64,7 +64,7 @@ impl TableRowFlow { self.col_pref_widths = ~[]; } - pub fn box_<'a>(&'a mut self) -> &'a Option<Box>{ + pub fn box_<'a>(&'a mut self) -> &'a Box { &self.block_flow.box_ } @@ -93,7 +93,8 @@ impl TableRowFlow { kid.assign_height_inorder(layout_context) } - for child_box in kid.as_table_cell().box_().iter() { + { + let child_box = kid.as_table_cell().box_(); // TODO: Percentage height let child_specified_height = MaybeAuto::from_style(child_box.style().Box.get().height, Au::new(0)).specified_or_zero(); @@ -105,28 +106,25 @@ impl TableRowFlow { } let mut height = max_y; - for box_ in self.block_flow.box_.iter() { - // TODO: Percentage height - height = match MaybeAuto::from_style(box_.style().Box.get().height, Au(0)) { - Auto => height, - Specified(value) => geometry::max(value, height) - }; - } + // TODO: Percentage height + height = match MaybeAuto::from_style(self.block_flow.box_.style().Box.get().height, Au(0)) { + Auto => height, + Specified(value) => geometry::max(value, height) + }; // cur_y = cur_y + height; // Assign the height of own box // // FIXME(pcwalton): Take `cur_y` into account. - for box_ in self.block_flow.box_.iter() { - let mut position = box_.border_box.get(); - position.size.height = height; - box_.border_box.set(position); - } + let mut position = self.block_flow.box_.border_box.get(); + position.size.height = height; + self.block_flow.box_.border_box.set(position); self.block_flow.base.position.size.height = height; // Assign the height of kid boxes, which is the same value as own height. for kid in self.block_flow.base.child_iter() { - for kid_box_ in kid.as_table_cell().box_().iter() { + { + let kid_box_ = kid.as_table_cell().box_(); let mut position = kid_box_.border_box.get(); position.size.height = height; kid_box_.border_box.set(position); @@ -185,7 +183,8 @@ impl Flow for TableRowFlow { assert!(kid.is_table_cell()); // collect the specified column widths of cells. These are used in fixed table layout calculation. - for child_box in kid.as_table_cell().box_().iter() { + { + let child_box = kid.as_table_cell().box_(); let child_specified_width = MaybeAuto::from_style(child_box.style().Box.get().width, Au::new(0)).specified_or_zero(); self.col_widths.push(child_specified_width); @@ -237,10 +236,7 @@ impl Flow for TableRowFlow { fn debug_str(&self) -> ~str { let txt = ~"TableRowFlow: "; - txt.append(match self.block_flow.box_ { - Some(ref rb) => rb.debug_str(), - None => ~"", - }) + txt.append(self.block_flow.box_.debug_str()) } } diff --git a/src/components/main/layout/table_rowgroup.rs b/src/components/main/layout/table_rowgroup.rs index a0b2364146c..af1e9a025e9 100644 --- a/src/components/main/layout/table_rowgroup.rs +++ b/src/components/main/layout/table_rowgroup.rs @@ -63,7 +63,7 @@ impl TableRowGroupFlow { self.col_pref_widths = ~[]; } - pub fn box_<'a>(&'a mut self) -> &'a Option<Box>{ + pub fn box_<'a>(&'a mut self) -> &'a Box { &self.block_flow.box_ } @@ -93,11 +93,9 @@ impl TableRowGroupFlow { let height = cur_y - top_offset; - for box_ in self.block_flow.box_.iter() { - let mut position = box_.border_box.get(); - position.size.height = height; - box_.border_box.set(position); - } + let mut position = self.block_flow.box_.border_box.get(); + position.size.height = height; + self.block_flow.box_.border_box.set(position); self.block_flow.base.position.size.height = height; } @@ -219,10 +217,7 @@ impl Flow for TableRowGroupFlow { fn debug_str(&self) -> ~str { let txt = ~"TableRowGroupFlow: "; - txt.append(match self.block_flow.box_ { - Some(ref rb) => rb.debug_str(), - None => ~"", - }) + txt.append(self.block_flow.box_.debug_str()) } } diff --git a/src/components/main/layout/table_wrapper.rs b/src/components/main/layout/table_wrapper.rs index 639eb542902..c124e46b5a7 100644 --- a/src/components/main/layout/table_wrapper.rs +++ b/src/components/main/layout/table_wrapper.rs @@ -166,16 +166,12 @@ impl Flow for TableWrapperFlow { // The position was set to the containing block by the flow's parent. let containing_block_width = self.block_flow.base.position.size.width; - let mut left_content_edge = Au::new(0); - let mut content_width = containing_block_width; let width_computer = TableWrapper; width_computer.compute_used_width_table_wrapper(self, ctx, containing_block_width); - for box_ in self.block_flow.box_.iter() { - left_content_edge = box_.border_box.get().origin.x; - content_width = box_.border_box.get().size.width; - } + let left_content_edge = self.block_flow.box_.border_box.get().origin.x; + let content_width = self.block_flow.box_.border_box.get().size.width; match self.table_layout { FixedLayout | _ if self.is_float() => @@ -221,10 +217,7 @@ impl Flow for TableWrapperFlow { } else { ~"TableWrapperFlow: " }; - txt.append(match self.block_flow.box_ { - Some(ref rb) => rb.debug_str(), - None => ~"", - }) + txt.append(self.block_flow.box_.debug_str()) } } @@ -258,23 +251,21 @@ impl TableWrapper { |sum, width| sum.add(width)); let mut computed_width = input.computed_width.specified_or_zero(); - for box_ in table_wrapper.block_flow.box_.iter() { - let style = box_.style(); - - // Get left and right paddings, borders for table. - // We get these values from the box's style since table_wrapper doesn't have it's own border or padding. - // input.available_width is same as containing_block_width in table_wrapper. - let padding_left = specified(style.Padding.get().padding_left, - input.available_width); - let padding_right = specified(style.Padding.get().padding_right, - input.available_width); - let border_left = style.Border.get().border_left_width; - let border_right = style.Border.get().border_right_width; - let padding_and_borders = padding_left + padding_right + border_left + border_right; - // Compare border-edge widths. Because fixed_cells_width indicates content-width, - // padding and border values are added to fixed_cells_width. - computed_width = geometry::max(fixed_cells_width + padding_and_borders, computed_width); - } + let style = table_wrapper.block_flow.box_.style(); + + // Get left and right paddings, borders for table. + // We get these values from the box's style since table_wrapper doesn't have it's own border or padding. + // input.available_width is same as containing_block_width in table_wrapper. + let padding_left = specified(style.Padding.get().padding_left, + input.available_width); + let padding_right = specified(style.Padding.get().padding_right, + input.available_width); + let border_left = style.Border.get().border_left_width; + let border_right = style.Border.get().border_right_width; + let padding_and_borders = padding_left + padding_right + border_left + border_right; + // Compare border-edge widths. Because fixed_cells_width indicates content-width, + // padding and border values are added to fixed_cells_width. + computed_width = geometry::max(fixed_cells_width + padding_and_borders, computed_width); computed_width }, AutoLayout => { diff --git a/src/components/main/platform/common/glut_windowing.rs b/src/components/main/platform/common/glut_windowing.rs index 2d59539a8d1..23d6ab2d4f6 100644 --- a/src/components/main/platform/common/glut_windowing.rs +++ b/src/components/main/platform/common/glut_windowing.rs @@ -97,7 +97,7 @@ impl WindowMethods<Application> for Window { impl glut::ReshapeCallback for ReshapeCallbackState { fn call(&self, width: c_int, height: c_int) { let tmp = local_window(); - tmp.borrow().event_queue.with_mut(|queue| queue.push(ResizeWindowEvent(width as uint, height as uint))) + tmp.event_queue.borrow_mut().push(ResizeWindowEvent(width as uint, height as uint)) } } glut::reshape_func(glut_window, ~ReshapeCallbackState); @@ -105,7 +105,7 @@ impl WindowMethods<Application> for Window { impl glut::KeyboardCallback for KeyboardCallbackState { fn call(&self, key: c_uchar, _x: c_int, _y: c_int) { let tmp = local_window(); - tmp.borrow().handle_key(key) + tmp.handle_key(key) } } glut::keyboard_func(~KeyboardCallbackState); @@ -114,16 +114,16 @@ impl WindowMethods<Application> for Window { fn call(&self, button: c_int, state: c_int, x: c_int, y: c_int) { if button < 3 { let tmp = local_window(); - tmp.borrow().handle_mouse(button, state, x, y); + tmp.handle_mouse(button, state, x, y); } else { match button { 3 => { let tmp = local_window(); - tmp.borrow().event_queue.with_mut(|queue| queue.push(ScrollWindowEvent(Point2D(0.0, 5.0 as f32), Point2D(0.0 as i32, 5.0 as i32)))); + tmp.event_queue.borrow_mut().push(ScrollWindowEvent(Point2D(0.0, 5.0 as f32), Point2D(0.0 as i32, 5.0 as i32))); }, 4 => { let tmp = local_window(); - tmp.borrow().event_queue.with_mut(|queue| queue.push(ScrollWindowEvent(Point2D(0.0, -5.0 as f32), Point2D(0.0 as i32, -5.0 as i32)))); + tmp.event_queue.borrow_mut().push(ScrollWindowEvent(Point2D(0.0, -5.0 as f32), Point2D(0.0 as i32, -5.0 as i32))); }, _ => {} } @@ -150,15 +150,13 @@ impl WindowMethods<Application> for Window { } fn recv(&self) -> WindowEvent { - if !self.event_queue.with_mut(|queue| queue.is_empty()) { - return self.event_queue.with_mut(|queue| queue.shift().unwrap()) + if !self.event_queue.borrow_mut().is_empty() { + return self.event_queue.borrow_mut().shift().unwrap(); } + glut::check_loop(); - if !self.event_queue.with_mut(|queue| queue.is_empty()) { - self.event_queue.with_mut(|queue| queue.shift().unwrap()) - } else { - IdleWindowEvent - } + + self.event_queue.borrow_mut().shift().unwrap_or(IdleWindowEvent) } /// Sets the ready state. @@ -174,7 +172,7 @@ impl WindowMethods<Application> for Window { self.render_state.get() == RenderingRenderState && render_state == IdleRenderState { // page loaded - self.event_queue.with_mut(|queue| queue.push(FinishedWindowEvent)); + self.event_queue.borrow_mut().push(FinishedWindowEvent); } self.render_state.set(render_state); @@ -219,16 +217,16 @@ impl Window { let modifiers = glut::get_modifiers(); match key { 42 => self.load_url(), - 43 => self.event_queue.with_mut(|queue| queue.push(ZoomWindowEvent(1.1))), - 45 => self.event_queue.with_mut(|queue| queue.push(ZoomWindowEvent(0.909090909))), - 56 => self.event_queue.with_mut(|queue| queue.push(ScrollWindowEvent(Point2D(0.0, 5.0 as f32), Point2D(0.0 as i32, 5.0 as i32)))), - 50 => self.event_queue.with_mut(|queue| queue.push(ScrollWindowEvent(Point2D(0.0, -5.0 as f32), Point2D(0.0 as i32, -5.0 as i32)))), + 43 => self.event_queue.borrow_mut().push(ZoomWindowEvent(1.1)), + 45 => self.event_queue.borrow_mut().push(ZoomWindowEvent(0.909090909)), + 56 => self.event_queue.borrow_mut().push(ScrollWindowEvent(Point2D(0.0, 5.0 as f32), Point2D(0.0 as i32, 5.0 as i32))), + 50 => self.event_queue.borrow_mut().push(ScrollWindowEvent(Point2D(0.0, -5.0 as f32), Point2D(0.0 as i32, -5.0 as i32))), 127 => { if (modifiers & ACTIVE_SHIFT) != 0 { - self.event_queue.with_mut(|queue| queue.push(NavigationWindowEvent(Forward))); + self.event_queue.borrow_mut().push(NavigationWindowEvent(Forward)); } else { - self.event_queue.with_mut(|queue| queue.push(NavigationWindowEvent(Back))); + self.event_queue.borrow_mut().push(NavigationWindowEvent(Back)); } } _ => {} @@ -253,14 +251,14 @@ impl Window { if pixel_dist < max_pixel_dist { let click_event = MouseWindowClickEvent(button as uint, Point2D(x as f32, y as f32)); - self.event_queue.with_mut(|queue| queue.push(MouseWindowEventClass(click_event))); + self.event_queue.borrow_mut().push(MouseWindowEventClass(click_event)); } } MouseWindowMouseUpEvent(button as uint, Point2D(x as f32, y as f32)) } _ => fail!("I cannot recognize the type of mouse action that occured. :-(") }; - self.event_queue.with_mut(|queue| queue.push(MouseWindowEventClass(event))); + self.event_queue.borrow_mut().push(MouseWindowEventClass(event)); } /// Helper function to pop up an alert box prompting the user to load a URL. @@ -270,9 +268,9 @@ impl Window { alert.run(); let value = alert.prompt_value(); if "" == value { // To avoid crashing on Linux. - self.event_queue.with_mut(|queue| queue.push(LoadUrlWindowEvent(~"http://purple.com/"))) + self.event_queue.borrow_mut().push(LoadUrlWindowEvent(~"http://purple.com/")) } else { - self.event_queue.with_mut(|queue| queue.push(LoadUrlWindowEvent(value.clone()))) + self.event_queue.borrow_mut().push(LoadUrlWindowEvent(value.clone())) } } } diff --git a/src/components/main/servo.rs b/src/components/main/servo.rs index 225922f01d6..72a28d93322 100755 --- a/src/components/main/servo.rs +++ b/src/components/main/servo.rs @@ -6,7 +6,7 @@ #[comment = "The Servo Parallel Browser Project"]; #[license = "MPL"]; -#[feature(globs, macro_rules, managed_boxes, phase, thread_local)]; +#[feature(globs, macro_rules, phase, thread_local)]; #[feature(phase)]; #[phase(syntax, link)] @@ -67,7 +67,8 @@ use servo_util::opts; #[cfg(not(test))] use servo_util::url::parse_url; -#[cfg(not(test))] + +#[cfg(not(test), not(target_os="android"))] use std::os; #[cfg(not(test), target_os="android")] use std::str; diff --git a/src/components/msg/compositor_msg.rs b/src/components/msg/compositor_msg.rs index 8518bd3024a..33e0230d687 100644 --- a/src/components/msg/compositor_msg.rs +++ b/src/components/msg/compositor_msg.rs @@ -121,7 +121,6 @@ pub struct LayerMetadata { /// submit them to be drawn to the display. pub trait RenderListener { fn get_graphics_metadata(&self) -> Option<NativeGraphicsMetadata>; - fn create_layer_group_for_pipeline(&self, PipelineId, Size2D<uint>); /// Informs the compositor of the layers for the given pipeline. The compositor responds by /// creating and/or destroying render layers as necessary. diff --git a/src/components/msg/msg.rs b/src/components/msg/msg.rs index 659de719d32..c3e332746f3 100644 --- a/src/components/msg/msg.rs +++ b/src/components/msg/msg.rs @@ -4,8 +4,8 @@ #[crate_id = "github.com/mozilla/servo#msg:0.1"]; #[crate_type = "lib"]; - -#[feature(managed_boxes)]; +#[crate_type = "dylib"]; +#[crate_type = "rlib"]; extern crate azure; extern crate geom; diff --git a/src/components/net/net.rs b/src/components/net/net.rs index 7f4b340cf84..c0f1080e699 100644 --- a/src/components/net/net.rs +++ b/src/components/net/net.rs @@ -4,8 +4,10 @@ #[crate_id = "github.com/mozilla/servo#net:0.1"]; #[crate_type = "lib"]; +#[crate_type = "dylib"]; +#[crate_type = "rlib"]; -#[feature(globs, managed_boxes)]; +#[feature(globs)]; #[feature(phase)]; #[phase(syntax, link)] diff --git a/src/components/script/dom/attr.rs b/src/components/script/dom/attr.rs index 8357665b63d..40da74cfbd2 100644 --- a/src/components/script/dom/attr.rs +++ b/src/components/script/dom/attr.rs @@ -6,7 +6,7 @@ use dom::bindings::codegen::AttrBinding; use dom::bindings::js::JS; use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object}; use dom::window::Window; -use servo_util::namespace::{Namespace, Null}; +use servo_util::namespace::Namespace; use servo_util::str::DOMString; #[deriving(Encodable)] @@ -43,20 +43,9 @@ impl Attr { } } - pub fn new(window: &JS<Window>, local_name: DOMString, value: DOMString) -> JS<Attr> { - let name = local_name.clone(); - Attr::new_helper(window, local_name, value, name, Null, None) - } - - pub fn new_ns(window: &JS<Window>, local_name: DOMString, value: DOMString, - name: DOMString, namespace: Namespace, - prefix: Option<DOMString>) -> JS<Attr> { - Attr::new_helper(window, local_name, value, name, namespace, prefix) - } - - fn new_helper(window: &JS<Window>, local_name: DOMString, value: DOMString, - name: DOMString, namespace: Namespace, - prefix: Option<DOMString>) -> JS<Attr> { + pub fn new(window: &JS<Window>, local_name: DOMString, value: DOMString, + name: DOMString, namespace: Namespace, + prefix: Option<DOMString>) -> JS<Attr> { let attr = Attr::new_inherited(local_name, value, name, namespace, prefix); reflect_dom_object(~attr, window, AttrBinding::Wrap) } diff --git a/src/components/script/dom/bindings/callback.rs b/src/components/script/dom/bindings/callback.rs index dff5aeb6a2b..a6d7eb6a507 100644 --- a/src/components/script/dom/bindings/callback.rs +++ b/src/components/script/dom/bindings/callback.rs @@ -5,7 +5,7 @@ use dom::bindings::utils::Reflectable; use js::jsapi::{JSContext, JSObject, JS_WrapObject, JS_ObjectIsCallable}; use js::jsapi::{JS_GetProperty, JSTracer, JS_CallTracer}; -use js::jsval::JSVal; +use js::jsval::{JSVal, UndefinedValue}; use js::JSTRACE_OBJECT; use std::cast; @@ -61,20 +61,20 @@ impl CallbackInterface { } } - pub fn GetCallableProperty(&self, cx: *JSContext, name: *libc::c_char, callable: &mut JSVal) -> bool { + pub fn GetCallableProperty(&self, cx: *JSContext, name: &str) -> Result<JSVal, ()> { + let mut callable = UndefinedValue(); unsafe { - if JS_GetProperty(cx, self.callback, name, &*callable) == 0 { - return false; + if name.to_c_str().with_ref(|name| JS_GetProperty(cx, self.callback, name, &mut callable as *mut JSVal as *JSVal)) == 0 { + return Err(()); } if !callable.is_object() || JS_ObjectIsCallable(cx, callable.to_object()) == 0 { //ThrowErrorMessage(cx, MSG_NOT_CALLABLE, description.get()); - return false; + return Err(()); } - - return true; } + Ok(callable) } } diff --git a/src/components/script/dom/bindings/codegen/CodegenRust.py b/src/components/script/dom/bindings/codegen/CodegenRust.py index d319ebe909e..506398570ce 100644 --- a/src/components/script/dom/bindings/codegen/CodegenRust.py +++ b/src/components/script/dom/bindings/codegen/CodegenRust.py @@ -1038,120 +1038,18 @@ class CGArgumentConverter(CGThing): self.replacementVariables, self.argcAndIndex).define() -def getWrapTemplateForType(type, descriptorProvider, result, successCode, - isCreator, exceptionCode): - """ - Reflect a C++ value stored in "result", of IDL type "type" into JS. The - "successCode" is the code to run once we have successfully done the - conversion. The resulting string should be used with string.Template, it - needs the following keys when substituting: jsvalPtr/jsvalRef/obj. - Returns (templateString, infallibility of conversion template) +def wrapForType(jsvalRef, result='result', successCode='return 1;'): """ - haveSuccessCode = successCode is not None - if not haveSuccessCode: - successCode = "return 1;" - - # We often want exceptionCode to be indented, since it often appears in an - # if body. - exceptionCodeIndented = CGIndenter(CGGeneric(exceptionCode)) - - def setValue(value, callWrapValue=False): - """ - Returns the code to set the jsval to value. If "callWrapValue" is true - JS_WrapValue will be called on the jsval. - """ - if not callWrapValue: - tail = successCode - elif haveSuccessCode: - tail = ("if JS_WrapValue(cx, ${jsvalPtr}) == 0 {\n" + - " return 0;\n" + - "}\n" + - successCode) - else: - tail = "return JS_WrapValue(cx, ${jsvalPtr} as *JSVal);" - return ("${jsvalRef} = %s;\n" + - tail) % (value) - - if type is None or type.isVoid(): - return (setValue("UndefinedValue()"), True) + Reflect a Rust value into JS. - if type.isArray(): - raise TypeError("Can't handle array return values yet") - - if type.isSequence(): - raise TypeError("Can't handle sequence return values yet") - - if type.isGeckoInterface(): - return (setValue("(%s).to_jsval(cx)" % result), True) - - if type.isString(): - return (setValue("(%s).to_jsval(cx)" % result), True) - - if type.isEnum(): - return (setValue("(%s).to_jsval(cx)" % result), True) - - if type.isCallback(): - assert not type.isInterface() - # XXXbz we're going to assume that callback types are always - # nullable and always have [TreatNonCallableAsNull] for now. - # See comments in WrapNewBindingObject explaining why we need - # to wrap here. - # NB: setValue(..., True) calls JS_WrapValue(), so is fallible - return (setValue("JS::ObjectOrNullValue(%s)" % result, True), False) - - if type.tag() == IDLType.Tags.any: - # See comments in WrapNewBindingObject explaining why we need - # to wrap here. - # NB: setValue(..., True) calls JS_WrapValue(), so is fallible - return (setValue(result, True), False) - - if type.isObject() or type.isSpiderMonkeyInterface(): - # See comments in WrapNewBindingObject explaining why we need - # to wrap here. - if type.nullable(): - toValue = "ObjectOrNullValue(%s)" - else: - toValue = "ObjectValue(&*(%s))" - # NB: setValue(..., True) calls JS_WrapValue(), so is fallible - return (setValue(toValue % result, True), False) - - if not type.isPrimitive(): - raise TypeError("Need to learn to wrap %s" % type) - - return (setValue("(%s).to_jsval(cx)" % result), True) - - -def wrapForType(type, descriptorProvider, templateValues): + * 'jsvalRef': a Rust reference to the JSVal in which to store the result + of the conversion; + * 'result': the name of the variable in which the Rust value is stored; + * 'successCode': the code to run once we have done the conversion. """ - Reflect a C++ value of IDL type "type" into JS. TemplateValues is a dict - that should contain: - - * 'jsvalRef': a C++ reference to the jsval in which to store the result of - the conversion - * 'jsvalPtr': a C++ pointer to the jsval in which to store the result of - the conversion - * 'obj' (optional): the name of the variable that contains the JSObject to - use as a scope when wrapping, if not supplied 'obj' - will be used as the name - * 'result' (optional): the name of the variable in which the C++ value is - stored, if not supplied 'result' will be used as - the name - * 'successCode' (optional): the code to run once we have successfully done - the conversion, if not supplied 'return true;' - will be used as the code - * 'isCreator' (optional): If true, we're wrapping for the return value of - a [Creator] method. Assumed false if not set. - """ - wrap = getWrapTemplateForType(type, descriptorProvider, - templateValues.get('result', 'result'), - templateValues.get('successCode', None), - templateValues.get('isCreator', False), - templateValues.get('exceptionCode', - "return 0;"),)[0] + return "%s = (%s).to_jsval(cx);\n%s" % (jsvalRef, result, successCode) - defaultValues = {'obj': 'obj'} - return string.Template(wrap).substitute(defaultValues, **templateValues) def typeNeedsCx(type, retVal=False): if type is None: @@ -1361,13 +1259,13 @@ class MethodDefiner(PropertyDefiner): if any(m.isGetter() and m.isIndexed() for m in methods): self.chrome.append({"name": 'iterator', "methodInfo": False, - "nativeName": "crust::JS_ArrayIterator", + "nativeName": "JS_ArrayIterator", "length": 0, "flags": "JSPROP_ENUMERATE", "pref": None }) self.regular.append({"name": 'iterator', "methodInfo": False, - "nativeName": "crust::JS_ArrayIterator", + "nativeName": "JS_ArrayIterator", "length": 0, "flags": "JSPROP_ENUMERATE", "pref": None }) @@ -1630,19 +1528,19 @@ static Class_name: [u8, ..%i] = %s; static Class: DOMJSClass = DOMJSClass { base: JSClass { name: &Class_name as *u8 as *libc::c_char, flags: JSCLASS_IS_DOMJSCLASS | %s | (((%s) & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT), //JSCLASS_HAS_RESERVED_SLOTS(%s), - addProperty: Some(%s), /* addProperty */ - delProperty: Some(crust::JS_PropertyStub), /* delProperty */ - getProperty: Some(crust::JS_PropertyStub), /* getProperty */ - setProperty: Some(crust::JS_StrictPropertyStub), /* setProperty */ - enumerate: Some(crust::JS_EnumerateStub), - resolve: Some(crust::JS_ResolveStub), - convert: Some(crust::JS_ConvertStub), - finalize: Some(%s), /* finalize */ - checkAccess: None, /* checkAccess */ - call: None, /* call */ - hasInstance: None, /* hasInstance */ - construct: None, /* construct */ - trace: %s, /* trace */ + addProperty: Some(JS_PropertyStub), + delProperty: Some(JS_PropertyStub), + getProperty: Some(JS_PropertyStub), + setProperty: Some(JS_StrictPropertyStub), + enumerate: Some(JS_EnumerateStub), + resolve: Some(JS_ResolveStub), + convert: Some(JS_ConvertStub), + finalize: Some(%s), + checkAccess: None, + call: None, + hasInstance: None, + construct: None, + trace: %s, reserved: (0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, // 05 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, // 10 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, // 15 @@ -1657,7 +1555,6 @@ static Class: DOMJSClass = DOMJSClass { """ % (len(self.descriptor.interface.identifier.name) + 1, str_to_const_array(self.descriptor.interface.identifier.name), flags, slots, slots, - 'crust::JS_PropertyStub', FINALIZE_HOOK_NAME, traceHook, CGIndenter(CGGeneric(DOMClass(self.descriptor))).define()) @@ -1675,19 +1572,19 @@ static PrototypeClassName__: [u8, ..%s] = %s; static PrototypeClass: JSClass = JSClass { name: &PrototypeClassName__ as *u8 as *libc::c_char, flags: (1 & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT, //JSCLASS_HAS_RESERVED_SLOTS(1) - addProperty: Some(crust::JS_PropertyStub), /* addProperty */ - delProperty: Some(crust::JS_PropertyStub), /* delProperty */ - getProperty: Some(crust::JS_PropertyStub), /* getProperty */ - setProperty: Some(crust::JS_StrictPropertyStub), /* setProperty */ - enumerate: Some(crust::JS_EnumerateStub), - resolve: Some(crust::JS_ResolveStub), - convert: Some(crust::JS_ConvertStub), - finalize: None, /* finalize */ - checkAccess: None, /* checkAccess */ - call: None, /* call */ - hasInstance: None, /* hasInstance */ - construct: None, /* construct */ - trace: None, /* trace */ + addProperty: Some(JS_PropertyStub), + delProperty: Some(JS_PropertyStub), + getProperty: Some(JS_PropertyStub), + setProperty: Some(JS_StrictPropertyStub), + enumerate: Some(JS_EnumerateStub), + resolve: Some(JS_ResolveStub), + convert: Some(JS_ConvertStub), + finalize: None, + checkAccess: None, + call: None, + hasInstance: None, + construct: None, + trace: None, reserved: (0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, // 05 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, // 10 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, 0 as *libc::c_void, // 15 @@ -1713,19 +1610,19 @@ class CGInterfaceObjectJSClass(CGThing): return """ static InterfaceObjectClass: JSClass = { %s, 0, - crust::JS_PropertyStub, /* addProperty */ - crust::JS_PropertyStub, /* delProperty */ - crust::JS_PropertyStub, /* getProperty */ - crust::JS_StrictPropertyStub, /* setProperty */ - crust::JS_EnumerateStub, - crust::JS_ResolveStub, - crust::JS_ConvertStub, - 0 as *u8, /* finalize */ - 0 as *u8, /* checkAccess */ - %s, /* call */ - %s, /* hasInstance */ - %s, /* construct */ - 0 as *u8, /* trace */ + JS_PropertyStub, + JS_PropertyStub, + JS_PropertyStub, + JS_StrictPropertyStub, + JS_EnumerateStub, + JS_ResolveStub, + JS_ConvertStub, + 0 as *u8, + 0 as *u8, + %s, + %s, + %s, + 0 as *u8, JSCLASS_NO_INTERNAL_MEMBERS }; """ % (str_to_const_array("Function"), ctorname, hasinstance, ctorname) @@ -1960,12 +1857,6 @@ class CGAbstractMethod(CGThing): def definition_body(self): assert(False) # Override me! -def DOMObjectPointerType(descriptor): - return "~" - -def DOMObjectPointerArg(descriptor): - return DOMObjectPointerType(descriptor) + descriptor.concreteType - def CreateBindingJSObject(descriptor, parent=None): create = " let mut raw: JS<%s> = JS::from_raw(&mut *aObject);\n" % descriptor.concreteType if descriptor.proxy: @@ -1998,10 +1889,10 @@ class CGWrapMethod(CGAbstractMethod): assert descriptor.interface.hasInterfacePrototypeObject() if not descriptor.createGlobal: args = [Argument('*JSContext', 'aCx'), Argument('&JS<Window>', 'aScope'), - Argument(DOMObjectPointerArg(descriptor), 'aObject', mutable=True)] + Argument("~" + descriptor.concreteType, 'aObject', mutable=True)] else: args = [Argument('*JSContext', 'aCx'), - Argument(DOMObjectPointerArg(descriptor), 'aObject', mutable=True)] + Argument("~" + descriptor.concreteType, 'aObject', mutable=True)] retval = 'JS<%s>' % descriptor.concreteType CGAbstractMethod.__init__(self, descriptor, 'Wrap', retval, args, pub=True) @@ -2232,7 +2123,7 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod): """ def __init__(self, descriptor): args = [Argument('&mut JSPageInfo', 'js_info')] - CGAbstractMethod.__init__(self, descriptor, 'DefineDOMInterface', 'bool', args, pub=True) + CGAbstractMethod.__init__(self, descriptor, 'DefineDOMInterface', 'void', args, pub=True) def define(self): return CGAbstractMethod.define(self) @@ -2289,7 +2180,7 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod): return (body + """ let cx = js_info.js_context.deref().ptr; let receiver = js_info.js_compartment.global_obj; let global: *JSObject = JS_GetGlobalForObject(cx, receiver); - return %s(cx, global, receiver).is_not_null();""" % (getter)) + assert!(%s(cx, global, receiver).is_not_null());""" % (getter)) def needCx(returnType, arguments, extendedAttributes, considerTypes): return (considerTypes and @@ -2445,18 +2336,7 @@ class CGPerSignatureCall(CGThing): return not 'infallible' in self.extendedAttributes def wrap_return_value(self): - isCreator = memberIsCreator(self.idlNode) - resultTemplateValues = { 'jsvalRef': '*vp', 'jsvalPtr': 'vp', - 'isCreator': isCreator} - try: - return wrapForType(self.returnType, self.descriptor, - resultTemplateValues) - except MethodNotCreatorError, err: - assert not isCreator - raise TypeError("%s being returned from non-creator method or property %s.%s" % - (err.typename, - self.descriptor.interface.identifier.name, - self.idlNode.identifier.name)) + return wrapForType('*vp') def getErrorReport(self): return CGGeneric( @@ -2617,7 +2497,7 @@ class CGSpecializedMethod(CGAbstractExternMethod): def __init__(self, descriptor, method): self.method = method name = method.identifier.name - args = [Argument('*JSContext', 'cx'), Argument('JSHandleObject', 'obj'), + args = [Argument('*JSContext', 'cx'), Argument('JSHandleObject', '_obj'), Argument('*mut %s' % descriptor.concreteType, 'this'), Argument('libc::c_uint', 'argc'), Argument('*mut JSVal', 'vp')] CGAbstractExternMethod.__init__(self, descriptor, name, 'JSBool', args) @@ -2634,7 +2514,6 @@ class CGSpecializedMethod(CGAbstractExternMethod): return CGWrapper(CGMethodCall(argsPre, nativeName, self.method.isStatic(), self.descriptor, self.method), pre=extraPre + - " let obj = *obj.unnamed;\n" + " let this = &mut *this;\n").define() class CGGenericGetter(CGAbstractBindingMethod): @@ -2672,7 +2551,7 @@ class CGSpecializedGetter(CGAbstractExternMethod): self.attr = attr name = 'get_' + attr.identifier.name args = [ Argument('*JSContext', 'cx'), - Argument('JSHandleObject', 'obj'), + Argument('JSHandleObject', '_obj'), Argument('*mut %s' % descriptor.concreteType, 'this'), Argument('*mut JSVal', 'vp') ] CGAbstractExternMethod.__init__(self, descriptor, name, "JSBool", args) @@ -2694,7 +2573,6 @@ class CGSpecializedGetter(CGAbstractExternMethod): return CGWrapper(CGIndenter(CGGetterCall(argsPre, self.attr.type, nativeName, self.descriptor, self.attr)), pre=extraPre + - " let obj = *obj.unnamed;\n" + " let this = &mut *this;\n").define() class CGGenericSetter(CGAbstractBindingMethod): @@ -2738,7 +2616,7 @@ class CGSpecializedSetter(CGAbstractExternMethod): self.attr = attr name = 'set_' + attr.identifier.name args = [ Argument('*JSContext', 'cx'), - Argument('JSHandleObject', 'obj'), + Argument('JSHandleObject', '_obj'), Argument('*mut %s' % descriptor.concreteType, 'this'), Argument('*mut JSVal', 'argv')] CGAbstractExternMethod.__init__(self, descriptor, name, "JSBool", args) @@ -2755,22 +2633,8 @@ class CGSpecializedSetter(CGAbstractExternMethod): return CGWrapper(CGIndenter(CGSetterCall(argsPre, self.attr.type, nativeName, self.descriptor, self.attr)), pre=extraPre + - " let obj = *obj.unnamed;\n" + " let this = &mut *this;\n").define() -def infallibleForMember(member, type, descriptorProvider): - """ - Determine the fallibility of changing a C++ value of IDL type "type" into - JS for the given attribute. Apart from isCreator, all the defaults are used, - since the fallbility does not change based on the boolean values, - and the template will be discarded. - - CURRENT ASSUMPTIONS: - We assume that successCode for wrapping up return values cannot contain - failure conditions. - """ - return getWrapTemplateForType(type, descriptorProvider, 'result', None,\ - memberIsCreator(member), "return false;",)[1] class CGMemberJITInfo(CGThing): """ @@ -2799,7 +2663,6 @@ class CGMemberJITInfo(CGThing): getterinfo = ("%s_getterinfo" % self.member.identifier.name) getter = ("get_%s" % self.member.identifier.name) getterinfal = "infallible" in self.descriptor.getExtendedAttributes(self.member, getter=True) - getterinfal = getterinfal and infallibleForMember(self.member, self.member.type, self.descriptor) result = self.defineJitInfo(getterinfo, getter, getterinfal) if not self.member.readonly: setterinfo = ("%s_setterinfo" % self.member.identifier.name) @@ -2821,7 +2684,7 @@ class CGMemberJITInfo(CGThing): # Don't handle overloading. If there's more than one signature, # one of them must take arguments. sig = sigs[0] - if len(sig[1]) == 0 and infallibleForMember(self.member, sig[0], self.descriptor): + if len(sig[1]) == 0: # No arguments and infallible return boxing methodInfal = True @@ -3693,7 +3556,7 @@ class CGProxySpecialOperation(CGPerSignatureCall): if not self.idlNode.isGetter() or self.templateValues is None: return "" - wrap = CGGeneric(wrapForType(self.returnType, self.descriptor, self.templateValues)) + wrap = CGGeneric(wrapForType(**self.templateValues)) wrap = CGIfWrapper(wrap, "found") return "\n" + wrap.define() @@ -3761,8 +3624,7 @@ class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod): if indexedGetter: readonly = toStringBool(self.descriptor.operations['IndexedSetter'] is None) fillDescriptor = "FillPropertyDescriptor(&mut *desc, proxy, %s);\nreturn 1;" % readonly - templateValues = {'jsvalRef': '(*desc).value', 'jsvalPtr': '&mut (*desc).value', - 'obj': 'proxy', 'successCode': fillDescriptor} + templateValues = {'jsvalRef': '(*desc).value', 'successCode': fillDescriptor} get = ("if index.is_some() {\n" + " let index = index.unwrap();\n" + " let this: *%s = UnwrapProxy(proxy);\n" + @@ -3803,8 +3665,7 @@ class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod): if namedGetter: readonly = toStringBool(self.descriptor.operations['NamedSetter'] is None) fillDescriptor = "FillPropertyDescriptor(&mut *desc, proxy, %s);\nreturn 1;" % readonly - templateValues = {'jsvalRef': '(*desc).value', 'jsvalPtr': '&mut(*desc).value', - 'obj': 'proxy', 'successCode': fillDescriptor} + templateValues = {'jsvalRef': '(*desc).value', 'successCode': fillDescriptor} # Once we start supporting OverrideBuiltins we need to make # ResolveOwnProperty or EnumerateOwnProperties filter out named # properties that shadow prototype properties. @@ -3958,7 +3819,7 @@ if expando.is_not_null() { } }""" - templateValues = {'jsvalRef': '*vp', 'jsvalPtr': 'vp', 'obj': 'proxy'} + templateValues = {'jsvalRef': '*vp'} indexedGetter = self.descriptor.operations['IndexedGetter'] if indexedGetter: @@ -4061,9 +3922,9 @@ class CGAbstractClassHook(CGAbstractExternMethod): def finalizeHook(descriptor, hookName, context): release = """let val = JS_GetReservedSlot(obj, dom_object_slot(obj)); -let _: %s %s = cast::transmute(val.to_private()); +let _: ~%s = cast::transmute(val.to_private()); debug!("%s finalize: {:p}", this); -""" % (DOMObjectPointerType(descriptor), descriptor.concreteType, descriptor.concreteType) +""" % (descriptor.concreteType, descriptor.concreteType) return release class CGClassTraceHook(CGAbstractClassHook): @@ -4514,7 +4375,7 @@ class CGRegisterProtos(CGAbstractMethod): self.config = config def _registerProtos(self): - lines = [" assert!(codegen::%sBinding::DefineDOMInterface(js_info));" % (desc.name) + lines = [" codegen::%sBinding::DefineDOMInterface(js_info);" % desc.name for desc in self.config.getDescriptors(hasInterfaceObject=True, register=True)] return '\n'.join(lines) + '\n' @@ -4587,7 +4448,7 @@ class CGBindingRoot(CGThing): #XXXjdm This should only import the namespace for the current binding, # not every binding ever. curr = CGImports(curr, [ - 'js::{crust, JS_ARGV, JS_CALLEE, JS_THIS_OBJECT}', + 'js::{JS_ARGV, JS_CALLEE, JS_THIS_OBJECT}', 'js::{JSCLASS_GLOBAL_SLOT_COUNT, JSCLASS_IS_DOMJSCLASS}', 'js::{JSCLASS_IS_GLOBAL, JSCLASS_RESERVED_SLOTS_SHIFT}', 'js::{JSCLASS_RESERVED_SLOTS_MASK, JSID_VOID, JSJitInfo}', @@ -4600,9 +4461,10 @@ class CGBindingRoot(CGThing): 'js::jsapi::{JS_NewObject, JS_ObjectIsCallable, JS_SetPrototype}', 'js::jsapi::{JS_SetReservedSlot, JS_WrapValue, JSBool, JSContext}', 'js::jsapi::{JSClass, JSFreeOp, JSFunctionSpec, JSHandleObject, jsid}', - 'js::jsapi::{JSNativeWrapper, JSObject, JSPropertyDescriptor}', - 'js::jsapi::{JSPropertyOpWrapper, JSPropertySpec}', - 'js::jsapi::{JSStrictPropertyOpWrapper, JSString, JSTracer}', + 'js::jsapi::{JSNativeWrapper, JSObject, JSPropertyDescriptor, JS_ArrayIterator}', + 'js::jsapi::{JSPropertyOpWrapper, JSPropertySpec, JS_PropertyStub}', + 'js::jsapi::{JSStrictPropertyOpWrapper, JSString, JSTracer, JS_ConvertStub}', + 'js::jsapi::{JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub}', 'js::jsval::JSVal', 'js::jsval::{ObjectValue, ObjectOrNullValue, PrivateValue}', 'js::jsval::{NullValue, UndefinedValue}', @@ -5293,21 +5155,9 @@ class CallbackMember(CGNativeMember): result = argval prepend = "" - conversion = prepend + wrapForType( - arg.type, self.descriptorProvider, - { - 'result' : result, - 'successCode' : "continue;" if arg.variadic else "break;", - 'jsvalRef' : "argv[%s]" % jsvalIndex, - 'jsvalHandle' : "argv.handleAt(%s)" % jsvalIndex, - 'jsvalPtr': "&mut argv[%s]" % jsvalIndex, - # XXXbz we don't have anything better to use for 'obj', - # really... It's OK to use CallbackPreserveColor because - # CallSetup already handled the unmark-gray bits for us. - 'obj' : 'ptr::null() /*XXXjdm proper scope*/', #XXXjdm 'CallbackPreserveColor()', - 'returnsNewObject': False, - 'exceptionCode' : self.exceptionCode - }) + conversion = prepend + wrapForType("argv[%s]" % jsvalIndex, + result=result, + successCode="continue;" if arg.variadic else "break;") if arg.variadic: conversion = string.Template( "for (uint32_t idx = 0; idx < ${arg}.Length(); ++idx) {\n" + @@ -5453,19 +5303,19 @@ class CallbackOperationBase(CallbackMethod): "methodName": self.methodName } getCallableFromProp = string.Template( - 'if "${methodName}".to_c_str().with_ref(|name| !self.parent.GetCallableProperty(cx, name, &mut callable)) {\n' - ' return${errorReturn};\n' - '}\n').substitute(replacements) + 'match self.parent.GetCallableProperty(cx, "${methodName}") {\n' + ' Err(_) => return${errorReturn},\n' + ' Ok(callable) => callable,\n' + '}').substitute(replacements) if not self.singleOperation: return 'JS::Rooted<JS::Value> callable(cx);\n' + getCallableFromProp return ( 'let isCallable = unsafe { JS_ObjectIsCallable(cx, self.parent.callback) != 0 };\n' - 'let mut callable = UndefinedValue();\n' - 'if isCallable {\n' - ' callable = unsafe { ObjectValue(&*self.parent.callback) };\n' - '} else {\n' - '%s' - '}\n' % CGIndenter(CGGeneric(getCallableFromProp)).define()) + 'let callable =\n' + + CGIndenter( + CGIfElseWrapper('isCallable', + CGGeneric('unsafe { ObjectValue(&*self.parent.callback) }'), + CGGeneric(getCallableFromProp))).define() + ';\n') class CallbackOperation(CallbackOperationBase): """ @@ -5712,7 +5562,7 @@ class GlobalGenRoots(): 'dom::bindings::error::throw_not_in_union', 'dom::bindings::js::JS', 'dom::types::*', - 'js::{crust, JS_ARGV, JS_CALLEE, JS_THIS_OBJECT}', + 'js::{JS_ARGV, JS_CALLEE, JS_THIS_OBJECT}', 'js::{JSCLASS_GLOBAL_SLOT_COUNT, JSCLASS_IS_DOMJSCLASS}', 'js::{JSCLASS_IS_GLOBAL, JSCLASS_RESERVED_SLOTS_SHIFT}', 'js::{JSCLASS_RESERVED_SLOTS_MASK, JSID_VOID, JSJitInfo}', diff --git a/src/components/script/dom/bindings/conversions.rs b/src/components/script/dom/bindings/conversions.rs index 513dac9964a..1826782ac84 100644 --- a/src/components/script/dom/bindings/conversions.rs +++ b/src/components/script/dom/bindings/conversions.rs @@ -14,8 +14,8 @@ use js::jsapi::{JS_ValueToUint16, JS_ValueToNumber, JS_ValueToBoolean}; use js::jsapi::{JS_NewUCStringCopyN, JS_ValueToString}; use js::jsapi::{JS_WrapValue}; use js::jsval::JSVal; -use js::jsval::{NullValue, BooleanValue, Int32Value, UInt32Value, StringValue}; -use js::jsval::ObjectValue; +use js::jsval::{UndefinedValue, NullValue, BooleanValue, Int32Value, UInt32Value}; +use js::jsval::{StringValue, ObjectValue}; use js::glue::RUST_JS_NumberValue; use std::default::Default; use std::libc; @@ -29,6 +29,22 @@ pub trait FromJSValConvertible<T> { } +impl ToJSValConvertible for () { + fn to_jsval(&self, _cx: *JSContext) -> JSVal { + UndefinedValue() + } +} + +impl ToJSValConvertible for JSVal { + fn to_jsval(&self, cx: *JSContext) -> JSVal { + let mut value = *self; + if unsafe { JS_WrapValue(cx, &mut value as *mut JSVal as *JSVal) } == 0 { + fail!("JS_WrapValue failed."); + } + value + } +} + unsafe fn convert_from_jsval<T: Default>( cx: *JSContext, value: JSVal, convert_fn: extern "C" unsafe fn(*JSContext, JSVal, *T) -> JSBool) -> Result<T, ()> { diff --git a/src/components/script/dom/bindings/proxyhandler.rs b/src/components/script/dom/bindings/proxyhandler.rs index 80320ec4cfb..22df6e0df86 100644 --- a/src/components/script/dom/bindings/proxyhandler.rs +++ b/src/components/script/dom/bindings/proxyhandler.rs @@ -6,11 +6,11 @@ use dom::bindings::utils::is_dom_proxy; use js::jsapi::{JSContext, jsid, JSPropertyDescriptor, JSObject, JSString, jschar}; use js::jsapi::{JS_GetPropertyDescriptorById, JS_NewUCString, JS_malloc, JS_free}; use js::jsapi::{JSBool, JS_DefinePropertyById, JS_NewObjectWithGivenProto}; +use js::jsapi::JS_StrictPropertyStub; use js::jsval::ObjectValue; use js::glue::GetProxyExtra; use js::glue::{GetObjectProto, GetObjectParent, SetProxyExtra, GetProxyHandler}; use js::glue::InvokeGetOwnPropertyDescriptor; -use js::crust::{JS_StrictPropertyStub}; use js::{JSPROP_GETTER, JSPROP_ENUMERATE, JSPROP_READONLY, JSRESOLVE_QUALIFIED}; use std::cast; @@ -46,7 +46,10 @@ pub extern fn getPropertyDescriptor(cx: *JSContext, proxy: *JSObject, id: jsid, pub fn defineProperty_(cx: *JSContext, proxy: *JSObject, id: jsid, desc: *JSPropertyDescriptor) -> JSBool { unsafe { - if ((*desc).attrs & JSPROP_GETTER) != 0 && (*desc).setter == Some(JS_StrictPropertyStub) { + //FIXME: Workaround for https://github.com/mozilla/rust/issues/13385 + let setter: *libc::c_void = cast::transmute((*desc).setter); + let setter_stub: *libc::c_void = cast::transmute(JS_StrictPropertyStub); + if ((*desc).attrs & JSPROP_GETTER) != 0 && setter == setter_stub { /*return JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING | JSREPORT_STRICT | JSREPORT_STRICT_MODE_ERROR, diff --git a/src/components/script/dom/document.rs b/src/components/script/dom/document.rs index 6d8c7fe9313..f4391e4e541 100644 --- a/src/components/script/dom/document.rs +++ b/src/components/script/dom/document.rs @@ -59,7 +59,7 @@ pub struct Document { node: Node, reflector_: Reflector, window: JS<Window>, - idmap: HashMap<DOMString, JS<Element>>, + idmap: HashMap<DOMString, ~[JS<Element>]>, implementation: Option<JS<DOMImplementation>>, content_type: DOMString, encoding_name: DOMString, @@ -249,7 +249,7 @@ impl Document { // http://dom.spec.whatwg.org/#dom-document-getelementbyid. match self.idmap.find_equiv(&id) { None => None, - Some(node) => Some(node.clone()), + Some(ref elements) => Some(elements[0].clone()), } } @@ -647,8 +647,22 @@ impl Document { /// Remove any existing association between the provided id and any elements in this document. pub fn unregister_named_element(&mut self, + abstract_self: &JS<Element>, id: DOMString) { - self.idmap.remove(&id); + let mut is_empty = false; + match self.idmap.find_mut(&id) { + None => {}, + Some(elements) => { + let position = elements.iter() + .position(|element| element == abstract_self) + .expect("This element should be in registered."); + elements.remove(position); + is_empty = elements.is_empty(); + } + } + if is_empty { + self.idmap.remove(&id); + } } /// Associate an element present in this document with the provided id. @@ -660,17 +674,32 @@ impl Document { node.is_in_doc() }); - // TODO: support the case if multiple elements - // which haves same id are in the same document. // FIXME https://github.com/mozilla/rust/issues/13195 // Use mangle() when it exists again. + let root = self.GetDocumentElement().expect("The element is in the document, so there must be a document element."); match self.idmap.find_mut(&id) { - Some(v) => { - *v = element.clone(); + Some(elements) => { + let new_node = NodeCast::from(element); + let mut head : uint = 0u; + let root: JS<Node> = NodeCast::from(&root); + for node in root.traverse_preorder() { + match ElementCast::to(&node) { + Some(elem) => { + if elements[head] == elem { + head = head + 1; + } + if new_node == node || head == elements.len() { + break; + } + } + None => {} + } + } + elements.insert(head, element.clone()); return; }, None => (), } - self.idmap.insert(id, element.clone()); + self.idmap.insert(id, ~[element.clone()]); } } diff --git a/src/components/script/dom/domexception.rs b/src/components/script/dom/domexception.rs index fe439a944e2..1c44a88af1f 100644 --- a/src/components/script/dom/domexception.rs +++ b/src/components/script/dom/domexception.rs @@ -11,7 +11,7 @@ use servo_util::str::DOMString; #[repr(uint)] #[deriving(Show, Encodable)] -enum DOMErrorName { +pub enum DOMErrorName { IndexSizeError = DOMExceptionConstants::INDEX_SIZE_ERR, HierarchyRequestError = DOMExceptionConstants::HIERARCHY_REQUEST_ERR, WrongDocumentError = DOMExceptionConstants::WRONG_DOCUMENT_ERR, diff --git a/src/components/script/dom/element.rs b/src/components/script/dom/element.rs index 8299f516119..3abe8de8edb 100644 --- a/src/components/script/dom/element.rs +++ b/src/components/script/dom/element.rs @@ -7,26 +7,22 @@ use dom::attr::Attr; use dom::attrlist::AttrList; use dom::bindings::codegen::ElementBinding; -use dom::bindings::codegen::InheritTypes::{ElementDerived, HTMLImageElementCast}; -use dom::bindings::codegen::InheritTypes::{HTMLIFrameElementCast, NodeCast}; -use dom::bindings::codegen::InheritTypes::HTMLObjectElementCast; +use dom::bindings::codegen::InheritTypes::{ElementDerived, NodeCast}; use dom::bindings::js::JS; use dom::bindings::utils::{Reflectable, Reflector}; use dom::bindings::error::{ErrorResult, Fallible, NamespaceError, InvalidCharacter}; use dom::bindings::utils::{QName, Name, InvalidXMLName, xml_name_type}; -use dom::htmlcollection::HTMLCollection; use dom::clientrect::ClientRect; use dom::clientrectlist::ClientRectList; use dom::document::Document; use dom::eventtarget::{EventTarget, NodeTargetTypeId}; -use dom::htmlimageelement::HTMLImageElement; -use dom::htmliframeelement::HTMLIFrameElement; -use dom::htmlobjectelement::HTMLObjectElement; -use dom::node::{ElementNodeTypeId, Node, NodeHelpers, NodeIterator, document_from_node}; +use dom::htmlcollection::HTMLCollection; use dom::htmlserializer::serialize; +use dom::node::{ElementNodeTypeId, Node, NodeHelpers, NodeIterator, document_from_node}; +use dom::virtualmethods::{VirtualMethods, vtable_for}; use layout_interface::{ContentBoxQuery, ContentBoxResponse, ContentBoxesQuery}; use layout_interface::{ContentBoxesResponse, ContentChangedDocumentDamage}; -use layout_interface::{MatchSelectorsDocumentDamage}; +use layout_interface::MatchSelectorsDocumentDamage; use style; use servo_util::namespace; use servo_util::namespace::{Namespace, Null}; @@ -195,9 +191,14 @@ pub trait AttributeHandlers { fn set_attr(&mut self, name: DOMString, value: DOMString) -> ErrorResult; fn set_attribute(&mut self, namespace: Namespace, name: DOMString, value: DOMString) -> ErrorResult; - fn after_set_attr(&mut self, local_name: DOMString, value: DOMString); + fn do_set_attribute(&mut self, local_name: DOMString, value: DOMString, + name: DOMString, namespace: Namespace, + prefix: Option<DOMString>, cb: |&JS<Attr>| -> bool); + fn SetAttribute(&mut self, name: DOMString, value: DOMString) -> ErrorResult; + fn SetAttributeNS(&mut self, namespace_url: Option<DOMString>, + name: DOMString, value: DOMString) -> ErrorResult; + fn remove_attribute(&mut self, namespace: Namespace, name: DOMString) -> ErrorResult; - fn before_remove_attr(&mut self, local_name: DOMString, old_value: DOMString); fn notify_attribute_changed(&self, local_name: DOMString); fn has_class(&self, name: &str) -> bool; @@ -209,14 +210,6 @@ pub trait AttributeHandlers { fn set_uint_attribute(&mut self, name: &str, value: u32); } -pub trait AfterSetAttrListener { - fn AfterSetAttr(&mut self, name: DOMString, value: DOMString); -} - -pub trait BeforeRemoveAttrListener { - fn BeforeRemoveAttr(&mut self, name: DOMString); -} - impl AttributeHandlers for JS<Element> { fn get_attribute(&self, namespace: Namespace, name: &str) -> Option<JS<Attr>> { if self.get().html_element_in_html_document() { @@ -253,76 +246,123 @@ impl AttributeHandlers for JS<Element> { let node: JS<Node> = NodeCast::from(self); node.get().wait_until_safe_to_modify_dom(); - // FIXME: reduce the time of `value.clone()`. - let idx = self.get().attrs.iter().position(|attr| { + let position: |&JS<Attr>| -> bool = if self.get().html_element_in_html_document() { - attr.get().local_name.eq_ignore_ascii_case(local_name) + |attr| attr.get().local_name.eq_ignore_ascii_case(local_name) } else { - attr.get().local_name == local_name - } - }); + |attr| attr.get().local_name == local_name + }; + self.do_set_attribute(name.clone(), value, name.clone(), namespace::Null, None, position); + Ok(()) + } + fn do_set_attribute(&mut self, local_name: DOMString, value: DOMString, + name: DOMString, namespace: Namespace, + prefix: Option<DOMString>, cb: |&JS<Attr>| -> bool) { + let node: JS<Node> = NodeCast::from(self); + let idx = self.get().attrs.iter().position(cb); match idx { Some(idx) => { if namespace == namespace::Null { let old_value = self.get().attrs[idx].get().Value(); - self.before_remove_attr(local_name.clone(), old_value); + vtable_for(&node).before_remove_attr(local_name.clone(), old_value); } self.get_mut().attrs[idx].get_mut().set_value(value.clone()); } + None => { - let node: JS<Node> = NodeCast::from(self); let doc = node.get().owner_doc().get(); - let new_attr = Attr::new_ns(&doc.window, local_name.clone(), value.clone(), - name.clone(), namespace.clone(), - prefix); + let new_attr = Attr::new(&doc.window, local_name.clone(), value.clone(), + name, namespace.clone(), prefix); self.get_mut().attrs.push(new_attr); } } if namespace == namespace::Null { - self.after_set_attr(local_name, value); + vtable_for(&node).after_set_attr(local_name, value); + } + } + + // http://dom.spec.whatwg.org/#dom-element-setattribute + fn SetAttribute(&mut self, name: DOMString, value: DOMString) -> ErrorResult { + let node: JS<Node> = NodeCast::from(self); + node.get().wait_until_safe_to_modify_dom(); + + // Step 1. + match xml_name_type(name) { + InvalidXMLName => return Err(InvalidCharacter), + _ => {} } + + // Step 2. + let name = if self.get().html_element_in_html_document() { + name.to_ascii_lower() + } else { + name + }; + + // Step 3-5. + self.do_set_attribute(name.clone(), value, name.clone(), namespace::Null, None, |attr| { + attr.get().name == name + }); Ok(()) } - fn after_set_attr(&mut self, local_name: DOMString, value: DOMString) { + fn SetAttributeNS(&mut self, namespace_url: Option<DOMString>, + name: DOMString, value: DOMString) -> ErrorResult { let node: JS<Node> = NodeCast::from(self); - match local_name.as_slice() { - "style" => { - let doc = node.get().owner_doc(); - let base_url = doc.get().url().clone(); - self.get_mut().style_attribute = Some(style::parse_style_attribute(value, &base_url)) - } - "id" if node.is_in_doc() => { - // XXX: this dual declaration are workaround to avoid the compile error: - // "borrowed value does not live long enough" - let mut doc = node.get().owner_doc().clone(); - let doc = doc.get_mut(); - doc.register_named_element(self, value.clone()); - } - _ => () + node.get().wait_until_safe_to_modify_dom(); + + // Step 1. + let namespace = Namespace::from_str(null_str_as_empty_ref(&namespace_url)); + + let name_type = xml_name_type(name); + match name_type { + // Step 2. + InvalidXMLName => return Err(InvalidCharacter), + // Step 3. + Name => return Err(NamespaceError), + QName => {} } - //XXXjdm We really need something like a vtable so we can call AfterSetAttr. - // This hardcoding is awful. - match node.type_id() { - ElementNodeTypeId(HTMLImageElementTypeId) => { - let mut elem: JS<HTMLImageElement> = HTMLImageElementCast::to(self).unwrap(); - elem.AfterSetAttr(local_name.clone(), value.clone()); - } - ElementNodeTypeId(HTMLIFrameElementTypeId) => { - let mut elem: JS<HTMLIFrameElement> = HTMLIFrameElementCast::to(self).unwrap(); - elem.AfterSetAttr(local_name.clone(), value.clone()); - } - ElementNodeTypeId(HTMLObjectElementTypeId) => { - let mut elem: JS<HTMLObjectElement> = HTMLObjectElementCast::to(self).unwrap(); - elem.AfterSetAttr(local_name.clone(), value.clone()); - } - _ => () + // Step 4. + let (prefix, local_name) = get_attribute_parts(name.clone()); + match prefix { + Some(ref prefix_str) => { + // Step 5. + if namespace == namespace::Null { + return Err(NamespaceError); + } + + // Step 6. + if "xml" == prefix_str.as_slice() && namespace != namespace::XML { + return Err(NamespaceError); + } + + // Step 7b. + if "xmlns" == prefix_str.as_slice() && namespace != namespace::XMLNS { + return Err(NamespaceError); + } + }, + None => {} } - self.notify_attribute_changed(local_name); + // Step 7a. + if "xmlns" == name && namespace != namespace::XMLNS { + return Err(NamespaceError); + } + + // Step 8. + if namespace == namespace::XMLNS && "xmlns" != name && Some(~"xmlns") != prefix { + return Err(NamespaceError); + } + + // Step 9. + self.do_set_attribute(local_name.clone(), value, name, namespace.clone(), prefix, |attr| { + attr.get().local_name == local_name && + attr.get().namespace == namespace + }); + Ok(()) } fn remove_attribute(&mut self, namespace: Namespace, name: DOMString) -> ErrorResult { @@ -340,7 +380,7 @@ impl AttributeHandlers for JS<Element> { Some(idx) => { if namespace == namespace::Null { let removed_raw_value = self.get().attrs[idx].get().Value(); - self.before_remove_attr(local_name, removed_raw_value); + vtable_for(&node).before_remove_attr(local_name.clone(), removed_raw_value); } self.get_mut().attrs.remove(idx); @@ -350,39 +390,6 @@ impl AttributeHandlers for JS<Element> { Ok(()) } - fn before_remove_attr(&mut self, local_name: DOMString, old_value: DOMString) { - let node: JS<Node> = NodeCast::from(self); - match local_name.as_slice() { - "style" => { - self.get_mut().style_attribute = None - } - "id" if node.is_in_doc() => { - // XXX: this dual declaration are workaround to avoid the compile error: - // "borrowed value does not live long enough" - let mut doc = node.get().owner_doc().clone(); - let doc = doc.get_mut(); - doc.unregister_named_element(old_value); - } - _ => () - } - - //XXXjdm We really need something like a vtable so we can call BeforeRemoveAttr. - // This hardcoding is awful. - match node.type_id() { - ElementNodeTypeId(HTMLImageElementTypeId) => { - let mut elem: JS<HTMLImageElement> = HTMLImageElementCast::to(self).unwrap(); - elem.BeforeRemoveAttr(local_name.clone()); - } - ElementNodeTypeId(HTMLIFrameElementTypeId) => { - let mut elem: JS<HTMLIFrameElement> = HTMLIFrameElementCast::to(self).unwrap(); - elem.BeforeRemoveAttr(local_name.clone()); - } - _ => () - } - - self.notify_attribute_changed(local_name); - } - fn notify_attribute_changed(&self, local_name: DOMString) { let node: JS<Node> = NodeCast::from(self); if node.is_in_doc() { @@ -443,6 +450,11 @@ impl Element { } impl Element { + // http://dom.spec.whatwg.org/#dom-element-namespaceuri + pub fn NamespaceURI(&self) -> DOMString { + self.namespace.to_str().to_owned() + } + // http://dom.spec.whatwg.org/#dom-element-tagname pub fn TagName(&self) -> DOMString { self.tag_name.to_ascii_upper() @@ -502,33 +514,19 @@ impl Element { } // http://dom.spec.whatwg.org/#dom-element-setattribute - pub fn SetAttribute(&mut self, abstract_self: &mut JS<Element>, + pub fn SetAttribute(&self, abstract_self: &mut JS<Element>, name: DOMString, value: DOMString) -> ErrorResult { - // FIXME: If name does not match the Name production in XML, throw an "InvalidCharacterError" exception. - let name = if self.html_element_in_html_document() { - name.to_ascii_lower() - } else { - name - }; - abstract_self.set_attr(name, value) + abstract_self.SetAttribute(name, value) } // http://dom.spec.whatwg.org/#dom-element-setattributens - pub fn SetAttributeNS(&mut self, + pub fn SetAttributeNS(&self, abstract_self: &mut JS<Element>, namespace_url: Option<DOMString>, name: DOMString, value: DOMString) -> ErrorResult { - let name_type = xml_name_type(name); - match name_type { - InvalidXMLName => return Err(InvalidCharacter), - Name => return Err(NamespaceError), - QName => {} - } - - let namespace = Namespace::from_str(null_str_as_empty_ref(&namespace_url)); - abstract_self.set_attribute(namespace, name, value) + abstract_self.SetAttributeNS(namespace_url, name, value) } // http://dom.spec.whatwg.org/#dom-element-removeattribute @@ -634,13 +632,81 @@ impl Element { } } -pub trait IElement { - fn bind_to_tree_impl(&self); - fn unbind_from_tree_impl(&self); +pub fn get_attribute_parts(name: DOMString) -> (Option<~str>, ~str) { + //FIXME: Throw for XML-invalid names + //FIXME: Throw for XMLNS-invalid names + let (prefix, local_name) = if name.contains(":") { + let parts: ~[&str] = name.splitn(':', 1).collect(); + (Some(parts[0].to_owned()), parts[1].to_owned()) + } else { + (None, name) + }; + + (prefix, local_name) } -impl IElement for JS<Element> { - fn bind_to_tree_impl(&self) { +impl VirtualMethods for JS<Element> { + fn super_type(&self) -> Option<~VirtualMethods:> { + let node: JS<Node> = NodeCast::from(self); + Some(~node as ~VirtualMethods:) + } + + fn after_set_attr(&mut self, name: DOMString, value: DOMString) { + match self.super_type() { + Some(ref mut s) => s.after_set_attr(name.clone(), value.clone()), + _ => (), + } + + let node: JS<Node> = NodeCast::from(self); + match name.as_slice() { + "style" => { + let doc = node.get().owner_doc(); + let base_url = doc.get().url().clone(); + self.get_mut().style_attribute = Some(style::parse_style_attribute(value, &base_url)) + } + "id" if node.is_in_doc() => { + // XXX: this dual declaration are workaround to avoid the compile error: + // "borrowed value does not live long enough" + let mut doc = node.get().owner_doc().clone(); + let doc = doc.get_mut(); + doc.register_named_element(self, value.clone()); + } + _ => () + } + + self.notify_attribute_changed(name); + } + + fn before_remove_attr(&mut self, name: DOMString, value: DOMString) { + match self.super_type() { + Some(ref mut s) => s.before_remove_attr(name.clone(), value.clone()), + _ => (), + } + + let node: JS<Node> = NodeCast::from(self); + match name.as_slice() { + "style" => { + self.get_mut().style_attribute = None + } + "id" if node.is_in_doc() => { + // XXX: this dual declaration are workaround to avoid the compile error: + // "borrowed value does not live long enough" + let mut doc = node.get().owner_doc().clone(); + let doc = doc.get_mut(); + doc.unregister_named_element(self, value); + } + _ => () + } + + self.notify_attribute_changed(name); + } + + fn bind_to_tree(&mut self) { + match self.super_type() { + Some(ref mut s) => s.bind_to_tree(), + _ => (), + } + match self.get_attribute(Null, "id") { Some(attr) => { let mut doc = document_from_node(self); @@ -650,26 +716,18 @@ impl IElement for JS<Element> { } } - fn unbind_from_tree_impl(&self) { + fn unbind_from_tree(&mut self) { + match self.super_type() { + Some(ref mut s) => s.unbind_from_tree(), + _ => (), + } + match self.get_attribute(Null, "id") { Some(attr) => { let mut doc = document_from_node(self); - doc.get_mut().unregister_named_element(attr.get().Value()); + doc.get_mut().unregister_named_element(self, attr.get().Value()); } _ => () } } } - -pub fn get_attribute_parts(name: DOMString) -> (Option<~str>, ~str) { - //FIXME: Throw for XML-invalid names - //FIXME: Throw for XMLNS-invalid names - let (prefix, local_name) = if name.contains(":") { - let parts: ~[&str] = name.splitn(':', 1).collect(); - (Some(parts[0].to_owned()), parts[1].to_owned()) - } else { - (None, name) - }; - - (prefix, local_name) -} diff --git a/src/components/script/dom/eventtarget.rs b/src/components/script/dom/eventtarget.rs index a1a3a9d7514..f953774bb5d 100644 --- a/src/components/script/dom/eventtarget.rs +++ b/src/components/script/dom/eventtarget.rs @@ -9,6 +9,7 @@ use dom::bindings::codegen::EventListenerBinding::EventListener; use dom::event::Event; use dom::eventdispatcher::dispatch_event; use dom::node::NodeTypeId; +use dom::virtualmethods::VirtualMethods; use servo_util::str::DOMString; use collections::hashmap::HashMap; @@ -26,7 +27,7 @@ pub enum EventTargetTypeId { } #[deriving(Eq,Encodable)] -struct EventListenerEntry { +pub struct EventListenerEntry { phase: ListenerPhase, listener: EventListener } @@ -123,3 +124,9 @@ impl Reflectable for EventTarget { &mut self.reflector_ } } + +impl VirtualMethods for JS<EventTarget> { + fn super_type(&self) -> Option<~VirtualMethods:> { + None + } +} diff --git a/src/components/script/dom/formdata.rs b/src/components/script/dom/formdata.rs index ac6cdac403e..db380af6a55 100644 --- a/src/components/script/dom/formdata.rs +++ b/src/components/script/dom/formdata.rs @@ -14,7 +14,7 @@ use servo_util::str::DOMString; use collections::hashmap::HashMap; #[deriving(Encodable)] -enum FormDatum { +pub enum FormDatum { StringData(DOMString), BlobData { blob: JS<Blob>, name: DOMString } } diff --git a/src/components/script/dom/htmlelement.rs b/src/components/script/dom/htmlelement.rs index f8a1cd96a9b..30f3e7b552c 100644 --- a/src/components/script/dom/htmlelement.rs +++ b/src/components/script/dom/htmlelement.rs @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use dom::bindings::codegen::HTMLElementBinding; +use dom::bindings::codegen::InheritTypes::ElementCast; use dom::bindings::codegen::InheritTypes::HTMLElementDerived; use dom::bindings::js::JS; use dom::bindings::error::{ErrorResult, Fallible}; @@ -10,6 +11,7 @@ use dom::document::Document; use dom::element::{Element, ElementTypeId, HTMLElementTypeId}; use dom::eventtarget::{EventTarget, NodeTargetTypeId}; use dom::node::{Node, ElementNodeTypeId}; +use dom::virtualmethods::VirtualMethods; use js::jsapi::JSContext; use js::jsval::{JSVal, NullValue}; use servo_util::namespace; @@ -23,6 +25,7 @@ pub struct HTMLElement { impl HTMLElementDerived for EventTarget { fn is_htmlelement(&self) -> bool { match self.type_id { + NodeTargetTypeId(ElementNodeTypeId(ElementTypeId)) => false, NodeTargetTypeId(ElementNodeTypeId(_)) => true, _ => false } @@ -160,3 +163,10 @@ impl HTMLElement { 0 } } + +impl VirtualMethods for JS<HTMLElement> { + fn super_type(&self) -> Option<~VirtualMethods:> { + let element: JS<Element> = ElementCast::from(self); + Some(~element as ~VirtualMethods:) + } +} diff --git a/src/components/script/dom/htmliframeelement.rs b/src/components/script/dom/htmliframeelement.rs index a33e5baf84d..c98634682a6 100644 --- a/src/components/script/dom/htmliframeelement.rs +++ b/src/components/script/dom/htmliframeelement.rs @@ -3,15 +3,16 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use dom::bindings::codegen::HTMLIFrameElementBinding; -use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLIFrameElementDerived}; +use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLIFrameElementDerived, HTMLElementCast}; use dom::bindings::js::JS; use dom::bindings::error::ErrorResult; use dom::document::Document; use dom::element::{HTMLIFrameElementTypeId, Element}; -use dom::element::{AttributeHandlers, AfterSetAttrListener, BeforeRemoveAttrListener}; +use dom::element::AttributeHandlers; use dom::eventtarget::{EventTarget, NodeTargetTypeId}; use dom::htmlelement::HTMLElement; use dom::node::{Node, ElementNodeTypeId}; +use dom::virtualmethods::VirtualMethods; use dom::windowproxy::WindowProxy; use servo_util::str::DOMString; @@ -210,8 +211,18 @@ impl HTMLIFrameElement { } } -impl AfterSetAttrListener for JS<HTMLIFrameElement> { - fn AfterSetAttr(&mut self, name: DOMString, value: DOMString) { +impl VirtualMethods for JS<HTMLIFrameElement> { + fn super_type(&self) -> Option<~VirtualMethods:> { + let htmlelement: JS<HTMLElement> = HTMLElementCast::from(self); + Some(~htmlelement as ~VirtualMethods:) + } + + fn after_set_attr(&mut self, name: DOMString, value: DOMString) { + match self.super_type() { + Some(ref mut s) => s.after_set_attr(name.clone(), value.clone()), + _ => (), + } + if "sandbox" == name { let mut modes = AllowNothing as u8; for word in value.split(' ') { @@ -230,10 +241,13 @@ impl AfterSetAttrListener for JS<HTMLIFrameElement> { self.get_mut().sandbox = Some(modes); } } -} -impl BeforeRemoveAttrListener for JS<HTMLIFrameElement> { - fn BeforeRemoveAttr(&mut self, name: DOMString) { + fn before_remove_attr(&mut self, name: DOMString, value: DOMString) { + match self.super_type() { + Some(ref mut s) => s.before_remove_attr(name.clone(), value), + _ => (), + } + if "sandbox" == name { self.get_mut().sandbox = None; } diff --git a/src/components/script/dom/htmlimageelement.rs b/src/components/script/dom/htmlimageelement.rs index 63ff2c4549b..3b966bbfe24 100644 --- a/src/components/script/dom/htmlimageelement.rs +++ b/src/components/script/dom/htmlimageelement.rs @@ -4,15 +4,16 @@ use dom::bindings::codegen::HTMLImageElementBinding; use dom::bindings::codegen::InheritTypes::{NodeCast, HTMLImageElementDerived}; -use dom::bindings::codegen::InheritTypes::{ElementCast}; +use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast}; use dom::bindings::js::JS; use dom::bindings::error::ErrorResult; use dom::document::Document; use dom::element::{Element, HTMLImageElementTypeId}; -use dom::element::{AttributeHandlers, AfterSetAttrListener, BeforeRemoveAttrListener}; +use dom::element::AttributeHandlers; use dom::eventtarget::{EventTarget, NodeTargetTypeId}; use dom::htmlelement::HTMLElement; use dom::node::{Node, ElementNodeTypeId, NodeHelpers, window_from_node}; +use dom::virtualmethods::VirtualMethods; use servo_util::geometry::to_px; use layout_interface::{ContentBoxQuery, ContentBoxResponse}; use servo_net::image_cache_task; @@ -244,18 +245,31 @@ impl HTMLImageElement { } } -impl AfterSetAttrListener for JS<HTMLImageElement> { - fn AfterSetAttr(&mut self, name: DOMString, value: DOMString) { +impl VirtualMethods for JS<HTMLImageElement> { + fn super_type(&self) -> Option<~VirtualMethods:> { + let htmlelement: JS<HTMLElement> = HTMLElementCast::from(self); + Some(~htmlelement as ~VirtualMethods:) + } + + fn after_set_attr(&mut self, name: DOMString, value: DOMString) { + match self.super_type() { + Some(ref mut s) => s.after_set_attr(name.clone(), value.clone()), + _ => (), + } + if "src" == name { let window = window_from_node(self); let url = Some(window.get().get_url()); self.get_mut().update_image(Some(value), url); } } -} -impl BeforeRemoveAttrListener for JS<HTMLImageElement> { - fn BeforeRemoveAttr(&mut self, name: DOMString) { + fn before_remove_attr(&mut self, name: DOMString, value: DOMString) { + match self.super_type() { + Some(ref mut s) => s.before_remove_attr(name.clone(), value.clone()), + _ => (), + } + if "src" == name { self.get_mut().update_image(None, None); } diff --git a/src/components/script/dom/htmlobjectelement.rs b/src/components/script/dom/htmlobjectelement.rs index 03fc8984845..6288dcfc33d 100644 --- a/src/components/script/dom/htmlobjectelement.rs +++ b/src/components/script/dom/htmlobjectelement.rs @@ -4,17 +4,18 @@ use dom::bindings::codegen::HTMLObjectElementBinding; use dom::bindings::codegen::InheritTypes::HTMLObjectElementDerived; -use dom::bindings::codegen::InheritTypes::ElementCast; +use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast}; use dom::bindings::js::JS; use dom::bindings::error::ErrorResult; use dom::document::Document; use dom::element::{Element, HTMLObjectElementTypeId}; -use dom::element::{AttributeHandlers, AfterSetAttrListener}; +use dom::element::AttributeHandlers; use dom::eventtarget::{EventTarget, NodeTargetTypeId}; use dom::htmlelement::HTMLElement; use dom::htmlformelement::HTMLFormElement; use dom::node::{Node, ElementNodeTypeId, NodeHelpers, window_from_node}; use dom::validitystate::ValidityState; +use dom::virtualmethods::VirtualMethods; use dom::windowproxy::WindowProxy; use servo_util::str::DOMString; @@ -244,8 +245,18 @@ impl HTMLObjectElement { } } -impl AfterSetAttrListener for JS<HTMLObjectElement> { - fn AfterSetAttr(&mut self, name: DOMString, _value: DOMString) { +impl VirtualMethods for JS<HTMLObjectElement> { + fn super_type(&self) -> Option<~VirtualMethods:> { + let htmlelement: JS<HTMLElement> = HTMLElementCast::from(self); + Some(~htmlelement as ~VirtualMethods:) + } + + fn after_set_attr(&mut self, name: DOMString, value: DOMString) { + match self.super_type() { + Some(ref mut s) => s.after_set_attr(name.clone(), value), + _ => (), + } + if "data" == name { let window = window_from_node(self); let url = Some(window.get().get_url()); diff --git a/src/components/script/dom/htmlstyleelement.rs b/src/components/script/dom/htmlstyleelement.rs index 8c09d6336c0..ed335dd70eb 100644 --- a/src/components/script/dom/htmlstyleelement.rs +++ b/src/components/script/dom/htmlstyleelement.rs @@ -3,14 +3,17 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use dom::bindings::codegen::HTMLStyleElementBinding; -use dom::bindings::codegen::InheritTypes::HTMLStyleElementDerived; +use dom::bindings::codegen::InheritTypes::{HTMLElementCast, HTMLStyleElementDerived, NodeCast}; use dom::bindings::js::JS; use dom::bindings::error::ErrorResult; use dom::document::Document; use dom::element::HTMLStyleElementTypeId; use dom::eventtarget::{EventTarget, NodeTargetTypeId}; use dom::htmlelement::HTMLElement; -use dom::node::{Node, ElementNodeTypeId}; +use dom::node::{Node, ElementNodeTypeId, window_from_node}; +use dom::virtualmethods::VirtualMethods; +use html::cssparse::parse_inline_css; +use layout_interface::{AddStylesheetMsg, LayoutChan}; use servo_util::str::DOMString; #[deriving(Encodable)] @@ -72,3 +75,35 @@ impl HTMLStyleElement { Ok(()) } } + +pub trait StyleElementHelpers { + fn parse_own_css(&self); +} + +impl StyleElementHelpers for JS<HTMLStyleElement> { + fn parse_own_css(&self) { + let node: JS<Node> = NodeCast::from(self); + let win = window_from_node(&node); + let url = win.get().page().get_url(); + + let data = node.get().GetTextContent(&node).expect("Element.textContent must be a string"); + let sheet = parse_inline_css(url, data); + let LayoutChan(ref layout_chan) = win.get().page().layout_chan; + layout_chan.send(AddStylesheetMsg(sheet)); + } +} + +impl VirtualMethods for JS<HTMLStyleElement> { + fn super_type(&self) -> Option<~VirtualMethods:> { + let htmlelement: JS<HTMLElement> = HTMLElementCast::from(self); + Some(~htmlelement as ~VirtualMethods:) + } + + fn child_inserted(&mut self, child: &JS<Node>) { + match self.super_type() { + Some(ref mut s) => s.child_inserted(child), + _ => (), + } + self.parse_own_css(); + } +} diff --git a/src/components/script/dom/node.rs b/src/components/script/dom/node.rs index 77ca388be9e..bf2669512ff 100644 --- a/src/components/script/dom/node.rs +++ b/src/components/script/dom/node.rs @@ -8,7 +8,7 @@ use dom::attr::Attr; use dom::bindings::codegen::InheritTypes::{CommentCast, DocumentCast, DocumentTypeCast}; use dom::bindings::codegen::InheritTypes::{ElementCast, TextCast, NodeCast}; use dom::bindings::codegen::InheritTypes::{CharacterDataCast, NodeBase, NodeDerived}; -use dom::bindings::codegen::InheritTypes::ProcessingInstructionCast; +use dom::bindings::codegen::InheritTypes::{ProcessingInstructionCast, EventTargetCast}; use dom::bindings::codegen::NodeBinding::NodeConstants; use dom::bindings::js::JS; use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object}; @@ -19,11 +19,12 @@ use dom::comment::Comment; use dom::document::{Document, HTMLDocument, NonHTMLDocument}; use dom::documentfragment::DocumentFragment; use dom::documenttype::DocumentType; -use dom::element::{Element, ElementTypeId, HTMLAnchorElementTypeId, IElement}; +use dom::element::{Element, ElementTypeId, HTMLAnchorElementTypeId}; use dom::eventtarget::{EventTarget, NodeTargetTypeId}; use dom::nodelist::{NodeList}; -use dom::text::Text; use dom::processinginstruction::ProcessingInstruction; +use dom::text::Text; +use dom::virtualmethods::{VirtualMethods, vtable_for}; use dom::window::Window; use html::hubbub_html_parser::build_element_from_tag; use layout_interface::{LayoutChan, ReapLayoutDataMsg, UntrustedNodeAddress}; @@ -403,13 +404,11 @@ impl NodeHelpers for JS<Node> { if self.is_in_doc() { for node in self.traverse_preorder() { - if node.is_element() { - let element: JS<Element> = ElementCast::to(&node).unwrap(); - element.bind_to_tree_impl(); - } + vtable_for(&node).bind_to_tree(); } } + self.parent_node().map(|parent| vtable_for(&parent).child_inserted(self)); document.get().content_changed(); } @@ -419,10 +418,8 @@ impl NodeHelpers for JS<Node> { let document = document_from_node(self); for node in self.traverse_preorder() { - if node.is_element() { - let element: JS<Element> = ElementCast::to(&node).unwrap(); - element.unbind_from_tree_impl(); - } + // XXX how about if the node wasn't in the tree in the first place? + vtable_for(&node).unbind_from_tree(); } document.get().content_changed(); @@ -573,7 +570,7 @@ impl NodeHelpers for JS<Node> { // Iteration and traversal // -type ChildElementIterator<'a> = Map<'a, JS<Node>, +pub type ChildElementIterator<'a> = Map<'a, JS<Node>, JS<Element>, Filter<'a, JS<Node>, AbstractNodeChildrenIterator>>; @@ -1372,10 +1369,10 @@ impl Node { copy_elem.namespace = node_elem.namespace.clone(); for attr in node_elem.attrs.iter() { let attr = attr.get(); - copy_elem.attrs.push(Attr::new_ns(&document.get().window, - attr.local_name.clone(), attr.value.clone(), - attr.name.clone(), attr.namespace.clone(), - attr.prefix.clone())); + copy_elem.attrs.push(Attr::new(&document.get().window, + attr.local_name.clone(), attr.value.clone(), + attr.name.clone(), attr.namespace.clone(), + attr.prefix.clone())); } }, _ => () @@ -1733,12 +1730,6 @@ impl Node { false } - // http://dom.spec.whatwg.org/#dom-node-namespaceuri - pub fn GetNamespaceURI(&self, abstract_self: &JS<Node>) -> Option<DOMString> { - let element: Option<JS<Element>> = ElementCast::to(abstract_self); - element.map(|element| element.get().namespace.to_str().to_owned()) - } - // http://dom.spec.whatwg.org/#dom-node-prefix pub fn GetPrefix(&self) -> Option<DOMString> { None @@ -1840,3 +1831,10 @@ pub fn window_from_node<T: NodeBase>(derived: &JS<T>) -> JS<Window> { let document: JS<Document> = document_from_node(derived); document.get().window.clone() } + +impl VirtualMethods for JS<Node> { + fn super_type(&self) -> Option<~VirtualMethods:> { + let eventtarget: JS<EventTarget> = EventTargetCast::from(self); + Some(~eventtarget as ~VirtualMethods:) + } +} diff --git a/src/components/script/dom/nodelist.rs b/src/components/script/dom/nodelist.rs index ab2bbb7f575..396fbad9c82 100644 --- a/src/components/script/dom/nodelist.rs +++ b/src/components/script/dom/nodelist.rs @@ -9,7 +9,7 @@ use dom::node::{Node, NodeHelpers}; use dom::window::Window; #[deriving(Encodable)] -enum NodeListType { +pub enum NodeListType { Simple(~[JS<Node>]), Children(JS<Node>) } diff --git a/src/components/script/dom/virtualmethods.rs b/src/components/script/dom/virtualmethods.rs new file mode 100644 index 00000000000..85ae37cb032 --- /dev/null +++ b/src/components/script/dom/virtualmethods.rs @@ -0,0 +1,107 @@ +/* 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/. */ + +use dom::bindings::codegen::InheritTypes::ElementCast; +use dom::bindings::codegen::InheritTypes::HTMLElementCast; +use dom::bindings::codegen::InheritTypes::HTMLIFrameElementCast; +use dom::bindings::codegen::InheritTypes::HTMLImageElementCast; +use dom::bindings::codegen::InheritTypes::HTMLObjectElementCast; +use dom::bindings::codegen::InheritTypes::HTMLStyleElementCast; +use dom::bindings::js::JS; +use dom::element::Element; +use dom::element::{ElementTypeId, HTMLImageElementTypeId}; +use dom::element::{HTMLIFrameElementTypeId, HTMLObjectElementTypeId, HTMLStyleElementTypeId}; +use dom::htmlelement::HTMLElement; +use dom::htmliframeelement::HTMLIFrameElement; +use dom::htmlimageelement::HTMLImageElement; +use dom::htmlobjectelement::HTMLObjectElement; +use dom::htmlstyleelement::HTMLStyleElement; +use dom::node::{Node, ElementNodeTypeId}; +use servo_util::str::DOMString; + +/// Trait to allow DOM nodes to opt-in to overriding (or adding to) common +/// behaviours. Replicates the effect of C++ virtual methods. +pub trait VirtualMethods { + /// Returns self as the superclass of the implementation for this trait, + /// if any. + fn super_type(&self) -> Option<~VirtualMethods:>; + + /// Called when changing or adding attributes, after the attribute's value + /// has been updated. + fn after_set_attr(&mut self, name: DOMString, value: DOMString) { + match self.super_type() { + Some(ref mut s) => s.after_set_attr(name, value), + _ => (), + } + } + + /// Called when changing or removing attributes, before any modification + /// has taken place. + fn before_remove_attr(&mut self, name: DOMString, value: DOMString) { + match self.super_type() { + Some(ref mut s) => s.before_remove_attr(name, value), + _ => (), + } + } + + /// Called when a Node is appended to a tree that is part of a Document. + fn bind_to_tree(&mut self) { + match self.super_type() { + Some(ref mut s) => s.bind_to_tree(), + _ => (), + } + } + + /// Called when a Node is removed from a tree that is part of a Document. + fn unbind_from_tree(&mut self) { + match self.super_type() { + Some(ref mut s) => s.unbind_from_tree(), + _ => (), + } + } + + /// Called on the parent when a node is added to its child list. + fn child_inserted(&mut self, child: &JS<Node>) { + match self.super_type() { + Some(ref mut s) => s.child_inserted(child), + _ => (), + } + } +} + +/// Obtain a VirtualMethods instance for a given Node-derived object. Any +/// method call on the trait object will invoke the corresponding method on the +/// concrete type, propagating up the parent hierarchy unless otherwise +/// interrupted. +pub fn vtable_for<'a>(node: &JS<Node>) -> ~VirtualMethods: { + match node.get().type_id { + ElementNodeTypeId(HTMLImageElementTypeId) => { + let element: JS<HTMLImageElement> = HTMLImageElementCast::to(node).unwrap(); + ~element as ~VirtualMethods: + } + ElementNodeTypeId(HTMLIFrameElementTypeId) => { + let element: JS<HTMLIFrameElement> = HTMLIFrameElementCast::to(node).unwrap(); + ~element as ~VirtualMethods: + } + ElementNodeTypeId(HTMLObjectElementTypeId) => { + let element: JS<HTMLObjectElement> = HTMLObjectElementCast::to(node).unwrap(); + ~element as ~VirtualMethods: + } + ElementNodeTypeId(HTMLStyleElementTypeId) => { + let element: JS<HTMLStyleElement> = HTMLStyleElementCast::to(node).unwrap(); + ~element as ~VirtualMethods: + } + ElementNodeTypeId(ElementTypeId) => { + let element: JS<Element> = ElementCast::to(node).unwrap(); + ~element as ~VirtualMethods: + } + ElementNodeTypeId(_) => { + let element: JS<HTMLElement> = HTMLElementCast::to(node).unwrap(); + ~element as ~VirtualMethods: + } + _ => { + ~node.clone() as ~VirtualMethods: + } + } +} diff --git a/src/components/script/dom/webidls/Element.webidl b/src/components/script/dom/webidls/Element.webidl index 2211fd5c887..aa0161204b0 100644 --- a/src/components/script/dom/webidls/Element.webidl +++ b/src/components/script/dom/webidls/Element.webidl @@ -18,10 +18,11 @@ interface Element : Node { We haven't moved these from Node to Element like the spec wants. [Throws] - readonly attribute DOMString? namespaceURI; readonly attribute DOMString? prefix; readonly attribute DOMString localName; */ + [Constant] + readonly attribute DOMString namespaceURI; // Not [Constant] because it depends on which document we're in [Pure] readonly attribute DOMString tagName; diff --git a/src/components/script/dom/webidls/Node.webidl b/src/components/script/dom/webidls/Node.webidl index 2a13d6ab381..39555e1e0d8 100644 --- a/src/components/script/dom/webidls/Node.webidl +++ b/src/components/script/dom/webidls/Node.webidl @@ -79,11 +79,9 @@ interface Node : EventTarget { // Mozilla-specific stuff // These have been moved to Element in the spec. - // If we move namespaceURI, prefix and localName to Element they should return + // If we move prefix and localName to Element they should return // a non-nullable type. [Constant] - readonly attribute DOMString? namespaceURI; - [Constant] readonly attribute DOMString? prefix; [Constant] readonly attribute DOMString? localName; diff --git a/src/components/script/dom/window.rs b/src/components/script/dom/window.rs index dae0020abe8..9ba9d00da82 100644 --- a/src/components/script/dom/window.rs +++ b/src/components/script/dom/window.rs @@ -19,14 +19,11 @@ use servo_net::image_cache_task::ImageCacheTask; use servo_util::str::DOMString; use servo_util::task::{spawn_named}; -use js::glue::*; -use js::jsapi::{JSObject, JSContext, JS_DefineProperty}; -use js::jsval::JSVal; -use js::jsval::{NullValue, ObjectValue}; +use js::jsapi::{JSObject, JSContext, JS_DefineProperty, JS_PropertyStub, JS_StrictPropertyStub}; +use js::jsval::{NullValue, ObjectValue, JSVal}; use js::JSPROP_ENUMERATE; use collections::hashmap::HashMap; -use std::cast; use std::cmp; use std::comm::{channel, Sender, Receiver}; use std::comm::Select; @@ -329,8 +326,8 @@ impl Window { unsafe { JS_DefineProperty(cx, object, name, ObjectValue(&*object), - Some(cast::transmute(GetJSClassHookStubPointer(PROPERTY_STUB))), - Some(cast::transmute(GetJSClassHookStubPointer(STRICT_PROPERTY_STUB))), + Some(JS_PropertyStub), + Some(JS_StrictPropertyStub), JSPROP_ENUMERATE); } }) diff --git a/src/components/script/html/cssparse.rs b/src/components/script/html/cssparse.rs index c5cad0849de..b538676edac 100644 --- a/src/components/script/html/cssparse.rs +++ b/src/components/script/html/cssparse.rs @@ -18,34 +18,45 @@ pub enum StylesheetProvenance { InlineProvenance(Url, ~str), } +// Parses the style data and returns the stylesheet +pub fn parse_inline_css(url: Url, data: ~str) -> Stylesheet { + let resource_task = ResourceTask(); // Resource task is not used for inline parsing + parse_css(InlineProvenance(url, data), resource_task) +} + +fn parse_css(provenance: StylesheetProvenance, + resource_task: ResourceTask) -> Stylesheet { + // TODO: Get the actual value. http://dev.w3.org/csswg/css-syntax/#environment-encoding + let environment_encoding = UTF_8 as EncodingRef; + + match provenance { + UrlProvenance(url) => { + debug!("cssparse: loading style sheet at {:s}", url.to_str()); + let (input_chan, input_port) = channel(); + resource_task.send(Load(url, input_chan)); + let LoadResponse { metadata: metadata, progress_port: progress_port } + = input_port.recv(); + let final_url = &metadata.final_url; + let protocol_encoding_label = metadata.charset.as_ref().map(|s| s.as_slice()); + let iter = ProgressMsgPortIterator { progress_port: progress_port }; + Stylesheet::from_bytes_iter( + iter, final_url.clone(), + protocol_encoding_label, Some(environment_encoding)) + } + InlineProvenance(base_url, data) => { + debug!("cssparse: loading inline stylesheet {:s}", data); + Stylesheet::from_str(data, base_url, environment_encoding) + } + } +} + pub fn spawn_css_parser(provenance: StylesheetProvenance, resource_task: ResourceTask) -> Receiver<Stylesheet> { let (result_chan, result_port) = channel(); - // TODO: Get the actual value. http://dev.w3.org/csswg/css-syntax/#environment-encoding - let environment_encoding = UTF_8 as EncodingRef; - spawn_named("cssparser", proc() { - let sheet = match provenance { - UrlProvenance(url) => { - debug!("cssparse: loading style sheet at {:s}", url.to_str()); - let (input_chan, input_port) = channel(); - resource_task.send(Load(url, input_chan)); - let LoadResponse { metadata: metadata, progress_port: progress_port } - = input_port.recv(); - let final_url = &metadata.final_url; - let protocol_encoding_label = metadata.charset.as_ref().map(|s| s.as_slice()); - let iter = ProgressMsgPortIterator { progress_port: progress_port }; - Stylesheet::from_bytes_iter( - iter, final_url.clone(), - protocol_encoding_label, Some(environment_encoding)) - } - InlineProvenance(base_url, data) => { - Stylesheet::from_str(data, base_url, environment_encoding) - } - }; - result_chan.send(sheet); + result_chan.send(parse_css(provenance, resource_task)); }); return result_port; diff --git a/src/components/script/html/hubbub_html_parser.rs b/src/components/script/html/hubbub_html_parser.rs index 438d28a4898..21d285632f8 100644 --- a/src/components/script/html/hubbub_html_parser.rs +++ b/src/components/script/html/hubbub_html_parser.rs @@ -14,7 +14,7 @@ use dom::htmliframeelement::IFrameSize; use dom::htmlformelement::HTMLFormElement; use dom::node::{ElementNodeTypeId, INode, NodeHelpers}; use dom::types::*; -use html::cssparse::{InlineProvenance, StylesheetProvenance, UrlProvenance, spawn_css_parser}; +use html::cssparse::{StylesheetProvenance, UrlProvenance, spawn_css_parser}; use script_task::Page; use hubbub::hubbub; @@ -50,7 +50,7 @@ pub struct JSFile { url: Url } -type JSResult = ~[JSFile]; +pub type JSResult = ~[JSFile]; enum CSSMessage { CSSTaskNewFile(StylesheetProvenance), @@ -298,7 +298,7 @@ pub fn parse_html(page: &Page, parser.enable_scripting(true); parser.enable_styling(true); - let (css_chan2, css_chan3, js_chan2) = (css_chan.clone(), css_chan.clone(), js_chan.clone()); + let (css_chan2, js_chan2) = (css_chan.clone(), js_chan.clone()); let next_subpage_id = RefCell::new(next_subpage_id); @@ -483,22 +483,8 @@ pub fn parse_html(page: &Page, } debug!("complete script"); }, - complete_style: |style| { - // We've reached the end of a <style> so we can submit all the text to the parser. - unsafe { - let style: JS<Node> = NodeWrapping::from_hubbub_node(style); - let mut data = ~[]; - debug!("iterating over children {:?}", style.first_child()); - for child in style.children() { - debug!("child = {:?}", child); - let text: JS<Text> = TextCast::to(&child).unwrap(); - data.push(text.get().characterdata.data.to_str()); // FIXME: Bad copy. - } - - debug!("style data = {:?}", data); - let provenance = InlineProvenance(base_url.clone(), data.concat()); - css_chan3.send(CSSTaskNewFile(provenance)); - } + complete_style: |_| { + // style parsing is handled in element::notify_child_list_changed. }, }; parser.set_tree_handler(&tree_handler); diff --git a/src/components/script/script.rs b/src/components/script/script.rs index 9ab4c2cc671..7b9f63c4dc4 100644 --- a/src/components/script/script.rs +++ b/src/components/script/script.rs @@ -4,11 +4,13 @@ #[crate_id = "github.com/mozilla/servo#script:0.1"]; #[crate_type = "lib"]; +#[crate_type = "dylib"]; +#[crate_type = "rlib"]; #[comment = "The Servo Parallel Browser Project"]; #[license = "MPL"]; -#[feature(globs, macro_rules, struct_variant, managed_boxes, phase)]; +#[feature(globs, macro_rules, struct_variant, phase)]; #[feature(phase)]; #[phase(syntax, link)] @@ -153,6 +155,7 @@ pub mod dom { pub mod uievent; pub mod text; pub mod validitystate; + pub mod virtualmethods; pub mod window; pub mod windowproxy; diff --git a/src/components/script/script_task.rs b/src/components/script/script_task.rs index dcee911c46a..a585c320ad9 100644 --- a/src/components/script/script_task.rs +++ b/src/components/script/script_task.rs @@ -405,6 +405,23 @@ impl Page { } } + fn find_fragment_node(&self, fragid: ~str) -> Option<JS<Element>> { + let document = self.frame().get_ref().document.clone(); + match document.get().GetElementById(fragid.to_owned()) { + Some(node) => Some(node), + None => { + let doc_node: JS<Node> = NodeCast::from(&document); + let mut anchors = doc_node.traverse_preorder().filter(|node| node.is_anchor_element()); + anchors.find(|node| { + let elem: JS<Element> = ElementCast::to(node).unwrap(); + elem.get_attribute(Null, "name").map_or(false, |attr| { + attr.get().value_ref() == fragid + }) + }).map(|node| ElementCast::to(&node).unwrap()) + } + } + } + pub fn initialize_js_info(&self, js_context: Rc<Cx>, global: *JSObject) { assert!(global.is_not_null()); @@ -896,30 +913,12 @@ impl ScriptTask { let _ = wintarget.get_mut().dispatch_event_with_target(&winclone, Some(doctarget), &mut event); let mut fragment_node = page.fragment_node.borrow_mut(); - *fragment_node = fragment.map_or(None, |fragid| self.find_fragment_node(page, fragid)); + *fragment_node = fragment.map_or(None, |fragid| page.find_fragment_node(fragid)); let ConstellationChan(ref chan) = self.constellation_chan; chan.send(LoadCompleteMsg(page.id, url)); } - fn find_fragment_node(&self, page: &Page, fragid: ~str) -> Option<JS<Element>> { - let frame = page.frame(); - let document = frame.get_ref().document.clone(); - match document.get().GetElementById(fragid.to_owned()) { - Some(node) => Some(node), - None => { - let doc_node: JS<Node> = NodeCast::from(&document); - let mut anchors = doc_node.traverse_preorder().filter(|node| node.is_anchor_element()); - anchors.find(|node| { - let elem: JS<Element> = ElementCast::to(node).unwrap(); - elem.get_attribute(Null, "name").map_or(false, |attr| { - attr.get().value_ref() == fragid - }) - }).map(|node| ElementCast::to(&node).unwrap()) - } - } - } - fn scroll_fragment_point(&self, pipeline_id: PipelineId, page: &Page, node: JS<Element>) { let (chan, port) = channel(); let node: JS<Node> = NodeCast::from(&node); @@ -1122,7 +1121,7 @@ impl ScriptTask { let url = parse_url(href.get().value_ref(), base_url); if click_frag { - match self.find_fragment_node(page, url.fragment.unwrap()) { + match page.find_fragment_node(url.fragment.unwrap()) { Some(node) => self.scroll_fragment_point(page.id, page, node), None => {} } diff --git a/src/components/style/style.rs b/src/components/style/style.rs index c2659665063..b296b34c035 100644 --- a/src/components/style/style.rs +++ b/src/components/style/style.rs @@ -4,11 +4,13 @@ #[crate_id = "github.com/mozilla/servo#style:0.1"]; #[crate_type = "lib"]; +#[crate_type = "dylib"]; +#[crate_type = "rlib"]; #[comment = "The Servo Parallel Browser Project"]; #[license = "MPL"]; -#[feature(globs, macro_rules, managed_boxes)]; +#[feature(globs, macro_rules)]; #[feature(phase)]; #[phase(syntax, link)] extern crate log; diff --git a/src/components/util/util.rs b/src/components/util/util.rs index 78ff97a5e05..08e06e43b6e 100644 --- a/src/components/util/util.rs +++ b/src/components/util/util.rs @@ -4,8 +4,10 @@ #[crate_id = "github.com/mozilla/servo#util:0.1"]; #[crate_type = "lib"]; +#[crate_type = "dylib"]; +#[crate_type = "rlib"]; -#[feature(macro_rules, managed_boxes)]; +#[feature(macro_rules)]; #[feature(phase)]; #[phase(syntax, link)] diff --git a/src/platform/android/servo-android-glue b/src/platform/android/servo-android-glue -Subproject caf03d371cb99c9c72a7127114d8f5365a02eb0 +Subproject 0941b7702380d57ffe95823cfb057d752fd150a diff --git a/src/platform/linux/fontconfig b/src/platform/linux/fontconfig -Subproject b2cfb1f4b3561e01a58359cd18929457a0486db +Subproject 0450af3d92f1fb4f269cc64e58647871a5bf728 diff --git a/src/platform/linux/rust-fontconfig b/src/platform/linux/rust-fontconfig -Subproject 7bac3e9f27c42ef74085dd002c922c2f051c602 +Subproject 51d0a1bfe3a2e6b5cd935d9a7bf4922a3105c63 diff --git a/src/support/egl/rust-egl b/src/support/egl/rust-egl -Subproject 38cc35371a88f6240cd4b35205b2ec8b6703f13 +Subproject ffb1be4fecbfadacd02e5a714025bc58e6833f2 diff --git a/src/support/glut/rust-glut b/src/support/glut/rust-glut -Subproject be49cbc2d5455744c7951b07160f0d29fed2364 +Subproject 6050ecb8e884b4eba1155dacb29d1c9567886c2 diff --git a/src/support/harfbuzz/rust-harfbuzz b/src/support/harfbuzz/rust-harfbuzz -Subproject c422c3ca200da371d73af2246b62e6d7c40125e +Subproject 9c2a78f3c43d3b52391b94aa43dc61d6bddab50 diff --git a/src/support/layers/rust-layers b/src/support/layers/rust-layers -Subproject 493a4311f1202907208aecdaf3fc4a4c192608e +Subproject 10d40153462cf7248fcf35db5c18cf026cd25ae diff --git a/src/support/spidermonkey/rust-mozjs b/src/support/spidermonkey/rust-mozjs -Subproject f81f450ba6a742041844d40154dfe8ad1e540a4 +Subproject 9f0ae0ab33f786c9d2d5e1a9fdfdc6c07fa9803 diff --git a/src/test/content/test_document_getElementById.html b/src/test/content/test_document_getElementById.html index 9d066137ef3..97b506f58af 100644 --- a/src/test/content/test_document_getElementById.html +++ b/src/test/content/test_document_getElementById.html @@ -76,9 +76,9 @@ is(document.getElementById("should-not-exist"), e, "test 4-1"); } - // TODO: // test5: "in tree order, within the context object's tree" // http://dom.spec.whatwg.org/#dom-document-getelementbyid. + // we test this in test_document_getElementById_tree_order.html // TODO: // test6: innerHTML diff --git a/src/test/content/test_document_getElementById_tree_order.html b/src/test/content/test_document_getElementById_tree_order.html new file mode 100644 index 00000000000..ccf0c37bb01 --- /dev/null +++ b/src/test/content/test_document_getElementById_tree_order.html @@ -0,0 +1,40 @@ +<html> + <head> + <script src="harness.js"></script> + </head> + <body> + <div id="a"> + </div> + <div id="b"> + <p id="b">P</p> + <input id="b" type="submit" value="Submit"> + </div> + <script> + { + var b = document.getElementById("b"); + is_a(b, HTMLDivElement); + var a = document.getElementById("a"); + var p = document.createElement("p"); + p.id = "b"; + a.appendChild(p); + var newB = document.getElementById("b"); + is_a(newB, HTMLParagraphElement); + } + { + var gbody = document.getElementsByTagName("body")[0]; + var div = document.createElement("div"); + div.setAttribute("id", "c"); + var h1 = document.createElement("h1"); + h1.setAttribute("id", "c"); + gbody.appendChild(div); + gbody.appendChild(h1); + var c = document.getElementById("c"); + is_a(c, HTMLDivElement); + gbody.removeChild(div); + var newC = document.getElementById("c"); + is_a(newC, HTMLHeadingElement); + } + finish(); + </script> + </body> +</html> diff --git a/src/test/content/test_element_attribute.html b/src/test/content/test_element_attribute.html index 8631138c767..d7ee6a23640 100644 --- a/src/test/content/test_element_attribute.html +++ b/src/test/content/test_element_attribute.html @@ -41,6 +41,25 @@ is(r2, null, "test4-1, Element.removeAttribute()."); } + { + test.setAttribute("xml:lang", "en"); + + let r1 = test.hasAttribute("xml:lang"); + is(r1, true, "test5-0, Element.setAttribute('xml:lang')."); + let r2 = test.getAttribute("xml:lang"); + is_not(r2, null, "test5-1, Element.setAttribute('xml:lang')."); + } + + should_throw(function () { + test.setAttributeNS("http://example.com", "xmlns", "foo"); + }); + should_throw(function () { + test.setAttributeNS("http://www.w3.org/2000/xmlns/", "attr", "value"); + }); + should_throw(function () { + test.setAttributeNS("http://www.w3.org/2000/xmlns/", "prefix:attr", "value"); + }); + finish(); </script> </body> diff --git a/src/test/html/test_pseudo.html b/src/test/html/test_pseudo.html new file mode 100644 index 00000000000..bfe528df145 --- /dev/null +++ b/src/test/html/test_pseudo.html @@ -0,0 +1,22 @@ +<!DOCTYPE html> +<html> +<head> +<style> +span.servo1:before { display:inline; content:'Hello'; color:blue} +span.servo1:after { display:inline; content:'ervo'; color:blue} +div.servo2:before { display:inline; content:'Hello'; color:blue} +div.servo2:after { display:inline; content:'ervo'; color:blue} +span.servo3:before { display:block; content:'Smile'; color:blue} +span.servo3:after { display:block; content:'And thanks';} +div.rust:before { display:block; content:'Hello,';} +div.rust:after { display:inline; content:'ust';} +</style> +</head> + +<body> +<span class="servo1">, S</span> +<div class="servo2">, S</div> +<span class="servo3">Servo</span> +<div class="rust">R</div> +</body> +</html> diff --git a/src/test/ref/append_style_a.html b/src/test/ref/append_style_a.html new file mode 100644 index 00000000000..40521ba3d08 --- /dev/null +++ b/src/test/ref/append_style_a.html @@ -0,0 +1 @@ +<div style="background-color: blue">this is the story of a girl</div> diff --git a/src/test/ref/append_style_b.html b/src/test/ref/append_style_b.html new file mode 100644 index 00000000000..4792dbc86e2 --- /dev/null +++ b/src/test/ref/append_style_b.html @@ -0,0 +1,6 @@ +<div id="hello">this is the story of a girl</div> +<script> + var style = document.createElement('style'); + style.textContent = "#hello { background-color: blue; }" + document.head.appendChild(style); +</script> diff --git a/src/test/ref/basic.list b/src/test/ref/basic.list index 4df86c52e8b..81b8f7761dd 100644 --- a/src/test/ref/basic.list +++ b/src/test/ref/basic.list @@ -27,12 +27,15 @@ # inline_border_a.html inline_border_b.html == anon_block_inherit_a.html anon_block_inherit_b.html == attr_exists_selector.html attr_exists_selector_ref.html +!= noteq_attr_exists_selector.html attr_exists_selector_ref.html == data_img_a.html data_img_b.html == background_style_attr.html background_ref.html == background_external_stylesheet.html background_ref.html == block_image.html 500x300_green.html +!= block_image.html noteq_500x300_white.html # == simple_iframe.html simple_iframe_ref.html -- disabled due to iframe crashiness == object_element_a.html object_element_b.html +== append_style_a.html append_style_b.html == height_compute_reset.html height_compute.html == width_nonreplaced_block_simple_a.html width_nonreplaced_block_simple_b.html == max_width_float_simple_a.html max_width_float_simple_b.html @@ -65,3 +68,5 @@ == background_repeat_y_a.html background_repeat_y_b.html == background_repeat_none_a.html background_repeat_none_b.html == background_repeat_both_a.html background_repeat_both_b.html +== setattribute_id_restyle_a.html setattribute_id_restyle_b.html +== pseudo_element_a.html pseudo_element_b.html diff --git a/src/test/ref/noteq_500x300_white.html b/src/test/ref/noteq_500x300_white.html new file mode 100644 index 00000000000..af89ba927e1 --- /dev/null +++ b/src/test/ref/noteq_500x300_white.html @@ -0,0 +1,5 @@ +<html> +<body> +<div style="width: 500px; height: 300px; background-color: #fff;"></div> +</body> +</html> diff --git a/src/test/ref/noteq_attr_exists_selector.html b/src/test/ref/noteq_attr_exists_selector.html new file mode 100644 index 00000000000..58bce6d5d39 --- /dev/null +++ b/src/test/ref/noteq_attr_exists_selector.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<html> + <head> + <title>Attribute exists selector: [foo]</title> + </head> + <body> + <p>This text should be green.</p> + <p>This text should be black.</p> + </body> +</html> diff --git a/src/test/ref/pseudo_element_a.html b/src/test/ref/pseudo_element_a.html new file mode 100644 index 00000000000..4700d0e593a --- /dev/null +++ b/src/test/ref/pseudo_element_a.html @@ -0,0 +1,22 @@ +<!DOCTYPE html> +<html> +<head> +<style> +span.servo1:before { display:inline; content:'Hello';} +span.servo1:after { display:inline; content:'ervo';} +div.servo2:before { display:inline; content:'Hello';} +div.servo2:after { display:inline; content:'ervo';} +span.servo3:before { display:block; content:'Smile'; color:blue} +span.servo3:after { display:block; content:'And thanks'; color:blue} +div.rust:before { display:block; content:'Hello,';} +div.rust:after { display:inline; content:'ust';} +</style> +</head> + +<body> +<span class="servo1">, S</span> +<div class="servo2">, S</div> +<span class="servo3">Servo</span> +<div class="rust">R</div> +</body> +</html> diff --git a/src/test/ref/pseudo_element_b.html b/src/test/ref/pseudo_element_b.html new file mode 100644 index 00000000000..892ce7ed4d9 --- /dev/null +++ b/src/test/ref/pseudo_element_b.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html> +<head> +<style> +.col { color:blue; } +</style> +</head> + +<body> +Hello,<span> Servo</span> +<div class="servo">Hello, Servo</div> +<div class="col">Smile</div> +<span>Servo</span> +<div class="col">And thanks</div> +<div>Hello,</div> +<span>Rust</span> +</body> +</html> diff --git a/src/test/ref/setattribute_id_restyle_a.html b/src/test/ref/setattribute_id_restyle_a.html new file mode 100644 index 00000000000..469ce797db7 --- /dev/null +++ b/src/test/ref/setattribute_id_restyle_a.html @@ -0,0 +1,12 @@ +<style> + #foo { background-color: #FF0000; } +</style> + +<div>hello</div> +<div id="">world</div> + +<script> + var divs = document.getElementsByTagName('div'); + divs[0].setAttribute('id', 'foo'); + divs[1].setAttribute('id', 'foo'); +</script> diff --git a/src/test/ref/setattribute_id_restyle_b.html b/src/test/ref/setattribute_id_restyle_b.html new file mode 100644 index 00000000000..f16fe454c50 --- /dev/null +++ b/src/test/ref/setattribute_id_restyle_b.html @@ -0,0 +1,6 @@ +<style> + #foo { background-color: #FF0000; } +</style> + +<div id="foo">hello</div> +<div id="foo">world</div> |