Skip to main content

style_traits/
lib.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//! This module contains shared types and messages for use by devtools/script.
6//! The traits are here instead of in script so that the devtools crate can be
7//! modified independently of the rest of Servo.
8
9#![crate_name = "style_traits"]
10#![crate_type = "rlib"]
11#![deny(unsafe_code, missing_docs)]
12
13#[macro_use]
14extern crate malloc_size_of_derive;
15#[macro_use]
16extern crate serde;
17#[macro_use]
18extern crate to_shmem_derive;
19#[cfg(feature = "servo")]
20extern crate url;
21
22use bitflags::bitflags;
23use selectors::parser::SelectorParseErrorKind;
24#[cfg(feature = "servo")]
25use stylo_atoms::Atom;
26
27/// One hardware pixel.
28///
29/// This unit corresponds to the smallest addressable element of the display hardware.
30#[derive(Clone, Copy, Debug)]
31pub enum DevicePixel {}
32
33/// Represents a mobile style pinch zoom factor.
34#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
35pub struct PinchZoomFactor(f32);
36
37impl PinchZoomFactor {
38    /// Construct a new pinch zoom factor.
39    pub fn new(scale: f32) -> PinchZoomFactor {
40        PinchZoomFactor(scale)
41    }
42
43    /// Get the pinch zoom factor as an untyped float.
44    pub fn get(&self) -> f32 {
45        self.0
46    }
47}
48
49/// One CSS "px" in the coordinate system of the "initial viewport":
50/// <http://www.w3.org/TR/css-device-adapt/#initial-viewport>
51///
52/// `CSSPixel` is equal to `DeviceIndependentPixel` times a "page zoom" factor controlled by the user.  This is
53/// the desktop-style "full page" zoom that enlarges content but then reflows the layout viewport
54/// so it still exactly fits the visible area.
55///
56/// At the default zoom level of 100%, one `CSSPixel` is equal to one `DeviceIndependentPixel`.  However, if the
57/// document is zoomed in or out then this scale may be larger or smaller.
58#[derive(Clone, Copy, Debug)]
59pub enum CSSPixel {}
60
61// In summary, the hierarchy of pixel units and the factors to convert from one to the next:
62//
63// DevicePixel
64//   / hidpi_ratio => DeviceIndependentPixel
65//     / desktop_zoom => CSSPixel
66
67pub mod arc_slice;
68pub mod dom;
69pub mod specified_value_info;
70#[macro_use]
71pub mod values;
72pub mod owned_array;
73pub mod owned_slice;
74pub mod owned_str;
75
76pub use crate::specified_value_info::{CssType, KeywordsCollectFn, SpecifiedValueInfo};
77pub use crate::values::{
78    Comma, CommaWithSpace, CssString, CssStringWriter, CssWriter, OneOrMoreSeparated, Separator,
79    Space, ToCss,
80};
81
82/// The error type for all CSS parsing routines.
83pub type ParseError = cssparser::ParseError<StyleParseErrorKind>;
84
85#[derive(Clone, Debug, PartialEq)]
86/// Errors that can be encountered while parsing CSS values.
87pub enum StyleParseErrorKind {
88    /// A bad URL token in a DVB.
89    BadUrlInDeclarationValueBlock,
90    /// A bad string token in a DVB.
91    BadStringInDeclarationValueBlock,
92    /// Unexpected closing parenthesis in a DVB.
93    UnbalancedCloseParenthesisInDeclarationValueBlock,
94    /// Unexpected closing bracket in a DVB.
95    UnbalancedCloseSquareBracketInDeclarationValueBlock,
96    /// Unexpected closing curly bracket in a DVB.
97    UnbalancedCloseCurlyBracketInDeclarationValueBlock,
98    /// A property declaration value had input remaining after successfully parsing.
99    PropertyDeclarationValueNotExhausted,
100    /// An unexpected dimension token was encountered.
101    UnexpectedDimension,
102    /// Missing or invalid media feature name.
103    MediaQueryExpectedFeatureName,
104    /// Missing or invalid media feature value.
105    MediaQueryExpectedFeatureValue,
106    /// A media feature range operator was not expected.
107    MediaQueryUnexpectedOperator,
108    /// min- or max- properties must have a value.
109    RangedExpressionWithNoValue,
110    /// A function was encountered that was not expected.
111    UnexpectedFunction,
112    /// Error encountered parsing a @property's `syntax` descriptor
113    PropertySyntaxField(PropertySyntaxParseError),
114    /// Error encountered parsing a @property's `inherits` descriptor.
115    ///
116    /// TODO(zrhoffman, bug 1920365): Include the custom property name in error messages.
117    PropertyInheritsField(PropertyInheritsParseError),
118    /// @namespace must be before any rule but @charset and @import
119    UnexpectedNamespaceRule,
120    /// @import must be before any rule but @charset
121    UnexpectedImportRule,
122    /// @import rules are disallowed in the parser.
123    DisallowedImportRule,
124    /// Unexpected @charset rule encountered.
125    UnexpectedCharsetRule,
126    /// The @property `<custom-property-name>` must start with `--`
127    UnexpectedIdent,
128    /// A placeholder for many sources of errors that require more specific variants.
129    UnspecifiedError,
130    /// An unexpected token was found within a namespace rule.
131    UnexpectedTokenWithinNamespace,
132    /// An error was encountered while parsing a selector
133    SelectorError(SelectorParseErrorKind),
134    /// The property declaration was for an unknown property.
135    UnknownProperty,
136    /// The property declaration was for a disabled experimental property.
137    ExperimentalProperty,
138    /// The property declaration contained an invalid value.
139    OtherInvalidValue,
140    /// `!important` declarations are disallowed in `@position-try` or keyframes.
141    UnexpectedImportantDeclaration,
142}
143
144impl From<SelectorParseErrorKind> for StyleParseErrorKind {
145    fn from(this: SelectorParseErrorKind) -> Self {
146        StyleParseErrorKind::SelectorError(this)
147    }
148}
149
150/// Errors that can be encountered while parsing the @property rule's syntax descriptor.
151#[derive(Clone, Debug, PartialEq)]
152pub enum PropertySyntaxParseError {
153    /// The syntax descriptor is required for the @property rule to be valid; if it’s missing, the
154    /// @property rule is invalid.
155    ///
156    /// <https://drafts.css-houdini.org/css-properties-values-api-1/#ref-for-descdef-property-syntax②>
157    NoSyntax,
158    /// The string's length was 0.
159    EmptyInput,
160    /// A non-whitespace, non-pipe character was fount after parsing a component.
161    ExpectedPipeBetweenComponents,
162    /// The start of an identifier was expected but not found.
163    ///
164    /// <https://drafts.csswg.org/css-syntax-3/#name-start-code-point>
165    InvalidNameStart,
166    /// The name is not a valid `<ident>`.
167    InvalidName,
168    /// The data type name was not closed.
169    ///
170    /// <https://drafts.css-houdini.org/css-properties-values-api-1/#consume-data-type-name>
171    UnclosedDataTypeName,
172    /// The next byte was expected while parsing, but EOF was found instead.
173    UnexpectedEOF,
174    /// The data type is not a supported syntax component name.
175    ///
176    /// <https://drafts.css-houdini.org/css-properties-values-api-1/#supported-names>
177    UnknownDataTypeName,
178}
179
180/// Errors that can be encountered while parsing the @property rule's inherits descriptor.
181#[derive(Clone, Debug, PartialEq)]
182pub enum PropertyInheritsParseError {
183    /// The inherits descriptor is required for the @property rule to be valid; if it’s missing,
184    /// the @property rule is invalid.
185    ///
186    /// <https://drafts.css-houdini.org/css-properties-values-api-1/#ref-for-descdef-property-inherits②>
187    NoInherits,
188
189    /// The inherits descriptor must successfully parse as `true` or `false`.
190    InvalidInherits,
191}
192
193bitflags! {
194    /// The mode to use when parsing values.
195    #[derive(Clone, Copy, Eq, PartialEq)]
196    #[repr(C)]
197    pub struct ParsingMode: u8 {
198        /// In CSS; lengths must have units, except for zero values, where the unit can be omitted.
199        /// <https://www.w3.org/TR/css3-values/#lengths>
200        const DEFAULT = 0;
201        /// In SVG; a coordinate or length value without a unit identifier (e.g., "25") is assumed
202        /// to be in user units (px).
203        /// <https://www.w3.org/TR/SVG/coords.html#Units>
204        const ALLOW_UNITLESS_LENGTH = 1;
205        /// In SVG; out-of-range values are not treated as an error in parsing.
206        /// <https://www.w3.org/TR/SVG/implnote.html#RangeClamping>
207        const ALLOW_ALL_NUMERIC_VALUES = 1 << 1;
208        /// In CSS Properties and Values, the initial value must be computationally
209        /// independent.
210        /// <https://drafts.css-houdini.org/css-properties-values-api-1/#ref-for-computationally-independent%E2%91%A0>
211        const DISALLOW_COMPUTATIONALLY_DEPENDENT = 1 << 2;
212        /// In Typed OM; unitless zero must not be interpreted as a length.
213        const DISALLOW_UNITLESS_ZERO_LENGTH = 1 << 3;
214        /// Media query conditions in the preludes for @media, @custom-media, and @import.
215        /// <https://drafts.csswg.org/mediaqueries/>
216        const MEDIA_QUERY_CONDITION = 1 << 4;
217    }
218}
219
220impl ParsingMode {
221    /// Whether the parsing mode allows unitless lengths for non-zero values to be intpreted as px.
222    #[inline]
223    pub fn allows_unitless_lengths(&self) -> bool {
224        self.intersects(ParsingMode::ALLOW_UNITLESS_LENGTH)
225    }
226
227    /// Whether the parsing mode allows all numeric values.
228    #[inline]
229    pub fn allows_all_numeric_values(&self) -> bool {
230        self.intersects(ParsingMode::ALLOW_ALL_NUMERIC_VALUES)
231    }
232
233    /// Whether the parsing mode allows units or functions that are not computationally independent.
234    #[inline]
235    pub fn allows_computational_dependence(&self) -> bool {
236        !self.intersects(ParsingMode::DISALLOW_COMPUTATIONALLY_DEPENDENT)
237    }
238
239    /// Whether the parsing mode allows unitless zero lengths to be interpreted as px.
240    #[inline]
241    pub fn allows_unitless_zero_lengths(&self) -> bool {
242        !self.intersects(ParsingMode::DISALLOW_UNITLESS_ZERO_LENGTH)
243    }
244}
245
246#[cfg(feature = "servo")]
247/// Speculatively execute paint code in the worklet thread pool.
248pub trait SpeculativePainter: Send + Sync {
249    /// <https://drafts.css-houdini.org/css-paint-api/#draw-a-paint-image>
250    fn speculatively_draw_a_paint_image(
251        &self,
252        properties: Vec<(Atom, String)>,
253        arguments: Vec<String>,
254    );
255}