style/values/specified/
intersection_observer.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5//! Specified types for intersection observer that utilizes style parser.
6//!
7//! <https://w3c.github.io/IntersectionObserver/#intersection-observer-api>
8
9use crate::parser::{Parse, ParserContext};
10use crate::values::computed::{self, Length, LengthPercentage};
11use crate::values::generics::rect::Rect;
12use cssparser::{Parser, Token};
13use std::fmt;
14use style_traits::values::SequenceWriter;
15use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
16
17fn parse_pixel_or_percent<'i, 't>(
18    _context: &ParserContext,
19    input: &mut Parser<'i, 't>,
20) -> Result<LengthPercentage, ParseError<'i>> {
21    let location = input.current_source_location();
22    let token = input.next()?;
23    let value = match *token {
24        Token::Dimension {
25            value, ref unit, ..
26        } => {
27            match_ignore_ascii_case! { unit,
28                "px" => Ok(LengthPercentage::new_length(Length::new(value))),
29                _ => Err(()),
30            }
31        },
32        Token::Percentage { unit_value, .. } => Ok(LengthPercentage::new_percent(
33            computed::Percentage(unit_value),
34        )),
35        _ => Err(()),
36    };
37    value.map_err(|()| location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
38}
39
40/// The value of an IntersectionObserver's (root or scroll) margin property.
41///
42/// Only bare px or percentage values are allowed. Other length units and
43/// calc() values are not allowed.
44///
45/// <https://w3c.github.io/IntersectionObserver/#parse-a-margin>
46#[repr(transparent)]
47pub struct IntersectionObserverMargin(pub Rect<LengthPercentage>);
48
49impl Parse for IntersectionObserverMargin {
50    fn parse<'i, 't>(
51        context: &ParserContext,
52        input: &mut Parser<'i, 't>,
53    ) -> Result<Self, ParseError<'i>> {
54        use crate::Zero;
55        if input.is_exhausted() {
56            // If there are zero elements in tokens, set tokens to ["0px"].
57            return Ok(IntersectionObserverMargin(Rect::all(
58                LengthPercentage::zero(),
59            )));
60        }
61        let rect = Rect::parse_with(context, input, parse_pixel_or_percent)?;
62        Ok(IntersectionObserverMargin(rect))
63    }
64}
65
66// Strictly speaking this is not ToCss. It's serializing for DOM. But
67// we can just reuse the infrastructure of this.
68//
69// <https://w3c.github.io/IntersectionObserver/#dom-intersectionobserver-rootmargin>
70impl ToCss for IntersectionObserverMargin {
71    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
72    where
73        W: fmt::Write,
74    {
75        // We cannot use the ToCss impl of Rect, because that would
76        // merge items when they are equal. We want to list them all.
77        let mut writer = SequenceWriter::new(dest, " ");
78        let rect = &self.0;
79        writer.item(&rect.0)?;
80        writer.item(&rect.1)?;
81        writer.item(&rect.2)?;
82        writer.item(&rect.3)
83    }
84}