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 extern crate app_units;
14 #[macro_use]
15 extern crate bitflags;
16 #[macro_use]
17 extern crate cssparser;
18 extern crate euclid;
19 #[macro_use]
20 extern crate lazy_static;
21 extern crate malloc_size_of;
22 #[macro_use]
23 extern crate malloc_size_of_derive;
24 extern crate selectors;
25 #[macro_use]
26 extern crate serde;
27 extern crate servo_arc;
28 #[cfg(feature = "servo")]
29 extern crate servo_atoms;
30 #[cfg(feature = "servo")]
31 extern crate servo_url;
32 extern crate to_shmem;
33 #[macro_use]
34 extern crate to_shmem_derive;
35 #[cfg(feature = "servo")]
36 extern crate webrender_api;
37 #[cfg(feature = "servo")]
38 pub use webrender_api::units::DevicePixel;
39 
40 use cssparser::{CowRcStr, Token};
41 use selectors::parser::SelectorParseErrorKind;
42 #[cfg(feature = "servo")]
43 use servo_atoms::Atom;
44 
45 /// One hardware pixel.
46 ///
47 /// This unit corresponds to the smallest addressable element of the display hardware.
48 #[cfg(not(feature = "servo"))]
49 #[derive(Clone, Copy, Debug)]
50 pub enum DevicePixel {}
51 
52 /// Represents a mobile style pinch zoom factor.
53 /// TODO(gw): Once WR supports pinch zoom, use a type directly from webrender_api.
54 #[derive(Clone, Copy, Debug, PartialEq)]
55 #[cfg_attr(feature = "servo", derive(Deserialize, Serialize, MallocSizeOf))]
56 pub struct PinchZoomFactor(f32);
57 
58 impl PinchZoomFactor {
59     /// Construct a new pinch zoom factor.
new(scale: f32) -> PinchZoomFactor60     pub fn new(scale: f32) -> PinchZoomFactor {
61         PinchZoomFactor(scale)
62     }
63 
64     /// Get the pinch zoom factor as an untyped float.
get(&self) -> f3265     pub fn get(&self) -> f32 {
66         self.0
67     }
68 }
69 
70 /// One CSS "px" in the coordinate system of the "initial viewport":
71 /// <http://www.w3.org/TR/css-device-adapt/#initial-viewport>
72 ///
73 /// `CSSPixel` is equal to `DeviceIndependentPixel` times a "page zoom" factor controlled by the user.  This is
74 /// the desktop-style "full page" zoom that enlarges content but then reflows the layout viewport
75 /// so it still exactly fits the visible area.
76 ///
77 /// At the default zoom level of 100%, one `CSSPixel` is equal to one `DeviceIndependentPixel`.  However, if the
78 /// document is zoomed in or out then this scale may be larger or smaller.
79 #[derive(Clone, Copy, Debug)]
80 pub enum CSSPixel {}
81 
82 // In summary, the hierarchy of pixel units and the factors to convert from one to the next:
83 //
84 // DevicePixel
85 //   / hidpi_ratio => DeviceIndependentPixel
86 //     / desktop_zoom => CSSPixel
87 
88 pub mod arc_slice;
89 pub mod dom;
90 pub mod specified_value_info;
91 #[macro_use]
92 pub mod values;
93 #[macro_use]
94 pub mod viewport;
95 pub mod owned_slice;
96 pub mod owned_str;
97 
98 pub use crate::specified_value_info::{CssType, KeywordsCollectFn, SpecifiedValueInfo};
99 pub use crate::values::{
100     Comma, CommaWithSpace, CssWriter, OneOrMoreSeparated, Separator, Space, ToCss,
101 };
102 
103 /// The error type for all CSS parsing routines.
104 pub type ParseError<'i> = cssparser::ParseError<'i, StyleParseErrorKind<'i>>;
105 
106 /// Error in property value parsing
107 pub type ValueParseError<'i> = cssparser::ParseError<'i, ValueParseErrorKind<'i>>;
108 
109 #[derive(Clone, Debug, PartialEq)]
110 /// Errors that can be encountered while parsing CSS values.
111 pub enum StyleParseErrorKind<'i> {
112     /// A bad URL token in a DVB.
113     BadUrlInDeclarationValueBlock(CowRcStr<'i>),
114     /// A bad string token in a DVB.
115     BadStringInDeclarationValueBlock(CowRcStr<'i>),
116     /// Unexpected closing parenthesis in a DVB.
117     UnbalancedCloseParenthesisInDeclarationValueBlock,
118     /// Unexpected closing bracket in a DVB.
119     UnbalancedCloseSquareBracketInDeclarationValueBlock,
120     /// Unexpected closing curly bracket in a DVB.
121     UnbalancedCloseCurlyBracketInDeclarationValueBlock,
122     /// A property declaration value had input remaining after successfully parsing.
123     PropertyDeclarationValueNotExhausted,
124     /// An unexpected dimension token was encountered.
125     UnexpectedDimension(CowRcStr<'i>),
126     /// Missing or invalid media feature name.
127     MediaQueryExpectedFeatureName(CowRcStr<'i>),
128     /// Missing or invalid media feature value.
129     MediaQueryExpectedFeatureValue,
130     /// A media feature range operator was not expected.
131     MediaQueryUnexpectedOperator,
132     /// min- or max- properties must have a value.
133     RangedExpressionWithNoValue,
134     /// A function was encountered that was not expected.
135     UnexpectedFunction(CowRcStr<'i>),
136     /// @namespace must be before any rule but @charset and @import
137     UnexpectedNamespaceRule,
138     /// @import must be before any rule but @charset
139     UnexpectedImportRule,
140     /// @import rules are disallowed in the parser.
141     DisallowedImportRule,
142     /// Unexpected @charset rule encountered.
143     UnexpectedCharsetRule,
144     /// Unsupported @ rule
145     UnsupportedAtRule(CowRcStr<'i>),
146     /// A placeholder for many sources of errors that require more specific variants.
147     UnspecifiedError,
148     /// An unexpected token was found within a namespace rule.
149     UnexpectedTokenWithinNamespace(Token<'i>),
150     /// An error was encountered while parsing a property value.
151     ValueError(ValueParseErrorKind<'i>),
152     /// An error was encountered while parsing a selector
153     SelectorError(SelectorParseErrorKind<'i>),
154     /// The property declaration was for an unknown property.
155     UnknownProperty(CowRcStr<'i>),
156     /// The property declaration was for a disabled experimental property.
157     ExperimentalProperty,
158     /// The property declaration contained an invalid color value.
159     InvalidColor(CowRcStr<'i>, Token<'i>),
160     /// The property declaration contained an invalid filter value.
161     InvalidFilter(CowRcStr<'i>, Token<'i>),
162     /// The property declaration contained an invalid value.
163     OtherInvalidValue(CowRcStr<'i>),
164     /// The declaration contained an animation property, and we were parsing
165     /// this as a keyframe block (so that property should be ignored).
166     ///
167     /// See: https://drafts.csswg.org/css-animations/#keyframes
168     AnimationPropertyInKeyframeBlock,
169     /// The property is not allowed within a page rule.
170     NotAllowedInPageRule,
171 }
172 
173 impl<'i> From<ValueParseErrorKind<'i>> for StyleParseErrorKind<'i> {
from(this: ValueParseErrorKind<'i>) -> Self174     fn from(this: ValueParseErrorKind<'i>) -> Self {
175         StyleParseErrorKind::ValueError(this)
176     }
177 }
178 
179 impl<'i> From<SelectorParseErrorKind<'i>> for StyleParseErrorKind<'i> {
from(this: SelectorParseErrorKind<'i>) -> Self180     fn from(this: SelectorParseErrorKind<'i>) -> Self {
181         StyleParseErrorKind::SelectorError(this)
182     }
183 }
184 
185 /// Specific errors that can be encountered while parsing property values.
186 #[derive(Clone, Debug, PartialEq)]
187 pub enum ValueParseErrorKind<'i> {
188     /// An invalid token was encountered while parsing a color value.
189     InvalidColor(Token<'i>),
190     /// An invalid filter value was encountered.
191     InvalidFilter(Token<'i>),
192 }
193 
194 impl<'i> StyleParseErrorKind<'i> {
195     /// Create an InvalidValue parse error
new_invalid<S>(name: S, value_error: ParseError<'i>) -> ParseError<'i> where S: Into<CowRcStr<'i>>,196     pub fn new_invalid<S>(name: S, value_error: ParseError<'i>) -> ParseError<'i>
197     where
198         S: Into<CowRcStr<'i>>,
199     {
200         let name = name.into();
201         let variant = match value_error.kind {
202             cssparser::ParseErrorKind::Custom(StyleParseErrorKind::ValueError(e)) => match e {
203                 ValueParseErrorKind::InvalidColor(token) => {
204                     StyleParseErrorKind::InvalidColor(name, token)
205                 },
206                 ValueParseErrorKind::InvalidFilter(token) => {
207                     StyleParseErrorKind::InvalidFilter(name, token)
208                 },
209             },
210             _ => StyleParseErrorKind::OtherInvalidValue(name),
211         };
212         cssparser::ParseError {
213             kind: cssparser::ParseErrorKind::Custom(variant),
214             location: value_error.location,
215         }
216     }
217 }
218 
219 bitflags! {
220     /// The mode to use when parsing values.
221     pub struct ParsingMode: u8 {
222         /// In CSS; lengths must have units, except for zero values, where the unit can be omitted.
223         /// <https://www.w3.org/TR/css3-values/#lengths>
224         const DEFAULT = 0x00;
225         /// In SVG; a coordinate or length value without a unit identifier (e.g., "25") is assumed
226         /// to be in user units (px).
227         /// <https://www.w3.org/TR/SVG/coords.html#Units>
228         const ALLOW_UNITLESS_LENGTH = 0x01;
229         /// In SVG; out-of-range values are not treated as an error in parsing.
230         /// <https://www.w3.org/TR/SVG/implnote.html#RangeClamping>
231         const ALLOW_ALL_NUMERIC_VALUES = 0x02;
232     }
233 }
234 
235 impl ParsingMode {
236     /// Whether the parsing mode allows unitless lengths for non-zero values to be intpreted as px.
237     #[inline]
allows_unitless_lengths(&self) -> bool238     pub fn allows_unitless_lengths(&self) -> bool {
239         self.intersects(ParsingMode::ALLOW_UNITLESS_LENGTH)
240     }
241 
242     /// Whether the parsing mode allows all numeric values.
243     #[inline]
allows_all_numeric_values(&self) -> bool244     pub fn allows_all_numeric_values(&self) -> bool {
245         self.intersects(ParsingMode::ALLOW_ALL_NUMERIC_VALUES)
246     }
247 }
248 
249 #[cfg(feature = "servo")]
250 /// Speculatively execute paint code in the worklet thread pool.
251 pub trait SpeculativePainter: Send + Sync {
252     /// <https://drafts.css-houdini.org/css-paint-api/#draw-a-paint-image>
speculatively_draw_a_paint_image( &self, properties: Vec<(Atom, String)>, arguments: Vec<String>, )253     fn speculatively_draw_a_paint_image(
254         &self,
255         properties: Vec<(Atom, String)>,
256         arguments: Vec<String>,
257     );
258 }
259