mirror of
https://github.com/servo/servo.git
synced 2025-09-10 15:08:21 +01:00
script/layout: Implement HTMLElement.scrollParent
(#39110)
This new API allows getting the element which establishes an element's scroll container. This will be used to properly implement `scrollIntoView`. There is still work to do for this API and `offsetParent` to properly handle ancestors which are closed-shadow-hidden from the original query element. In addition, fix an issue where inline boxes were establishing scrolling containers (they shouldn't do that). Testing: There are tests for this change. Fixes: #39096. Signed-off-by: Martin Robinson <mrobinson@igalia.com> Co-authored-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
parent
5c7ea4bdee
commit
2c7866eb24
13 changed files with 173 additions and 49 deletions
|
@ -29,7 +29,8 @@ use layout_api::wrapper_traits::LayoutNode;
|
||||||
use layout_api::{
|
use layout_api::{
|
||||||
BoxAreaType, IFrameSizes, Layout, LayoutConfig, LayoutDamage, LayoutFactory,
|
BoxAreaType, IFrameSizes, Layout, LayoutConfig, LayoutDamage, LayoutFactory,
|
||||||
OffsetParentResponse, PropertyRegistration, QueryMsg, ReflowGoal, ReflowPhasesRun,
|
OffsetParentResponse, PropertyRegistration, QueryMsg, ReflowGoal, ReflowPhasesRun,
|
||||||
ReflowRequest, ReflowRequestRestyle, ReflowResult, RegisterPropertyError, TrustedNodeAddress,
|
ReflowRequest, ReflowRequestRestyle, ReflowResult, RegisterPropertyError, ScrollParentResponse,
|
||||||
|
TrustedNodeAddress,
|
||||||
};
|
};
|
||||||
use log::{debug, error, warn};
|
use log::{debug, error, warn};
|
||||||
use malloc_size_of::{MallocConditionalSizeOf, MallocSizeOf, MallocSizeOfOps};
|
use malloc_size_of::{MallocConditionalSizeOf, MallocSizeOf, MallocSizeOfOps};
|
||||||
|
@ -91,7 +92,8 @@ use crate::display_list::{DisplayListBuilder, HitTest, StackingContextTree};
|
||||||
use crate::query::{
|
use crate::query::{
|
||||||
get_the_text_steps, process_box_area_request, process_box_areas_request,
|
get_the_text_steps, process_box_area_request, process_box_areas_request,
|
||||||
process_client_rect_request, process_node_scroll_area_request, process_offset_parent_query,
|
process_client_rect_request, process_node_scroll_area_request, process_offset_parent_query,
|
||||||
process_resolved_font_style_query, process_resolved_style_request, process_text_index_request,
|
process_resolved_font_style_query, process_resolved_style_request, process_scroll_parent_query,
|
||||||
|
process_text_index_request,
|
||||||
};
|
};
|
||||||
use crate::traversal::{RecalcStyle, compute_damage_and_repair_style};
|
use crate::traversal::{RecalcStyle, compute_damage_and_repair_style};
|
||||||
use crate::{BoxTree, FragmentTree};
|
use crate::{BoxTree, FragmentTree};
|
||||||
|
@ -323,6 +325,12 @@ impl Layout for LayoutThread {
|
||||||
process_offset_parent_query(node).unwrap_or_default()
|
process_offset_parent_query(node).unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[servo_tracing::instrument(skip_all)]
|
||||||
|
fn query_scroll_parent(&self, node: TrustedNodeAddress) -> Option<ScrollParentResponse> {
|
||||||
|
let node = unsafe { ServoLayoutNode::new(&node) };
|
||||||
|
process_scroll_parent_query(node)
|
||||||
|
}
|
||||||
|
|
||||||
#[servo_tracing::instrument(skip_all)]
|
#[servo_tracing::instrument(skip_all)]
|
||||||
fn query_resolved_style(
|
fn query_resolved_style(
|
||||||
&self,
|
&self,
|
||||||
|
@ -1608,6 +1616,7 @@ impl ReflowPhases {
|
||||||
QueryMsg::ElementInnerOuterTextQuery |
|
QueryMsg::ElementInnerOuterTextQuery |
|
||||||
QueryMsg::InnerWindowDimensionsQuery |
|
QueryMsg::InnerWindowDimensionsQuery |
|
||||||
QueryMsg::OffsetParentQuery |
|
QueryMsg::OffsetParentQuery |
|
||||||
|
QueryMsg::ScrollParentQuery |
|
||||||
QueryMsg::ResolvedFontStyleQuery |
|
QueryMsg::ResolvedFontStyleQuery |
|
||||||
QueryMsg::TextIndexQuery |
|
QueryMsg::TextIndexQuery |
|
||||||
QueryMsg::StyleQuery => Self::empty(),
|
QueryMsg::StyleQuery => Self::empty(),
|
||||||
|
|
|
@ -11,7 +11,9 @@ use euclid::default::{Point2D, Rect};
|
||||||
use euclid::{SideOffsets2D, Size2D};
|
use euclid::{SideOffsets2D, Size2D};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use layout_api::wrapper_traits::{LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
|
use layout_api::wrapper_traits::{LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
|
||||||
use layout_api::{BoxAreaType, LayoutElementType, LayoutNodeType, OffsetParentResponse};
|
use layout_api::{
|
||||||
|
BoxAreaType, LayoutElementType, LayoutNodeType, OffsetParentResponse, ScrollParentResponse,
|
||||||
|
};
|
||||||
use script::layout_dom::{ServoLayoutNode, ServoThreadSafeLayoutNode};
|
use script::layout_dom::{ServoLayoutNode, ServoThreadSafeLayoutNode};
|
||||||
use servo_arc::Arc as ServoArc;
|
use servo_arc::Arc as ServoArc;
|
||||||
use servo_geometry::{FastLayoutTransform, au_rect_to_f32_rect, f32_rect_to_au_rect};
|
use servo_geometry::{FastLayoutTransform, au_rect_to_f32_rect, f32_rect_to_au_rect};
|
||||||
|
@ -47,6 +49,7 @@ use crate::flow::inline::construct::{TextTransformation, WhitespaceCollapse, cap
|
||||||
use crate::fragment_tree::{
|
use crate::fragment_tree::{
|
||||||
BoxFragment, Fragment, FragmentFlags, FragmentTree, SpecificLayoutInfo,
|
BoxFragment, Fragment, FragmentFlags, FragmentTree, SpecificLayoutInfo,
|
||||||
};
|
};
|
||||||
|
use crate::style_ext::ComputedValuesExt;
|
||||||
use crate::taffy::SpecificTaffyGridInfo;
|
use crate::taffy::SpecificTaffyGridInfo;
|
||||||
|
|
||||||
/// Get a scroll node that would represents this [`ServoLayoutNode`]'s transform and
|
/// Get a scroll node that would represents this [`ServoLayoutNode`]'s transform and
|
||||||
|
@ -638,6 +641,95 @@ pub fn process_offset_parent_query(node: ServoLayoutNode<'_>) -> Option<OffsetPa
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This is an implementation of
|
||||||
|
/// <https://drafts.csswg.org/cssom-view/#dom-htmlelement-scrollparent>.
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn process_scroll_parent_query(
|
||||||
|
node: ServoLayoutNode<'_>,
|
||||||
|
) -> Option<ScrollParentResponse> {
|
||||||
|
let layout_data = node.to_threadsafe().inner_layout_data()?;
|
||||||
|
|
||||||
|
// 1. If any of the following holds true, return null and terminate this algorithm:
|
||||||
|
// - The element does not have an associated box.
|
||||||
|
let layout_box = layout_data.self_box.borrow();
|
||||||
|
let layout_box = layout_box.as_ref()?;
|
||||||
|
|
||||||
|
let (mut current_position_value, flags) = layout_box
|
||||||
|
.with_base_flat(|base| vec![(base.style.clone_position(), base.base_fragment_info.flags)])
|
||||||
|
.first()
|
||||||
|
.cloned()?;
|
||||||
|
|
||||||
|
// - The element is the root element.
|
||||||
|
// - The element is the body element.
|
||||||
|
// - The element’s computed value of the position property is fixed and no ancestor
|
||||||
|
// establishes a fixed position containing block.
|
||||||
|
if flags.intersects(
|
||||||
|
FragmentFlags::IS_ROOT_ELEMENT | FragmentFlags::IS_BODY_ELEMENT_OF_HTML_ELEMENT_ROOT,
|
||||||
|
) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Let ancestor be the containing block of the element in the flat tree and repeat these substeps:
|
||||||
|
// - If ancestor is the initial containing block, return the scrollingElement for the
|
||||||
|
// element’s document if it is not closed-shadow-hidden from the element, otherwise
|
||||||
|
// return null.
|
||||||
|
// - If ancestor is not closed-shadow-hidden from the element, and is a scroll
|
||||||
|
// container, terminate this algorithm and return ancestor.
|
||||||
|
// - If the computed value of the position property of ancestor is fixed, and no
|
||||||
|
// ancestor establishes a fixed position containing block, terminate this algorithm
|
||||||
|
// and return null.
|
||||||
|
// - Let ancestor be the containing block of ancestor in the flat tree.
|
||||||
|
//
|
||||||
|
// Notes: We don't follow the specification exactly below, but we follow the spirit.
|
||||||
|
//
|
||||||
|
// TODO: Handle the situation where the ancestor is "closed-shadow-hidden" from the element.
|
||||||
|
let mut current_ancestor = node.as_element()?;
|
||||||
|
while let Some(ancestor) = current_ancestor.traversal_parent() {
|
||||||
|
current_ancestor = ancestor;
|
||||||
|
|
||||||
|
let Some(layout_data) = ancestor.as_node().to_threadsafe().inner_layout_data() else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let ancestor_layout_box = layout_data.self_box.borrow();
|
||||||
|
let Some(ancestor_layout_box) = ancestor_layout_box.as_ref() else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
let (ancestor_style, ancestor_flags) = ancestor_layout_box
|
||||||
|
.with_base_flat(|base| vec![(base.style.clone(), base.base_fragment_info.flags)])
|
||||||
|
.first()
|
||||||
|
.cloned()?;
|
||||||
|
|
||||||
|
let is_containing_block = match current_position_value {
|
||||||
|
Position::Static | Position::Relative | Position::Sticky => {
|
||||||
|
!ancestor_style.is_inline_box(ancestor_flags)
|
||||||
|
},
|
||||||
|
Position::Absolute => {
|
||||||
|
ancestor_style.establishes_containing_block_for_absolute_descendants(ancestor_flags)
|
||||||
|
},
|
||||||
|
Position::Fixed => {
|
||||||
|
ancestor_style.establishes_containing_block_for_all_descendants(ancestor_flags)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
if !is_containing_block {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ancestor_style.establishes_scroll_container(ancestor_flags) {
|
||||||
|
return Some(ScrollParentResponse::Element(
|
||||||
|
ancestor.as_node().opaque().into(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
current_position_value = ancestor_style.clone_position();
|
||||||
|
}
|
||||||
|
|
||||||
|
match current_position_value {
|
||||||
|
Position::Fixed => None,
|
||||||
|
_ => Some(ScrollParentResponse::DocumentScrollingElement),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <https://html.spec.whatwg.org/multipage/#get-the-text-steps>
|
/// <https://html.spec.whatwg.org/multipage/#get-the-text-steps>
|
||||||
pub fn get_the_text_steps(node: ServoLayoutNode<'_>) -> String {
|
pub fn get_the_text_steps(node: ServoLayoutNode<'_>) -> String {
|
||||||
// Step 1: If element is not being rendered or if the user agent is a non-CSS user agent, then
|
// Step 1: If element is not being rendered or if the user agent is a non-CSS user agent, then
|
||||||
|
|
|
@ -598,6 +598,14 @@ impl ComputedValuesExt for ComputedValues {
|
||||||
let mut overflow_x = style_box.overflow_x;
|
let mut overflow_x = style_box.overflow_x;
|
||||||
let mut overflow_y = style_box.overflow_y;
|
let mut overflow_y = style_box.overflow_y;
|
||||||
|
|
||||||
|
// Inline boxes should never establish scroll containers.
|
||||||
|
if self.is_inline_box(fragment_flags) {
|
||||||
|
return AxesOverflow {
|
||||||
|
x: Overflow::Visible,
|
||||||
|
y: Overflow::Visible,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// https://www.w3.org/TR/css-overflow-3/#overflow-propagation
|
// https://www.w3.org/TR/css-overflow-3/#overflow-propagation
|
||||||
// The element from which the value is propagated must then have a used overflow value of visible.
|
// The element from which the value is propagated must then have a used overflow value of visible.
|
||||||
if fragment_flags.contains(FragmentFlags::PROPAGATED_OVERFLOW_TO_VIEWPORT) {
|
if fragment_flags.contains(FragmentFlags::PROPAGATED_OVERFLOW_TO_VIEWPORT) {
|
||||||
|
|
|
@ -444,6 +444,11 @@ impl HTMLElementMethods<crate::DomTypeHolder> for HTMLElement {
|
||||||
document.request_focus(None, FocusInitiator::Local, can_gc);
|
document.request_focus(None, FocusInitiator::Local, can_gc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <https://drafts.csswg.org/cssom-view/#dom-htmlelement-scrollparent>
|
||||||
|
fn GetScrollParent(&self) -> Option<DomRoot<Element>> {
|
||||||
|
self.owner_window().scroll_parent_query(self.upcast())
|
||||||
|
}
|
||||||
|
|
||||||
/// <https://drafts.csswg.org/cssom-view/#dom-htmlelement-offsetparent>
|
/// <https://drafts.csswg.org/cssom-view/#dom-htmlelement-offsetparent>
|
||||||
fn GetOffsetParent(&self) -> Option<DomRoot<Element>> {
|
fn GetOffsetParent(&self) -> Option<DomRoot<Element>> {
|
||||||
if self.is_body_element() || self.is::<HTMLHtmlElement>() {
|
if self.is_body_element() || self.is::<HTMLHtmlElement>() {
|
||||||
|
|
|
@ -56,8 +56,8 @@ use js::rust::{
|
||||||
use layout_api::{
|
use layout_api::{
|
||||||
BoxAreaType, ElementsFromPointFlags, ElementsFromPointResult, FragmentType, Layout,
|
BoxAreaType, ElementsFromPointFlags, ElementsFromPointResult, FragmentType, Layout,
|
||||||
PendingImage, PendingImageState, PendingRasterizationImage, QueryMsg, ReflowGoal,
|
PendingImage, PendingImageState, PendingRasterizationImage, QueryMsg, ReflowGoal,
|
||||||
ReflowPhasesRun, ReflowRequest, ReflowRequestRestyle, RestyleReason, TrustedNodeAddress,
|
ReflowPhasesRun, ReflowRequest, ReflowRequestRestyle, RestyleReason, ScrollParentResponse,
|
||||||
combine_id_with_fragment_type,
|
TrustedNodeAddress, combine_id_with_fragment_type,
|
||||||
};
|
};
|
||||||
use malloc_size_of::MallocSizeOf;
|
use malloc_size_of::MallocSizeOf;
|
||||||
use media::WindowGLContext;
|
use media::WindowGLContext;
|
||||||
|
@ -2599,6 +2599,23 @@ impl Window {
|
||||||
(element, response.rect)
|
(element, response.rect)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unsafe_code)]
|
||||||
|
pub(crate) fn scroll_parent_query(&self, node: &Node) -> Option<DomRoot<Element>> {
|
||||||
|
self.layout_reflow(QueryMsg::ScrollParentQuery);
|
||||||
|
self.layout
|
||||||
|
.borrow()
|
||||||
|
.query_scroll_parent(node.to_trusted_node_address())
|
||||||
|
.and_then(|response| match response {
|
||||||
|
ScrollParentResponse::DocumentScrollingElement => {
|
||||||
|
self.Document().GetScrollingElement()
|
||||||
|
},
|
||||||
|
ScrollParentResponse::Element(parent_node_address) => {
|
||||||
|
let node = unsafe { from_untrusted_node_address(parent_node_address) };
|
||||||
|
DomRoot::downcast(node)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn text_index_query(
|
pub(crate) fn text_index_query(
|
||||||
&self,
|
&self,
|
||||||
node: &Node,
|
node: &Node,
|
||||||
|
|
|
@ -64,6 +64,7 @@ interface HTMLElement : Element {
|
||||||
// http://dev.w3.org/csswg/cssom-view/#extensions-to-the-htmlelement-interface
|
// http://dev.w3.org/csswg/cssom-view/#extensions-to-the-htmlelement-interface
|
||||||
partial interface HTMLElement {
|
partial interface HTMLElement {
|
||||||
// CSSOM things are not [Pure] because they can flush
|
// CSSOM things are not [Pure] because they can flush
|
||||||
|
readonly attribute Element? scrollParent;
|
||||||
readonly attribute Element? offsetParent;
|
readonly attribute Element? offsetParent;
|
||||||
readonly attribute long offsetTop;
|
readonly attribute long offsetTop;
|
||||||
readonly attribute long offsetLeft;
|
readonly attribute long offsetLeft;
|
||||||
|
|
|
@ -295,6 +295,7 @@ pub trait Layout {
|
||||||
fn query_client_rect(&self, node: TrustedNodeAddress) -> Rect<i32>;
|
fn query_client_rect(&self, node: TrustedNodeAddress) -> Rect<i32>;
|
||||||
fn query_element_inner_outer_text(&self, node: TrustedNodeAddress) -> String;
|
fn query_element_inner_outer_text(&self, node: TrustedNodeAddress) -> String;
|
||||||
fn query_offset_parent(&self, node: TrustedNodeAddress) -> OffsetParentResponse;
|
fn query_offset_parent(&self, node: TrustedNodeAddress) -> OffsetParentResponse;
|
||||||
|
fn query_scroll_parent(&self, node: TrustedNodeAddress) -> Option<ScrollParentResponse>;
|
||||||
fn query_resolved_style(
|
fn query_resolved_style(
|
||||||
&self,
|
&self,
|
||||||
node: TrustedNodeAddress,
|
node: TrustedNodeAddress,
|
||||||
|
@ -351,6 +352,12 @@ pub struct OffsetParentResponse {
|
||||||
pub rect: Rect<Au>,
|
pub rect: Rect<Au>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum ScrollParentResponse {
|
||||||
|
DocumentScrollingElement,
|
||||||
|
Element(UntrustedNodeAddress),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum QueryMsg {
|
pub enum QueryMsg {
|
||||||
BoxArea,
|
BoxArea,
|
||||||
|
@ -361,6 +368,7 @@ pub enum QueryMsg {
|
||||||
InnerWindowDimensionsQuery,
|
InnerWindowDimensionsQuery,
|
||||||
NodesFromPointQuery,
|
NodesFromPointQuery,
|
||||||
OffsetParentQuery,
|
OffsetParentQuery,
|
||||||
|
ScrollParentQuery,
|
||||||
ResolvedFontStyleQuery,
|
ResolvedFontStyleQuery,
|
||||||
ResolvedStyleQuery,
|
ResolvedStyleQuery,
|
||||||
ScrollingAreaOrOffsetQuery,
|
ScrollingAreaOrOffsetQuery,
|
||||||
|
|
15
tests/wpt/meta/MANIFEST.json
vendored
15
tests/wpt/meta/MANIFEST.json
vendored
|
@ -232173,6 +232173,19 @@
|
||||||
{}
|
{}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
"overflow-does-not-apply-to-inline-box.html": [
|
||||||
|
"f4c8a1816399ed368fb219bd1a4e49f61f18d083",
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
"/css/reference/ref-filled-green-100px-square.xht",
|
||||||
|
"=="
|
||||||
|
]
|
||||||
|
],
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
],
|
||||||
"overflow-ellipsis-dynamic-001.html": [
|
"overflow-ellipsis-dynamic-001.html": [
|
||||||
"2a9edba9308bf06009d7b9a27f21f1e0f1a231c7",
|
"2a9edba9308bf06009d7b9a27f21f1e0f1a231c7",
|
||||||
[
|
[
|
||||||
|
@ -630023,7 +630036,7 @@
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"scrollParent.html": [
|
"scrollParent.html": [
|
||||||
"9faa0c9a3e92e38662ac77d25b08731fe00a7db3",
|
"344ee522ef2664e0b963e79812074f08f343f5bf",
|
||||||
[
|
[
|
||||||
null,
|
null,
|
||||||
{}
|
{}
|
||||||
|
|
|
@ -574,12 +574,3 @@
|
||||||
|
|
||||||
[Document interface: calling caretPositionFromPoint(double, double, optional CaretPositionFromPointOptions) on document with too few arguments must throw TypeError]
|
[Document interface: calling caretPositionFromPoint(double, double, optional CaretPositionFromPointOptions) on document with too few arguments must throw TypeError]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[HTMLElement interface: attribute scrollParent]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[HTMLElement interface: document.createElement("div") must inherit property "scrollParent" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[HTMLElement interface: document.createElement("img") must inherit property "scrollParent" with the proper type]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -4,9 +4,3 @@
|
||||||
|
|
||||||
[scrollParent skips intermediate open shadow tree nodes]
|
[scrollParent skips intermediate open shadow tree nodes]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[scrollParent from inside closed shadow tree]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[scrollParent from inside open shadow tree]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
[scrollParent.html]
|
|
||||||
[scrollParent returns the nearest scroll container.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[hidden element is a scroll container.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Element with no box has null scrollParent.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[scrollParent follows absolute positioned containing block chain.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[scrollParent follows fixed positioned containing block chain.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[scrollParent of element fixed to root is null.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[scrollParent of child in root viewport returns document scrolling element.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[scrollParent of fixed element contained within root is document scrolling element.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[scrollParent of body is null.]
|
|
||||||
expected: FAIL
|
|
12
tests/wpt/tests/css/css-overflow/overflow-does-not-apply-to-inline-box.html
vendored
Normal file
12
tests/wpt/tests/css/css-overflow/overflow-does-not-apply-to-inline-box.html
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com">
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#overflow-control">
|
||||||
|
<meta name="assert" content="Overflow does not apply to inline boxes so they do not establish scroll containers.">
|
||||||
|
<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
|
||||||
|
<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
|
||||||
|
|
||||||
|
<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
|
||||||
|
<div style="font: 100px/1 Ahem; background: red; width: 100px">
|
||||||
|
<span style="overflow: hidden; border-radius: 50%; color: green">X</span>
|
||||||
|
</div>
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.contains-fixed {
|
.contains-fixed {
|
||||||
|
transform: scale(1);
|
||||||
contain: paint;
|
contain: paint;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -83,4 +84,4 @@ test(() => { assert_equals(document.body.scrollParent, null); },
|
||||||
"scrollParent of body is null.");
|
"scrollParent of body is null.");
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</html>
|
</html>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue