script: Replace usage of IntersectionObserverRootMargin with Stylo'sIntersectionObserverMargin (#38519)

@stevennovaryo 
Created wrapper for Stylo's IntersectionObserverMargin and cleaned up
repeated code.
Testing: Code compiles and `./mach test-unit tests/unit/style/` doesn't
have any errors. intersectionobserver.rs is able to utilize the struct.
Fixes: https://github.com/servo/servo/issues/35907

---------------------------
Signed-off-by: samir <samir.khan720a@gmail.com>

---------

Signed-off-by: samir <samir.khan720a@gmail.com>
This commit is contained in:
Labros 2025-08-10 03:01:44 +09:30 committed by GitHub
parent 0b2c0cd055
commit 7b057be780
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 20 additions and 117 deletions

View file

@ -10,11 +10,12 @@ use app_units::Au;
use base::cross_process_instant::CrossProcessInstant; use base::cross_process_instant::CrossProcessInstant;
use cssparser::{Parser, ParserInput}; use cssparser::{Parser, ParserInput};
use dom_struct::dom_struct; use dom_struct::dom_struct;
use euclid::default::{Rect, Size2D}; use euclid::default::{Rect, SideOffsets2D, Size2D};
use js::rust::{HandleObject, MutableHandleValue}; use js::rust::{HandleObject, MutableHandleValue};
use style::context::QuirksMode; use style::context::QuirksMode;
use style::parser::{Parse, ParserContext}; use style::parser::{Parse, ParserContext};
use style::stylesheets::{CssRuleType, Origin}; use style::stylesheets::{CssRuleType, Origin};
use style::values::specified::intersection_observer::IntersectionObserverMargin;
use style_traits::{ParsingMode, ToCss}; use style_traits::{ParsingMode, ToCss};
use url::Url; use url::Url;
@ -36,7 +37,6 @@ use crate::dom::document::Document;
use crate::dom::domrectreadonly::DOMRectReadOnly; use crate::dom::domrectreadonly::DOMRectReadOnly;
use crate::dom::element::Element; use crate::dom::element::Element;
use crate::dom::intersectionobserverentry::IntersectionObserverEntry; use crate::dom::intersectionobserverentry::IntersectionObserverEntry;
use crate::dom::intersectionobserverrootmargin::IntersectionObserverRootMargin;
use crate::dom::node::{Node, NodeTraits}; use crate::dom::node::{Node, NodeTraits};
use crate::dom::window::Window; use crate::dom::window::Window;
use crate::script_runtime::{CanGc, JSContext}; use crate::script_runtime::{CanGc, JSContext};
@ -82,12 +82,12 @@ pub(crate) struct IntersectionObserver {
/// <https://w3c.github.io/IntersectionObserver/#dom-intersectionobserver-rootmargin-slot> /// <https://w3c.github.io/IntersectionObserver/#dom-intersectionobserver-rootmargin-slot>
#[no_trace] #[no_trace]
#[ignore_malloc_size_of = "Defined in style"] #[ignore_malloc_size_of = "Defined in style"]
root_margin: RefCell<IntersectionObserverRootMargin>, root_margin: RefCell<IntersectionObserverMargin>,
/// <https://w3c.github.io/IntersectionObserver/#dom-intersectionobserver-scrollmargin-slot> /// <https://w3c.github.io/IntersectionObserver/#dom-intersectionobserver-scrollmargin-slot>
#[no_trace] #[no_trace]
#[ignore_malloc_size_of = "Defined in style"] #[ignore_malloc_size_of = "Defined in style"]
scroll_margin: RefCell<IntersectionObserverRootMargin>, scroll_margin: RefCell<IntersectionObserverMargin>,
/// <https://w3c.github.io/IntersectionObserver/#dom-intersectionobserver-thresholds-slot> /// <https://w3c.github.io/IntersectionObserver/#dom-intersectionobserver-thresholds-slot>
thresholds: RefCell<Vec<Finite<f64>>>, thresholds: RefCell<Vec<Finite<f64>>>,
@ -104,8 +104,8 @@ impl IntersectionObserver {
window: &Window, window: &Window,
callback: Rc<IntersectionObserverCallback>, callback: Rc<IntersectionObserverCallback>,
root: IntersectionRoot, root: IntersectionRoot,
root_margin: IntersectionObserverRootMargin, root_margin: IntersectionObserverMargin,
scroll_margin: IntersectionObserverRootMargin, scroll_margin: IntersectionObserverMargin,
) -> Self { ) -> Self {
Self { Self {
reflector_: Reflector::new(), reflector_: Reflector::new(),
@ -462,10 +462,7 @@ impl IntersectionObserver {
// > the width of the undilated rectangle. // > the width of the undilated rectangle.
// TODO(stevennovaryo): add check for same-origin-domain // TODO(stevennovaryo): add check for same-origin-domain
intersection_rectangle.map(|intersection_rectangle| { intersection_rectangle.map(|intersection_rectangle| {
let margin = self let margin = self.resolve_percentages_with_basis(intersection_rectangle);
.root_margin
.borrow()
.resolve_percentages_with_basis(intersection_rectangle);
intersection_rectangle.outer_rect(margin) intersection_rectangle.outer_rect(margin)
}) })
} }
@ -661,6 +658,16 @@ impl IntersectionObserver {
.set(intersection_output.is_visible); .set(intersection_output.is_visible);
} }
} }
fn resolve_percentages_with_basis(&self, containing_block: Rect<Au>) -> SideOffsets2D<Au> {
let inner = &self.root_margin.borrow().0;
SideOffsets2D::new(
inner.0.to_used_value(containing_block.height()),
inner.1.to_used_value(containing_block.width()),
inner.2.to_used_value(containing_block.height()),
inner.3.to_used_value(containing_block.width()),
)
}
} }
impl IntersectionObserverMethods<crate::DomTypeHolder> for IntersectionObserver { impl IntersectionObserverMethods<crate::DomTypeHolder> for IntersectionObserver {
@ -799,7 +806,7 @@ impl IntersectionObserverRegistration {
} }
/// <https://w3c.github.io/IntersectionObserver/#parse-a-margin> /// <https://w3c.github.io/IntersectionObserver/#parse-a-margin>
fn parse_a_margin(value: Option<&DOMString>) -> Result<IntersectionObserverRootMargin, ()> { fn parse_a_margin(value: Option<&DOMString>) -> Result<IntersectionObserverMargin, ()> {
// <https://w3c.github.io/IntersectionObserver/#dom-intersectionobserverinit-rootmargin> && // <https://w3c.github.io/IntersectionObserver/#dom-intersectionobserverinit-rootmargin> &&
// <https://w3c.github.io/IntersectionObserver/#dom-intersectionobserverinit-scrollmargin> // <https://w3c.github.io/IntersectionObserver/#dom-intersectionobserverinit-scrollmargin>
// > ... defaulting to "0px". // > ... defaulting to "0px".
@ -808,7 +815,7 @@ fn parse_a_margin(value: Option<&DOMString>) -> Result<IntersectionObserverRootM
_ => "0px", _ => "0px",
}; };
// Create necessary style ParserContext and utilize stylo's IntersectionObserverRootMargin // Create necessary style ParserContext and utilize stylo's IntersectionObserverMargin
let mut input = ParserInput::new(value); let mut input = ParserInput::new(value);
let mut parser = Parser::new(&mut input); let mut parser = Parser::new(&mut input);
@ -825,7 +832,7 @@ fn parse_a_margin(value: Option<&DOMString>) -> Result<IntersectionObserverRootM
); );
parser parser
.parse_entirely(|p| IntersectionObserverRootMargin::parse(&context, p)) .parse_entirely(|p| IntersectionObserverMargin::parse(&context, p))
.map_err(|_| ()) .map_err(|_| ())
} }

