diff options
78 files changed, 934 insertions, 314 deletions
diff --git a/components/gfx/Cargo.toml b/components/gfx/Cargo.toml index 9ec80d3e091..a776bc2f709 100644 --- a/components/gfx/Cargo.toml +++ b/components/gfx/Cargo.toml @@ -8,6 +8,22 @@ authors = ["The Servo Project Developers"] name = "gfx" path = "lib.rs" +[dependencies] +bitflags = "0.3" +euclid = "0.1" +fnv = "1.0" +harfbuzz = "0.1" +lazy_static = "0.1" +libc = "0.1" +log = "0.3" +rand = "0.3" +rustc-serialize = "0.3" +serde = "0.4" +serde_macros = "0.4" +smallvec = "0.1" +string_cache = "0.1" +time = "0.1.12" + [dependencies.plugins] path = "../plugins" @@ -51,21 +67,6 @@ git = "https://github.com/pcwalton/ipc-channel" version = "0.2" features = [ "serde_serialization" ] -[dependencies] -log = "0.3" -fnv = "1.0" -time = "0.1.12" -bitflags = "0.3" -rustc-serialize = "0.3" -libc = "0.1" -rand = "0.3" -harfbuzz = "0.1" -smallvec = "0.1" -string_cache = "0.1" -euclid = "0.1" -serde = "0.4" -serde_macros = "0.4" - [target.x86_64-apple-darwin.dependencies] core-foundation = "0.1" core-graphics = "0.1" diff --git a/components/gfx/font.rs b/components/gfx/font.rs index 22261f1fc29..17625dc7fe4 100644 --- a/components/gfx/font.rs +++ b/components/gfx/font.rs @@ -146,7 +146,8 @@ impl Font { } let mut glyphs = GlyphStore::new(text.chars().count(), - options.flags.contains(IS_WHITESPACE_SHAPING_FLAG)); + options.flags.contains(IS_WHITESPACE_SHAPING_FLAG), + options.flags.contains(RTL_FLAG)); shaper.as_ref().unwrap().shape_text(text, options, &mut glyphs); let glyphs = Arc::new(glyphs); diff --git a/components/gfx/lib.rs b/components/gfx/lib.rs index d13251123ca..6ffbe36fb5b 100644 --- a/components/gfx/lib.rs +++ b/components/gfx/lib.rs @@ -12,6 +12,7 @@ #![feature(mpsc_select)] #![feature(plugin)] #![feature(str_char)] +#![feature(unique)] #![feature(vec_push_all)] #![plugin(plugins)] @@ -26,6 +27,8 @@ extern crate azure; extern crate fnv; extern crate euclid; extern crate ipc_channel; +#[macro_use] +extern crate lazy_static; extern crate layers; extern crate libc; #[macro_use] diff --git a/components/gfx/text/glyph.rs b/components/gfx/text/glyph.rs index 435096486a8..75017144155 100644 --- a/components/gfx/text/glyph.rs +++ b/components/gfx/text/glyph.rs @@ -512,6 +512,7 @@ pub struct GlyphStore { detail_store: DetailedGlyphStore, is_whitespace: bool, + is_rtl: bool, } int_range_index! { @@ -526,13 +527,14 @@ impl<'a> GlyphStore { /// Initializes the glyph store, but doesn't actually shape anything. /// /// Use the `add_*` methods to store glyph data. - pub fn new(length: usize, is_whitespace: bool) -> GlyphStore { + pub fn new(length: usize, is_whitespace: bool, is_rtl: bool) -> GlyphStore { assert!(length > 0); GlyphStore { entry_buffer: vec![GlyphEntry::initial(); length], detail_store: DetailedGlyphStore::new(), is_whitespace: is_whitespace, + is_rtl: is_rtl, } } @@ -633,8 +635,8 @@ impl<'a> GlyphStore { GlyphIterator { store: self, - char_index: rang.begin(), - char_range: rang.each_index(), + char_index: if self.is_rtl { rang.end() } else { rang.begin() - CharIndex(1) }, + char_range: *rang, glyph_range: None, } } @@ -736,7 +738,7 @@ impl<'a> GlyphStore { pub struct GlyphIterator<'a> { store: &'a GlyphStore, char_index: CharIndex, - char_range: EachIndex<isize, CharIndex>, + char_range: Range<CharIndex>, glyph_range: Option<EachIndex<isize, CharIndex>>, } @@ -776,23 +778,28 @@ impl<'a> Iterator for GlyphIterator<'a> { // `next_complex_glyph()`. #[inline(always)] fn next(&mut self) -> Option<(CharIndex, GlyphInfo<'a>)> { - // Would use 'match' here but it borrows contents in a way that - // interferes with mutation. + // Would use 'match' here but it borrows contents in a way that interferes with mutation. if self.glyph_range.is_some() { - self.next_glyph_range() + return self.next_glyph_range() + } + + // No glyph range. Look at next character. + self.char_index = self.char_index + if self.store.is_rtl { + CharIndex(-1) + } else { + CharIndex(1) + }; + let i = self.char_index; + if !self.char_range.contains(i) { + return None + } + debug_assert!(i < self.store.char_len()); + let entry = self.store.entry_buffer[i.to_usize()]; + if entry.is_simple() { + Some((i, GlyphInfo::Simple(self.store, i))) } else { - // No glyph range. Look at next character. - self.char_range.next().and_then(|i| { - self.char_index = i; - assert!(i < self.store.char_len()); - let entry = self.store.entry_buffer[i.to_usize()]; - if entry.is_simple() { - Some((self.char_index, GlyphInfo::Simple(self.store, i))) - } else { - // Fall back to the slow path. - self.next_complex_glyph(&entry, i) - } - }) + // Fall back to the slow path. + self.next_complex_glyph(&entry, i) } } } diff --git a/components/gfx/text/shaping/harfbuzz.rs b/components/gfx/text/shaping/harfbuzz.rs index 74a3b4e6d25..1359c304fee 100644 --- a/components/gfx/text/shaping/harfbuzz.rs +++ b/components/gfx/text/shaping/harfbuzz.rs @@ -9,7 +9,7 @@ use font::{IGNORE_LIGATURES_SHAPING_FLAG, RTL_FLAG, ShapingOptions}; use platform::font::FontTable; use text::glyph::{CharIndex, GlyphStore, GlyphId, GlyphData}; use text::shaping::ShaperMethods; -use text::util::{float_to_fixed, fixed_to_float}; +use text::util::{float_to_fixed, fixed_to_float, is_bidi_control}; use euclid::Point2D; use harfbuzz::{HB_MEMORY_MODE_READONLY, HB_DIRECTION_LTR, HB_DIRECTION_RTL}; @@ -149,7 +149,6 @@ struct FontAndShapingOptions { pub struct Shaper { hb_face: *mut hb_face_t, hb_font: *mut hb_font_t, - hb_funcs: *mut hb_font_funcs_t, font_and_shaping_options: Box<FontAndShapingOptions>, } @@ -161,9 +160,6 @@ impl Drop for Shaper { assert!(!self.hb_font.is_null()); RUST_hb_font_destroy(self.hb_font); - - assert!(!self.hb_funcs.is_null()); - RUST_hb_font_funcs_destroy(self.hb_funcs); } } } @@ -193,18 +189,11 @@ impl Shaper { Shaper::float_to_fixed(pt_size) as c_int); // configure static function callbacks. - // NB. This funcs structure could be reused globally, as it never changes. - let hb_funcs: *mut hb_font_funcs_t = RUST_hb_font_funcs_create(); - RUST_hb_font_funcs_set_glyph_func(hb_funcs, glyph_func, ptr::null_mut(), None); - RUST_hb_font_funcs_set_glyph_h_advance_func(hb_funcs, glyph_h_advance_func, ptr::null_mut(), None); - RUST_hb_font_funcs_set_glyph_h_kerning_func( - hb_funcs, glyph_h_kerning_func, ptr::null_mut(), ptr::null_mut()); - RUST_hb_font_set_funcs(hb_font, hb_funcs, font as *mut Font as *mut c_void, None); + RUST_hb_font_set_funcs(hb_font, **HB_FONT_FUNCS, font as *mut Font as *mut c_void, None); Shaper { hb_face: hb_face, hb_font: hb_font, - hb_funcs: hb_funcs, font_and_shaping_options: font_and_shaping_options, } } @@ -279,7 +268,11 @@ impl Shaper { // GlyphStore records are indexed by character, not byte offset. // so, we must be careful to increment this when saving glyph entries. - let mut char_idx = CharIndex(0); + let (mut char_idx, char_step) = if options.flags.contains(RTL_FLAG) { + (CharIndex(char_max as isize - 1), CharIndex(-1)) + } else { + (CharIndex(0), CharIndex(1)) + }; debug!("Shaped text[char count={}], got back {} glyph info records.", char_max, @@ -318,10 +311,10 @@ impl Shaper { debug!("{} -> {}", i, loc); } - debug!("text: {}", text); + debug!("text: {:?}", text); debug!("(char idx): char->(glyph index):"); for (i, ch) in text.char_indices() { - debug!("{}: {} --> {}", i, ch, byte_to_glyph[i]); + debug!("{}: {:?} --> {}", i, ch, byte_to_glyph[i]); } // some helpers @@ -453,16 +446,20 @@ impl Shaper { // // NB: When we acquire the ability to handle ligatures that cross word boundaries, // we'll need to do something special to handle `word-spacing` properly. - let shape = glyph_data.get_entry_for_glyph(glyph_span.begin(), &mut y_pos); let character = text.char_at(char_byte_span.begin()); - let advance = self.advance_for_shaped_glyph(shape.advance, character, options); - let data = GlyphData::new(shape.codepoint, - advance, - shape.offset, - false, - true, - true); - glyphs.add_glyph_for_char_index(char_idx, Some(character), &data); + if is_bidi_control(character) { + glyphs.add_nonglyph_for_char_index(char_idx, false, false); + } else { + let shape = glyph_data.get_entry_for_glyph(glyph_span.begin(), &mut y_pos); + let advance = self.advance_for_shaped_glyph(shape.advance, character, options); + let data = GlyphData::new(shape.codepoint, + advance, + shape.offset, + false, + true, + true); + glyphs.add_glyph_for_char_index(char_idx, Some(character), &data); + } } else { // collect all glyphs to be assigned to the first character. let mut datas = vec!(); @@ -488,7 +485,7 @@ impl Shaper { drop(range.ch); i = range.next; if i >= covered_byte_span.end() { break; } - char_idx = char_idx + CharIndex(1); + char_idx = char_idx + char_step; glyphs.add_nonglyph_for_char_index(char_idx, false, false); } } @@ -498,7 +495,7 @@ impl Shaper { glyph_span.reset(end, 0); let end = char_byte_span.end();; // FIXME: borrow checker workaround char_byte_span.reset(end, 0); - char_idx = char_idx + CharIndex(1); + char_idx = char_idx + char_step; } // this must be called after adding all glyph data; it sorts the @@ -528,7 +525,20 @@ impl Shaper { } } -/// Callbacks from Harfbuzz when font map and glyph advance lookup needed. +// Callbacks from Harfbuzz when font map and glyph advance lookup needed. +lazy_static! { + static ref HB_FONT_FUNCS: ptr::Unique<hb_font_funcs_t> = unsafe { + let hb_funcs = RUST_hb_font_funcs_create(); + RUST_hb_font_funcs_set_glyph_func(hb_funcs, glyph_func, ptr::null_mut(), None); + RUST_hb_font_funcs_set_glyph_h_advance_func( + hb_funcs, glyph_h_advance_func, ptr::null_mut(), None); + RUST_hb_font_funcs_set_glyph_h_kerning_func( + hb_funcs, glyph_h_kerning_func, ptr::null_mut(), ptr::null_mut()); + + ptr::Unique::new(hb_funcs) + }; +} + extern fn glyph_func(_: *mut hb_font_t, font_data: *mut c_void, unicode: hb_codepoint_t, diff --git a/components/gfx/text/util.rs b/components/gfx/text/util.rs index 59f3010c87d..1b78e42e792 100644 --- a/components/gfx/text/util.rs +++ b/components/gfx/text/util.rs @@ -92,9 +92,9 @@ pub fn transform_text(text: &str, } } - fn is_always_discardable_char(_ch: char) -> bool { - // TODO: check for bidi control chars, soft hyphens. - false + fn is_always_discardable_char(ch: char) -> bool { + // TODO: check for soft hyphens. + is_bidi_control(ch) } } @@ -105,3 +105,12 @@ pub fn float_to_fixed(before: usize, f: f64) -> i32 { pub fn fixed_to_float(before: usize, f: i32) -> f64 { f as f64 * 1.0f64 / ((1i32 << before) as f64) } + +pub fn is_bidi_control(c: char) -> bool { + match c { + '\u{202A}'...'\u{202E}' => true, + '\u{2066}'...'\u{2069}' => true, + '\u{200E}' | '\u{200F}' | '\u{061C}' => true, + _ => false + } +} diff --git a/components/layout/block.rs b/components/layout/block.rs index 7bd383b30e8..ee3e603e11f 100644 --- a/components/layout/block.rs +++ b/components/layout/block.rs @@ -2011,12 +2011,14 @@ impl Flow for BlockFlow { fn iterate_through_fragment_border_boxes(&self, iterator: &mut FragmentBorderBoxIterator, + level: i32, stacking_context_position: &Point2D<Au>) { if !iterator.should_process(&self.fragment) { return } iterator.process(&self.fragment, + level, &self.fragment .stacking_relative_border_box(&self.base.stacking_relative_position, &self.base diff --git a/components/layout/construct.rs b/components/layout/construct.rs index 89e88847a22..9ab1dfc6675 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -194,6 +194,12 @@ struct InlineFragmentsAccumulator { /// Whether we've created a range to enclose all the fragments. This will be Some() if the /// outer node is an inline and None otherwise. enclosing_node: Option<InlineFragmentNodeInfo>, + + /// Restyle damage to use for fragments created in this node. + restyle_damage: RestyleDamage, + + /// Bidi control characters to insert before and after these fragments. + bidi_control_chars: Option<(&'static str, &'static str)>, } impl InlineFragmentsAccumulator { @@ -201,6 +207,8 @@ impl InlineFragmentsAccumulator { InlineFragmentsAccumulator { fragments: IntermediateInlineFragments::new(), enclosing_node: None, + bidi_control_chars: None, + restyle_damage: RestyleDamage::empty(), } } @@ -211,6 +219,8 @@ impl InlineFragmentsAccumulator { address: node.opaque(), style: node.style().clone(), }), + bidi_control_chars: None, + restyle_damage: node.restyle_damage(), } } @@ -227,6 +237,8 @@ impl InlineFragmentsAccumulator { let InlineFragmentsAccumulator { mut fragments, enclosing_node, + bidi_control_chars, + restyle_damage, } = self; if let Some(enclosing_node) = enclosing_node { let frag_len = fragments.fragments.len(); @@ -239,6 +251,15 @@ impl InlineFragmentsAccumulator { frag.add_inline_context_style(enclosing_node.clone(), is_first, is_last); } + + // Control characters are later discarded in transform_text, so they don't affect the + // is_first/is_last styles above. + if let Some((start, end)) = bidi_control_chars { + fragments.fragments.push_front( + control_chars_to_fragment(&enclosing_node, start, restyle_damage)); + fragments.fragments.push_back( + control_chars_to_fragment(&enclosing_node, end, restyle_damage)); + } } fragments } @@ -744,6 +765,8 @@ impl<'a> FlowConstructor<'a> { -> ConstructionResult { let mut opt_inline_block_splits: LinkedList<InlineBlockSplit> = LinkedList::new(); let mut fragment_accumulator = InlineFragmentsAccumulator::from_inline_node(node); + fragment_accumulator.bidi_control_chars = bidi_control_chars(&*node.style()); + let mut abs_descendants = Descendants::new(); // Concatenate all the fragments of our kids, creating {ib} splits as necessary. @@ -1272,6 +1295,11 @@ impl<'a> FlowConstructor<'a> { for fragment in inline_fragments_construction_result.fragments .fragments .iter_mut() { + // Only mutate the styles of fragments that represent the dirty node. + if fragment.node != node.opaque() { + continue + } + match fragment.specific { SpecificFragmentInfo::InlineBlock(ref mut inline_block_fragment) => { flow::mut_base(&mut *inline_block_fragment.flow_ref).restyle_damage @@ -1631,3 +1659,37 @@ pub fn strip_ignorable_whitespace_from_end(this: &mut LinkedList<Fragment>) { drop(this.pop_back()); } } + +/// If the 'unicode-bidi' property has a value other than 'normal', return the bidi control codes +/// to inject before and after the text content of the element. +fn bidi_control_chars(style: &Arc<ComputedValues>) -> Option<(&'static str, &'static str)> { + use style::computed_values::unicode_bidi::T::*; + use style::computed_values::direction::T::*; + + let unicode_bidi = style.get_text().unicode_bidi; + let direction = style.get_inheritedbox().direction; + + // See the table in http://dev.w3.org/csswg/css-writing-modes/#unicode-bidi + match (unicode_bidi, direction) { + (normal, _) => None, + (embed, ltr) => Some(("\u{202A}", "\u{202C}")), + (embed, rtl) => Some(("\u{202B}", "\u{202C}")), + (isolate, ltr) => Some(("\u{2066}", "\u{2069}")), + (isolate, rtl) => Some(("\u{2067}", "\u{2069}")), + (bidi_override, ltr) => Some(("\u{202D}", "\u{202C}")), + (bidi_override, rtl) => Some(("\u{202E}", "\u{202C}")), + (isolate_override, ltr) => Some(("\u{2068}\u{202D}", "\u{202C}\u{2069}")), + (isolate_override, rtl) => Some(("\u{2068}\u{202E}", "\u{202C}\u{2069}")), + (plaintext, _) => Some(("\u{2068}", "\u{2069}")), + } +} + +fn control_chars_to_fragment(node: &InlineFragmentNodeInfo, text: &str, + restyle_damage: RestyleDamage) -> Fragment { + let info = SpecificFragmentInfo::UnscannedText( + UnscannedTextFragmentInfo::from_text(String::from(text))); + Fragment::from_opaque_node_and_style(node.address, + node.style.clone(), + restyle_damage, + info) +} diff --git a/components/layout/flow.rs b/components/layout/flow.rs index d315b9962db..6d2d6df0070 100644 --- a/components/layout/flow.rs +++ b/components/layout/flow.rs @@ -5,25 +5,25 @@ //! Servo's experimental layout system builds a tree of `Flow` and `Fragment` objects and solves //! layout constraints to obtain positions and display attributes of tree nodes. Positions are //! computed in several tree traversals driven by the fundamental data dependencies required by -/// inline and block layout. -/// -/// Flows are interior nodes in the layout tree and correspond closely to *flow contexts* in the -/// CSS specification. Flows are responsible for positioning their child flow contexts and -/// fragments. Flows have purpose-specific fields, such as auxiliary line structs, out-of-flow -/// child lists, and so on. -/// -/// Currently, the important types of flows are: -/// -/// * `BlockFlow`: A flow that establishes a block context. It has several child flows, each of -/// which are positioned according to block formatting context rules (CSS block boxes). Block -/// flows also contain a single box to represent their rendered borders, padding, etc. -/// The BlockFlow at the root of the tree has special behavior: it stretches to the boundaries of -/// the viewport. -/// -/// * `InlineFlow`: A flow that establishes an inline context. It has a flat list of child -/// fragments/flows that are subject to inline layout and line breaking and structs to represent -/// line breaks and mapping to CSS boxes, for the purpose of handling `getClientRects()` and -/// similar methods. +//! inline and block layout. +//! +//! Flows are interior nodes in the layout tree and correspond closely to *flow contexts* in the +//! CSS specification. Flows are responsible for positioning their child flow contexts and +//! fragments. Flows have purpose-specific fields, such as auxiliary line structs, out-of-flow +//! child lists, and so on. +//! +//! Currently, the important types of flows are: +//! +//! * `BlockFlow`: A flow that establishes a block context. It has several child flows, each of +//! which are positioned according to block formatting context rules (CSS block boxes). Block +//! flows also contain a single box to represent their rendered borders, padding, etc. +//! The BlockFlow at the root of the tree has special behavior: it stretches to the boundaries of +//! the viewport. +//! +//! * `InlineFlow`: A flow that establishes an inline context. It has a flat list of child +//! fragments/flows that are subject to inline layout and line breaking and structs to represent +//! line breaks and mapping to CSS boxes, for the purpose of handling `getClientRects()` and +//! similar methods. use block::BlockFlow; use context::LayoutContext; @@ -281,8 +281,11 @@ pub trait Flow: fmt::Debug + Sync { fn compute_overflow(&self) -> Rect<Au>; /// Iterates through border boxes of all of this flow's fragments. + /// Level provides a zero based index indicating the current + /// depth of the flow tree during fragment iteration. fn iterate_through_fragment_border_boxes(&self, iterator: &mut FragmentBorderBoxIterator, + level: i32, stacking_context_position: &Point2D<Au>); /// Mutably iterates through fragments in this flow. @@ -1436,4 +1439,3 @@ impl OpaqueFlow { OpaqueFlow(base_flow as *const BaseFlow as usize) } } - diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index 475535bbe97..61a6042b6df 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -1621,7 +1621,7 @@ impl Fragment { } match self.specific { SpecificFragmentInfo::UnscannedText(ref text_fragment_info) => { - util::str::is_whitespace(&text_fragment_info.text) + is_whitespace(&text_fragment_info.text) } _ => false, } @@ -2164,7 +2164,7 @@ bitflags! { /// A top-down fragment border box iteration handler. pub trait FragmentBorderBoxIterator { /// The operation to perform. - fn process(&mut self, fragment: &Fragment, overflow: &Rect<Au>); + fn process(&mut self, fragment: &Fragment, level: i32, overflow: &Rect<Au>); /// Returns true if this fragment must be processed in-order. If this returns false, /// we skip the operation for this fragment, but continue processing siblings. diff --git a/components/layout/inline.rs b/components/layout/inline.rs index 0d8e1e19347..6d4d67e6bbb 100644 --- a/components/layout/inline.rs +++ b/components/layout/inline.rs @@ -1623,6 +1623,7 @@ impl Flow for InlineFlow { fn iterate_through_fragment_border_boxes(&self, iterator: &mut FragmentBorderBoxIterator, + level: i32, stacking_context_position: &Point2D<Au>) { // FIXME(#2795): Get the real container size. for fragment in self.fragments.fragments.iter() { @@ -1636,6 +1637,7 @@ impl Flow for InlineFlow { let relative_containing_block_mode = self.base.absolute_position_info.relative_containing_block_mode; iterator.process(fragment, + level, &fragment.stacking_relative_border_box(stacking_relative_position, relative_containing_block_size, relative_containing_block_mode, diff --git a/components/layout/layout_task.rs b/components/layout/layout_task.rs index c7eab0fdb50..e9a644105b2 100644 --- a/components/layout/layout_task.rs +++ b/components/layout/layout_task.rs @@ -15,7 +15,7 @@ use data::LayoutDataWrapper; use display_list_builder::ToGfxColor; use flow::{self, Flow, ImmutableFlowUtils, MutableFlowUtils, MutableOwnedFlowUtils}; use flow_ref::FlowRef; -use fragment::{Fragment, FragmentBorderBoxIterator}; +use fragment::{Fragment, FragmentBorderBoxIterator, SpecificFragmentInfo}; use incremental::{LayoutDamageComputation, REFLOW, REFLOW_ENTIRE_DOCUMENT, REPAINT}; use layout_debug; use opaque_node::OpaqueNodeMethods; @@ -53,7 +53,7 @@ use net_traits::image_cache_task::{ImageCacheTask, ImageCacheResult, ImageCacheC use script::dom::bindings::js::LayoutJS; use script::dom::node::{LayoutData, Node}; use script::layout_interface::{Animation, ContentBoxResponse, ContentBoxesResponse, NodeGeometryResponse}; -use script::layout_interface::{HitTestResponse, LayoutChan, LayoutRPC, MouseOverResponse}; +use script::layout_interface::{HitTestResponse, LayoutChan, LayoutRPC, MouseOverResponse, OffsetParentResponse}; use script::layout_interface::{NewLayoutTaskInfo, Msg, Reflow, ReflowGoal, ReflowQueryType}; use script::layout_interface::{ResolvedStyleResponse, ScriptLayoutChan, ScriptReflow, TrustedNodeAddress}; use script_traits::{ConstellationControlMsg, LayoutControlMsg, OpaqueScriptLayoutChannel}; @@ -69,7 +69,7 @@ use std::ops::{Deref, DerefMut}; use std::sync::mpsc::{channel, Sender, Receiver, Select}; use std::sync::{Arc, Mutex, MutexGuard}; use string_cache::Atom; -use style::computed_values::{filter, mix_blend_mode}; +use style::computed_values::{self, filter, mix_blend_mode}; use style::media_queries::{MediaType, MediaQueryList, Device}; use style::properties::style_structs; use style::properties::longhands::{display, position}; @@ -137,6 +137,9 @@ pub struct LayoutTaskData { /// A queued response for the resolved style property of an element. pub resolved_style_response: Option<String>, + /// A queued response for the offset parent/rect of a node. + pub offset_parent_response: OffsetParentResponse, + /// The list of currently-running animations. pub running_animations: Arc<HashMap<OpaqueNode,Vec<Animation>>>, @@ -382,6 +385,7 @@ impl LayoutTask { client_rect_response: Rect::zero(), resolved_style_response: None, running_animations: Arc::new(HashMap::new()), + offset_parent_response: OffsetParentResponse::empty(), visible_rects: Arc::new(HashMap::with_hash_state(Default::default())), new_animations_receiver: new_animations_receiver, new_animations_sender: new_animations_sender, @@ -999,6 +1003,29 @@ impl LayoutTask { }; } + fn process_offset_parent_query<'a>(&'a self, + requested_node: TrustedNodeAddress, + layout_root: &mut FlowRef, + rw_data: &mut RWGuard<'a>) { + let requested_node: OpaqueNode = OpaqueNodeMethods::from_script_node(requested_node); + let mut iterator = ParentOffsetBorderBoxIterator::new(requested_node); + sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, &mut iterator); + let parent_info_index = iterator.parent_nodes.iter().rposition(|info| info.is_some()); + match parent_info_index { + Some(parent_info_index) => { + let parent = iterator.parent_nodes[parent_info_index].as_ref().unwrap(); + let origin = iterator.node_border_box.origin - parent.border_box.origin; + let size = iterator.node_border_box.size; + rw_data.offset_parent_response = OffsetParentResponse { + node_address: Some(parent.node_address.to_untrusted_node_address()), + rect: Rect::new(origin, size), + }; + } + None => { + rw_data.offset_parent_response = OffsetParentResponse::empty(); + } + } + } fn compute_abs_pos_and_build_display_list<'a>(&'a self, data: &Reflow, @@ -1198,6 +1225,8 @@ impl LayoutTask { self.process_node_geometry_request(node, &mut root_flow, &mut rw_data), ReflowQueryType::ResolvedStyleQuery(node, ref pseudo, ref property) => self.process_resolved_style_request(node, pseudo, property, &mut root_flow, &mut rw_data), + ReflowQueryType::OffsetParentQuery(node) => + self.process_offset_parent_query(node, &mut root_flow, &mut rw_data), ReflowQueryType::NoQuery => {} } @@ -1516,6 +1545,12 @@ impl LayoutRPC for LayoutRPCImpl { Ok(MouseOverResponse(response_list)) } } + + fn offset_parent(&self) -> OffsetParentResponse { + let &LayoutRPCImpl(ref rw_data) = self; + let rw_data = rw_data.lock().unwrap(); + rw_data.offset_parent_response.clone() + } } struct UnioningFragmentBorderBoxIterator { @@ -1533,7 +1568,7 @@ impl UnioningFragmentBorderBoxIterator { } impl FragmentBorderBoxIterator for UnioningFragmentBorderBoxIterator { - fn process(&mut self, _: &Fragment, border_box: &Rect<Au>) { + fn process(&mut self, _: &Fragment, _: i32, border_box: &Rect<Au>) { self.rect = match self.rect { Some(rect) => { Some(rect.union(border_box)) @@ -1564,7 +1599,7 @@ impl CollectingFragmentBorderBoxIterator { } impl FragmentBorderBoxIterator for CollectingFragmentBorderBoxIterator { - fn process(&mut self, _: &Fragment, border_box: &Rect<Au>) { + fn process(&mut self, _: &Fragment, _: i32, border_box: &Rect<Au>) { self.rects.push(*border_box); } @@ -1587,8 +1622,33 @@ impl FragmentLocatingFragmentIterator { } } +struct ParentBorderBoxInfo { + node_address: OpaqueNode, + border_box: Rect<Au>, +} + +struct ParentOffsetBorderBoxIterator { + node_address: OpaqueNode, + last_level: i32, + has_found_node: bool, + node_border_box: Rect<Au>, + parent_nodes: Vec<Option<ParentBorderBoxInfo>>, +} + +impl ParentOffsetBorderBoxIterator { + fn new(node_address: OpaqueNode) -> ParentOffsetBorderBoxIterator { + ParentOffsetBorderBoxIterator { + node_address: node_address, + last_level: -1, + has_found_node: false, + node_border_box: Rect::zero(), + parent_nodes: Vec::new(), + } + } +} + impl FragmentBorderBoxIterator for FragmentLocatingFragmentIterator { - fn process(&mut self, fragment: &Fragment, border_box: &Rect<Au>) { + fn process(&mut self, fragment: &Fragment, _: i32, border_box: &Rect<Au>) { let style_structs::Border { border_top_width: top_width, border_right_width: right_width, @@ -1649,7 +1709,7 @@ impl PositionRetrievingFragmentBorderBoxIterator { } impl FragmentBorderBoxIterator for PositionRetrievingFragmentBorderBoxIterator { - fn process(&mut self, _: &Fragment, border_box: &Rect<Au>) { + fn process(&mut self, _: &Fragment, _: i32, border_box: &Rect<Au>) { self.result = Some(match self.property { PositionProperty::Left => self.position.x, @@ -1691,7 +1751,7 @@ impl MarginRetrievingFragmentBorderBoxIterator { } impl FragmentBorderBoxIterator for MarginRetrievingFragmentBorderBoxIterator { - fn process(&mut self, fragment: &Fragment, _: &Rect<Au>) { + fn process(&mut self, fragment: &Fragment, _: i32, _: &Rect<Au>) { let rect = match self.margin_padding { MarginPadding::Margin => &fragment.margin, MarginPadding::Padding => &fragment.border_padding @@ -1709,6 +1769,63 @@ impl FragmentBorderBoxIterator for MarginRetrievingFragmentBorderBoxIterator { } } +// https://drafts.csswg.org/cssom-view/#extensions-to-the-htmlelement-interface +impl FragmentBorderBoxIterator for ParentOffsetBorderBoxIterator { + fn process(&mut self, fragment: &Fragment, level: i32, border_box: &Rect<Au>) { + if fragment.node == self.node_address { + // Found the fragment in the flow tree that matches the + // DOM node being looked for. + self.has_found_node = true; + self.node_border_box = *border_box; + + // offsetParent returns null if the node is fixed. + if fragment.style.get_box().position == computed_values::position::T::fixed { + self.parent_nodes.clear(); + } + } else if level > self.last_level { + // TODO(gw): Is there a less fragile way of checking whether this + // fragment is the body element, rather than just checking that + // the parent nodes stack contains the root node only? + let is_body_element = self.parent_nodes.len() == 1; + + let is_valid_parent = match (is_body_element, + fragment.style.get_box().position, + &fragment.specific) { + // Spec says it's valid if any of these are true: + // 1) Is the body element + // 2) Is static position *and* is a table or table cell + // 3) Is not static position + (true, _, _) | + (false, computed_values::position::T::static_, &SpecificFragmentInfo::Table) | + (false, computed_values::position::T::static_, &SpecificFragmentInfo::TableCell) | + (false, computed_values::position::T::absolute, _) | + (false, computed_values::position::T::relative, _) | + (false, computed_values::position::T::fixed, _) => true, + + // Otherwise, it's not a valid parent + (false, computed_values::position::T::static_, _) => false, + }; + + let parent_info = if is_valid_parent { + Some(ParentBorderBoxInfo { + border_box: *border_box, + node_address: fragment.node, + }) + } else { + None + }; + + self.parent_nodes.push(parent_info); + } else if level < self.last_level { + self.parent_nodes.pop(); + } + } + + fn should_process(&mut self, _: &Fragment) -> bool { + !self.has_found_node + } +} + // The default computed value for background-color is transparent (see // http://dev.w3.org/csswg/css-backgrounds/#background-color). However, we // need to propagate the background color from the root HTML/Body diff --git a/components/layout/list_item.rs b/components/layout/list_item.rs index 24ed6633d45..63caca9d4d5 100644 --- a/components/layout/list_item.rs +++ b/components/layout/list_item.rs @@ -158,13 +158,15 @@ impl Flow for ListItemFlow { fn iterate_through_fragment_border_boxes(&self, iterator: &mut FragmentBorderBoxIterator, + level: i32, stacking_context_position: &Point2D<Au>) { - self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position); + self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position); if let Some(ref marker) = self.marker { if iterator.should_process(marker) { iterator.process( marker, + level, &marker.stacking_relative_border_box(&self.block_flow .base .stacking_relative_position, diff --git a/components/layout/multicol.rs b/components/layout/multicol.rs index 20cc7d5c1c5..3e9ff257c9c 100644 --- a/components/layout/multicol.rs +++ b/components/layout/multicol.rs @@ -98,8 +98,9 @@ impl Flow for MulticolFlow { fn iterate_through_fragment_border_boxes(&self, iterator: &mut FragmentBorderBoxIterator, + level: i32, stacking_context_position: &Point2D<Au>) { - self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position) + self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position) } fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) { diff --git a/components/layout/sequential.rs b/components/layout/sequential.rs index b4c8270e804..6f806f69bf8 100644 --- a/components/layout/sequential.rs +++ b/components/layout/sequential.rs @@ -122,22 +122,24 @@ pub fn build_display_list_for_subtree(root: &mut FlowRef, pub fn iterate_through_flow_tree_fragment_border_boxes(root: &mut FlowRef, iterator: &mut FragmentBorderBoxIterator) { fn doit(flow: &mut Flow, + level: i32, iterator: &mut FragmentBorderBoxIterator, stacking_context_position: &Point2D<Au>) { - flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position); + flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position); for kid in flow::mut_base(flow).child_iter() { let stacking_context_position = if kid.is_block_flow() && kid.as_block().fragment.establishes_stacking_context() { - *stacking_context_position + flow::base(kid).stacking_relative_position + let margin = Point2D::new(kid.as_block().fragment.margin.inline_start, Au(0)); + *stacking_context_position + flow::base(kid).stacking_relative_position + margin } else { *stacking_context_position }; // FIXME(#2795): Get the real container size. - doit(kid, iterator, &stacking_context_position); + doit(kid, level+1, iterator, &stacking_context_position); } } - doit(&mut **root, iterator, &ZERO_POINT); + doit(&mut **root, 0, iterator, &ZERO_POINT); } diff --git a/components/layout/table.rs b/components/layout/table.rs index 633454097e2..197dc89db17 100644 --- a/components/layout/table.rs +++ b/components/layout/table.rs @@ -547,8 +547,9 @@ impl Flow for TableFlow { fn iterate_through_fragment_border_boxes(&self, iterator: &mut FragmentBorderBoxIterator, + level: i32, stacking_context_position: &Point2D<Au>) { - self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position) + self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position) } fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) { diff --git a/components/layout/table_caption.rs b/components/layout/table_caption.rs index c840ab866ce..003f03c92c2 100644 --- a/components/layout/table_caption.rs +++ b/components/layout/table_caption.rs @@ -95,8 +95,9 @@ impl Flow for TableCaptionFlow { fn iterate_through_fragment_border_boxes(&self, iterator: &mut FragmentBorderBoxIterator, + level: i32, stacking_context_position: &Point2D<Au>) { - self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position) + self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position) } fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) { diff --git a/components/layout/table_cell.rs b/components/layout/table_cell.rs index 66f9ec72259..90cc27854cc 100644 --- a/components/layout/table_cell.rs +++ b/components/layout/table_cell.rs @@ -209,8 +209,9 @@ impl Flow for TableCellFlow { fn iterate_through_fragment_border_boxes(&self, iterator: &mut FragmentBorderBoxIterator, + level: i32, stacking_context_position: &Point2D<Au>) { - self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position) + self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position) } fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) { diff --git a/components/layout/table_colgroup.rs b/components/layout/table_colgroup.rs index d58c361da4d..3af39fe0347 100644 --- a/components/layout/table_colgroup.rs +++ b/components/layout/table_colgroup.rs @@ -107,6 +107,7 @@ impl Flow for TableColGroupFlow { fn iterate_through_fragment_border_boxes(&self, _: &mut FragmentBorderBoxIterator, + _: i32, _: &Point2D<Au>) {} fn mutate_fragments(&mut self, _: &mut FnMut(&mut Fragment)) {} diff --git a/components/layout/table_row.rs b/components/layout/table_row.rs index 5048644b755..e1cde61b361 100644 --- a/components/layout/table_row.rs +++ b/components/layout/table_row.rs @@ -444,8 +444,9 @@ impl Flow for TableRowFlow { fn iterate_through_fragment_border_boxes(&self, iterator: &mut FragmentBorderBoxIterator, + level: i32, stacking_context_position: &Point2D<Au>) { - self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position) + self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position) } fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) { diff --git a/components/layout/table_rowgroup.rs b/components/layout/table_rowgroup.rs index 51c700ae480..f633d241218 100644 --- a/components/layout/table_rowgroup.rs +++ b/components/layout/table_rowgroup.rs @@ -234,8 +234,9 @@ impl Flow for TableRowGroupFlow { fn iterate_through_fragment_border_boxes(&self, iterator: &mut FragmentBorderBoxIterator, + level: i32, stacking_context_position: &Point2D<Au>) { - self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position) + self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position) } fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) { diff --git a/components/layout/table_wrapper.rs b/components/layout/table_wrapper.rs index 56934ea875a..ecf9596f746 100644 --- a/components/layout/table_wrapper.rs +++ b/components/layout/table_wrapper.rs @@ -431,8 +431,9 @@ impl Flow for TableWrapperFlow { fn iterate_through_fragment_border_boxes(&self, iterator: &mut FragmentBorderBoxIterator, + level: i32, stacking_context_position: &Point2D<Au>) { - self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position) + self.block_flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position) } fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) { diff --git a/components/msg/Cargo.toml b/components/msg/Cargo.toml index edb799eee14..0575608d294 100644 --- a/components/msg/Cargo.toml +++ b/components/msg/Cargo.toml @@ -41,6 +41,9 @@ git = "https://github.com/pcwalton/ipc-channel" git = "https://github.com/ecoal95/rust-offscreen-rendering-context" features = ["texture_surface"] +[dependencies.plugins] +path = "../plugins" + [dependencies] bitflags = "0.3" rustc-serialize = "0.3.4" diff --git a/components/msg/constellation_msg.rs b/components/msg/constellation_msg.rs index 97d673deecb..286d0f71a2b 100644 --- a/components/msg/constellation_msg.rs +++ b/components/msg/constellation_msg.rs @@ -48,7 +48,7 @@ pub struct Failure { pub parent_info: Option<(PipelineId, SubpageId)>, } -#[derive(Copy, Clone, Deserialize, Serialize)] +#[derive(Copy, Clone, Deserialize, Serialize, HeapSizeOf)] pub struct WindowSizeData { /// The size of the initial layout viewport, before parsing an /// http://www.w3.org/TR/css-device-adapt/#initial-viewport @@ -386,13 +386,13 @@ pub enum NavigationDirection { #[derive(Clone, PartialEq, Eq, Copy, Hash, Debug, Deserialize, Serialize)] pub struct FrameId(pub u32); -#[derive(Clone, PartialEq, Eq, Copy, Hash, Debug, Deserialize, Serialize)] +#[derive(Clone, PartialEq, Eq, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)] pub struct WorkerId(pub u32); -#[derive(Clone, PartialEq, Eq, Copy, Hash, Debug, Deserialize, Serialize)] +#[derive(Clone, PartialEq, Eq, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)] pub struct PipelineId(pub u32); -#[derive(Clone, PartialEq, Eq, Copy, Hash, Debug, Deserialize, Serialize)] +#[derive(Clone, PartialEq, Eq, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)] pub struct SubpageId(pub u32); // The type of pipeline exit. During complete shutdowns, pipelines do not have to diff --git a/components/msg/lib.rs b/components/msg/lib.rs index 4c2dd1f999b..7c03b73d591 100644 --- a/components/msg/lib.rs +++ b/components/msg/lib.rs @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #![feature(custom_derive, plugin)] -#![plugin(serde_macros)] +#![plugin(serde_macros, plugins)] extern crate azure; #[macro_use] extern crate bitflags; diff --git a/components/script/devtools.rs b/components/script/devtools.rs index 60d410bbda8..8b4dfb12e6f 100644 --- a/components/script/devtools.rs +++ b/components/script/devtools.rs @@ -43,7 +43,6 @@ pub fn handle_evaluate_js(global: &GlobalRef, eval: String, reply: IpcSender<Eva } else if rval.ptr.is_null() { EvaluateJSReply::NullValue } else { - //FIXME: jsvals don't have an is_int32/is_number yet assert!(rval.ptr.is_object()); panic!("object values unimplemented") }).unwrap(); diff --git a/components/script/document_loader.rs b/components/script/document_loader.rs index 56ee98bdbbf..9046f5cbbcf 100644 --- a/components/script/document_loader.rs +++ b/components/script/document_loader.rs @@ -12,7 +12,7 @@ use net_traits::AsyncResponseTarget; use std::sync::Arc; use url::Url; -#[derive(JSTraceable, PartialEq, Clone, Debug)] +#[derive(JSTraceable, PartialEq, Clone, Debug, HeapSizeOf)] pub enum LoadType { Image(Url), Script(Url), @@ -33,17 +33,19 @@ impl LoadType { } } -#[derive(JSTraceable)] +#[derive(JSTraceable, HeapSizeOf)] pub struct DocumentLoader { /// We use an `Arc<ResourceTask>` here in order to avoid file descriptor exhaustion when there /// are lots of iframes. + #[ignore_heap_size_of = "channels are hard"] pub resource_task: Arc<ResourceTask>, notifier_data: Option<NotifierData>, blocking_loads: Vec<LoadType>, } -#[derive(JSTraceable)] +#[derive(JSTraceable, HeapSizeOf)] pub struct NotifierData { + #[ignore_heap_size_of = "trait objects are hard"] pub script_chan: Box<ScriptChan + Send>, pub pipeline: PipelineId, } diff --git a/components/script/dom/bindings/cell.rs b/components/script/dom/bindings/cell.rs index 35b20d0a417..80bab8839bc 100644 --- a/components/script/dom/bindings/cell.rs +++ b/components/script/dom/bindings/cell.rs @@ -16,7 +16,7 @@ use std::cell::{BorrowState, RefCell, Ref, RefMut}; /// /// This extends the API of `core::cell::RefCell` to allow unsafe access in /// certain situations, with dynamic checking in debug builds. -#[derive(Clone)] +#[derive(Clone, HeapSizeOf)] pub struct DOMRefCell<T> { value: RefCell<T>, } diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index a46c58ff7c7..9bfaa0c9cfd 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -3314,7 +3314,7 @@ class CGEnum(CGThing): decl = """\ #[repr(usize)] -#[derive(JSTraceable, PartialEq, Copy, Clone)] +#[derive(JSTraceable, PartialEq, Copy, Clone, HeapSizeOf)] pub enum %s { %s } diff --git a/components/script/dom/bindings/global.rs b/components/script/dom/bindings/global.rs index 4a2879e9f41..053059cec9f 100644 --- a/components/script/dom/bindings/global.rs +++ b/components/script/dom/bindings/global.rs @@ -125,7 +125,7 @@ impl<'a> GlobalRef<'a> { pub fn get_worker_id(&self) -> Option<WorkerId> { match *self { GlobalRef::Window(_) => None, - GlobalRef::Worker(ref worker) => worker.get_worker_id(), + GlobalRef::Worker(ref worker) => Some(worker.get_worker_id()), } } diff --git a/components/script/dom/bindings/js.rs b/components/script/dom/bindings/js.rs index fc929db1cac..0fde5678ab2 100644 --- a/components/script/dom/bindings/js.rs +++ b/components/script/dom/bindings/js.rs @@ -31,6 +31,7 @@ use js::jsapi::{JSObject, Heap, JSTracer}; use js::jsval::JSVal; use layout_interface::TrustedNodeAddress; use script_task::STACK_ROOTS; +use util::mem::HeapSizeOf; use core::nonzero::NonZero; use std::cell::{Cell, UnsafeCell}; @@ -44,6 +45,14 @@ pub struct JS<T> { ptr: NonZero<*const T> } +// JS<T> is similar to Rc<T>, in that it's not always clear how to avoid double-counting. +// For now, we choose not to follow any such pointers. +impl<T> HeapSizeOf for JS<T> { + fn heap_size_of_children(&self) -> usize { + 0 + } +} + impl<T> JS<T> { /// Returns `LayoutJS<T>` containing the same pointer. pub unsafe fn to_layout(self) -> LayoutJS<T> { @@ -226,7 +235,7 @@ impl<T: HeapGCValue+Copy> MutHeap<T> { /// place of traditional internal mutability to ensure that the proper GC /// barriers are enforced. #[must_root] -#[derive(JSTraceable)] +#[derive(JSTraceable, HeapSizeOf)] pub struct MutNullableHeap<T: HeapGCValue+Copy> { ptr: Cell<Option<T>> } diff --git a/components/script/dom/bindings/utils.rs b/components/script/dom/bindings/utils.rs index bacb6bc05ae..80db27bd894 100644 --- a/components/script/dom/bindings/utils.rs +++ b/components/script/dom/bindings/utils.rs @@ -16,6 +16,7 @@ use dom::bindings::js::Root; use dom::bindings::trace::trace_object; use dom::browsercontext; use dom::window; +use util::mem::HeapSizeOf; use util::str::DOMString; use libc; @@ -61,10 +62,18 @@ use js; use string_cache::{Atom, Namespace}; /// Proxy handler for a WindowProxy. +#[allow(raw_pointer_derive)] pub struct WindowProxyHandler(pub *const libc::c_void); +impl HeapSizeOf for WindowProxyHandler { + fn heap_size_of_children(&self) -> usize { + //FIXME(#6907) this is a pointer to memory allocated by `new` in NewProxyHandler in rust-mozjs. + 0 + } +} + #[allow(raw_pointer_derive)] -#[derive(JSTraceable)] +#[derive(JSTraceable, HeapSizeOf)] /// Static data associated with a global object. pub struct GlobalStaticData { /// The WindowProxy proxy handler for this global. @@ -416,8 +425,10 @@ pub fn reflect_dom_object<T: Reflectable> #[allow(raw_pointer_derive, unrooted_must_root)] #[must_root] #[servo_lang = "reflector"] +#[derive(HeapSizeOf)] // If you're renaming or moving this field, update the path in plugins::reflector as well pub struct Reflector { + #[ignore_heap_size_of = "defined and measured in rust-mozjs"] object: UnsafeCell<*mut JSObject>, } diff --git a/components/script/dom/browsercontext.rs b/components/script/dom/browsercontext.rs index cc4dc346c3f..8fe518844ba 100644 --- a/components/script/dom/browsercontext.rs +++ b/components/script/dom/browsercontext.rs @@ -27,7 +27,7 @@ use js::{JSTrue, JSFalse}; use std::ptr; use std::default::Default; -#[derive(JSTraceable)] +#[derive(JSTraceable, HeapSizeOf)] #[privatize] #[allow(raw_pointer_derive)] #[must_root] @@ -88,7 +88,7 @@ impl BrowsingContext { // without a reflector, so we don't mark this as #[dom_struct] #[must_root] #[privatize] -#[derive(JSTraceable)] +#[derive(JSTraceable, HeapSizeOf)] pub struct SessionHistoryEntry { document: JS<Document>, children: Vec<BrowsingContext> diff --git a/components/script/dom/characterdata.rs b/components/script/dom/characterdata.rs index 377a69b3d2d..f15b66c68f8 100644 --- a/components/script/dom/characterdata.rs +++ b/components/script/dom/characterdata.rs @@ -24,6 +24,7 @@ use std::cell::Ref; // https://dom.spec.whatwg.org/#characterdata #[dom_struct] +#[derive(HeapSizeOf)] pub struct CharacterData { node: Node, data: DOMRefCell<DOMString>, @@ -150,7 +151,7 @@ impl<'a> CharacterDataMethods for &'a CharacterData { } /// The different types of CharacterData. -#[derive(JSTraceable, Copy, Clone, PartialEq, Debug)] +#[derive(JSTraceable, Copy, Clone, PartialEq, Debug, HeapSizeOf)] pub enum CharacterDataTypeId { Comment, Text, diff --git a/components/script/dom/dedicatedworkerglobalscope.rs b/components/script/dom/dedicatedworkerglobalscope.rs index 90fb0283507..cef9c5f9789 100644 --- a/components/script/dom/dedicatedworkerglobalscope.rs +++ b/components/script/dom/dedicatedworkerglobalscope.rs @@ -21,21 +21,19 @@ use dom::eventtarget::{EventTarget, EventTargetHelpers, EventTargetTypeId}; use dom::messageevent::MessageEvent; use dom::worker::{TrustedWorkerAddress, WorkerMessageHandler, WorkerEventHandler, WorkerErrorHandler}; use dom::workerglobalscope::{WorkerGlobalScope, WorkerGlobalScopeHelpers}; -use dom::workerglobalscope::WorkerGlobalScopeTypeId; +use dom::workerglobalscope::{WorkerGlobalScopeTypeId, WorkerGlobalScopeInit}; use script_task::{ScriptTask, ScriptChan, ScriptMsg, TimerSource, ScriptPort}; use script_task::StackRootTLS; -use msg::constellation_msg::{ConstellationChan, PipelineId, WorkerId}; - -use devtools_traits::{ScriptToDevtoolsControlMsg, DevtoolScriptControlMsg}; - -use net_traits::{load_whole_resource, ResourceTask}; +use devtools_traits::DevtoolScriptControlMsg; +use msg::constellation_msg::PipelineId; +use net_traits::load_whole_resource; use profile_traits::mem::{self, Reporter, ReporterRequest}; use util::task::spawn_named; use util::task_state; use util::task_state::{SCRIPT, IN_WORKER}; -use ipc_channel::ipc::{self, IpcSender, IpcReceiver}; +use ipc_channel::ipc::{self, IpcReceiver}; use ipc_channel::router::ROUTER; use js::jsapi::{JSContext, RootedValue, HandleValue}; use js::jsapi::{JSAutoRequest, JSAutoCompartment}; @@ -107,25 +105,19 @@ pub struct DedicatedWorkerGlobalScope { } impl DedicatedWorkerGlobalScope { - fn new_inherited(worker_url: Url, + fn new_inherited(init: WorkerGlobalScopeInit, + worker_url: Url, id: PipelineId, - mem_profiler_chan: mem::ProfilerChan, - devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>, - devtools_sender: Option<IpcSender<DevtoolScriptControlMsg>>, devtools_port: Receiver<DevtoolScriptControlMsg>, runtime: Rc<Runtime>, - resource_task: ResourceTask, - constellation_chan: ConstellationChan, parent_sender: Box<ScriptChan+Send>, own_sender: Sender<(TrustedWorkerAddress, ScriptMsg)>, - receiver: Receiver<(TrustedWorkerAddress, ScriptMsg)>, - worker_id: Option<WorkerId>) + receiver: Receiver<(TrustedWorkerAddress, ScriptMsg)>) -> DedicatedWorkerGlobalScope { DedicatedWorkerGlobalScope { workerglobalscope: WorkerGlobalScope::new_inherited( - WorkerGlobalScopeTypeId::DedicatedGlobalScope, worker_url, runtime, resource_task, - mem_profiler_chan, devtools_chan, devtools_sender, devtools_port, constellation_chan, - worker_id), + WorkerGlobalScopeTypeId::DedicatedGlobalScope, init, worker_url, + runtime, devtools_port), id: id, receiver: receiver, own_sender: own_sender, @@ -134,43 +126,32 @@ impl DedicatedWorkerGlobalScope { } } - pub fn new(worker_url: Url, + pub fn new(init: WorkerGlobalScopeInit, + worker_url: Url, id: PipelineId, - mem_profiler_chan: mem::ProfilerChan, - devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>, - devtools_sender: Option<IpcSender<DevtoolScriptControlMsg>>, devtools_port: Receiver<DevtoolScriptControlMsg>, runtime: Rc<Runtime>, - resource_task: ResourceTask, - constellation_chan: ConstellationChan, parent_sender: Box<ScriptChan+Send>, own_sender: Sender<(TrustedWorkerAddress, ScriptMsg)>, - receiver: Receiver<(TrustedWorkerAddress, ScriptMsg)>, - worker_id: Option<WorkerId>) + receiver: Receiver<(TrustedWorkerAddress, ScriptMsg)>) -> Root<DedicatedWorkerGlobalScope> { let scope = box DedicatedWorkerGlobalScope::new_inherited( - worker_url, id, mem_profiler_chan, devtools_chan, devtools_sender, devtools_port, - runtime.clone(), resource_task, constellation_chan, parent_sender, own_sender, receiver, - worker_id); + init, worker_url, id, devtools_port, runtime.clone(), parent_sender, + own_sender, receiver); DedicatedWorkerGlobalScopeBinding::Wrap(runtime.cx(), scope) } } impl DedicatedWorkerGlobalScope { #[allow(unsafe_code)] - pub fn run_worker_scope(worker_url: Url, + pub fn run_worker_scope(init: WorkerGlobalScopeInit, + worker_url: Url, id: PipelineId, - mem_profiler_chan: mem::ProfilerChan, - devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>, - devtools_ipc_chan: Option<IpcSender<DevtoolScriptControlMsg>>, devtools_ipc_port: IpcReceiver<DevtoolScriptControlMsg>, worker: TrustedWorkerAddress, - resource_task: ResourceTask, - constellation_chan: ConstellationChan, parent_sender: Box<ScriptChan+Send>, own_sender: Sender<(TrustedWorkerAddress, ScriptMsg)>, - receiver: Receiver<(TrustedWorkerAddress, ScriptMsg)>, - worker_id: Option<WorkerId>) { + receiver: Receiver<(TrustedWorkerAddress, ScriptMsg)>) { let serialized_worker_url = worker_url.serialize(); spawn_named(format!("WebWorker for {}", serialized_worker_url), move || { task_state::initialize(SCRIPT | IN_WORKER); @@ -178,7 +159,7 @@ impl DedicatedWorkerGlobalScope { let roots = RootCollection::new(); let _stack_roots_tls = StackRootTLS::new(&roots); - let (url, source) = match load_whole_resource(&resource_task, worker_url) { + let (url, source) = match load_whole_resource(&init.resource_task, worker_url) { Err(_) => { println!("error loading script {}", serialized_worker_url); parent_sender.send(ScriptMsg::RunnableMsg( @@ -198,9 +179,8 @@ impl DedicatedWorkerGlobalScope { ROUTER.route_ipc_receiver_to_mpsc_sender(devtools_ipc_port, devtools_mpsc_chan); let global = DedicatedWorkerGlobalScope::new( - url, id, mem_profiler_chan.clone(), devtools_chan, devtools_ipc_chan, devtools_mpsc_port, - runtime.clone(), resource_task, constellation_chan, parent_sender, own_sender, receiver, - worker_id); + init, url, id, devtools_mpsc_port, runtime.clone(), + parent_sender, own_sender, receiver); // FIXME(njn): workers currently don't have a unique ID suitable for using in reporter // registration (#6631), so we instead use a random number and cross our fingers. let scope = WorkerGlobalScopeCast::from_ref(global.r()); @@ -230,7 +210,7 @@ impl DedicatedWorkerGlobalScope { parent_sender_for_reporter.send(ScriptMsg::CollectReports( reporter_request.reports_channel)).unwrap() }); - mem_profiler_chan.send(mem::ProfilerMsg::RegisterReporter( + scope.mem_profiler_chan().send(mem::ProfilerMsg::RegisterReporter( reporter_name.clone(), Reporter(reporter_sender))); } @@ -292,7 +272,7 @@ impl DedicatedWorkerGlobalScope { // Unregister this task as a memory reporter. let msg = mem::ProfilerMsg::UnregisterReporter(reporter_name); - mem_profiler_chan.send(msg); + scope.mem_profiler_chan().send(msg); }); } } diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index dd7dc90e0fe..5383ea6df33 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -110,6 +110,7 @@ pub enum IsHTMLDocument { // https://dom.spec.whatwg.org/#document #[dom_struct] +#[derive(HeapSizeOf)] pub struct Document { node: Node, window: JS<Window>, @@ -144,6 +145,7 @@ pub struct Document { animation_frame_ident: Cell<i32>, /// https://html.spec.whatwg.org/multipage/#list-of-animation-frame-callbacks /// List of animation frame callbacks + #[ignore_heap_size_of = "closures are hard"] animation_frame_list: RefCell<HashMap<i32, Box<Fn(f64)>>>, /// Tracks all outstanding loads related to this document. loader: DOMRefCell<DocumentLoader>, diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 046b9a57c5f..1b200ed4e61 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -120,7 +120,7 @@ impl PartialEq for Element { } } -#[derive(JSTraceable, Copy, Clone, PartialEq, Debug)] +#[derive(JSTraceable, Copy, Clone, PartialEq, Debug, HeapSizeOf)] pub enum ElementTypeId { HTMLElement(HTMLElementTypeId), Element, diff --git a/components/script/dom/eventtarget.rs b/components/script/dom/eventtarget.rs index dfeae4ff08f..79679ff14d2 100644 --- a/components/script/dom/eventtarget.rs +++ b/components/script/dom/eventtarget.rs @@ -20,6 +20,7 @@ use js::jsapi::{CompileFunction, JS_GetFunctionObject}; use js::jsapi::{JSContext, RootedFunction, HandleObject}; use js::jsapi::{JSAutoCompartment, JSAutoRequest}; use js::rust::{AutoObjectVectorWrapper, CompileOptionsWrapper}; +use util::mem::HeapSizeOf; use util::str::DOMString; use fnv::FnvHasher; @@ -36,13 +37,14 @@ use url::Url; use std::collections::HashMap; -#[derive(JSTraceable, Copy, Clone, PartialEq)] +#[derive(JSTraceable, Copy, Clone, PartialEq, HeapSizeOf)] pub enum ListenerPhase { Capturing, Bubbling, } #[derive(JSTraceable, Copy, Clone)] +#[derive(HeapSizeOf)] pub enum EventTargetTypeId { Node(NodeTypeId), WebSocket, @@ -95,6 +97,13 @@ pub enum EventListenerType { Inline(Rc<EventListener>), } +impl HeapSizeOf for EventListenerType { + fn heap_size_of_children(&self) -> usize { + // FIXME: Rc<T> isn't HeapSizeOf and we can't ignore it due to #6870 and #6871 + 0 + } +} + impl EventListenerType { fn get_listener(&self) -> Rc<EventListener> { match *self { @@ -104,7 +113,7 @@ impl EventListenerType { } } -#[derive(JSTraceable, Clone, PartialEq)] +#[derive(JSTraceable, Clone, PartialEq, HeapSizeOf)] #[privatize] pub struct EventListenerEntry { phase: ListenerPhase, @@ -112,6 +121,7 @@ pub struct EventListenerEntry { } #[dom_struct] +#[derive(HeapSizeOf)] pub struct EventTarget { reflector_: Reflector, type_id: EventTargetTypeId, diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs index 513a9d39775..2a196073513 100644 --- a/components/script/dom/htmlelement.rs +++ b/components/script/dom/htmlelement.rs @@ -12,7 +12,7 @@ use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementM use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLFrameSetElementDerived}; use dom::bindings::codegen::InheritTypes::{EventTargetCast, HTMLInputElementCast, NodeCast}; -use dom::bindings::codegen::InheritTypes::{HTMLElementDerived, HTMLBodyElementDerived}; +use dom::bindings::codegen::InheritTypes::{HTMLElementDerived, HTMLBodyElementDerived, HTMLHtmlElementDerived}; use dom::bindings::js::{JS, MutNullableHeap, Root}; use dom::bindings::error::ErrorResult; use dom::bindings::error::Error::Syntax; @@ -216,6 +216,63 @@ impl<'a> HTMLElementMethods for &'a HTMLElement { // If `request_focus` is not called, focus will be set to None. document.r().commit_focus_transaction(FocusType::Element); } + + // https://drafts.csswg.org/cssom-view/#extensions-to-the-htmlelement-interface + fn GetOffsetParent(self) -> Option<Root<Element>> { + if self.is_htmlbodyelement() || self.is_htmlhtmlelement() { + return None; + } + + let node = NodeCast::from_ref(self); + let window = window_from_node(self); + let (element, _) = window.offset_parent_query(node.to_trusted_node_address()); + + element + } + + // https://drafts.csswg.org/cssom-view/#extensions-to-the-htmlelement-interface + fn OffsetTop(self) -> i32 { + if self.is_htmlbodyelement() { + return 0; + } + + let node = NodeCast::from_ref(self); + let window = window_from_node(self); + let (_, rect) = window.offset_parent_query(node.to_trusted_node_address()); + + rect.origin.y.to_nearest_px() + } + + // https://drafts.csswg.org/cssom-view/#extensions-to-the-htmlelement-interface + fn OffsetLeft(self) -> i32 { + if self.is_htmlbodyelement() { + return 0; + } + + let node = NodeCast::from_ref(self); + let window = window_from_node(self); + let (_, rect) = window.offset_parent_query(node.to_trusted_node_address()); + + rect.origin.x.to_nearest_px() + } + + // https://drafts.csswg.org/cssom-view/#extensions-to-the-htmlelement-interface + fn OffsetWidth(self) -> i32 { + let node = NodeCast::from_ref(self); + let window = window_from_node(self); + let (_, rect) = window.offset_parent_query(node.to_trusted_node_address()); + + rect.size.width.to_nearest_px() + } + + // https://drafts.csswg.org/cssom-view/#extensions-to-the-htmlelement-interface + fn OffsetHeight(self) -> i32 { + let node = NodeCast::from_ref(self); + let window = window_from_node(self); + let (_, rect) = window.offset_parent_query(node.to_trusted_node_address()); + + rect.size.height.to_nearest_px() + } } // https://html.spec.whatwg.org/#attr-data-* @@ -309,7 +366,7 @@ impl<'a> VirtualMethods for &'a HTMLElement { } } -#[derive(JSTraceable, Copy, Clone, Debug)] +#[derive(JSTraceable, Copy, Clone, Debug, HeapSizeOf)] pub enum HTMLElementTypeId { HTMLElement, diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index b0b3ae9c6e9..847132c6452 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -41,7 +41,7 @@ impl HTMLMediaElement { } } -#[derive(JSTraceable, Copy, Clone, Debug)] +#[derive(JSTraceable, Copy, Clone, Debug, HeapSizeOf)] pub enum HTMLMediaElementTypeId { HTMLAudioElement = 0, HTMLVideoElement = 1, diff --git a/components/script/dom/htmltablecellelement.rs b/components/script/dom/htmltablecellelement.rs index 66359deb22f..873cbb184e8 100644 --- a/components/script/dom/htmltablecellelement.rs +++ b/components/script/dom/htmltablecellelement.rs @@ -22,7 +22,7 @@ use std::cmp::max; const DEFAULT_COLSPAN: u32 = 1; -#[derive(JSTraceable, Copy, Clone, Debug)] +#[derive(JSTraceable, Copy, Clone, Debug, HeapSizeOf)] pub enum HTMLTableCellElementTypeId { HTMLTableDataCellElement = 0, HTMLTableHeaderCellElement = 1, diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 1f6a681e582..94a0a1e05c0 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -78,6 +78,7 @@ use string_cache::{Atom, Namespace, QualName}; /// An HTML node. #[dom_struct] +#[derive(HeapSizeOf)] pub struct Node { /// The JavaScript reflector for this node. eventtarget: EventTarget, @@ -135,7 +136,7 @@ impl NodeDerived for EventTarget { bitflags! { #[doc = "Flags for node items."] - #[derive(JSTraceable)] + #[derive(JSTraceable, HeapSizeOf)] flags NodeFlags: u16 { #[doc = "Specifies whether this node is in a document."] const IS_IN_DOC = 0x01, @@ -206,20 +207,25 @@ enum SuppressObserver { } /// Layout data that is shared between the script and layout tasks. +#[derive(HeapSizeOf)] pub struct SharedLayoutData { /// The results of CSS styling for this node. pub style: Option<Arc<ComputedValues>>, } /// Encapsulates the abstract layout data. +#[allow(raw_pointer_derive)] +#[derive(HeapSizeOf)] pub struct LayoutData { _shared_data: SharedLayoutData, + #[ignore_heap_size_of = "TODO(#6910) Box value that should be counted but the type lives in layout"] _data: NonZero<*const ()>, } #[allow(unsafe_code)] unsafe impl Send for LayoutData {} +#[derive(HeapSizeOf)] pub struct LayoutDataRef { data_cell: RefCell<Option<LayoutData>>, } @@ -274,6 +280,7 @@ impl LayoutDataRef { /// The different types of nodes. #[derive(JSTraceable, Copy, Clone, PartialEq, Debug)] +#[derive(HeapSizeOf)] pub enum NodeTypeId { CharacterData(CharacterDataTypeId), DocumentType, diff --git a/components/script/dom/webidls/CSSStyleDeclaration.webidl b/components/script/dom/webidls/CSSStyleDeclaration.webidl index 16fc0c63a6a..85506b8173c 100644 --- a/components/script/dom/webidls/CSSStyleDeclaration.webidl +++ b/components/script/dom/webidls/CSSStyleDeclaration.webidl @@ -99,6 +99,7 @@ partial interface CSSStyleDeclaration { [TreatNullAs=EmptyString] attribute DOMString backfaceVisibility; [TreatNullAs=EmptyString] attribute DOMString direction; + [TreatNullAs=EmptyString] attribute DOMString unicodeBidi; [TreatNullAs=EmptyString] attribute DOMString filter; diff --git a/components/script/dom/webidls/HTMLElement.webidl b/components/script/dom/webidls/HTMLElement.webidl index f4c0376b618..90b11d85bff 100644 --- a/components/script/dom/webidls/HTMLElement.webidl +++ b/components/script/dom/webidls/HTMLElement.webidl @@ -45,5 +45,16 @@ interface HTMLElement : Element { //readonly attribute boolean? commandDisabled; //readonly attribute boolean? commandChecked; }; + +// http://dev.w3.org/csswg/cssom-view/#extensions-to-the-htmlelement-interface +partial interface HTMLElement { + // CSSOM things are not [Pure] because they can flush + readonly attribute Element? offsetParent; + readonly attribute long offsetTop; + readonly attribute long offsetLeft; + readonly attribute long offsetWidth; + readonly attribute long offsetHeight; +}; + HTMLElement implements GlobalEventHandlers; HTMLElement implements ElementCSSInlineStyle; diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index d7a9e9f243a..ba86c85b3ac 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -8,7 +8,7 @@ use dom::bindings::codegen::Bindings::EventHandlerBinding::{OnErrorEventHandlerN use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods; use dom::bindings::codegen::Bindings::FunctionBinding::Function; use dom::bindings::codegen::Bindings::WindowBinding::{self, WindowMethods, FrameRequestCallback}; -use dom::bindings::codegen::InheritTypes::{NodeCast, EventTargetCast}; +use dom::bindings::codegen::InheritTypes::{NodeCast, ElementCast, EventTargetCast, WindowDerived}; use dom::bindings::global::global_object_for_js_object; use dom::bindings::error::{report_pending_exception, Fallible}; use dom::bindings::error::Error::InvalidCharacter; @@ -27,7 +27,7 @@ use dom::eventtarget::{EventTarget, EventTargetHelpers, EventTargetTypeId}; use dom::htmlelement::HTMLElement; use dom::location::Location; use dom::navigator::Navigator; -use dom::node::{window_from_node, TrustedNodeAddress, NodeHelpers}; +use dom::node::{window_from_node, TrustedNodeAddress, NodeHelpers, from_untrusted_node_address}; use dom::performance::Performance; use dom::screen::Screen; use dom::storage::Storage; @@ -72,6 +72,7 @@ use std::cell::{Cell, Ref, RefMut, RefCell}; use std::collections::HashSet; use std::default::Default; use std::ffi::CString; +use std::io::{stdout, Write}; use std::mem as std_mem; use std::rc::Rc; use std::sync::Arc; @@ -80,7 +81,7 @@ use std::sync::mpsc::{channel, Receiver}; use time; /// Current state of the window object -#[derive(JSTraceable, Copy, Clone, Debug, PartialEq)] +#[derive(JSTraceable, Copy, Clone, Debug, PartialEq, HeapSizeOf)] enum WindowState { Alive, Zombie, // Pipeline is closed, but the window hasn't been GCed yet. @@ -105,15 +106,21 @@ pub enum ReflowReason { } #[dom_struct] +#[derive(HeapSizeOf)] pub struct Window { eventtarget: EventTarget, + #[ignore_heap_size_of = "trait objects are hard"] script_chan: Box<ScriptChan+Send>, + #[ignore_heap_size_of = "channels are hard"] control_chan: ScriptControlChan, console: MutNullableHeap<JS<Console>>, crypto: MutNullableHeap<JS<Crypto>>, navigator: MutNullableHeap<JS<Navigator>>, + #[ignore_heap_size_of = "channels are hard"] image_cache_task: ImageCacheTask, + #[ignore_heap_size_of = "channels are hard"] image_cache_chan: ImageCacheChan, + #[ignore_heap_size_of = "TODO(#6911) newtypes containing unmeasurable types are hard"] compositor: DOMRefCell<ScriptListener>, browsing_context: DOMRefCell<Option<BrowsingContext>>, page: Rc<Page>, @@ -128,13 +135,17 @@ pub struct Window { next_worker_id: Cell<WorkerId>, /// For sending messages to the memory profiler. + #[ignore_heap_size_of = "channels are hard"] mem_profiler_chan: mem::ProfilerChan, /// For providing instructions to an optional devtools server. + #[ignore_heap_size_of = "channels are hard"] devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>, /// For sending timeline markers. Will be ignored if /// no devtools server + #[ignore_heap_size_of = "TODO(#6909) need to measure HashSet"] devtools_markers: RefCell<HashSet<TimelineMarkerType>>, + #[ignore_heap_size_of = "channels are hard"] devtools_marker_sender: RefCell<Option<IpcSender<TimelineMarker>>>, /// A flag to indicate whether the developer tools have requested live updates of @@ -159,27 +170,34 @@ pub struct Window { dom_static: GlobalStaticData, /// The JavaScript runtime. + #[ignore_heap_size_of = "Rc<T> is hard"] js_runtime: DOMRefCell<Option<Rc<Runtime>>>, /// A handle for communicating messages to the layout task. + #[ignore_heap_size_of = "channels are hard"] layout_chan: LayoutChan, /// A handle to perform RPC calls into the layout, quickly. + #[ignore_heap_size_of = "trait objects are hard"] layout_rpc: Box<LayoutRPC+'static>, /// The port that we will use to join layout. If this is `None`, then layout is not running. + #[ignore_heap_size_of = "channels are hard"] layout_join_port: DOMRefCell<Option<Receiver<()>>>, /// The current size of the window, in pixels. window_size: Cell<Option<WindowSizeData>>, /// Associated resource task for use by DOM objects like XMLHttpRequest + #[ignore_heap_size_of = "channels are hard"] resource_task: Arc<ResourceTask>, /// A handle for communicating messages to the storage task. + #[ignore_heap_size_of = "channels are hard"] storage_task: StorageTask, /// A handle for communicating messages to the constellation task. + #[ignore_heap_size_of = "channels are hard"] constellation_chan: ConstellationChan, /// Pending scroll to fragment event, if any @@ -193,6 +211,7 @@ pub struct Window { pending_reflow_count: Cell<u32>, /// A channel for communicating results of async scripts back to the webdriver server + #[ignore_heap_size_of = "channels are hard"] webdriver_script_chan: RefCell<Option<IpcSender<WebDriverJSResult>>>, /// The current state of the window object @@ -342,7 +361,10 @@ impl<'a> WindowMethods for &'a Window { // https://html.spec.whatwg.org/#dom-alert fn Alert(self, s: DOMString) { // Right now, just print to the console - println!("ALERT: {}", s); + let stdout = stdout(); + let mut stdout = stdout.lock(); + writeln!(&mut stdout, "ALERT: {}", s).unwrap(); + stdout.flush().unwrap(); } // https://html.spec.whatwg.org/multipage/#dom-window-close @@ -578,6 +600,7 @@ pub trait WindowHelpers { fn client_rect_query(self, node_geometry_request: TrustedNodeAddress) -> Rect<i32>; fn resolved_style_query(self, element: TrustedNodeAddress, pseudo: Option<PseudoElement>, property: &Atom) -> Option<String>; + fn offset_parent_query(self, node: TrustedNodeAddress) -> (Option<Root<Element>>, Rect<Au>); fn handle_reflow_complete_msg(self, reflow_id: u32); fn set_fragment_name(self, fragment: Option<String>); fn steal_fragment_name(self) -> Option<String>; @@ -827,6 +850,27 @@ impl<'a> WindowHelpers for &'a Window { resolved } + fn offset_parent_query(self, node: TrustedNodeAddress) -> (Option<Root<Element>>, Rect<Au>) { + self.reflow(ReflowGoal::ForScriptQuery, + ReflowQueryType::OffsetParentQuery(node), + ReflowReason::Query); + let response = self.layout_rpc.offset_parent(); + let js_runtime = self.js_runtime.borrow(); + let js_runtime = js_runtime.as_ref().unwrap(); + let element = match response.node_address { + Some(parent_node_address) => { + let node = from_untrusted_node_address(js_runtime.rt(), + parent_node_address); + let element = ElementCast::to_ref(node.r()); + element.map(Root::from_ref) + } + None => { + None + } + }; + (element, response.rect) + } + fn handle_reflow_complete_msg(self, reflow_id: u32) { let last_reflow_id = self.last_reflow_id.get(); if last_reflow_id == reflow_id { @@ -1135,6 +1179,7 @@ fn debug_reflow_events(goal: &ReflowGoal, query_type: &ReflowQueryType, reason: ReflowQueryType::ContentBoxesQuery(_n) => "\tContentBoxesQuery", ReflowQueryType::NodeGeometryQuery(_n) => "\tNodeGeometryQuery", ReflowQueryType::ResolvedStyleQuery(_, _, _) => "\tResolvedStyleQuery", + ReflowQueryType::OffsetParentQuery(_n) => "\tOffsetParentQuery", }); debug_msg.push_str(match *reason { @@ -1155,3 +1200,9 @@ fn debug_reflow_events(goal: &ReflowGoal, query_type: &ReflowQueryType, reason: println!("{}", debug_msg); } + +impl WindowDerived for EventTarget { + fn is_window(&self) -> bool { + self.type_id() == &EventTargetTypeId::Window + } +} diff --git a/components/script/dom/worker.rs b/components/script/dom/worker.rs index daa752052b7..628b1178c32 100644 --- a/components/script/dom/worker.rs +++ b/components/script/dom/worker.rs @@ -20,6 +20,7 @@ use dom::errorevent::ErrorEvent; use dom::event::{Event, EventBubbles, EventCancelable, EventHelpers}; use dom::eventtarget::{EventTarget, EventTargetHelpers, EventTargetTypeId}; use dom::messageevent::MessageEvent; +use dom::workerglobalscope::WorkerGlobalScopeInit; use script_task::{ScriptChan, ScriptMsg, Runnable}; use devtools_traits::{DevtoolsPageInfo, ScriptToDevtoolsControlMsg}; @@ -95,10 +96,17 @@ impl Worker { None => None, }; + let init = WorkerGlobalScopeInit { + resource_task: resource_task, + mem_profiler_chan: global.mem_profiler_chan(), + devtools_chan: global.devtools_chan(), + devtools_sender: optional_sender, + constellation_chan: constellation_chan, + worker_id: worker_id, + }; DedicatedWorkerGlobalScope::run_worker_scope( - worker_url, global.pipeline(), global.mem_profiler_chan(), global.devtools_chan(), - optional_sender, devtools_receiver, worker_ref, resource_task, - constellation_chan, global.script_chan(), sender, receiver, Some(worker_id)); + init, worker_url, global.pipeline(), devtools_receiver, worker_ref, + global.script_chan(), sender, receiver); Ok(worker) } diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs index 0887b6addcf..550834f7d09 100644 --- a/components/script/dom/workerglobalscope.rs +++ b/components/script/dom/workerglobalscope.rs @@ -37,16 +37,25 @@ use std::cell::Cell; use std::rc::Rc; use std::sync::mpsc::Receiver; -#[derive(JSTraceable, Copy, Clone, PartialEq)] +#[derive(JSTraceable, Copy, Clone, PartialEq, HeapSizeOf)] pub enum WorkerGlobalScopeTypeId { DedicatedGlobalScope, } +pub struct WorkerGlobalScopeInit { + pub resource_task: ResourceTask, + pub mem_profiler_chan: mem::ProfilerChan, + pub devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>, + pub devtools_sender: Option<IpcSender<DevtoolScriptControlMsg>>, + pub constellation_chan: ConstellationChan, + pub worker_id: WorkerId, +} + // https://html.spec.whatwg.org/multipage/#the-workerglobalscope-common-interface #[dom_struct] pub struct WorkerGlobalScope { eventtarget: EventTarget, - worker_id: Option<WorkerId>, + worker_id: WorkerId, worker_url: Url, runtime: Rc<Runtime>, next_worker_id: Cell<WorkerId>, @@ -76,34 +85,29 @@ pub struct WorkerGlobalScope { impl WorkerGlobalScope { pub fn new_inherited(type_id: WorkerGlobalScopeTypeId, + init: WorkerGlobalScopeInit, worker_url: Url, runtime: Rc<Runtime>, - resource_task: ResourceTask, - mem_profiler_chan: mem::ProfilerChan, - devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>, - devtools_sender: Option<IpcSender<DevtoolScriptControlMsg>>, - devtools_receiver: Receiver<DevtoolScriptControlMsg>, - constellation_chan: ConstellationChan, - worker_id: Option<WorkerId>) + devtools_receiver: Receiver<DevtoolScriptControlMsg>) -> WorkerGlobalScope { WorkerGlobalScope { eventtarget: EventTarget::new_inherited(EventTargetTypeId::WorkerGlobalScope(type_id)), next_worker_id: Cell::new(WorkerId(0)), - worker_id: worker_id, + worker_id: init.worker_id, worker_url: worker_url, runtime: runtime, - resource_task: resource_task, + resource_task: init.resource_task, location: Default::default(), navigator: Default::default(), console: Default::default(), crypto: Default::default(), timers: TimerManager::new(), - mem_profiler_chan: mem_profiler_chan, - devtools_chan: devtools_chan, - devtools_sender: devtools_sender, + mem_profiler_chan: init.mem_profiler_chan, + devtools_chan: init.devtools_chan, + devtools_sender: init.devtools_sender, devtools_receiver: devtools_receiver, devtools_wants_updates: Cell::new(false), - constellation_chan: constellation_chan, + constellation_chan: init.constellation_chan, } } @@ -144,7 +148,7 @@ impl WorkerGlobalScope { &self.worker_url } - pub fn get_worker_id(&self) -> Option<WorkerId> { + pub fn get_worker_id(&self) -> WorkerId { self.worker_id.clone() } diff --git a/components/script/dom/xmlhttprequesteventtarget.rs b/components/script/dom/xmlhttprequesteventtarget.rs index 8c17d3c8b1a..6b50898ab27 100644 --- a/components/script/dom/xmlhttprequesteventtarget.rs +++ b/components/script/dom/xmlhttprequesteventtarget.rs @@ -8,7 +8,7 @@ use dom::bindings::codegen::InheritTypes::EventTargetCast; use dom::bindings::codegen::InheritTypes::XMLHttpRequestEventTargetDerived; use dom::eventtarget::{EventTarget, EventTargetHelpers, EventTargetTypeId}; -#[derive(JSTraceable, Copy, Clone, PartialEq)] +#[derive(JSTraceable, Copy, Clone, PartialEq, HeapSizeOf)] pub enum XMLHttpRequestEventTargetTypeId { XMLHttpRequest, XMLHttpRequestUpload, diff --git a/components/script/layout_interface.rs b/components/script/layout_interface.rs index 8fcb298880c..a6fb9ad8491 100644 --- a/components/script/layout_interface.rs +++ b/components/script/layout_interface.rs @@ -104,6 +104,7 @@ pub trait LayoutRPC { fn mouse_over(&self, node: TrustedNodeAddress, point: Point2D<f32>) -> Result<MouseOverResponse, ()>; /// Query layout for the resolved value of a given CSS property fn resolved_style(&self) -> ResolvedStyleResponse; + fn offset_parent(&self) -> OffsetParentResponse; } @@ -116,6 +117,21 @@ pub struct HitTestResponse(pub UntrustedNodeAddress); pub struct MouseOverResponse(pub Vec<UntrustedNodeAddress>); pub struct ResolvedStyleResponse(pub Option<String>); +#[derive(Clone)] +pub struct OffsetParentResponse { + pub node_address: Option<UntrustedNodeAddress>, + pub rect: Rect<Au>, +} + +impl OffsetParentResponse { + pub fn empty() -> OffsetParentResponse { + OffsetParentResponse { + node_address: None, + rect: Rect::zero(), + } + } +} + /// Why we're doing reflow. #[derive(PartialEq, Copy, Clone, Debug)] pub enum ReflowGoal { @@ -133,6 +149,7 @@ pub enum ReflowQueryType { ContentBoxesQuery(TrustedNodeAddress), NodeGeometryQuery(TrustedNodeAddress), ResolvedStyleQuery(TrustedNodeAddress, Option<PseudoElement>, Atom), + OffsetParentQuery(TrustedNodeAddress), } /// Information needed for a reflow. diff --git a/components/script/lib.rs b/components/script/lib.rs index 47dadf0d956..8fc23dc78b4 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -84,6 +84,7 @@ pub mod dom; pub mod parse; pub mod layout_interface; +mod mem; mod network_listener; pub mod page; pub mod script_task; diff --git a/components/script/mem.rs b/components/script/mem.rs new file mode 100644 index 00000000000..6dbd45e5b8a --- /dev/null +++ b/components/script/mem.rs @@ -0,0 +1,36 @@ +/* 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/. */ + +//! Routines for handling measuring the memory usage of arbitrary DOM nodes. + +use dom::bindings::codegen::InheritTypes::{DocumentCast, WindowCast, CharacterDataCast, NodeCast}; +use dom::eventtarget::{EventTarget, EventTargetTypeId}; +use dom::node::NodeTypeId; +use libc; +use util::mem::{HeapSizeOf, heap_size_of}; + +// This is equivalent to measuring a Box<T>, except that DOM objects lose their +// associated box in order to stash their pointers in a reserved slot of their +// JS reflector. It is assumed that the caller passes a pointer to the most-derived +// type that this pointer represents, or the actual heap usage of the pointee will +// be under-reported. +fn heap_size_of_self_and_children<T: HeapSizeOf>(obj: &T) -> usize { + heap_size_of(obj as *const T as *const libc::c_void) + obj.heap_size_of_children() +} + +pub fn heap_size_of_eventtarget(target: &EventTarget) -> usize { + //TODO: add more specific matches for concrete element types as derive(HeapSizeOf) is + // added to each one. + match target.type_id() { + &EventTargetTypeId::Window => + heap_size_of_self_and_children(WindowCast::to_ref(target).unwrap()), + &EventTargetTypeId::Node(NodeTypeId::CharacterData(_)) => + heap_size_of_self_and_children(CharacterDataCast::to_ref(target).unwrap()), + &EventTargetTypeId::Node(NodeTypeId::Document) => + heap_size_of_self_and_children(DocumentCast::to_ref(target).unwrap()), + &EventTargetTypeId::Node(_) => + heap_size_of_self_and_children(NodeCast::to_ref(target).unwrap()), + _ => 0, + } +} diff --git a/components/script/page.rs b/components/script/page.rs index 1286a1427f1..f4b3fd6cd18 100644 --- a/components/script/page.rs +++ b/components/script/page.rs @@ -13,7 +13,7 @@ use std::cell::Cell; use std::rc::Rc; /// Encapsulates a handle to a frame in a frame tree. -#[derive(JSTraceable)] +#[derive(JSTraceable, HeapSizeOf)] #[allow(unrooted_must_root)] // FIXME(#6687) this is wrong pub struct Page { /// Pipeline id associated with this page. @@ -127,7 +127,7 @@ impl Page { } /// Information for one frame in the browsing context. -#[derive(JSTraceable)] +#[derive(JSTraceable, HeapSizeOf)] #[must_root] pub struct Frame { /// The document for this frame. diff --git a/components/script/script_task.rs b/components/script/script_task.rs index 279ff364bda..b3ea5b16818 100644 --- a/components/script/script_task.rs +++ b/components/script/script_task.rs @@ -46,6 +46,7 @@ use dom::worker::TrustedWorkerAddress; use parse::html::{ParseContext, parse_html}; use layout_interface::{self, NewLayoutTaskInfo, ScriptLayoutChan, LayoutChan, ReflowGoal}; use layout_interface::{ReflowQueryType}; +use mem::heap_size_of_eventtarget; use network_listener::NetworkListener; use page::{Page, IterablePage, Frame}; use timers::TimerId; @@ -1104,11 +1105,28 @@ impl ScriptTask { fn collect_reports(&self, reports_chan: ReportsChan) { let mut urls = vec![]; + let mut dom_tree_size = 0; + let mut reports = vec![]; for it_page in self.root_page().iter() { - urls.push(it_page.document().url().serialize()); + let current_url = it_page.document().url().serialize(); + urls.push(current_url.clone()); + + for child in NodeCast::from_ref(&*it_page.document()).traverse_preorder() { + let target = EventTargetCast::from_ref(&*child); + dom_tree_size += heap_size_of_eventtarget(target); + } + let window = it_page.window(); + let target = EventTargetCast::from_ref(&*window); + dom_tree_size += heap_size_of_eventtarget(target); + + reports.push(Report { + path: path![format!("url({})", current_url), "dom-tree"], + kind: ReportKind::ExplicitJemallocHeapSize, + size: dom_tree_size, + }) } let path_seg = format!("url({})", urls.join(", ")); - let reports = ScriptTask::get_reports(self.get_cx(), path_seg); + reports.extend(ScriptTask::get_reports(self.get_cx(), path_seg)); reports_chan.send(reports); } diff --git a/components/script/timers.rs b/components/script/timers.rs index 0a0a37e0a7a..ac7142914ad 100644 --- a/components/script/timers.rs +++ b/components/script/timers.rs @@ -13,6 +13,7 @@ use dom::window::ScriptHelpers; use script_task::{ScriptChan, ScriptMsg, TimerSource}; use horribly_inefficient_timers; +use util::mem::HeapSizeOf; use util::task::spawn_named; use util::str::DOMString; @@ -29,14 +30,15 @@ use std::hash::{Hash, Hasher}; use std::rc::Rc; use std::default::Default; -#[derive(JSTraceable, PartialEq, Eq, Copy, Clone)] +#[derive(JSTraceable, PartialEq, Eq, Copy, Clone, HeapSizeOf)] pub struct TimerId(i32); -#[derive(JSTraceable)] +#[derive(JSTraceable, HeapSizeOf)] #[privatize] struct TimerHandle { handle: TimerId, data: TimerData, + #[ignore_heap_size_of = "channels are hard"] control_chan: Option<Sender<TimerControlMsg>>, } @@ -46,6 +48,13 @@ pub enum TimerCallback { FunctionTimerCallback(Rc<Function>) } +impl HeapSizeOf for TimerCallback { + fn heap_size_of_children(&self) -> usize { + // FIXME: Rc<T> isn't HeapSizeOf and we can't ignore it due to #6870 and #6871 + 0 + } +} + impl Hash for TimerId { fn hash<H: Hasher>(&self, state: &mut H) { let TimerId(id) = *self; @@ -65,7 +74,7 @@ impl TimerHandle { } } -#[derive(JSTraceable)] +#[derive(JSTraceable, HeapSizeOf)] #[privatize] pub struct TimerManager { active_timers: DOMRefCell<HashMap<TimerId, TimerHandle>>, @@ -82,7 +91,7 @@ impl Drop for TimerManager { } // Enum allowing more descriptive values for the is_interval field -#[derive(JSTraceable, PartialEq, Copy, Clone)] +#[derive(JSTraceable, PartialEq, Copy, Clone, HeapSizeOf)] pub enum IsInterval { Interval, NonInterval, @@ -100,7 +109,7 @@ pub enum TimerControlMsg { // (ie. function value to invoke and all arguments to pass // to the function when calling it) // TODO: Handle rooting during fire_timer when movable GC is turned on -#[derive(JSTraceable)] +#[derive(JSTraceable, HeapSizeOf)] #[privatize] struct TimerData { is_interval: IsInterval, diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index 14f8284ed3e..597c7170e9b 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -466,6 +466,7 @@ dependencies = [ "harfbuzz 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)", "layers 0.1.0 (git+https://github.com/servo/rust-layers)", + "lazy_static 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "msg 0.0.1", @@ -872,6 +873,7 @@ dependencies = [ "ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)", "layers 0.1.0 (git+https://github.com/servo/rust-layers)", "offscreen_gl_context 0.1.0 (git+https://github.com/ecoal95/rust-offscreen-rendering-context)", + "plugins 0.0.1", "png 0.1.0 (git+https://github.com/servo/rust-png)", "rustc-serialize 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1502,7 +1504,10 @@ dependencies = [ "bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cssparser 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "html5ever 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)", + "js 0.1.0 (git+https://github.com/servo/rust-mozjs)", + "layers 0.1.0 (git+https://github.com/servo/rust-layers)", "lazy_static 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1514,6 +1519,7 @@ dependencies = [ "serde 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "serde_macros 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "string_cache 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/components/style/properties.mako.rs b/components/style/properties.mako.rs index 23618284757..36c2787dc76 100644 --- a/components/style/properties.mako.rs +++ b/components/style/properties.mako.rs @@ -486,7 +486,7 @@ pub mod longhands { use cssparser::ToCss; use std::fmt; - #[derive(PartialEq, Clone, Eq, Copy, Debug)] + #[derive(PartialEq, Clone, Eq, Copy, Debug, HeapSizeOf)] pub enum T { Auto, Number(i32), @@ -604,7 +604,7 @@ pub mod longhands { use values::CSSFloat; use util::geometry::Au; use std::fmt; - #[derive(PartialEq, Copy, Clone)] + #[derive(PartialEq, Copy, Clone, HeapSizeOf)] pub enum T { Normal, Length(Au), @@ -704,7 +704,7 @@ pub mod longhands { use util::geometry::Au; use std::fmt; #[allow(non_camel_case_types)] - #[derive(PartialEq, Copy, Clone)] + #[derive(PartialEq, Copy, Clone, HeapSizeOf)] pub enum T { % for keyword in vertical_align_keywords: ${to_rust_ident(keyword)}, @@ -812,7 +812,7 @@ pub mod longhands { } pub mod computed_value { - #[derive(Clone, Copy, PartialEq)] + #[derive(Clone, Copy, PartialEq, HeapSizeOf)] pub struct T(pub super::super::overflow_x::computed_value::T); } @@ -865,7 +865,7 @@ pub mod longhands { use cssparser::{self, ToCss}; use std::fmt; - #[derive(PartialEq, Eq, Clone)] + #[derive(PartialEq, Eq, Clone, HeapSizeOf)] pub enum ContentItem { /// Literal string content. String(String), @@ -914,7 +914,7 @@ pub mod longhands { } #[allow(non_camel_case_types)] - #[derive(PartialEq, Eq, Clone)] + #[derive(PartialEq, Eq, Clone, HeapSizeOf)] pub enum T { normal, none, @@ -1055,7 +1055,7 @@ pub mod longhands { use cssparser::{ToCss, Token}; use std::fmt; - #[derive(Clone, PartialEq)] + #[derive(Clone, PartialEq, HeapSizeOf)] pub struct T(pub Option<Url>); impl ToCss for T { @@ -1103,7 +1103,7 @@ pub mod longhands { pub use self::computed_value::T as SpecifiedValue; pub mod computed_value { - #[derive(Clone, PartialEq)] + #[derive(Clone, PartialEq, HeapSizeOf)] pub struct T(pub Vec<(String,String)>); } @@ -1172,7 +1172,7 @@ pub mod longhands { pub use self::computed_value::T as SpecifiedValue; pub mod computed_value { - #[derive(Clone, PartialEq)] + #[derive(Clone, PartialEq, HeapSizeOf)] pub struct T(pub Vec<(String,i32)>); } @@ -1247,7 +1247,7 @@ pub mod longhands { pub mod computed_value { use values::computed; - #[derive(Clone, PartialEq)] + #[derive(Clone, PartialEq, HeapSizeOf)] pub struct T(pub Option<computed::Image>); } @@ -1308,7 +1308,7 @@ pub mod longhands { pub mod computed_value { use values::computed::LengthOrPercentage; - #[derive(PartialEq, Copy, Clone, Debug)] + #[derive(PartialEq, Copy, Clone, Debug, HeapSizeOf)] pub struct T { pub horizontal: LengthOrPercentage, pub vertical: LengthOrPercentage, @@ -1431,13 +1431,13 @@ pub mod longhands { pub mod computed_value { use values::computed::LengthOrPercentageOrAuto; - #[derive(PartialEq, Clone, Debug)] + #[derive(PartialEq, Clone, Debug, HeapSizeOf)] pub struct ExplicitSize { pub width: LengthOrPercentageOrAuto, pub height: LengthOrPercentageOrAuto, } - #[derive(PartialEq, Clone, Debug)] + #[derive(PartialEq, Clone, Debug, HeapSizeOf)] pub enum T { Explicit(ExplicitSize), Cover, @@ -1613,7 +1613,7 @@ pub mod longhands { use string_cache::Atom; use std::fmt; - #[derive(PartialEq, Eq, Clone, Hash)] + #[derive(PartialEq, Eq, Clone, Hash, HeapSizeOf)] pub enum FontFamily { FamilyName(Atom), // Generic @@ -1649,7 +1649,7 @@ pub mod longhands { Ok(()) } } - #[derive(Clone, PartialEq, Eq, Hash)] + #[derive(Clone, PartialEq, Eq, Hash, HeapSizeOf)] pub struct T(pub Vec<FontFamily>); } @@ -1741,7 +1741,7 @@ pub mod longhands { } pub mod computed_value { use std::fmt; - #[derive(PartialEq, Eq, Copy, Clone, Hash, Deserialize, Serialize)] + #[derive(PartialEq, Eq, Copy, Clone, Hash, Deserialize, Serialize, HeapSizeOf)] pub enum T { % for weight in range(100, 901, 100): Weight${weight} = ${weight}, @@ -1958,7 +1958,7 @@ pub mod longhands { pub mod computed_value { use util::geometry::Au; - #[derive(Clone, PartialEq)] + #[derive(Clone, PartialEq, HeapSizeOf)] pub struct T(pub Option<Au>); } @@ -2020,7 +2020,7 @@ pub mod longhands { pub mod computed_value { use util::geometry::Au; - #[derive(Clone, PartialEq)] + #[derive(Clone, PartialEq, HeapSizeOf)] pub struct T(pub Option<Au>); } @@ -2076,6 +2076,8 @@ pub mod longhands { ${new_style_struct("Text", is_inherited=False)} + ${single_keyword("unicode-bidi", "normal embed isolate bidi-override isolate-override plaintext")} + <%self:longhand name="text-decoration" custom_cascade="True"> use cssparser::ToCss; use std::fmt; @@ -2083,7 +2085,7 @@ pub mod longhands { impl ComputedValueAsSpecified for SpecifiedValue {} - #[derive(PartialEq, Eq, Copy, Clone, Debug)] + #[derive(PartialEq, Eq, Copy, Clone, Debug, HeapSizeOf)] pub struct SpecifiedValue { pub underline: bool, pub overline: bool, @@ -2176,7 +2178,7 @@ pub mod longhands { impl ComputedValueAsSpecified for SpecifiedValue {} - #[derive(Clone, PartialEq, Copy, Debug)] + #[derive(Clone, PartialEq, Copy, Debug, HeapSizeOf)] pub struct SpecifiedValue { pub underline: Option<RGBA>, pub overline: Option<RGBA>, @@ -2284,7 +2286,7 @@ pub mod longhands { pub mod computed_value { use util::geometry::Au; - #[derive(Clone, Copy, Debug, PartialEq, RustcEncodable)] + #[derive(Clone, Copy, Debug, PartialEq, RustcEncodable, HeapSizeOf)] pub struct T { pub horizontal: Au, pub vertical: Au, @@ -2396,7 +2398,7 @@ pub mod longhands { use std::fmt; use util::cursor::Cursor; - #[derive(Clone, PartialEq, Eq, Copy, Debug)] + #[derive(Clone, PartialEq, Eq, Copy, Debug, HeapSizeOf)] pub enum T { AutoCursor, SpecifiedCursor(Cursor), @@ -2458,7 +2460,7 @@ pub mod longhands { pub mod computed_value { use util::geometry::Au; - #[derive(Clone, PartialEq)] + #[derive(Clone, PartialEq, HeapSizeOf)] pub struct T(pub Option<Au>); } @@ -2519,7 +2521,7 @@ pub mod longhands { } pub mod computed_value { - #[derive(Clone, PartialEq)] + #[derive(Clone, PartialEq, HeapSizeOf)] pub struct T(pub Option<u32>); } @@ -2586,7 +2588,7 @@ pub mod longhands { pub mod computed_value { use util::geometry::Au; - #[derive(Clone, PartialEq)] + #[derive(Clone, PartialEq, HeapSizeOf)] pub struct T(pub Option<Au>); } @@ -2732,10 +2734,10 @@ pub mod longhands { use values::computed; use std::fmt; - #[derive(Clone, PartialEq)] + #[derive(Clone, PartialEq, HeapSizeOf)] pub struct T(pub Vec<BoxShadow>); - #[derive(Clone, PartialEq, Copy)] + #[derive(Clone, PartialEq, Copy, HeapSizeOf)] pub struct BoxShadow { pub offset_x: Au, pub offset_y: Au, @@ -2901,7 +2903,7 @@ pub mod longhands { pub mod computed_value { use util::geometry::Au; - #[derive(Clone, PartialEq, Eq, Copy, Debug)] + #[derive(Clone, PartialEq, Eq, Copy, Debug, HeapSizeOf)] pub struct ClipRect { pub top: Au, pub right: Option<Au>, @@ -2909,7 +2911,7 @@ pub mod longhands { pub left: Au, } - #[derive(Clone, PartialEq)] + #[derive(Clone, PartialEq, HeapSizeOf)] pub struct T(pub Option<ClipRect>); } @@ -3079,10 +3081,10 @@ pub mod longhands { use cssparser::Color; use util::geometry::Au; - #[derive(Clone, PartialEq, Debug)] + #[derive(Clone, PartialEq, Debug, HeapSizeOf)] pub struct T(pub Vec<TextShadow>); - #[derive(Clone, PartialEq, Debug)] + #[derive(Clone, PartialEq, Debug, HeapSizeOf)] pub struct TextShadow { pub offset_x: Au, pub offset_y: Au, @@ -3482,7 +3484,7 @@ pub mod longhands { use values::CSSFloat; use values::computed; - #[derive(Clone, Copy, Debug, PartialEq)] + #[derive(Clone, Copy, Debug, PartialEq, HeapSizeOf)] pub struct ComputedMatrix { pub m11: CSSFloat, pub m12: CSSFloat, pub m13: CSSFloat, pub m14: CSSFloat, pub m21: CSSFloat, pub m22: CSSFloat, pub m23: CSSFloat, pub m24: CSSFloat, @@ -3501,7 +3503,7 @@ pub mod longhands { } } - #[derive(Clone, Debug, PartialEq)] + #[derive(Clone, Debug, PartialEq, HeapSizeOf)] pub enum ComputedOperation { Matrix(ComputedMatrix), Skew(CSSFloat, CSSFloat), @@ -3513,7 +3515,7 @@ pub mod longhands { Perspective(computed::Length), } - #[derive(Clone, Debug, PartialEq)] + #[derive(Clone, Debug, PartialEq, HeapSizeOf)] pub struct T(pub Option<Vec<ComputedOperation>>); } @@ -3932,7 +3934,7 @@ pub mod longhands { pub mod computed_value { use values::computed::{Length, LengthOrPercentage}; - #[derive(Clone, Copy, Debug, PartialEq)] + #[derive(Clone, Copy, Debug, PartialEq, HeapSizeOf)] pub struct T { pub horizontal: LengthOrPercentage, pub vertical: LengthOrPercentage, @@ -4080,7 +4082,7 @@ pub mod longhands { pub mod computed_value { use values::computed::LengthOrPercentage; - #[derive(Clone, Copy, Debug, PartialEq)] + #[derive(Clone, Copy, Debug, PartialEq, HeapSizeOf)] pub struct T { pub horizontal: LengthOrPercentage, pub vertical: LengthOrPercentage, @@ -4273,7 +4275,7 @@ pub mod longhands { pub use values::computed::Time as SingleComputedValue; - #[derive(Clone, PartialEq)] + #[derive(Clone, PartialEq, HeapSizeOf)] pub struct T(pub Vec<SingleComputedValue>); impl ToComputedValue for T { @@ -4380,7 +4382,7 @@ pub mod longhands { pub use self::TransitionTimingFunction as SingleComputedValue; - #[derive(Copy, Clone, Debug, PartialEq)] + #[derive(Copy, Clone, Debug, PartialEq, HeapSizeOf)] pub enum TransitionTimingFunction { CubicBezier(Point2D<f32>, Point2D<f32>), Steps(u32, StartEnd), @@ -4411,7 +4413,7 @@ pub mod longhands { } } - #[derive(Copy, Clone, Debug, PartialEq)] + #[derive(Copy, Clone, Debug, PartialEq, HeapSizeOf)] pub enum StartEnd { Start, End, @@ -4426,7 +4428,7 @@ pub mod longhands { } } - #[derive(Clone, Debug, PartialEq)] + #[derive(Clone, Debug, PartialEq, HeapSizeOf)] pub struct T(pub Vec<TransitionTimingFunction>); impl ToCss for T { @@ -4533,7 +4535,7 @@ pub mod longhands { pub use self::TransitionProperty as SingleComputedValue; - #[derive(Copy, Clone, Debug, PartialEq)] + #[derive(Copy, Clone, Debug, PartialEq, HeapSizeOf)] pub enum TransitionProperty { All, BackgroundColor, @@ -4684,7 +4686,7 @@ pub mod longhands { } } - #[derive(Clone, Debug, PartialEq)] + #[derive(Clone, Debug, PartialEq, HeapSizeOf)] pub struct T(pub Vec<SingleComputedValue>); impl ToCss for T { @@ -5779,7 +5781,7 @@ pub mod style_structs { use super::longhands; % for style_struct in STYLE_STRUCTS: - #[derive(PartialEq, Clone)] + #[derive(PartialEq, Clone, HeapSizeOf)] pub struct ${style_struct.name} { % for longhand in style_struct.longhands: pub ${longhand.ident}: longhands::${longhand.ident}::computed_value::T, @@ -5791,7 +5793,7 @@ pub mod style_structs { % endfor } -#[derive(Clone)] +#[derive(Clone, HeapSizeOf)] pub struct ComputedValues { % for style_struct in STYLE_STRUCTS: ${style_struct.ident}: Arc<style_structs::${style_struct.name}>, diff --git a/components/style/values.rs b/components/style/values.rs index 03167b3fd36..da542f812fe 100644 --- a/components/style/values.rs +++ b/components/style/values.rs @@ -103,7 +103,7 @@ pub mod specified { } } - #[derive(Clone, PartialEq, Debug)] + #[derive(Clone, PartialEq, Debug, HeapSizeOf)] pub struct CSSColor { pub parsed: cssparser::Color, pub authored: Option<String>, @@ -147,7 +147,7 @@ pub mod specified { } } - #[derive(Clone, PartialEq, Copy, Debug)] + #[derive(Clone, PartialEq, Copy, Debug, HeapSizeOf)] pub enum FontRelativeLength { Em(CSSFloat), Ex(CSSFloat), @@ -181,7 +181,7 @@ pub mod specified { } } - #[derive(Clone, PartialEq, Copy, Debug)] + #[derive(Clone, PartialEq, Copy, Debug, HeapSizeOf)] pub enum ViewportPercentageLength { Vw(CSSFloat), Vh(CSSFloat), @@ -222,7 +222,7 @@ pub mod specified { } } - #[derive(Clone, PartialEq, Copy, Debug)] + #[derive(Clone, PartialEq, Copy, Debug, HeapSizeOf)] pub struct CharacterWidth(pub i32); impl CharacterWidth { @@ -237,7 +237,7 @@ pub mod specified { } } - #[derive(Clone, PartialEq, Copy, Debug)] + #[derive(Clone, PartialEq, Copy, Debug, HeapSizeOf)] pub enum Length { Absolute(Au), // application units FontRelative(FontRelativeLength), @@ -354,7 +354,7 @@ pub mod specified { } - #[derive(Clone, PartialEq, Copy, Debug)] + #[derive(Clone, PartialEq, Copy, Debug, HeapSizeOf)] pub enum LengthOrPercentage { Length(Length), Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0] @@ -398,7 +398,7 @@ pub mod specified { } } - #[derive(Clone, PartialEq, Copy, Debug)] + #[derive(Clone, PartialEq, Copy, Debug, HeapSizeOf)] pub enum LengthOrPercentageOrAuto { Length(Length), Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0] @@ -442,7 +442,7 @@ pub mod specified { } } - #[derive(Clone, PartialEq, Copy, Debug)] + #[derive(Clone, PartialEq, Copy, Debug, HeapSizeOf)] pub enum LengthOrPercentageOrNone { Length(Length), Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0] @@ -486,7 +486,7 @@ pub mod specified { } } - #[derive(Clone, PartialEq, Copy, Debug)] + #[derive(Clone, PartialEq, Copy, Debug, HeapSizeOf)] pub enum LengthOrNone { Length(Length), None, @@ -617,7 +617,7 @@ pub mod specified { } /// Specified values for an image according to CSS-IMAGES. - #[derive(Clone, PartialEq, Debug)] + #[derive(Clone, PartialEq, Debug, HeapSizeOf)] pub enum Image { Url(Url), LinearGradient(LinearGradient), @@ -658,7 +658,7 @@ pub mod specified { } /// Specified values for a CSS linear gradient. - #[derive(Clone, PartialEq, Debug)] + #[derive(Clone, PartialEq, Debug, HeapSizeOf)] pub struct LinearGradient { /// The angle or corner of the gradient. pub angle_or_corner: AngleOrCorner, @@ -681,7 +681,7 @@ pub mod specified { } /// Specified values for an angle or a corner in a linear gradient. - #[derive(Clone, PartialEq, Copy, Debug)] + #[derive(Clone, PartialEq, Copy, Debug, HeapSizeOf)] pub enum AngleOrCorner { Angle(Angle), Corner(HorizontalDirection, VerticalDirection), @@ -703,7 +703,7 @@ pub mod specified { } /// Specified values for one color stop in a linear gradient. - #[derive(Clone, PartialEq, Debug)] + #[derive(Clone, PartialEq, Debug, HeapSizeOf)] pub struct ColorStop { /// The color of this stop. pub color: CSSColor, @@ -810,7 +810,7 @@ pub mod specified { } /// A time in seconds according to CSS-VALUES § 6.2. - #[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] + #[derive(Clone, Copy, Debug, PartialEq, PartialOrd, HeapSizeOf)] pub struct Time(pub CSSFloat); impl Time { @@ -938,7 +938,7 @@ pub mod computed { } } - #[derive(PartialEq, Clone, Copy)] + #[derive(PartialEq, Clone, Copy, HeapSizeOf)] pub enum LengthOrPercentage { Length(Au), Percentage(CSSFloat), @@ -984,7 +984,7 @@ pub mod computed { } } - #[derive(PartialEq, Clone, Copy)] + #[derive(PartialEq, Clone, Copy, HeapSizeOf)] pub enum LengthOrPercentageOrAuto { Length(Au), Percentage(CSSFloat), @@ -1030,7 +1030,7 @@ pub mod computed { } } - #[derive(PartialEq, Clone, Copy)] + #[derive(PartialEq, Clone, Copy, HeapSizeOf)] pub enum LengthOrPercentageOrNone { Length(Au), Percentage(CSSFloat), @@ -1076,7 +1076,7 @@ pub mod computed { } } - #[derive(PartialEq, Clone, Copy)] + #[derive(PartialEq, Clone, Copy, HeapSizeOf)] pub enum LengthOrNone { Length(Au), None, @@ -1131,7 +1131,7 @@ pub mod computed { /// Computed values for an image according to CSS-IMAGES. - #[derive(Clone, PartialEq)] + #[derive(Clone, PartialEq, HeapSizeOf)] pub enum Image { Url(Url), LinearGradient(LinearGradient), @@ -1147,7 +1147,7 @@ pub mod computed { } /// Computed values for a CSS linear gradient. - #[derive(Clone, PartialEq)] + #[derive(Clone, PartialEq, HeapSizeOf)] pub struct LinearGradient { /// The angle or corner of the gradient. pub angle_or_corner: AngleOrCorner, @@ -1180,7 +1180,7 @@ pub mod computed { } /// Computed values for one color stop in a linear gradient. - #[derive(Clone, PartialEq, Copy)] + #[derive(Clone, PartialEq, Copy, HeapSizeOf)] pub struct ColorStop { /// The color of this stop. pub color: CSSColor, diff --git a/components/util/Cargo.toml b/components/util/Cargo.toml index 4d9027653f9..5b8e9f726f8 100644 --- a/components/util/Cargo.toml +++ b/components/util/Cargo.toml @@ -21,6 +21,12 @@ path = "../plugins" [dependencies.azure] git = "https://github.com/servo/rust-azure" +[dependencies.js] +git = "https://github.com/servo/rust-mozjs" + +[dependencies.layers] +git = "https://github.com/servo/rust-layers" + [dependencies.cssparser] version = "0.3" features = [ "serde-serialization" ] @@ -35,6 +41,7 @@ features = [ "serde_serialization" ] [dependencies] log = "0.3" bitflags = "0.3" +html5ever = { version = "0.2.1", features = ["unstable"] } libc = "0.1" rand = "0.3" rustc-serialize = "0.3" @@ -44,4 +51,5 @@ num = "0.1.24" euclid = "0.1" serde = "0.4" serde_macros = "0.4" +string_cache = "0.1" lazy_static = "0.1" diff --git a/components/util/lib.rs b/components/util/lib.rs index 8db4b17f5ec..df3f90f5dfb 100644 --- a/components/util/lib.rs +++ b/components/util/lib.rs @@ -31,7 +31,10 @@ extern crate alloc; #[macro_use] extern crate cssparser; extern crate euclid; extern crate getopts; +extern crate html5ever; extern crate ipc_channel; +extern crate js; +extern crate layers; extern crate libc; extern crate num as num_lib; extern crate num_cpus; @@ -39,6 +42,7 @@ extern crate rand; extern crate rustc_serialize; extern crate serde; extern crate smallvec; +extern crate string_cache; extern crate url; use std::sync::Arc; diff --git a/components/util/mem.rs b/components/util/mem.rs index 87c61652a60..370840b7a16 100644 --- a/components/util/mem.rs +++ b/components/util/mem.rs @@ -5,17 +5,31 @@ //! Data structure measurement. use libc::{c_void, size_t}; -use std::cell::RefCell; -use std::collections::LinkedList; -use std::mem::transmute; +use std::cell::{Cell, RefCell}; +use std::collections::{HashMap, LinkedList, hash_state}; +use std::hash::Hash; +use std::mem::{size_of, transmute}; use std::sync::Arc; +use std::rc::Rc; use azure::azure_hl::Color; +use cssparser::Color as CSSParserColor; +use cssparser::RGBA; use cursor::Cursor; use euclid::{Point2D, Rect, SideOffsets2D, Size2D, Matrix2D, Matrix4}; -use geometry::Au; +use euclid::length::Length; +use euclid::scale_factor::ScaleFactor; +use geometry::{PagePx, ViewportPx, Au}; +use html5ever::tree_builder::QuirksMode; +use layers::geometry::DevicePixel; +use js::jsapi::Heap; +use js::rust::GCMethods; +use js::jsval::JSVal; +use logical_geometry::WritingMode; use range::Range; +use string_cache::atom::Atom; +use url; extern { // Get the size of a heap block. @@ -87,6 +101,53 @@ impl<T: HeapSizeOf> HeapSizeOf for Option<T> { } } +impl HeapSizeOf for url::Url { + fn heap_size_of_children(&self) -> usize { + let &url::Url { ref scheme, ref scheme_data, ref query, ref fragment } = self; + scheme.heap_size_of_children() + + scheme_data.heap_size_of_children() + + query.heap_size_of_children() + + fragment.heap_size_of_children() + } +} + +impl HeapSizeOf for url::SchemeData { + fn heap_size_of_children(&self) -> usize { + match self { + &url::SchemeData::Relative(ref data) => data.heap_size_of_children(), + &url::SchemeData::NonRelative(ref str) => str.heap_size_of_children() + } + } +} + +impl HeapSizeOf for url::RelativeSchemeData { + fn heap_size_of_children(&self) -> usize { + let &url::RelativeSchemeData { ref username, ref password, ref host, + ref port, ref default_port, ref path } = self; + username.heap_size_of_children() + + password.heap_size_of_children() + + host.heap_size_of_children() + + port.heap_size_of_children() + + default_port.heap_size_of_children() + + path.heap_size_of_children() + } +} + +impl HeapSizeOf for url::Host { + fn heap_size_of_children(&self) -> usize { + match self { + &url::Host::Domain(ref str) => str.heap_size_of_children(), + &url::Host::Ipv6(_) => 0 + } + } +} + +impl<T: HeapSizeOf, U: HeapSizeOf> HeapSizeOf for (T, U) { + fn heap_size_of_children(&self) -> usize { + self.0.heap_size_of_children() + self.1.heap_size_of_children() + } +} + impl<T: HeapSizeOf> HeapSizeOf for Arc<T> { fn heap_size_of_children(&self) -> usize { (**self).heap_size_of_children() @@ -99,6 +160,12 @@ impl<T: HeapSizeOf> HeapSizeOf for RefCell<T> { } } +impl<T: HeapSizeOf + Copy> HeapSizeOf for Cell<T> { + fn heap_size_of_children(&self) -> usize { + self.get().heap_size_of_children() + } +} + impl<T: HeapSizeOf> HeapSizeOf for Vec<T> { fn heap_size_of_children(&self) -> usize { heap_size_of(self.as_ptr() as *const c_void) + @@ -106,6 +173,25 @@ impl<T: HeapSizeOf> HeapSizeOf for Vec<T> { } } +impl<T> HeapSizeOf for Vec<Rc<T>> { + fn heap_size_of_children(&self) -> usize { + // The fate of measuring Rc<T> is still undecided, but we still want to measure + // the space used for storing them. + heap_size_of(self.as_ptr() as *const c_void) + } +} + +impl<K: HeapSizeOf, V: HeapSizeOf, S> HeapSizeOf for HashMap<K, V, S> + where K: Eq + Hash, S: hash_state::HashState { + fn heap_size_of_children(&self) -> usize { + //TODO(#6908) measure actual bucket memory usage instead of approximating + let size = self.capacity() * (size_of::<V>() + size_of::<K>()); + self.iter().fold(size, |n, (key, value)| { + n + key.heap_size_of_children() + value.heap_size_of_children() + }) + } +} + // FIXME(njn): We can't implement HeapSizeOf accurately for LinkedList because it requires access // to the private Node type. Eventually we'll want to add HeapSizeOf (or equivalent) to Rust // itself. In the meantime, we use the dirty hack of transmuting LinkedList into an identical type @@ -200,7 +286,15 @@ known_heap_size!(0, u8, u16, u32, u64, usize); known_heap_size!(0, i8, i16, i32, i64, isize); known_heap_size!(0, bool, f32, f64); -known_heap_size!(0, Rect<T>, Point2D<T>, Size2D<T>, Matrix2D<T>, SideOffsets2D<T>); +known_heap_size!(0, Rect<T>, Point2D<T>, Size2D<T>, Matrix2D<T>, SideOffsets2D<T>, Range<T>); +known_heap_size!(0, Length<T, U>, ScaleFactor<T, U, V>); -known_heap_size!(0, Au, Color, Cursor, Matrix4); -known_heap_size!(0, Range<T>); +known_heap_size!(0, Au, WritingMode, CSSParserColor, Color, RGBA, Cursor, Matrix4, Atom); +known_heap_size!(0, JSVal, PagePx, ViewportPx, DevicePixel, QuirksMode); + +// This is measured properly by the heap measurement implemented in SpiderMonkey. +impl<T: Copy + GCMethods<T>> HeapSizeOf for Heap<T> { + fn heap_size_of_children(&self) -> usize { + 0 + } +} diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock index 72efd080eda..67ac282bfec 100644 --- a/ports/cef/Cargo.lock +++ b/ports/cef/Cargo.lock @@ -869,6 +869,7 @@ dependencies = [ "ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)", "layers 0.1.0 (git+https://github.com/servo/rust-layers)", "offscreen_gl_context 0.1.0 (git+https://github.com/ecoal95/rust-offscreen-rendering-context)", + "plugins 0.0.1", "png 0.1.0 (git+https://github.com/servo/rust-png)", "rustc-serialize 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1490,6 +1491,8 @@ dependencies = [ "cssparser 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)", + "js 0.1.0 (git+https://github.com/servo/rust-mozjs)", + "layers 0.1.0 (git+https://github.com/servo/rust-layers)", "lazy_static 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1501,6 +1504,7 @@ dependencies = [ "serde 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "serde_macros 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "string_cache 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/ports/gonk/Cargo.lock b/ports/gonk/Cargo.lock index 0e3c601ee9d..1b45696a94e 100644 --- a/ports/gonk/Cargo.lock +++ b/ports/gonk/Cargo.lock @@ -789,6 +789,7 @@ dependencies = [ "ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)", "layers 0.1.0 (git+https://github.com/servo/rust-layers)", "offscreen_gl_context 0.1.0 (git+https://github.com/ecoal95/rust-offscreen-rendering-context)", + "plugins 0.0.1", "png 0.1.0 (git+https://github.com/servo/rust-png)", "rustc-serialize 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1373,6 +1374,8 @@ dependencies = [ "cssparser 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)", + "js 0.1.0 (git+https://github.com/servo/rust-mozjs)", + "layers 0.1.0 (git+https://github.com/servo/rust-layers)", "lazy_static 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1384,6 +1387,7 @@ dependencies = [ "serde 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "serde_macros 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "string_cache 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/tests/wpt/metadata-css/css21_dev/html4/bidi-006b.htm.ini b/tests/wpt/metadata-css/css21_dev/html4/bidi-006b.htm.ini deleted file mode 100644 index 21eacdb847c..00000000000 --- a/tests/wpt/metadata-css/css21_dev/html4/bidi-006b.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[bidi-006b.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css21_dev/html4/bidi-007b.htm.ini b/tests/wpt/metadata-css/css21_dev/html4/bidi-007b.htm.ini deleted file mode 100644 index 9fb4efa2c70..00000000000 --- a/tests/wpt/metadata-css/css21_dev/html4/bidi-007b.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[bidi-007b.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css21_dev/html4/bidi-008b.htm.ini b/tests/wpt/metadata-css/css21_dev/html4/bidi-008b.htm.ini deleted file mode 100644 index 9078eee2a96..00000000000 --- a/tests/wpt/metadata-css/css21_dev/html4/bidi-008b.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[bidi-008b.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css21_dev/html4/bidi-010b.htm.ini b/tests/wpt/metadata-css/css21_dev/html4/bidi-010b.htm.ini deleted file mode 100644 index 55d48142534..00000000000 --- a/tests/wpt/metadata-css/css21_dev/html4/bidi-010b.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[bidi-010b.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css21_dev/html4/bidi-box-model-006.htm.ini b/tests/wpt/metadata-css/css21_dev/html4/bidi-box-model-006.htm.ini deleted file mode 100644 index 9ab9b4e6e3e..00000000000 --- a/tests/wpt/metadata-css/css21_dev/html4/bidi-box-model-006.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[bidi-box-model-006.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css21_dev/html4/bidi-inline-001.htm.ini b/tests/wpt/metadata-css/css21_dev/html4/bidi-inline-001.htm.ini deleted file mode 100644 index 185562ec797..00000000000 --- a/tests/wpt/metadata-css/css21_dev/html4/bidi-inline-001.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[bidi-inline-001.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css21_dev/html4/bidi-001.htm.ini b/tests/wpt/metadata-css/css21_dev/html4/first-letter-dynamic-003a.htm.ini index 51fcc37e0c7..f6c4c8d90d6 100644 --- a/tests/wpt/metadata-css/css21_dev/html4/bidi-001.htm.ini +++ b/tests/wpt/metadata-css/css21_dev/html4/first-letter-dynamic-003a.htm.ini @@ -1,3 +1,3 @@ -[bidi-001.htm] +[first-letter-dynamic-003a.htm] type: reftest expected: FAIL diff --git a/tests/wpt/metadata-css/css21_dev/html4/bidi-005b.htm.ini b/tests/wpt/metadata-css/css21_dev/html4/first-letter-dynamic-003b.htm.ini index 121ce6fc5f6..95499887574 100644 --- a/tests/wpt/metadata-css/css21_dev/html4/bidi-005b.htm.ini +++ b/tests/wpt/metadata-css/css21_dev/html4/first-letter-dynamic-003b.htm.ini @@ -1,3 +1,3 @@ -[bidi-005b.htm] +[first-letter-dynamic-003b.htm] type: reftest expected: FAIL diff --git a/tests/wpt/metadata-css/css21_dev/html4/inline-formatting-context-007.htm.ini b/tests/wpt/metadata-css/css21_dev/html4/inline-formatting-context-007.htm.ini index 8bc13abc629..b9f024e1851 100644 --- a/tests/wpt/metadata-css/css21_dev/html4/inline-formatting-context-007.htm.ini +++ b/tests/wpt/metadata-css/css21_dev/html4/inline-formatting-context-007.htm.ini @@ -1,3 +1,4 @@ [inline-formatting-context-007.htm] type: reftest - expected: FAIL + expected: + if os == "mac": FAIL diff --git a/tests/wpt/metadata-css/css21_dev/html4/run-in-basic-017.htm.ini b/tests/wpt/metadata-css/css21_dev/html4/run-in-basic-017.htm.ini new file mode 100644 index 00000000000..c7e1e1f65d2 --- /dev/null +++ b/tests/wpt/metadata-css/css21_dev/html4/run-in-basic-017.htm.ini @@ -0,0 +1,3 @@ +[run-in-basic-017.htm] + type: reftest + expected: FAIL
\ No newline at end of file diff --git a/tests/wpt/metadata-css/css21_dev/html4/unicode-bidi-002.htm.ini b/tests/wpt/metadata-css/css21_dev/html4/unicode-bidi-002.htm.ini deleted file mode 100644 index 3f0ec3ccfef..00000000000 --- a/tests/wpt/metadata-css/css21_dev/html4/unicode-bidi-002.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[unicode-bidi-002.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata/html/semantics/forms/the-input-element/input-type-button.html.ini b/tests/wpt/metadata/html/semantics/forms/the-input-element/input-type-button.html.ini deleted file mode 100644 index e0fd34f9938..00000000000 --- a/tests/wpt/metadata/html/semantics/forms/the-input-element/input-type-button.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[input-type-button.html] - type: testharness - [label value] - expected: FAIL - diff --git a/tests/wpt/metadata/html/semantics/text-level-semantics/the-bdi-element/bdi-neutral-nested.html.ini b/tests/wpt/metadata/html/semantics/text-level-semantics/the-bdi-element/bdi-neutral-nested.html.ini index 00381dabe51..0d304a3f007 100644 --- a/tests/wpt/metadata/html/semantics/text-level-semantics/the-bdi-element/bdi-neutral-nested.html.ini +++ b/tests/wpt/metadata/html/semantics/text-level-semantics/the-bdi-element/bdi-neutral-nested.html.ini @@ -2,4 +2,5 @@ type: reftest reftype: == refurl: /html/semantics/text-level-semantics/the-bdi-element/bdi-neutral-nested-ref.html - expected: FAIL + expected: + if os != "mac": FAIL diff --git a/tests/wpt/metadata/html/semantics/text-level-semantics/the-bdo-element/bdo-override.html.ini b/tests/wpt/metadata/html/semantics/text-level-semantics/the-bdo-element/bdo-override.html.ini deleted file mode 100644 index 1093b89f0c6..00000000000 --- a/tests/wpt/metadata/html/semantics/text-level-semantics/the-bdo-element/bdo-override.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[bdo-override.html] - type: reftest - expected: FAIL diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json index 18329c0c5f3..8dda0aba215 100644 --- a/tests/wpt/mozilla/meta/MANIFEST.json +++ b/tests/wpt/mozilla/meta/MANIFEST.json @@ -473,6 +473,12 @@ "url": "/_mozilla/mozilla/element_matches_empty.html" } ], + "mozilla/element_parentOffset.html": [ + { + "path": "mozilla/element_parentOffset.html", + "url": "/_mozilla/mozilla/element_parentOffset.html" + } + ], "mozilla/empty_clientrect.html": [ { "path": "mozilla/empty_clientrect.html", diff --git a/tests/wpt/mozilla/tests/mozilla/element_parentOffset.html b/tests/wpt/mozilla/tests/mozilla/element_parentOffset.html new file mode 100644 index 00000000000..d2b390c05cb --- /dev/null +++ b/tests/wpt/mozilla/tests/mozilla/element_parentOffset.html @@ -0,0 +1,51 @@ +<!DOCTYPE html> +<html> + <head> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <style type="text/css"> + #outer { + position: absolute; + margin-left: 50px; + width: 400px; + height: 400px; + background-color: red; + } + #inner { + margin-left: 100px; + width: 200px; + height: 200px; + background-color: green; + } + #div { + margin: 25px; + position: absolute; + width: 80px; + height: 130px; + background-color: blue; + } + </style> + </head> + <body> + <div id="outer"> + <div id="inner"> + <div id="div"></div> + </div> + </div> + + <script> + test(function() { + var div = document.getElementById("div"); + var outer = document.getElementById("outer"); + + var parent = div.offsetParent; + assert_equals(parent, outer); + + assert_equals(div.offsetLeft, 125); + assert_equals(div.offsetTop, 25); + assert_equals(div.offsetWidth, 80); + assert_equals(div.offsetHeight, 130); + }); + </script> + </body> +</html> |