aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/gfx/Cargo.toml31
-rw-r--r--components/gfx/font.rs3
-rw-r--r--components/gfx/lib.rs3
-rw-r--r--components/gfx/text/glyph.rs45
-rw-r--r--components/gfx/text/shaping/harfbuzz.rs66
-rw-r--r--components/gfx/text/util.rs15
-rw-r--r--components/layout/block.rs2
-rw-r--r--components/layout/construct.rs62
-rw-r--r--components/layout/flow.rs42
-rw-r--r--components/layout/fragment.rs4
-rw-r--r--components/layout/inline.rs2
-rw-r--r--components/layout/layout_task.rs133
-rw-r--r--components/layout/list_item.rs4
-rw-r--r--components/layout/multicol.rs3
-rw-r--r--components/layout/sequential.rs10
-rw-r--r--components/layout/table.rs3
-rw-r--r--components/layout/table_caption.rs3
-rw-r--r--components/layout/table_cell.rs3
-rw-r--r--components/layout/table_colgroup.rs1
-rw-r--r--components/layout/table_row.rs3
-rw-r--r--components/layout/table_rowgroup.rs3
-rw-r--r--components/layout/table_wrapper.rs3
-rw-r--r--components/msg/Cargo.toml3
-rw-r--r--components/msg/constellation_msg.rs8
-rw-r--r--components/msg/lib.rs2
-rw-r--r--components/script/devtools.rs1
-rw-r--r--components/script/document_loader.rs8
-rw-r--r--components/script/dom/bindings/cell.rs2
-rw-r--r--components/script/dom/bindings/codegen/CodegenRust.py2
-rw-r--r--components/script/dom/bindings/global.rs2
-rw-r--r--components/script/dom/bindings/js.rs11
-rw-r--r--components/script/dom/bindings/utils.rs13
-rw-r--r--components/script/dom/browsercontext.rs4
-rw-r--r--components/script/dom/characterdata.rs3
-rw-r--r--components/script/dom/dedicatedworkerglobalscope.rs66
-rw-r--r--components/script/dom/document.rs2
-rw-r--r--components/script/dom/element.rs2
-rw-r--r--components/script/dom/eventtarget.rs14
-rw-r--r--components/script/dom/htmlelement.rs61
-rw-r--r--components/script/dom/htmlmediaelement.rs2
-rw-r--r--components/script/dom/htmltablecellelement.rs2
-rw-r--r--components/script/dom/node.rs9
-rw-r--r--components/script/dom/webidls/CSSStyleDeclaration.webidl1
-rw-r--r--components/script/dom/webidls/HTMLElement.webidl11
-rw-r--r--components/script/dom/window.rs59
-rw-r--r--components/script/dom/worker.rs14
-rw-r--r--components/script/dom/workerglobalscope.rs36
-rw-r--r--components/script/dom/xmlhttprequesteventtarget.rs2
-rw-r--r--components/script/layout_interface.rs17
-rw-r--r--components/script/lib.rs1
-rw-r--r--components/script/mem.rs36
-rw-r--r--components/script/page.rs4
-rw-r--r--components/script/script_task.rs22
-rw-r--r--components/script/timers.rs19
-rw-r--r--components/servo/Cargo.lock6
-rw-r--r--components/style/properties.mako.rs90
-rw-r--r--components/style/values.rs42
-rw-r--r--components/util/Cargo.toml8
-rw-r--r--components/util/lib.rs4
-rw-r--r--components/util/mem.rs108
-rw-r--r--ports/cef/Cargo.lock4
-rw-r--r--ports/gonk/Cargo.lock4
-rw-r--r--tests/wpt/metadata-css/css21_dev/html4/bidi-006b.htm.ini3
-rw-r--r--tests/wpt/metadata-css/css21_dev/html4/bidi-007b.htm.ini3
-rw-r--r--tests/wpt/metadata-css/css21_dev/html4/bidi-008b.htm.ini3
-rw-r--r--tests/wpt/metadata-css/css21_dev/html4/bidi-010b.htm.ini3
-rw-r--r--tests/wpt/metadata-css/css21_dev/html4/bidi-box-model-006.htm.ini3
-rw-r--r--tests/wpt/metadata-css/css21_dev/html4/bidi-inline-001.htm.ini3
-rw-r--r--tests/wpt/metadata-css/css21_dev/html4/first-letter-dynamic-003a.htm.ini (renamed from tests/wpt/metadata-css/css21_dev/html4/bidi-001.htm.ini)2
-rw-r--r--tests/wpt/metadata-css/css21_dev/html4/first-letter-dynamic-003b.htm.ini (renamed from tests/wpt/metadata-css/css21_dev/html4/bidi-005b.htm.ini)2
-rw-r--r--tests/wpt/metadata-css/css21_dev/html4/inline-formatting-context-007.htm.ini3
-rw-r--r--tests/wpt/metadata-css/css21_dev/html4/run-in-basic-017.htm.ini3
-rw-r--r--tests/wpt/metadata-css/css21_dev/html4/unicode-bidi-002.htm.ini3
-rw-r--r--tests/wpt/metadata/html/semantics/forms/the-input-element/input-type-button.html.ini5
-rw-r--r--tests/wpt/metadata/html/semantics/text-level-semantics/the-bdi-element/bdi-neutral-nested.html.ini3
-rw-r--r--tests/wpt/metadata/html/semantics/text-level-semantics/the-bdo-element/bdo-override.html.ini3
-rw-r--r--tests/wpt/mozilla/meta/MANIFEST.json6
-rw-r--r--tests/wpt/mozilla/tests/mozilla/element_parentOffset.html51
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>