diff --git a/components/layout/query.rs b/components/layout/query.rs index bd6088a1e05..cbfeb98c8e3 100644 --- a/components/layout/query.rs +++ b/components/layout/query.rs @@ -14,6 +14,7 @@ use flow::{self, Flow}; use fragment::{Fragment, FragmentBorderBoxIterator, SpecificFragmentInfo}; use gfx::display_list::{DisplayItemMetadata, DisplayList, OpaqueNode, ScrollOffsetMap}; use gfx_traits::ScrollRootId; +use inline::LAST_FRAGMENT_OF_ELEMENT; use ipc_channel::ipc::IpcSender; use opaque_node::OpaqueNodeMethods; use script_layout_interface::rpc::{ContentBoxResponse, ContentBoxesResponse}; @@ -437,16 +438,20 @@ impl UnioningFragmentScrollAreaIterator { } } +struct NodeOffsetBoxInfo { + offset: Point2D, + rectangle: Rect, +} + struct ParentBorderBoxInfo { node_address: OpaqueNode, - border_box: Rect, + origin: Point2D, } struct ParentOffsetBorderBoxIterator { node_address: OpaqueNode, - last_level: i32, - has_found_node: bool, - node_border_box: Rect, + has_processed_node: bool, + node_offset_box: Option, parent_nodes: Vec>, } @@ -454,9 +459,8 @@ 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(), + has_processed_node: false, + node_offset_box: None, parent_nodes: Vec::new(), } } @@ -533,21 +537,81 @@ impl FragmentBorderBoxIterator for UnioningFragmentScrollAreaIterator { // 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) { + if self.node_offset_box.is_none() { + // We haven't found the node yet, so we're still looking + // for its parent. Remove all nodes at this level or + // higher, as they can't be parents of this node. + self.parent_nodes.truncate(level as usize); + assert_eq!(self.parent_nodes.len(), level as usize, + "Skipped at least one level in the flow tree!"); + } + + if !fragment.is_primary_fragment() { + // This fragment doesn't correspond to anything worth + // taking measurements from. + + if self.node_offset_box.is_none() { + // If this is the only fragment in the flow, we need to + // do this to avoid failing the above assertion. + self.parent_nodes.push(None); + } + + return; + } + 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; + + assert!(self.node_offset_box.is_none(), + "Node was being treated as inline, but it has an associated fragment!"); + + self.has_processed_node = true; + self.node_offset_box = Some(NodeOffsetBoxInfo { + offset: border_box.origin, + rectangle: *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 { + } else if let Some(node) = fragment.inline_context.as_ref().and_then(|inline_context| { + inline_context.nodes.iter().find(|node| node.address == self.node_address) + }) { + // TODO: Handle cases where the `offsetParent` is an inline + // element. This will likely be impossible until + // https://github.com/servo/servo/issues/13982 is fixed. + + // Found a fragment in the flow tree whose inline context + // contains the DOM node we're looking for, i.e. the node + // is inline and contains this fragment. + match self.node_offset_box { + Some(NodeOffsetBoxInfo { ref mut rectangle, .. }) => { + *rectangle = rectangle.union(border_box); + }, + None => { + // https://github.com/servo/servo/issues/13982 will + // cause this assertion to fail sometimes, so it's + // commented out for now. + /*assert!(node.flags.contains(FIRST_FRAGMENT_OF_ELEMENT), + "First fragment of inline node found wasn't its first fragment!");*/ + + self.node_offset_box = Some(NodeOffsetBoxInfo { + offset: border_box.origin, + rectangle: *border_box, + }); + }, + } + + if node.flags.contains(LAST_FRAGMENT_OF_ELEMENT) { + self.has_processed_node = true; + } + } else if self.node_offset_box.is_none() { // 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; + // it's at level 1 (below the root node)? + let is_body_element = level == 1; let is_valid_parent = match (is_body_element, fragment.style.get_box().position, @@ -568,22 +632,22 @@ impl FragmentBorderBoxIterator for ParentOffsetBorderBoxIterator { }; let parent_info = if is_valid_parent { + let border_width = fragment.border_width().to_physical(fragment.style.writing_mode); + Some(ParentBorderBoxInfo { - border_box: *border_box, node_address: fragment.node, + origin: border_box.origin + Point2D::new(border_width.left, border_width.top), }) } 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 + !self.has_processed_node } } @@ -804,18 +868,19 @@ pub fn process_offset_parent_query(requested_node: N, layout_root -> OffsetParentResponse { let mut iterator = ParentOffsetBorderBoxIterator::new(requested_node.opaque()); 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; + + let node_offset_box = iterator.node_offset_box; + let parent_info = iterator.parent_nodes.into_iter().rev().filter_map(|info| info).next(); + match (node_offset_box, parent_info) { + (Some(node_offset_box), Some(parent_info)) => { + let origin = node_offset_box.offset - parent_info.origin; + let size = node_offset_box.rectangle.size; OffsetParentResponse { - node_address: Some(parent.node_address.to_untrusted_node_address()), + node_address: Some(parent_info.node_address.to_untrusted_node_address()), rect: Rect::new(origin, size), } } - None => { + _ => { OffsetParentResponse::empty() } } diff --git a/tests/wpt/metadata-css/css-text-3_dev/html/seg-break-transformation-001.htm.ini b/tests/wpt/metadata-css/css-text-3_dev/html/seg-break-transformation-001.htm.ini new file mode 100644 index 00000000000..3f6e6065d1c --- /dev/null +++ b/tests/wpt/metadata-css/css-text-3_dev/html/seg-break-transformation-001.htm.ini @@ -0,0 +1,20 @@ +[seg-break-transformation-001.htm] + type: testharness + [linebreak only] + expected: FAIL + + [spaces linebreak] + expected: FAIL + + [linebreak spaces] + expected: FAIL + + [spaces linebreak spaces] + expected: FAIL + + [multiple linebreaks] + expected: FAIL + + [multiple linebreaks + spaces] + expected: FAIL + diff --git a/tests/wpt/metadata-css/css-text-3_dev/html/seg-break-transformation-002.htm.ini b/tests/wpt/metadata-css/css-text-3_dev/html/seg-break-transformation-002.htm.ini new file mode 100644 index 00000000000..84355512269 --- /dev/null +++ b/tests/wpt/metadata-css/css-text-3_dev/html/seg-break-transformation-002.htm.ini @@ -0,0 +1,20 @@ +[seg-break-transformation-002.htm] + type: testharness + [linebreak only] + expected: FAIL + + [spaces linebreak] + expected: FAIL + + [linebreak spaces] + expected: FAIL + + [spaces linebreak spaces] + expected: FAIL + + [multiple linebreaks] + expected: FAIL + + [multiple linebreaks + spaces] + expected: FAIL + diff --git a/tests/wpt/metadata-css/css-text-3_dev/html/seg-break-transformation-003.htm.ini b/tests/wpt/metadata-css/css-text-3_dev/html/seg-break-transformation-003.htm.ini new file mode 100644 index 00000000000..8bfcbbd9b31 --- /dev/null +++ b/tests/wpt/metadata-css/css-text-3_dev/html/seg-break-transformation-003.htm.ini @@ -0,0 +1,20 @@ +[seg-break-transformation-003.htm] + type: testharness + [linebreak only] + expected: FAIL + + [spaces linebreak] + expected: FAIL + + [linebreak spaces] + expected: FAIL + + [spaces linebreak spaces] + expected: FAIL + + [multiple linebreaks] + expected: FAIL + + [multiple linebreaks + spaces] + expected: FAIL + diff --git a/tests/wpt/metadata-css/css-text-3_dev/html/seg-break-transformation-004.htm.ini b/tests/wpt/metadata-css/css-text-3_dev/html/seg-break-transformation-004.htm.ini new file mode 100644 index 00000000000..1e9bac0f56d --- /dev/null +++ b/tests/wpt/metadata-css/css-text-3_dev/html/seg-break-transformation-004.htm.ini @@ -0,0 +1,38 @@ +[seg-break-transformation-004.htm] + type: testharness + [linebreak only ₩24] + expected: FAIL + + [spaces linebreak ₩24] + expected: FAIL + + [linebreak spaces ₩24] + expected: FAIL + + [spaces linebreak spaces ₩24] + expected: FAIL + + [multiple linebreaks ₩24] + expected: FAIL + + [multiple linebreaks + spaces ₩24] + expected: FAIL + + [linebreak only 24₩] + expected: FAIL + + [spaces linebreak 24₩] + expected: FAIL + + [linebreak spaces 24₩] + expected: FAIL + + [spaces linebreak spaces 24₩] + expected: FAIL + + [multiple linebreaks 24₩] + expected: FAIL + + [multiple linebreaks + spaces 24₩] + expected: FAIL + diff --git a/tests/wpt/metadata-css/css-text-3_dev/html/seg-break-transformation-006.htm.ini b/tests/wpt/metadata-css/css-text-3_dev/html/seg-break-transformation-006.htm.ini new file mode 100644 index 00000000000..7fbc15c654f --- /dev/null +++ b/tests/wpt/metadata-css/css-text-3_dev/html/seg-break-transformation-006.htm.ini @@ -0,0 +1,5 @@ +[seg-break-transformation-006.htm] + type: testharness + [spaces linebreak] + expected: FAIL + diff --git a/tests/wpt/metadata-css/css-text-3_dev/html/seg-break-transformation-008.htm.ini b/tests/wpt/metadata-css/css-text-3_dev/html/seg-break-transformation-008.htm.ini new file mode 100644 index 00000000000..248d1c2ca3e --- /dev/null +++ b/tests/wpt/metadata-css/css-text-3_dev/html/seg-break-transformation-008.htm.ini @@ -0,0 +1,20 @@ +[seg-break-transformation-008.htm] + type: testharness + [linebreak only] + expected: FAIL + + [spaces linebreak] + expected: FAIL + + [linebreak spaces] + expected: FAIL + + [spaces linebreak spaces] + expected: FAIL + + [multiple linebreaks] + expected: FAIL + + [multiple linebreaks + spaces] + expected: FAIL + diff --git a/tests/wpt/metadata-css/css-text-3_dev/html/seg-break-transformation-009.htm.ini b/tests/wpt/metadata-css/css-text-3_dev/html/seg-break-transformation-009.htm.ini new file mode 100644 index 00000000000..1c80bf143a2 --- /dev/null +++ b/tests/wpt/metadata-css/css-text-3_dev/html/seg-break-transformation-009.htm.ini @@ -0,0 +1,20 @@ +[seg-break-transformation-009.htm] + type: testharness + [linebreak only] + expected: FAIL + + [spaces linebreak] + expected: FAIL + + [linebreak spaces] + expected: FAIL + + [spaces linebreak spaces] + expected: FAIL + + [multiple linebreaks] + expected: FAIL + + [multiple linebreaks + spaces] + expected: FAIL + diff --git a/tests/wpt/metadata-css/css-text-3_dev/html/seg-break-transformation-016.htm.ini b/tests/wpt/metadata-css/css-text-3_dev/html/seg-break-transformation-016.htm.ini new file mode 100644 index 00000000000..1acaa955d11 --- /dev/null +++ b/tests/wpt/metadata-css/css-text-3_dev/html/seg-break-transformation-016.htm.ini @@ -0,0 +1,20 @@ +[seg-break-transformation-016.htm] + type: testharness + [linebreak only] + expected: FAIL + + [spaces linebreak] + expected: FAIL + + [linebreak spaces] + expected: FAIL + + [spaces linebreak spaces] + expected: FAIL + + [multiple linebreaks] + expected: FAIL + + [multiple linebreaks + spaces] + expected: FAIL + diff --git a/tests/wpt/metadata-css/css-text-3_dev/html/seg-break-transformation-017.htm.ini b/tests/wpt/metadata-css/css-text-3_dev/html/seg-break-transformation-017.htm.ini new file mode 100644 index 00000000000..7345d4e7e47 --- /dev/null +++ b/tests/wpt/metadata-css/css-text-3_dev/html/seg-break-transformation-017.htm.ini @@ -0,0 +1,20 @@ +[seg-break-transformation-017.htm] + type: testharness + [linebreak only] + expected: FAIL + + [spaces linebreak] + expected: FAIL + + [linebreak spaces] + expected: FAIL + + [spaces linebreak spaces] + expected: FAIL + + [multiple linebreaks] + expected: FAIL + + [multiple linebreaks + spaces] + expected: FAIL + diff --git a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-break-all-001.htm.ini b/tests/wpt/metadata-css/css-text-3_dev/html/word-break-break-all-001.htm.ini deleted file mode 100644 index f3614c22d24..00000000000 --- a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-break-all-001.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[word-break-break-all-001.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-break-all-002.htm.ini b/tests/wpt/metadata-css/css-text-3_dev/html/word-break-break-all-002.htm.ini deleted file mode 100644 index 0ecba6c9ff6..00000000000 --- a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-break-all-002.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[word-break-break-all-002.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-break-all-003.htm.ini b/tests/wpt/metadata-css/css-text-3_dev/html/word-break-break-all-003.htm.ini deleted file mode 100644 index 702492d69b5..00000000000 --- a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-break-all-003.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[word-break-break-all-003.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-break-all-005.htm.ini b/tests/wpt/metadata-css/css-text-3_dev/html/word-break-break-all-005.htm.ini deleted file mode 100644 index 41a4c4f8769..00000000000 --- a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-break-all-005.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[word-break-break-all-005.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-break-all-000.htm.ini b/tests/wpt/metadata-css/css-text-3_dev/html/word-break-break-all-007.htm.ini similarity index 51% rename from tests/wpt/metadata-css/css-text-3_dev/html/word-break-break-all-000.htm.ini rename to tests/wpt/metadata-css/css-text-3_dev/html/word-break-break-all-007.htm.ini index 6791b9dc852..b2b3212943b 100644 --- a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-break-all-000.htm.ini +++ b/tests/wpt/metadata-css/css-text-3_dev/html/word-break-break-all-007.htm.ini @@ -1,3 +1,3 @@ -[word-break-break-all-000.htm] +[word-break-break-all-007.htm] type: reftest expected: FAIL diff --git a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-keep-all-000.htm.ini b/tests/wpt/metadata-css/css-text-3_dev/html/word-break-keep-all-000.htm.ini deleted file mode 100644 index 37cf6325fa5..00000000000 --- a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-keep-all-000.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[word-break-keep-all-000.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-keep-all-001.htm.ini b/tests/wpt/metadata-css/css-text-3_dev/html/word-break-keep-all-001.htm.ini deleted file mode 100644 index 42b40a9663a..00000000000 --- a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-keep-all-001.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[word-break-keep-all-001.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-keep-all-002.htm.ini b/tests/wpt/metadata-css/css-text-3_dev/html/word-break-keep-all-002.htm.ini deleted file mode 100644 index ea759eb186f..00000000000 --- a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-keep-all-002.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[word-break-keep-all-002.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-normal-001.htm.ini b/tests/wpt/metadata-css/css-text-3_dev/html/word-break-normal-001.htm.ini deleted file mode 100644 index 1351d775750..00000000000 --- a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-normal-001.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[word-break-normal-001.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-normal-bo-000.htm.ini b/tests/wpt/metadata-css/css-text-3_dev/html/word-break-normal-bo-000.htm.ini deleted file mode 100644 index 2b2af21d60d..00000000000 --- a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-normal-bo-000.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[word-break-normal-bo-000.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-normal-en-000.htm.ini b/tests/wpt/metadata-css/css-text-3_dev/html/word-break-normal-en-000.htm.ini deleted file mode 100644 index 30ace8ddc84..00000000000 --- a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-normal-en-000.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[word-break-normal-en-000.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-normal-hi-000.htm.ini b/tests/wpt/metadata-css/css-text-3_dev/html/word-break-normal-hi-000.htm.ini deleted file mode 100644 index f325fa6949a..00000000000 --- a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-normal-hi-000.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[word-break-normal-hi-000.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-normal-ja-000.htm.ini b/tests/wpt/metadata-css/css-text-3_dev/html/word-break-normal-ja-000.htm.ini deleted file mode 100644 index dfa0f8fc076..00000000000 --- a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-normal-ja-000.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[word-break-normal-ja-000.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-normal-ja-001.htm.ini b/tests/wpt/metadata-css/css-text-3_dev/html/word-break-normal-ja-001.htm.ini deleted file mode 100644 index 0b6a8e5be42..00000000000 --- a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-normal-ja-001.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[word-break-normal-ja-001.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-normal-ja-002.htm.ini b/tests/wpt/metadata-css/css-text-3_dev/html/word-break-normal-ja-002.htm.ini deleted file mode 100644 index 4cdf1c684b4..00000000000 --- a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-normal-ja-002.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[word-break-normal-ja-002.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-normal-ja-004.htm.ini b/tests/wpt/metadata-css/css-text-3_dev/html/word-break-normal-ja-004.htm.ini deleted file mode 100644 index 41f09527230..00000000000 --- a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-normal-ja-004.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[word-break-normal-ja-004.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-normal-ko-000.htm.ini b/tests/wpt/metadata-css/css-text-3_dev/html/word-break-normal-ko-000.htm.ini deleted file mode 100644 index 156d02d97f5..00000000000 --- a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-normal-ko-000.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[word-break-normal-ko-000.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-normal-zh-000.htm.ini b/tests/wpt/metadata-css/css-text-3_dev/html/word-break-normal-zh-000.htm.ini index 89776256c31..b042003870b 100644 --- a/tests/wpt/metadata-css/css-text-3_dev/html/word-break-normal-zh-000.htm.ini +++ b/tests/wpt/metadata-css/css-text-3_dev/html/word-break-normal-zh-000.htm.ini @@ -1,3 +1,4 @@ [word-break-normal-zh-000.htm] type: reftest - expected: FAIL + expected: + if os == "mac": FAIL diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json index 9791fb0d084..99a9304ba6a 100644 --- a/tests/wpt/mozilla/meta/MANIFEST.json +++ b/tests/wpt/mozilla/meta/MANIFEST.json @@ -6734,6 +6734,12 @@ "url": "/_mozilla/css/meta_viewport_resize.html" } ], + "css/offset_properties_inline.html": [ + { + "path": "css/offset_properties_inline.html", + "url": "/_mozilla/css/offset_properties_inline.html" + } + ], "css/test_variable_legal_values.html": [ { "path": "css/test_variable_legal_values.html", diff --git a/tests/wpt/mozilla/tests/css/offset_properties_inline.html b/tests/wpt/mozilla/tests/css/offset_properties_inline.html new file mode 100644 index 00000000000..cb88fa3a246 --- /dev/null +++ b/tests/wpt/mozilla/tests/css/offset_properties_inline.html @@ -0,0 +1,83 @@ + + +cssom-view - offsetParent, offsetTop, offsetLeft, offsetWidth, and offsetHeight on inline elements + + + + +
+ ABC + ABC
ABC
+ ABC +
+
+ +
+ +