View file

@ -1,103 +0,0 @@
/* 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 https://mozilla.org/MPL/2.0/. */
//! Copy of Stylo Gecko's [`style::values::specified::gecko::IntersectionObserverRootMargin`] implementation.
//! TODO(#35907): make a thin wrapper and remove copied codes
use std::fmt;
use app_units::Au;
use cssparser::{Parser, Token, match_ignore_ascii_case};
use euclid::default::{Rect, SideOffsets2D};
use style::parser::{Parse, ParserContext};
use style::values::computed::{self, Length, LengthPercentage};
use style::values::generics::rect::Rect as StyleRect;
use style_traits::values::SequenceWriter;
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
fn parse_pixel_or_percent<'i>(
_context: &ParserContext,
input: &mut Parser<'i, '_>,
) -> Result<LengthPercentage, ParseError<'i>> {
let location = input.current_source_location();
let token = input.next()?;
let value = match *token {
Token::Dimension {
value, ref unit, ..
} => {
match_ignore_ascii_case! { unit,
"px" => Ok(LengthPercentage::new_length(Length::new(value))),
_ => Err(()),
}
},
Token::Percentage { unit_value, .. } => Ok(LengthPercentage::new_percent(
computed::Percentage(unit_value),
)),
_ => Err(()),
};
value.map_err(|()| location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
}
/// The value of an IntersectionObserver's rootMargin property.
///
/// Only bare px or percentage values are allowed. Other length units and
/// calc() values are not allowed.
///
/// <https://w3c.github.io/IntersectionObserver/#parse-a-root-margin>
#[repr(transparent)]
pub struct IntersectionObserverRootMargin(pub StyleRect<LengthPercentage>);
impl Parse for IntersectionObserverRootMargin {
fn parse<'i>(
context: &ParserContext,
input: &mut Parser<'i, '_>,
) -> Result<Self, ParseError<'i>> {
use style::Zero;
if input.is_exhausted() {
// If there are zero elements in tokens, set tokens to ["0px"].
return Ok(IntersectionObserverRootMargin(StyleRect::all(
LengthPercentage::zero(),
)));
}
let rect = StyleRect::parse_with(context, input, parse_pixel_or_percent)?;
Ok(IntersectionObserverRootMargin(rect))
}
}
// Strictly speaking this is not ToCss. It's serializing for DOM. But
// we can just reuse the infrastructure of this.
//
// <https://w3c.github.io/IntersectionObserver/#dom-intersectionobserver-rootmargin>
impl ToCss for IntersectionObserverRootMargin {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: fmt::Write,
{
// We cannot use the ToCss impl of Rect, because that would
// merge items when they are equal. We want to list them all.
let mut writer = SequenceWriter::new(dest, " ");
let rect = &self.0;
writer.item(&rect.0)?;
writer.item(&rect.1)?;
writer.item(&rect.2)?;
writer.item(&rect.3)
}
}
// TODO(stevennovaryo): move this to the wrapper later
impl IntersectionObserverRootMargin {
// Resolve to used values.
pub(crate) fn resolve_percentages_with_basis(
&self,
containing_block: Rect<Au>,
) -> SideOffsets2D<Au> {
let inner = &self.0;
SideOffsets2D::new(
inner.0.to_used_value(containing_block.height()),
inner.1.to_used_value(containing_block.width()),
inner.2.to_used_value(containing_block.height()),
inner.3.to_used_value(containing_block.width()),
)
}
}

View file

@ -438,7 +438,6 @@ pub(crate) mod imagedata;
pub(crate) mod inputevent; pub(crate) mod inputevent;
pub(crate) mod intersectionobserver; pub(crate) mod intersectionobserver;
pub(crate) mod intersectionobserverentry; pub(crate) mod intersectionobserverentry;
pub(crate) mod intersectionobserverrootmargin;
pub(crate) mod keyboardevent; pub(crate) mod keyboardevent;
pub(crate) mod location; pub(crate) mod location;
pub(crate) mod mediadeviceinfo; pub(crate) mod mediadeviceinfo;