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 http://mozilla.org/MPL/2.0/. */
4 
5 // This file is a Mako template: http://www.makotemplates.org/
6 
7 // Please note that valid Rust syntax may be mangled by the Mako parser.
8 // For example, Vec<&Foo> will be mangled as Vec&Foo>. To work around these issues, the code
9 // can be escaped. In the above example, Vec<<&Foo> or Vec< &Foo> achieves the desired result of Vec<&Foo>.
10 
11 <%namespace name="helpers" file="/helpers.mako.rs" />
12 
13 #[cfg(feature = "servo")]
14 use app_units::Au;
15 use dom::TElement;
16 use custom_properties::CustomPropertiesBuilder;
17 use servo_arc::{Arc, UniqueArc};
18 use smallbitvec::SmallBitVec;
19 use std::borrow::Cow;
20 use std::{ops, ptr};
21 use std::cell::RefCell;
22 use std::fmt::{self, Write};
23 use std::mem::{self, ManuallyDrop};
24 
25 #[cfg(feature = "servo")] use cssparser::RGBA;
26 use cssparser::{CowRcStr, Parser, TokenSerializationType, serialize_identifier};
27 use cssparser::ParserInput;
28 #[cfg(feature = "servo")] use euclid::SideOffsets2D;
29 use context::QuirksMode;
30 use font_metrics::FontMetricsProvider;
31 #[cfg(feature = "gecko")] use gecko_bindings::bindings;
32 #[cfg(feature = "gecko")] use gecko_bindings::structs::{self, nsCSSPropertyID};
33 #[cfg(feature = "servo")] use logical_geometry::LogicalMargin;
34 #[cfg(feature = "servo")] use computed_values;
35 use logical_geometry::WritingMode;
36 #[cfg(feature = "gecko")] use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
37 use media_queries::Device;
38 use parser::ParserContext;
39 #[cfg(feature = "gecko")] use properties::longhands::system_font::SystemFont;
40 use rule_cache::{RuleCache, RuleCacheConditions};
41 use selector_parser::PseudoElement;
42 use selectors::parser::SelectorParseErrorKind;
43 #[cfg(feature = "servo")] use servo_config::prefs::PREFS;
44 use shared_lock::StylesheetGuards;
45 use style_traits::{CssWriter, ParseError, ParsingMode, StyleParseErrorKind, ToCss};
46 use stylesheets::{CssRuleType, Origin, UrlExtraData};
47 #[cfg(feature = "servo")] use values::Either;
48 use values::generics::text::LineHeight;
49 use values::computed;
50 use values::computed::NonNegativeLength;
51 use rule_tree::{CascadeLevel, StrongRuleNode};
52 use self::computed_value_flags::*;
53 use str::{CssString, CssStringBorrow, CssStringWriter};
54 use style_adjuster::StyleAdjuster;
55 
56 pub use self::declaration_block::*;
57 
58 #[cfg(feature = "gecko")]
59 #[macro_export]
60 macro_rules! property_name {
61     ($s: tt) => { atom!($s) }
62 }
63 
64 <%!
65     from data import Method, Keyword, to_rust_ident, to_camel_case, SYSTEM_FONT_LONGHANDS
66     import os.path
67 %>
68 
69 #[path="${repr(os.path.join(os.path.dirname(__file__), 'computed_value_flags.rs'))[1:-1]}"]
70 pub mod computed_value_flags;
71 #[path="${repr(os.path.join(os.path.dirname(__file__), 'declaration_block.rs'))[1:-1]}"]
72 pub mod declaration_block;
73 
74 /// Conversion with fewer impls than From/Into
75 pub trait MaybeBoxed<Out> {
76     /// Convert
maybe_boxed(self) -> Out77     fn maybe_boxed(self) -> Out;
78 }
79 
80 impl<T> MaybeBoxed<T> for T {
81     #[inline]
maybe_boxed(self) -> T82     fn maybe_boxed(self) -> T { self }
83 }
84 
85 impl<T> MaybeBoxed<Box<T>> for T {
86     #[inline]
maybe_boxed(self) -> Box<T>87     fn maybe_boxed(self) -> Box<T> { Box::new(self) }
88 }
89 
90 macro_rules! expanded {
91     ( $( $name: ident: $value: expr ),+ ) => {
92         expanded!( $( $name: $value, )+ )
93     };
94     ( $( $name: ident: $value: expr, )+ ) => {
95         Longhands {
96             $(
97                 $name: MaybeBoxed::maybe_boxed($value),
98             )+
99         }
100     }
101 }
102 
103 /// A module with all the code for longhand properties.
104 #[allow(missing_docs)]
105 pub mod longhands {
106     <%include file="/longhand/background.mako.rs" />
107     <%include file="/longhand/border.mako.rs" />
108     <%include file="/longhand/box.mako.rs" />
109     <%include file="/longhand/color.mako.rs" />
110     <%include file="/longhand/column.mako.rs" />
111     <%include file="/longhand/counters.mako.rs" />
112     <%include file="/longhand/effects.mako.rs" />
113     <%include file="/longhand/font.mako.rs" />
114     <%include file="/longhand/inherited_box.mako.rs" />
115     <%include file="/longhand/inherited_table.mako.rs" />
116     <%include file="/longhand/inherited_text.mako.rs" />
117     <%include file="/longhand/list.mako.rs" />
118     <%include file="/longhand/margin.mako.rs" />
119     <%include file="/longhand/outline.mako.rs" />
120     <%include file="/longhand/padding.mako.rs" />
121     <%include file="/longhand/pointing.mako.rs" />
122     <%include file="/longhand/position.mako.rs" />
123     <%include file="/longhand/table.mako.rs" />
124     <%include file="/longhand/text.mako.rs" />
125     <%include file="/longhand/ui.mako.rs" />
126     <%include file="/longhand/inherited_svg.mako.rs" />
127     <%include file="/longhand/svg.mako.rs" />
128     <%include file="/longhand/xul.mako.rs" />
129 }
130 
131 macro_rules! unwrap_or_initial {
132     ($prop: ident) => (unwrap_or_initial!($prop, $prop));
133     ($prop: ident, $expr: expr) =>
134         ($expr.unwrap_or_else(|| $prop::get_initial_specified_value()));
135 }
136 
137 /// A module with code for all the shorthand css properties, and a few
138 /// serialization helpers.
139 #[allow(missing_docs)]
140 pub mod shorthands {
141     use cssparser::Parser;
142     use parser::{Parse, ParserContext};
143     use style_traits::{ParseError, StyleParseErrorKind};
144     use values::specified;
145 
146     <%include file="/shorthand/serialize.mako.rs" />
147     <%include file="/shorthand/background.mako.rs" />
148     <%include file="/shorthand/border.mako.rs" />
149     <%include file="/shorthand/box.mako.rs" />
150     <%include file="/shorthand/column.mako.rs" />
151     <%include file="/shorthand/font.mako.rs" />
152     <%include file="/shorthand/inherited_text.mako.rs" />
153     <%include file="/shorthand/list.mako.rs" />
154     <%include file="/shorthand/margin.mako.rs" />
155     <%include file="/shorthand/mask.mako.rs" />
156     <%include file="/shorthand/outline.mako.rs" />
157     <%include file="/shorthand/padding.mako.rs" />
158     <%include file="/shorthand/position.mako.rs" />
159     <%include file="/shorthand/inherited_svg.mako.rs" />
160     <%include file="/shorthand/text.mako.rs" />
161 
162     // We don't defined the 'all' shorthand using the regular helpers:shorthand
163     // mechanism, since it causes some very large types to be generated.
164     //
165     // Also, make sure logical properties appear before its physical
166     // counter-parts, in order to prevent bugs like:
167     //
168     //   https://bugzilla.mozilla.org/show_bug.cgi?id=1410028
169     //
170     // FIXME(emilio): Adopt the resolution from:
171     //
172     //   https://github.com/w3c/csswg-drafts/issues/1898
173     //
174     // when there is one, whatever that is.
175     <%
176         logical_longhands = []
177         other_longhands = []
178 
179         for p in data.longhands:
180             if p.name in ['direction', 'unicode-bidi']:
181                 continue;
182             if not p.enabled_in_content() and not p.experimental(product):
183                 continue;
184             if p.logical:
185                 logical_longhands.append(p.name)
186             else:
187                 other_longhands.append(p.name)
188 
189         data.declare_shorthand(
190             "all",
191             logical_longhands + other_longhands,
192             gecko_pref="layout.css.all-shorthand.enabled",
193             spec="https://drafts.csswg.org/css-cascade-3/#all-shorthand"
194         )
195     %>
196 
197     /// The max amount of longhands that the `all` shorthand will ever contain.
198     pub const ALL_SHORTHAND_MAX_LEN: usize = ${len(logical_longhands + other_longhands)};
199 }
200 
201 <%
202     from itertools import groupby
203 
204     # After this code, `data.longhands` is sorted in the following order:
205     # - first all keyword variants and all variants known to be Copy,
206     # - second all the other variants, such as all variants with the same field
207     #   have consecutive discriminants.
208     # The variable `variants` contain the same entries as `data.longhands` in
209     # the same order, but must exist separately to the data source, because
210     # we then need to add three additional variants `WideKeywordDeclaration`,
211     # `VariableDeclaration` and `CustomDeclaration`.
212 
213     variants = []
214     for property in data.longhands:
215         variants.append({
216             "name": property.camel_case,
217             "type": property.specified_type(),
218             "doc": "`" + property.name + "`",
219             "copy": property.specified_is_copy(),
220         })
221 
222     groups = {}
223     keyfunc = lambda x: x["type"]
224     sortkeys = {}
225     for ty, group in groupby(sorted(variants, key=keyfunc), keyfunc):
226         group = list(group)
227         groups[ty] = group
228         for v in group:
229             if len(group) == 1:
230                 sortkeys[v["name"]] = (not v["copy"], 1, v["name"], "")
231             else:
232                 sortkeys[v["name"]] = (not v["copy"], len(group), ty, v["name"])
233     variants.sort(key=lambda x: sortkeys[x["name"]])
234 
235     # It is extremely important to sort the `data.longhands` array here so
236     # that it is in the same order as `variants`, for `LonghandId` and
237     # `PropertyDeclarationId` to coincide.
238     data.longhands.sort(key=lambda x: sortkeys[x.camel_case])
239 %>
240 
241 // WARNING: It is *really* important for the variants of `LonghandId`
242 // and `PropertyDeclaration` to be defined in the exact same order,
243 // with the exception of `CSSWideKeyword`, `WithVariables` and `Custom`,
244 // which don't exist in `LonghandId`.
245 
246 <%
247     extra = [
248         {
249             "name": "CSSWideKeyword",
250             "type": "WideKeywordDeclaration",
251             "doc": "A CSS-wide keyword.",
252             "copy": False,
253         },
254         {
255             "name": "WithVariables",
256             "type": "VariableDeclaration",
257             "doc": "An unparsed declaration.",
258             "copy": False,
259         },
260         {
261             "name": "Custom",
262             "type": "CustomDeclaration",
263             "doc": "A custom property declaration.",
264             "copy": False,
265         },
266     ]
267     for v in extra:
268         variants.append(v)
269         groups[v["type"]] = [v]
270 %>
271 
272 /// Servo's representation for a property declaration.
273 #[repr(u16)]
274 pub enum PropertyDeclaration {
275     % for variant in variants:
276     /// ${variant["doc"]}
277     ${variant["name"]}(${variant["type"]}),
278     % endfor
279 }
280 
281 #[repr(C)]
282 struct PropertyDeclarationVariantRepr<T> {
283     tag: u16,
284     value: T
285 }
286 
287 impl Clone for PropertyDeclaration {
288     #[inline]
clone(&self) -> Self289     fn clone(&self) -> Self {
290         use self::PropertyDeclaration::*;
291 
292         <%
293             [copy, others] = [list(g) for _, g in groupby(variants, key=lambda x: not x["copy"])]
294         %>
295 
296         let self_tag = unsafe {
297             (*(self as *const _ as *const PropertyDeclarationVariantRepr<()>)).tag
298         };
299         if self_tag <= LonghandId::${copy[-1]["name"]} as u16 {
300             #[derive(Clone, Copy)]
301             #[repr(u16)]
302             enum CopyVariants {
303                 % for v in copy:
304                 _${v["name"]}(${v["type"]}),
305                 % endfor
306             }
307 
308             unsafe {
309                 let mut out = mem::uninitialized();
310                 ptr::write(
311                     &mut out as *mut _ as *mut CopyVariants,
312                     *(self as *const _ as *const CopyVariants),
313                 );
314                 return out;
315             }
316         }
317 
318         match *self {
319             ${" |\n".join("{}(..)".format(v["name"]) for v in copy)} => {
320                 unsafe { debug_unreachable!() }
321             }
322             % for ty, vs in groupby(others, key=lambda x: x["type"]):
323             <%
324                 vs = list(vs)
325             %>
326             % if len(vs) == 1:
327             ${vs[0]["name"]}(ref value) => {
328                 ${vs[0]["name"]}(value.clone())
329             }
330             % else:
331             ${" |\n".join("{}(ref value)".format(v["name"]) for v in vs)} => {
332                 unsafe {
333                     let mut out = ManuallyDrop::new(mem::uninitialized());
334                     ptr::write(
335                         &mut out as *mut _ as *mut PropertyDeclarationVariantRepr<${ty}>,
336                         PropertyDeclarationVariantRepr {
337                             tag: *(self as *const _ as *const u16),
338                             value: value.clone(),
339                         },
340                     );
341                     ManuallyDrop::into_inner(out)
342                 }
343             }
344             % endif
345             % endfor
346         }
347     }
348 }
349 
350 impl PartialEq for PropertyDeclaration {
351     #[inline]
eq(&self, other: &Self) -> bool352     fn eq(&self, other: &Self) -> bool {
353         use self::PropertyDeclaration::*;
354 
355         unsafe {
356             let this_repr =
357                 &*(self as *const _ as *const PropertyDeclarationVariantRepr<()>);
358             let other_repr =
359                 &*(other as *const _ as *const PropertyDeclarationVariantRepr<()>);
360             if this_repr.tag != other_repr.tag {
361                 return false;
362             }
363             match *self {
364                 % for ty, vs in groupby(variants, key=lambda x: x["type"]):
365                 ${" |\n".join("{}(ref this)".format(v["name"]) for v in vs)} => {
366                     let other_repr =
367                         &*(other as *const _ as *const PropertyDeclarationVariantRepr<${ty}>);
368                     *this == other_repr.value
369                 }
370                 % endfor
371             }
372         }
373     }
374 }
375 
376 #[cfg(feature = "gecko")]
377 impl MallocSizeOf for PropertyDeclaration {
378     #[inline]
size_of(&self, ops: &mut MallocSizeOfOps) -> usize379     fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
380         use self::PropertyDeclaration::*;
381 
382         match *self {
383             % for ty, vs in groupby(variants, key=lambda x: x["type"]):
384             ${" | ".join("{}(ref value)".format(v["name"]) for v in vs)} => {
385                 value.size_of(ops)
386             }
387             % endfor
388         }
389     }
390 }
391 
392 
393 impl PropertyDeclaration {
394     /// Like the method on ToCss, but without the type parameter to avoid
395     /// accidentally monomorphizing this large function multiple times for
396     /// different writers.
to_css(&self, dest: &mut CssStringWriter) -> fmt::Result397     pub fn to_css(&self, dest: &mut CssStringWriter) -> fmt::Result {
398         use self::PropertyDeclaration::*;
399 
400         let mut dest = CssWriter::new(dest);
401         match *self {
402             % for ty, vs in groupby(variants, key=lambda x: x["type"]):
403             ${" | ".join("{}(ref value)".format(v["name"]) for v in vs)} => {
404                 value.to_css(&mut dest)
405             }
406             % endfor
407         }
408     }
409 }
410 
411 /// A module with all the code related to animated properties.
412 ///
413 /// This needs to be "included" by mako at least after all longhand modules,
414 /// given they populate the global data.
415 pub mod animated_properties {
416     <%include file="/helpers/animated_properties.mako.rs" />
417 }
418 
419 /// A longhand or shorthand property.
420 #[derive(Clone, Copy, Debug)]
421 pub struct NonCustomPropertyId(usize);
422 
423 impl NonCustomPropertyId {
424     #[cfg(feature = "gecko")]
to_nscsspropertyid(self) -> nsCSSPropertyID425     fn to_nscsspropertyid(self) -> nsCSSPropertyID {
426         static MAP: [nsCSSPropertyID; ${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())}] = [
427             % for property in data.longhands:
428                 ${helpers.to_nscsspropertyid(property.ident)},
429             % endfor
430             % for property in data.shorthands:
431                 ${helpers.to_nscsspropertyid(property.ident)},
432             % endfor
433             % for property in data.all_aliases():
434                 ${helpers.alias_to_nscsspropertyid(property.ident)},
435             % endfor
436         ];
437 
438         MAP[self.0]
439     }
440 
441     #[inline]
enabled_for_all_content(self) -> bool442     fn enabled_for_all_content(self) -> bool {
443         ${static_non_custom_property_id_set(
444             "EXPERIMENTAL",
445             lambda p: p.experimental(product)
446         )}
447 
448         ${static_non_custom_property_id_set(
449             "ALWAYS_ENABLED",
450             lambda p: (not p.experimental(product)) and p.enabled_in_content()
451         )}
452 
453         let passes_pref_check = || {
454             % if product == "servo":
455                 static PREF_NAME: [Option< &str>; ${len(data.longhands) + len(data.shorthands)}] = [
456                     % for property in data.longhands + data.shorthands:
457                         % if property.servo_pref:
458                             Some("${property.servo_pref}"),
459                         % else:
460                             None,
461                         % endif
462                     % endfor
463                 ];
464                 let pref = match PREF_NAME[self.0] {
465                     None => return true,
466                     Some(pref) => pref,
467                 };
468 
469                 PREFS.get(pref).as_boolean().unwrap_or(false)
470             % else:
471                 unsafe { structs::nsCSSProps_gPropertyEnabled[self.to_nscsspropertyid() as usize] }
472             % endif
473         };
474 
475         if ALWAYS_ENABLED.contains(self) {
476             return true
477         }
478 
479         if EXPERIMENTAL.contains(self) && passes_pref_check() {
480             return true
481         }
482 
483         false
484     }
485 
allowed_in(self, context: &ParserContext) -> bool486     fn allowed_in(self, context: &ParserContext) -> bool {
487         debug_assert!(
488             matches!(
489                 context.rule_type(),
490                 CssRuleType::Keyframe | CssRuleType::Page | CssRuleType::Style
491             ),
492             "Declarations are only expected inside a keyframe, page, or style rule."
493         );
494 
495         ${static_non_custom_property_id_set(
496             "DISALLOWED_IN_KEYFRAME_BLOCK",
497             lambda p: not p.allowed_in_keyframe_block
498         )}
499         ${static_non_custom_property_id_set(
500             "DISALLOWED_IN_PAGE_RULE",
501             lambda p: not p.allowed_in_page_rule
502         )}
503         match context.rule_type() {
504             CssRuleType::Keyframe if DISALLOWED_IN_KEYFRAME_BLOCK.contains(self) => {
505                 return false;
506             }
507             CssRuleType::Page if DISALLOWED_IN_PAGE_RULE.contains(self) => {
508                 return false;
509             }
510             _ => {}
511         }
512 
513         // The semantics of these are kinda hard to reason about, what follows
514         // is a description of the different combinations that can happen with
515         // these three sets.
516         //
517         // Experimental properties are generally controlled by prefs, but an
518         // experimental property explicitly enabled in certain context (UA or
519         // chrome sheets) is always usable in the context regardless of the
520         // pref value.
521         //
522         // Non-experimental properties are either normal properties which are
523         // usable everywhere, or internal-only properties which are only usable
524         // in certain context they are explicitly enabled in.
525         if self.enabled_for_all_content() {
526             return true;
527         }
528 
529         ${static_non_custom_property_id_set(
530             "ENABLED_IN_UA_SHEETS",
531             lambda p: p.explicitly_enabled_in_ua_sheets()
532         )}
533         ${static_non_custom_property_id_set(
534             "ENABLED_IN_CHROME",
535             lambda p: p.explicitly_enabled_in_chrome()
536         )}
537 
538         if context.stylesheet_origin == Origin::UserAgent &&
539             ENABLED_IN_UA_SHEETS.contains(self)
540         {
541             return true
542         }
543 
544         if context.chrome_rules_enabled() && ENABLED_IN_CHROME.contains(self) {
545             return true
546         }
547 
548         false
549     }
550 }
551 
552 impl From<LonghandId> for NonCustomPropertyId {
from(id: LonghandId) -> Self553     fn from(id: LonghandId) -> Self {
554         NonCustomPropertyId(id as usize)
555     }
556 }
557 
558 impl From<ShorthandId> for NonCustomPropertyId {
from(id: ShorthandId) -> Self559     fn from(id: ShorthandId) -> Self {
560         NonCustomPropertyId((id as usize) + ${len(data.longhands)})
561     }
562 }
563 
564 impl From<AliasId> for NonCustomPropertyId {
from(id: AliasId) -> Self565     fn from(id: AliasId) -> Self {
566         NonCustomPropertyId(id as usize + ${len(data.longhands) + len(data.shorthands)})
567     }
568 }
569 
570 /// A set of all properties
571 #[derive(Clone, PartialEq)]
572 pub struct NonCustomPropertyIdSet {
573     storage: [u32; (${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())} - 1 + 32) / 32]
574 }
575 
576 impl NonCustomPropertyIdSet {
577     /// Creates an empty `NonCustomPropertyIdSet`.
new() -> Self578     pub fn new() -> Self {
579         Self {
580             storage: Default::default(),
581         }
582     }
583 
584     /// Insert a non-custom-property in the set.
585     #[inline]
insert(&mut self, id: NonCustomPropertyId)586     pub fn insert(&mut self, id: NonCustomPropertyId) {
587         let bit = id.0;
588         self.storage[bit / 32] |= 1 << (bit % 32);
589     }
590 
591     /// Return whether the given property is in the set
592     #[inline]
contains(&self, id: NonCustomPropertyId) -> bool593     pub fn contains(&self, id: NonCustomPropertyId) -> bool {
594         let bit = id.0;
595         (self.storage[bit / 32] & (1 << (bit % 32))) != 0
596     }
597 }
598 
599 <%def name="static_non_custom_property_id_set(name, is_member)">
600 static ${name}: NonCustomPropertyIdSet = NonCustomPropertyIdSet {
601     <%
602         storage = [0] * ((len(data.longhands) + len(data.shorthands) + len(data.all_aliases()) - 1 + 32) / 32)
603         for i, property in enumerate(data.longhands + data.shorthands + data.all_aliases()):
604             if is_member(property):
605                 storage[i / 32] |= 1 << (i % 32)
606     %>
607     storage: [${", ".join("0x%x" % word for word in storage)}]
608 };
609 </%def>
610 
611 <%def name="static_longhand_id_set(name, is_member)">
612 static ${name}: LonghandIdSet = LonghandIdSet {
613     <%
614         storage = [0] * ((len(data.longhands) - 1 + 32) / 32)
615         for i, property in enumerate(data.longhands):
616             if is_member(property):
617                 storage[i / 32] |= 1 << (i % 32)
618     %>
619     storage: [${", ".join("0x%x" % word for word in storage)}]
620 };
621 </%def>
622 
623 /// A set of longhand properties
624 #[derive(Clone, Debug, MallocSizeOf, PartialEq)]
625 pub struct LonghandIdSet {
626     storage: [u32; (${len(data.longhands)} - 1 + 32) / 32]
627 }
628 
629 /// An iterator over a set of longhand ids.
630 pub struct LonghandIdSetIterator<'a> {
631     longhands: &'a LonghandIdSet,
632     cur: usize,
633 }
634 
635 impl<'a> Iterator for LonghandIdSetIterator<'a> {
636     type Item = LonghandId;
637 
next(&mut self) -> Option<Self::Item>638     fn next(&mut self) -> Option<Self::Item> {
639         use std::mem;
640 
641         loop {
642             if self.cur >= ${len(data.longhands)} {
643                 return None;
644             }
645 
646             let id: LonghandId = unsafe { mem::transmute(self.cur as u16) };
647             self.cur += 1;
648 
649             if self.longhands.contains(id) {
650                 return Some(id);
651             }
652         }
653     }
654 }
655 
656 impl LonghandIdSet {
657     /// Iterate over the current longhand id set.
iter(&self) -> LonghandIdSetIterator658     pub fn iter(&self) -> LonghandIdSetIterator {
659         LonghandIdSetIterator { longhands: self, cur: 0, }
660     }
661 
662     /// Returns whether this set contains at least every longhand that `other`
663     /// also contains.
contains_all(&self, other: &Self) -> bool664     pub fn contains_all(&self, other: &Self) -> bool {
665         for (self_cell, other_cell) in self.storage.iter().zip(other.storage.iter()) {
666             if (*self_cell & *other_cell) != *other_cell {
667                 return false;
668             }
669         }
670         true
671     }
672 
673     /// Returns whether this set contains any longhand that `other` also contains.
contains_any(&self, other: &Self) -> bool674     pub fn contains_any(&self, other: &Self) -> bool {
675         for (self_cell, other_cell) in self.storage.iter().zip(other.storage.iter()) {
676             if (*self_cell & *other_cell) != 0 {
677                 return true;
678             }
679         }
680         false
681     }
682 
683     /// Create an empty set
684     #[inline]
new() -> LonghandIdSet685     pub fn new() -> LonghandIdSet {
686         LonghandIdSet { storage: [0; (${len(data.longhands)} - 1 + 32) / 32] }
687     }
688 
689     /// Return whether the given property is in the set
690     #[inline]
contains(&self, id: LonghandId) -> bool691     pub fn contains(&self, id: LonghandId) -> bool {
692         let bit = id as usize;
693         (self.storage[bit / 32] & (1 << (bit % 32))) != 0
694     }
695 
696     /// Return whether this set contains any reset longhand.
697     #[inline]
contains_any_reset(&self) -> bool698     pub fn contains_any_reset(&self) -> bool {
699         ${static_longhand_id_set("RESET", lambda p: not p.style_struct.inherited)}
700         self.contains_any(&RESET)
701     }
702 
703     /// Add the given property to the set
704     #[inline]
insert(&mut self, id: LonghandId)705     pub fn insert(&mut self, id: LonghandId) {
706         let bit = id as usize;
707         self.storage[bit / 32] |= 1 << (bit % 32);
708     }
709 
710     /// Remove the given property from the set
711     #[inline]
remove(&mut self, id: LonghandId)712     pub fn remove(&mut self, id: LonghandId) {
713         let bit = id as usize;
714         self.storage[bit / 32] &= !(1 << (bit % 32));
715     }
716 
717     /// Clear all bits
718     #[inline]
clear(&mut self)719     pub fn clear(&mut self) {
720         for cell in &mut self.storage {
721             *cell = 0
722         }
723     }
724 
725     /// Returns whether the set is empty.
726     #[inline]
is_empty(&self) -> bool727     pub fn is_empty(&self) -> bool {
728         self.storage.iter().all(|c| *c == 0)
729     }
730 }
731 
732 /// An enum to represent a CSS Wide keyword.
733 #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToCss)]
734 pub enum CSSWideKeyword {
735     /// The `initial` keyword.
736     Initial,
737     /// The `inherit` keyword.
738     Inherit,
739     /// The `unset` keyword.
740     Unset,
741 }
742 
743 impl CSSWideKeyword {
to_str(&self) -> &'static str744     fn to_str(&self) -> &'static str {
745         match *self {
746             CSSWideKeyword::Initial => "initial",
747             CSSWideKeyword::Inherit => "inherit",
748             CSSWideKeyword::Unset => "unset",
749         }
750     }
751 
752     /// Takes the result of cssparser::Parser::expect_ident() and converts it
753     /// to a CSSWideKeyword.
from_ident<'i>(ident: &str) -> Option<Self>754     pub fn from_ident<'i>(ident: &str) -> Option<Self> {
755         match_ignore_ascii_case! { ident,
756             // If modifying this set of keyword, also update values::CustomIdent::from_ident
757             "initial" => Some(CSSWideKeyword::Initial),
758             "inherit" => Some(CSSWideKeyword::Inherit),
759             "unset" => Some(CSSWideKeyword::Unset),
760             _ => None
761         }
762     }
763 }
764 
765 impl CSSWideKeyword {
parse(input: &mut Parser) -> Result<Self, ()>766     fn parse(input: &mut Parser) -> Result<Self, ()> {
767         let ident = input.expect_ident().map_err(|_| ())?.clone();
768         input.expect_exhausted().map_err(|_| ())?;
769         CSSWideKeyword::from_ident(&ident).ok_or(())
770     }
771 }
772 
773 bitflags! {
774     /// A set of flags for properties.
775     pub struct PropertyFlags: u8 {
776         /// This property requires a stacking context.
777         const CREATES_STACKING_CONTEXT = 1 << 0;
778         /// This property has values that can establish a containing block for
779         /// fixed positioned and absolutely positioned elements.
780         const FIXPOS_CB = 1 << 1;
781         /// This property has values that can establish a containing block for
782         /// absolutely positioned elements.
783         const ABSPOS_CB = 1 << 2;
784         /// This longhand property applies to ::first-letter.
785         const APPLIES_TO_FIRST_LETTER = 1 << 3;
786         /// This longhand property applies to ::first-line.
787         const APPLIES_TO_FIRST_LINE = 1 << 4;
788         /// This longhand property applies to ::placeholder.
789         const APPLIES_TO_PLACEHOLDER = 1 << 5;
790     }
791 }
792 
793 /// An identifier for a given longhand property.
794 #[derive(Clone, Copy, Eq, Hash, MallocSizeOf, PartialEq)]
795 #[repr(u16)]
796 pub enum LonghandId {
797     % for i, property in enumerate(data.longhands):
798         /// ${property.name}
799         ${property.camel_case} = ${i},
800     % endfor
801 }
802 
803 impl ToCss for LonghandId {
804     #[inline]
to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: Write,805     fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
806     where
807         W: Write,
808     {
809         dest.write_str(self.name())
810     }
811 }
812 
813 impl fmt::Debug for LonghandId {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result814     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
815         formatter.write_str(self.name())
816     }
817 }
818 
819 impl LonghandId {
820     /// Get the name of this longhand property.
name(&self) -> &'static str821     pub fn name(&self) -> &'static str {
822         match *self {
823             % for property in data.longhands:
824                 LonghandId::${property.camel_case} => "${property.name}",
825             % endfor
826         }
827     }
828 
inherited(&self) -> bool829     fn inherited(&self) -> bool {
830         ${static_longhand_id_set("INHERITED", lambda p: p.style_struct.inherited)}
831         INHERITED.contains(*self)
832     }
833 
shorthands(&self) -> NonCustomPropertyIterator<ShorthandId>834     fn shorthands(&self) -> NonCustomPropertyIterator<ShorthandId> {
835         // first generate longhand to shorthands lookup map
836         //
837         // NOTE(emilio): This currently doesn't exclude the "all" shorthand. It
838         // could potentially do so, which would speed up serialization
839         // algorithms and what not, I guess.
840         <%
841             longhand_to_shorthand_map = {}
842             num_sub_properties = {}
843             for shorthand in data.shorthands:
844                 num_sub_properties[shorthand.camel_case] = len(shorthand.sub_properties)
845                 for sub_property in shorthand.sub_properties:
846                     if sub_property.ident not in longhand_to_shorthand_map:
847                         longhand_to_shorthand_map[sub_property.ident] = []
848 
849                     longhand_to_shorthand_map[sub_property.ident].append(shorthand.camel_case)
850 
851             def preferred_order(x, y):
852                 # Since we want properties in order from most subproperties to least,
853                 # reverse the arguments to cmp from the expected order.
854                 result = cmp(num_sub_properties.get(y, 0), num_sub_properties.get(x, 0))
855                 if result:
856                     return result
857                 # Fall back to lexicographic comparison.
858                 return cmp(x, y)
859 
860             # Sort the lists of shorthand properties according to preferred order:
861             # https://drafts.csswg.org/cssom/#concept-shorthands-preferred-order
862             for shorthand_list in longhand_to_shorthand_map.itervalues():
863                 shorthand_list.sort(cmp=preferred_order)
864         %>
865 
866         // based on lookup results for each longhand, create result arrays
867         % for property in data.longhands:
868             static ${property.ident.upper()}: &'static [ShorthandId] = &[
869                 % for shorthand in longhand_to_shorthand_map.get(property.ident, []):
870                     ShorthandId::${shorthand},
871                 % endfor
872             ];
873         % endfor
874 
875         NonCustomPropertyIterator {
876             filter: NonCustomPropertyId::from(*self).enabled_for_all_content(),
877             iter: match *self {
878                 % for property in data.longhands:
879                     LonghandId::${property.camel_case} => ${property.ident.upper()},
880                 % endfor
881             }.iter(),
882         }
883     }
884 
parse_value<'i, 't>( &self, context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<PropertyDeclaration, ParseError<'i>>885     fn parse_value<'i, 't>(
886         &self,
887         context: &ParserContext,
888         input: &mut Parser<'i, 't>,
889     ) -> Result<PropertyDeclaration, ParseError<'i>> {
890         match *self {
891             % for property in data.longhands:
892                 LonghandId::${property.camel_case} => {
893                     longhands::${property.ident}::parse_declared(context, input)
894                 }
895             % endfor
896         }
897     }
898 
899     /// Returns whether this property is animatable.
is_animatable(self) -> bool900     pub fn is_animatable(self) -> bool {
901         match self {
902             % for property in data.longhands:
903             LonghandId::${property.camel_case} => {
904                 ${str(property.animatable).lower()}
905             }
906             % endfor
907         }
908     }
909 
910     /// Returns whether this property is animatable in a discrete way.
is_discrete_animatable(self) -> bool911     pub fn is_discrete_animatable(self) -> bool {
912         match self {
913             % for property in data.longhands:
914             LonghandId::${property.camel_case} => {
915                 ${str(property.animation_value_type == "discrete").lower()}
916             }
917             % endfor
918         }
919     }
920 
921     /// Converts from a LonghandId to an adequate nsCSSPropertyID.
922     #[cfg(feature = "gecko")]
923     #[inline]
to_nscsspropertyid(self) -> nsCSSPropertyID924     pub fn to_nscsspropertyid(self) -> nsCSSPropertyID {
925         NonCustomPropertyId::from(self).to_nscsspropertyid()
926     }
927 
928     #[cfg(feature = "gecko")]
929     #[allow(non_upper_case_globals)]
930     /// Returns a longhand id from Gecko's nsCSSPropertyID.
from_nscsspropertyid(id: nsCSSPropertyID) -> Result<Self, ()>931     pub fn from_nscsspropertyid(id: nsCSSPropertyID) -> Result<Self, ()> {
932         match PropertyId::from_nscsspropertyid(id) {
933             Ok(PropertyId::Longhand(id)) |
934             Ok(PropertyId::LonghandAlias(id, _)) => Ok(id),
935             _ => Err(()),
936         }
937     }
938 
939     /// If this is a logical property, return the corresponding physical one in the given writing mode.
940     /// Otherwise, return unchanged.
to_physical(&self, wm: WritingMode) -> Self941     pub fn to_physical(&self, wm: WritingMode) -> Self {
942         match *self {
943             % for property in data.longhands:
944                 % if property.logical:
945                     LonghandId::${property.camel_case} => {
946                         <%helpers:logical_setter_helper name="${property.name}">
947                             <%def name="inner(physical_ident)">
948                                 LonghandId::${to_camel_case(physical_ident)}
949                             </%def>
950                         </%helpers:logical_setter_helper>
951                     }
952                 % endif
953             % endfor
954             _ => *self
955         }
956     }
957 
958     /// Returns PropertyFlags for given longhand property.
flags(&self) -> PropertyFlags959     pub fn flags(&self) -> PropertyFlags {
960         match *self {
961             % for property in data.longhands:
962                 LonghandId::${property.camel_case} =>
963                     % for flag in property.flags:
964                         PropertyFlags::${flag} |
965                     % endfor
966                     PropertyFlags::empty(),
967             % endfor
968         }
969     }
970 
971     /// Only a few properties are allowed to depend on the visited state of
972     /// links. When cascading visited styles, we can save time by only
973     /// processing these properties.
is_visited_dependent(&self) -> bool974     fn is_visited_dependent(&self) -> bool {
975         matches!(*self,
976             % if product == "gecko":
977             LonghandId::ColumnRuleColor |
978             LonghandId::TextEmphasisColor |
979             LonghandId::WebkitTextFillColor |
980             LonghandId::WebkitTextStrokeColor |
981             LonghandId::TextDecorationColor |
982             LonghandId::Fill |
983             LonghandId::Stroke |
984             LonghandId::CaretColor |
985             % endif
986             LonghandId::Color |
987             LonghandId::BackgroundColor |
988             LonghandId::BorderTopColor |
989             LonghandId::BorderRightColor |
990             LonghandId::BorderBottomColor |
991             LonghandId::BorderLeftColor |
992             LonghandId::OutlineColor
993         )
994     }
995 
996     /// Returns true if the property is one that is ignored when document
997     /// colors are disabled.
is_ignored_when_document_colors_disabled( &self, cascade_level: CascadeLevel, pseudo: Option<<&PseudoElement>, ) -> bool998     fn is_ignored_when_document_colors_disabled(
999         &self,
1000         cascade_level: CascadeLevel,
1001         pseudo: Option<<&PseudoElement>,
1002     ) -> bool {
1003         let is_ua_or_user_rule = matches!(
1004             cascade_level,
1005             CascadeLevel::UANormal |
1006             CascadeLevel::UserNormal |
1007             CascadeLevel::UserImportant |
1008             CascadeLevel::UAImportant
1009         );
1010 
1011         if is_ua_or_user_rule {
1012             return false;
1013         }
1014 
1015         let is_style_attribute = matches!(
1016             cascade_level,
1017             CascadeLevel::StyleAttributeNormal |
1018             CascadeLevel::StyleAttributeImportant
1019         );
1020         // Don't override colors on pseudo-element's style attributes. The
1021         // background-color on ::-moz-color-swatch is an example. Those are set
1022         // as an author style (via the style attribute), but it's pretty
1023         // important for it to show up for obvious reasons :)
1024         if pseudo.is_some() && is_style_attribute {
1025             return false;
1026         }
1027 
1028         matches!(*self,
1029             ${" | ".join([("LonghandId::" + p.camel_case)
1030                           for p in data.longhands if p.ignored_when_colors_disabled])}
1031         )
1032     }
1033 
1034     /// The computed value of some properties depends on the (sometimes
1035     /// computed) value of *other* properties.
1036     ///
1037     /// So we classify properties into "early" and "other", such that the only
1038     /// dependencies can be from "other" to "early".
1039     ///
1040     /// Unfortunately, it’s not easy to check that this classification is
1041     /// correct.
is_early_property(&self) -> bool1042     fn is_early_property(&self) -> bool {
1043         matches!(*self,
1044             % if product == 'gecko':
1045 
1046             // Needed to properly compute the writing mode, to resolve logical
1047             // properties, and similar stuff. In this block instead of along
1048             // `WritingMode` and `Direction` just for convenience, since it's
1049             // Gecko-only (for now at least).
1050             //
1051             // see WritingMode::new.
1052             LonghandId::TextOrientation |
1053 
1054             // Needed to properly compute the zoomed font-size.
1055             //
1056             // FIXME(emilio): This could probably just be a cascade flag like
1057             // IN_SVG_SUBTREE or such, and we could nuke this property.
1058             LonghandId::XTextZoom |
1059 
1060             // Needed to do font-size computation in a language-dependent way.
1061             LonghandId::XLang |
1062             // Needed for ruby to respect language-dependent min-font-size
1063             // preferences properly, see bug 1165538.
1064             LonghandId::MozMinFontSizeRatio |
1065 
1066             // Needed to do font-size for MathML. :(
1067             LonghandId::MozScriptLevel |
1068             % endif
1069 
1070             // Needed to compute font-relative lengths correctly.
1071             LonghandId::FontSize |
1072             LonghandId::FontFamily |
1073 
1074             // Needed to resolve currentcolor at computed value time properly.
1075             //
1076             // FIXME(emilio): All the properties should be moved to currentcolor
1077             // as a computed-value (and thus resolving it at used-value time).
1078             //
1079             // This would allow this property to go away from this list.
1080             LonghandId::Color |
1081 
1082             // FIXME(emilio): There's no reason for this afaict, nuke it.
1083             LonghandId::TextDecorationLine |
1084 
1085             // Needed to properly compute the writing mode, to resolve logical
1086             // properties, and similar stuff.
1087             LonghandId::WritingMode |
1088             LonghandId::Direction
1089         )
1090     }
1091 
1092     /// Whether computed values of this property lossily convert any complex
1093     /// colors into RGBA colors.
1094     ///
1095     /// In Gecko, there are some properties still that compute currentcolor
1096     /// down to an RGBA color at computed value time, instead of as
1097     /// `StyleComplexColor`s. For these properties, we must return `false`,
1098     /// so that we correctly avoid caching style data in the rule tree.
stores_complex_colors_lossily(&self) -> bool1099     pub fn stores_complex_colors_lossily(&self) -> bool {
1100         % if product == "gecko":
1101         matches!(*self,
1102             % for property in data.longhands:
1103             % if property.predefined_type == "RGBAColor":
1104             LonghandId::${property.camel_case} |
1105             % endif
1106             % endfor
1107             LonghandId::BackgroundImage |
1108             LonghandId::BorderImageSource |
1109             LonghandId::BoxShadow |
1110             LonghandId::MaskImage |
1111             LonghandId::TextShadow
1112         )
1113         % else:
1114         false
1115         % endif
1116     }
1117 }
1118 
1119 /// An iterator over all the property ids that are enabled for a given
1120 /// shorthand, if that shorthand is enabled for all content too.
1121 pub struct NonCustomPropertyIterator<Item: 'static> {
1122     filter: bool,
1123     iter: ::std::slice::Iter<'static, Item>,
1124 }
1125 
1126 impl<Item> Iterator for NonCustomPropertyIterator<Item>
1127 where
1128     Item: 'static + Copy + Into<NonCustomPropertyId>,
1129 {
1130     type Item = Item;
1131 
next(&mut self) -> Option<Self::Item>1132     fn next(&mut self) -> Option<Self::Item> {
1133         loop {
1134             let id = *self.iter.next()?;
1135             if !self.filter || id.into().enabled_for_all_content() {
1136                 return Some(id)
1137             }
1138         }
1139     }
1140 }
1141 
1142 /// An identifier for a given shorthand property.
1143 #[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
1144 pub enum ShorthandId {
1145     % for property in data.shorthands:
1146         /// ${property.name}
1147         ${property.camel_case},
1148     % endfor
1149 }
1150 
1151 impl ToCss for ShorthandId {
1152     #[inline]
to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: Write,1153     fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1154     where
1155         W: Write,
1156     {
1157         dest.write_str(self.name())
1158     }
1159 }
1160 
1161 impl ShorthandId {
1162     /// Get the name for this shorthand property.
name(&self) -> &'static str1163     pub fn name(&self) -> &'static str {
1164         match *self {
1165             % for property in data.shorthands:
1166                 ShorthandId::${property.camel_case} => "${property.name}",
1167             % endfor
1168         }
1169     }
1170 
1171     /// Converts from a ShorthandId to an adequate nsCSSPropertyID.
1172     #[cfg(feature = "gecko")]
1173     #[inline]
to_nscsspropertyid(self) -> nsCSSPropertyID1174     pub fn to_nscsspropertyid(self) -> nsCSSPropertyID {
1175         NonCustomPropertyId::from(self).to_nscsspropertyid()
1176     }
1177 
1178     /// Get the longhand ids that form this shorthand.
longhands(&self) -> NonCustomPropertyIterator<LonghandId>1179     pub fn longhands(&self) -> NonCustomPropertyIterator<LonghandId> {
1180         % for property in data.shorthands:
1181             static ${property.ident.upper()}: &'static [LonghandId] = &[
1182                 % for sub in property.sub_properties:
1183                     LonghandId::${sub.camel_case},
1184                 % endfor
1185             ];
1186         % endfor
1187         NonCustomPropertyIterator {
1188             filter: NonCustomPropertyId::from(*self).enabled_for_all_content(),
1189             iter: match *self {
1190                 % for property in data.shorthands:
1191                     ShorthandId::${property.camel_case} => ${property.ident.upper()},
1192                 % endfor
1193             }.iter()
1194         }
1195     }
1196 
1197     /// Try to serialize the given declarations as this shorthand.
1198     ///
1199     /// Returns an error if writing to the stream fails, or if the declarations
1200     /// do not map to a shorthand.
longhands_to_css<'a, W, I>( &self, declarations: I, dest: &mut CssWriter<W>, ) -> fmt::Result where W: Write, I: Iterator<Item=&'a PropertyDeclaration>,1201     pub fn longhands_to_css<'a, W, I>(
1202         &self,
1203         declarations: I,
1204         dest: &mut CssWriter<W>,
1205     ) -> fmt::Result
1206     where
1207         W: Write,
1208         I: Iterator<Item=&'a PropertyDeclaration>,
1209     {
1210         match *self {
1211             ShorthandId::All => {
1212                 // No need to try to serialize the declarations as the 'all'
1213                 // shorthand, since it only accepts CSS-wide keywords (and
1214                 // variable references), which will be handled in
1215                 // get_shorthand_appendable_value.
1216                 Err(fmt::Error)
1217             }
1218             % for property in data.shorthands_except_all():
1219                 ShorthandId::${property.camel_case} => {
1220                     match shorthands::${property.ident}::LonghandsToSerialize::from_iter(declarations) {
1221                         Ok(longhands) => longhands.to_css(dest),
1222                         Err(_) => Err(fmt::Error)
1223                     }
1224                 },
1225             % endfor
1226         }
1227     }
1228 
1229     /// Finds and returns an appendable value for the given declarations.
1230     ///
1231     /// Returns the optional appendable value.
get_shorthand_appendable_value<'a, I>( self, declarations: I, ) -> Option<AppendableValue<'a, I::IntoIter>> where I: IntoIterator<Item=&'a PropertyDeclaration>, I::IntoIter: Clone,1232     pub fn get_shorthand_appendable_value<'a, I>(
1233         self,
1234         declarations: I,
1235     ) -> Option<AppendableValue<'a, I::IntoIter>>
1236     where
1237         I: IntoIterator<Item=&'a PropertyDeclaration>,
1238         I::IntoIter: Clone,
1239     {
1240         let declarations = declarations.into_iter();
1241 
1242         // Only cloning iterators (a few pointers each) not declarations.
1243         let mut declarations2 = declarations.clone();
1244         let mut declarations3 = declarations.clone();
1245 
1246         let first_declaration = declarations2.next()?;
1247 
1248         // https://drafts.csswg.org/css-variables/#variables-in-shorthands
1249         if let Some(css) = first_declaration.with_variables_from_shorthand(self) {
1250             if declarations2.all(|d| d.with_variables_from_shorthand(self) == Some(css)) {
1251                return Some(AppendableValue::Css {
1252                    css: CssStringBorrow::from(css),
1253                    with_variables: true,
1254                });
1255             }
1256             return None;
1257         }
1258 
1259         // Check whether they are all the same CSS-wide keyword.
1260         if let Some(keyword) = first_declaration.get_css_wide_keyword() {
1261             if declarations2.all(|d| d.get_css_wide_keyword() == Some(keyword)) {
1262                 return Some(AppendableValue::Css {
1263                     css: CssStringBorrow::from(keyword.to_str()),
1264                     with_variables: false,
1265                 });
1266             }
1267             return None;
1268         }
1269 
1270         // Check whether all declarations can be serialized as part of shorthand.
1271         if declarations3.all(|d| d.may_serialize_as_part_of_shorthand()) {
1272             return Some(AppendableValue::DeclarationsForShorthand(self, declarations));
1273         }
1274 
1275         None
1276     }
1277 
1278     /// Returns PropertyFlags for given shorthand property.
flags(&self) -> PropertyFlags1279     pub fn flags(&self) -> PropertyFlags {
1280         match *self {
1281             % for property in data.shorthands:
1282                 ShorthandId::${property.camel_case} =>
1283                     % for flag in property.flags:
1284                         PropertyFlags::${flag} |
1285                     % endfor
1286                     PropertyFlags::empty(),
1287             % endfor
1288         }
1289     }
1290 
parse_into<'i, 't>( &self, declarations: &mut SourcePropertyDeclaration, context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<(), ParseError<'i>>1291     fn parse_into<'i, 't>(
1292         &self,
1293         declarations: &mut SourcePropertyDeclaration,
1294         context: &ParserContext,
1295         input: &mut Parser<'i, 't>,
1296     ) -> Result<(), ParseError<'i>> {
1297         match *self {
1298             % for shorthand in data.shorthands_except_all():
1299                 ShorthandId::${shorthand.camel_case} => {
1300                     shorthands::${shorthand.ident}::parse_into(declarations, context, input)
1301                 }
1302             % endfor
1303             // 'all' accepts no value other than CSS-wide keywords
1304             ShorthandId::All => Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
1305         }
1306     }
1307 }
1308 
1309 /// Servo's representation of a declared value for a given `T`, which is the
1310 /// declared value for that property.
1311 #[derive(Clone, Debug, Eq, PartialEq)]
1312 pub enum DeclaredValue<'a, T: 'a> {
1313     /// A known specified value from the stylesheet.
1314     Value(&'a T),
1315     /// An unparsed value that contains `var()` functions.
1316     WithVariables(&'a Arc<UnparsedValue>),
1317     /// An CSS-wide keyword.
1318     CSSWideKeyword(CSSWideKeyword),
1319 }
1320 
1321 /// A variant of DeclaredValue that owns its data. This separation exists so
1322 /// that PropertyDeclaration can avoid embedding a DeclaredValue (and its
1323 /// extra discriminant word) and synthesize dependent DeclaredValues for
1324 /// PropertyDeclaration instances as needed.
1325 #[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
1326 #[derive(Clone, Debug, Eq, PartialEq, ToCss)]
1327 pub enum DeclaredValueOwned<T> {
1328     /// A known specified value from the stylesheet.
1329     Value(T),
1330     /// An unparsed value that contains `var()` functions.
1331     WithVariables(
1332         #[cfg_attr(feature = "gecko", ignore_malloc_size_of = "XXX: how to handle this?")]
1333         Arc<UnparsedValue>
1334     ),
1335     /// An CSS-wide keyword.
1336     CSSWideKeyword(CSSWideKeyword),
1337 }
1338 
1339 impl<T> DeclaredValueOwned<T> {
1340     /// Creates a dependent DeclaredValue from this DeclaredValueOwned.
borrow(&self) -> DeclaredValue<T>1341     fn borrow(&self) -> DeclaredValue<T> {
1342         match *self {
1343             DeclaredValueOwned::Value(ref v) => DeclaredValue::Value(v),
1344             DeclaredValueOwned::WithVariables(ref v) => DeclaredValue::WithVariables(v),
1345             DeclaredValueOwned::CSSWideKeyword(v) => DeclaredValue::CSSWideKeyword(v),
1346         }
1347     }
1348 }
1349 
1350 /// An unparsed property value that contains `var()` functions.
1351 #[derive(Debug, Eq, PartialEq)]
1352 pub struct UnparsedValue {
1353     /// The css serialization for this value.
1354     css: String,
1355     /// The first token type for this serialization.
1356     first_token_type: TokenSerializationType,
1357     /// The url data for resolving url values.
1358     url_data: UrlExtraData,
1359     /// The shorthand this came from.
1360     from_shorthand: Option<ShorthandId>,
1361 }
1362 
1363 impl ToCss for UnparsedValue {
to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: Write,1364     fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1365     where
1366         W: Write,
1367     {
1368         // https://drafts.csswg.org/css-variables/#variables-in-shorthands
1369         if self.from_shorthand.is_none() {
1370             dest.write_str(&*self.css)?;
1371         }
1372         Ok(())
1373     }
1374 }
1375 
1376 impl UnparsedValue {
substitute_variables( &self, longhand_id: LonghandId, custom_properties: Option<<&Arc<::custom_properties::CustomPropertiesMap>>, quirks_mode: QuirksMode, ) -> PropertyDeclaration1377     fn substitute_variables(
1378         &self,
1379         longhand_id: LonghandId,
1380         custom_properties: Option<<&Arc<::custom_properties::CustomPropertiesMap>>,
1381         quirks_mode: QuirksMode,
1382     ) -> PropertyDeclaration {
1383         ::custom_properties::substitute(&self.css, self.first_token_type, custom_properties)
1384         .ok()
1385         .and_then(|css| {
1386             // As of this writing, only the base URL is used for property
1387             // values.
1388             let context = ParserContext::new(
1389                 Origin::Author,
1390                 &self.url_data,
1391                 None,
1392                 ParsingMode::DEFAULT,
1393                 quirks_mode,
1394             );
1395 
1396             let mut input = ParserInput::new(&css);
1397             Parser::new(&mut input).parse_entirely(|input| {
1398                 match self.from_shorthand {
1399                     None => longhand_id.parse_value(&context, input),
1400                     Some(ShorthandId::All) => {
1401                         // No need to parse the 'all' shorthand as anything other than a CSS-wide
1402                         // keyword, after variable substitution.
1403                         Err(input.new_custom_error(SelectorParseErrorKind::UnexpectedIdent("all".into())))
1404                     }
1405                     % for shorthand in data.shorthands_except_all():
1406                         Some(ShorthandId::${shorthand.camel_case}) => {
1407                             shorthands::${shorthand.ident}::parse_value(&context, input)
1408                             .map(|longhands| {
1409                                 match longhand_id {
1410                                     % for property in shorthand.sub_properties:
1411                                         LonghandId::${property.camel_case} => {
1412                                             PropertyDeclaration::${property.camel_case}(
1413                                                 longhands.${property.ident}
1414                                             )
1415                                         }
1416                                     % endfor
1417                                     _ => unreachable!()
1418                                 }
1419                             })
1420                         }
1421                     % endfor
1422                 }
1423             })
1424             .ok()
1425         })
1426         .unwrap_or_else(|| {
1427             // Invalid at computed-value time.
1428             let keyword = if longhand_id.inherited() {
1429                 CSSWideKeyword::Inherit
1430             } else {
1431                 CSSWideKeyword::Initial
1432             };
1433             PropertyDeclaration::CSSWideKeyword(WideKeywordDeclaration {
1434                 id: longhand_id,
1435                 keyword,
1436         })
1437         })
1438     }
1439 }
1440 
1441 /// An identifier for a given property declaration, which can be either a
1442 /// longhand or a custom property.
1443 #[derive(Clone, Copy, PartialEq)]
1444 #[cfg_attr(feature = "servo", derive(MallocSizeOf))]
1445 pub enum PropertyDeclarationId<'a> {
1446     /// A longhand.
1447     Longhand(LonghandId),
1448     /// A custom property declaration.
1449     Custom(&'a ::custom_properties::Name),
1450 }
1451 
1452 impl<'a> ToCss for PropertyDeclarationId<'a> {
to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: Write,1453     fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1454     where
1455         W: Write,
1456     {
1457         match *self {
1458             PropertyDeclarationId::Longhand(id) => dest.write_str(id.name()),
1459             PropertyDeclarationId::Custom(_) => {
1460                 serialize_identifier(&self.name(), dest)
1461             }
1462         }
1463     }
1464 }
1465 
1466 impl<'a> PropertyDeclarationId<'a> {
1467     /// Whether a given declaration id is either the same as `other`, or a
1468     /// longhand of it.
is_or_is_longhand_of(&self, other: &PropertyId) -> bool1469     pub fn is_or_is_longhand_of(&self, other: &PropertyId) -> bool {
1470         match *self {
1471             PropertyDeclarationId::Longhand(id) => {
1472                 match *other {
1473                     PropertyId::Longhand(other_id) |
1474                     PropertyId::LonghandAlias(other_id, _) => id == other_id,
1475                     PropertyId::Shorthand(shorthand) |
1476                     PropertyId::ShorthandAlias(shorthand, _) => self.is_longhand_of(shorthand),
1477                     PropertyId::Custom(_) => false,
1478                 }
1479             }
1480             PropertyDeclarationId::Custom(name) => {
1481                 matches!(*other, PropertyId::Custom(ref other_name) if name == other_name)
1482             }
1483         }
1484     }
1485 
1486     /// Whether a given declaration id is a longhand belonging to this
1487     /// shorthand.
is_longhand_of(&self, shorthand: ShorthandId) -> bool1488     pub fn is_longhand_of(&self, shorthand: ShorthandId) -> bool {
1489         match *self {
1490             PropertyDeclarationId::Longhand(ref id) => id.shorthands().any(|s| s == shorthand),
1491             _ => false,
1492         }
1493     }
1494 
1495     /// Returns the name of the property without CSS escaping.
name(&self) -> Cow<'static, str>1496     pub fn name(&self) -> Cow<'static, str> {
1497         match *self {
1498             PropertyDeclarationId::Longhand(id) => id.name().into(),
1499             PropertyDeclarationId::Custom(name) => {
1500                 let mut s = String::new();
1501                 write!(&mut s, "--{}", name).unwrap();
1502                 s.into()
1503             }
1504         }
1505     }
1506 }
1507 
1508 /// Servo's representation of a CSS property, that is, either a longhand, a
1509 /// shorthand, or a custom property.
1510 #[derive(Clone, Eq, PartialEq)]
1511 pub enum PropertyId {
1512     /// A longhand property.
1513     Longhand(LonghandId),
1514     /// A shorthand property.
1515     Shorthand(ShorthandId),
1516     /// An alias for a longhand property.
1517     LonghandAlias(LonghandId, AliasId),
1518     /// An alias for a shorthand property.
1519     ShorthandAlias(ShorthandId, AliasId),
1520     /// A custom property.
1521     Custom(::custom_properties::Name),
1522 }
1523 
1524 impl fmt::Debug for PropertyId {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result1525     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1526         self.to_css(&mut CssWriter::new(formatter))
1527     }
1528 }
1529 
1530 impl ToCss for PropertyId {
to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: Write,1531     fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1532     where
1533         W: Write,
1534     {
1535         match *self {
1536             PropertyId::Longhand(id) => dest.write_str(id.name()),
1537             PropertyId::Shorthand(id) => dest.write_str(id.name()),
1538             PropertyId::LonghandAlias(id, _) => dest.write_str(id.name()),
1539             PropertyId::ShorthandAlias(id, _) => dest.write_str(id.name()),
1540             PropertyId::Custom(_) => {
1541                 serialize_identifier(&self.name(), dest)
1542             }
1543         }
1544     }
1545 }
1546 
1547 impl PropertyId {
1548     /// Return the longhand id that this property id represents.
1549     #[inline]
longhand_id(&self) -> Option<LonghandId>1550     pub fn longhand_id(&self) -> Option<LonghandId> {
1551         Some(match *self {
1552             PropertyId::Longhand(id) => id,
1553             PropertyId::LonghandAlias(id, _) => id,
1554             _ => return None,
1555         })
1556     }
1557 
1558     /// Returns a given property from the string `s`.
1559     ///
1560     /// Returns Err(()) for unknown non-custom properties.
parse(property_name: &str) -> Result<Self, ()>1561     pub fn parse(property_name: &str) -> Result<Self, ()> {
1562         // FIXME(https://github.com/rust-lang/rust/issues/33156): remove this
1563         // enum and use PropertyId when stable Rust allows destructors in
1564         // statics.
1565         //
1566         // ShorthandAlias is not used in the Servo build.
1567         // That's why we need to allow dead_code.
1568         #[allow(dead_code)]
1569         pub enum StaticId {
1570             Longhand(LonghandId),
1571             Shorthand(ShorthandId),
1572             LonghandAlias(LonghandId, AliasId),
1573             ShorthandAlias(ShorthandId, AliasId),
1574         }
1575         ascii_case_insensitive_phf_map! {
1576             static_id -> StaticId = {
1577                 % for (kind, properties) in [("Longhand", data.longhands), ("Shorthand", data.shorthands)]:
1578                     % for property in properties:
1579                         "${property.name}" => StaticId::${kind}(${kind}Id::${property.camel_case}),
1580                         % for name in property.alias:
1581                             "${name}" => {
1582                                 StaticId::${kind}Alias(${kind}Id::${property.camel_case},
1583                                                        AliasId::${to_camel_case(name)})
1584                             },
1585                         % endfor
1586                     % endfor
1587                 % endfor
1588             }
1589         }
1590 
1591         Ok(match static_id(property_name) {
1592             Some(&StaticId::Longhand(id)) => {
1593                 PropertyId::Longhand(id)
1594             },
1595             Some(&StaticId::Shorthand(id)) => {
1596                 PropertyId::Shorthand(id)
1597             },
1598             Some(&StaticId::LonghandAlias(id, alias)) => {
1599                 PropertyId::LonghandAlias(id, alias)
1600             },
1601             Some(&StaticId::ShorthandAlias(id, alias)) => {
1602                 PropertyId::ShorthandAlias(id, alias)
1603             },
1604             None => {
1605                 return ::custom_properties::parse_name(property_name).map(|name| {
1606                     PropertyId::Custom(::custom_properties::Name::from(name))
1607                 })
1608             },
1609         })
1610     }
1611 
1612     /// Returns a property id from Gecko's nsCSSPropertyID.
1613     #[cfg(feature = "gecko")]
1614     #[allow(non_upper_case_globals)]
from_nscsspropertyid(id: nsCSSPropertyID) -> Result<Self, ()>1615     pub fn from_nscsspropertyid(id: nsCSSPropertyID) -> Result<Self, ()> {
1616         use gecko_bindings::structs::*;
1617         match id {
1618             % for property in data.longhands:
1619                 ${helpers.to_nscsspropertyid(property.ident)} => {
1620                     Ok(PropertyId::Longhand(LonghandId::${property.camel_case}))
1621                 }
1622                 % for alias in property.alias:
1623                     ${helpers.alias_to_nscsspropertyid(alias)} => {
1624                         Ok(PropertyId::LonghandAlias(
1625                             LonghandId::${property.camel_case},
1626                             AliasId::${to_camel_case(alias)}
1627                         ))
1628                     }
1629                 % endfor
1630             % endfor
1631             % for property in data.shorthands:
1632                 ${helpers.to_nscsspropertyid(property.ident)} => {
1633                     Ok(PropertyId::Shorthand(ShorthandId::${property.camel_case}))
1634                 }
1635                 % for alias in property.alias:
1636                     ${helpers.alias_to_nscsspropertyid(alias)} => {
1637                         Ok(PropertyId::ShorthandAlias(
1638                             ShorthandId::${property.camel_case},
1639                             AliasId::${to_camel_case(alias)}
1640                         ))
1641                     }
1642                 % endfor
1643             % endfor
1644             _ => Err(())
1645         }
1646     }
1647 
1648     /// Given this property id, get it either as a shorthand or as a
1649     /// `PropertyDeclarationId`.
as_shorthand(&self) -> Result<ShorthandId, PropertyDeclarationId>1650     pub fn as_shorthand(&self) -> Result<ShorthandId, PropertyDeclarationId> {
1651         match *self {
1652             PropertyId::ShorthandAlias(id, _) |
1653             PropertyId::Shorthand(id) => Ok(id),
1654             PropertyId::LonghandAlias(id, _) |
1655             PropertyId::Longhand(id) => Err(PropertyDeclarationId::Longhand(id)),
1656             PropertyId::Custom(ref name) => Err(PropertyDeclarationId::Custom(name)),
1657         }
1658     }
1659 
1660     /// Returns the name of the property without CSS escaping.
name(&self) -> Cow<'static, str>1661     pub fn name(&self) -> Cow<'static, str> {
1662         match *self {
1663             PropertyId::ShorthandAlias(id, _) |
1664             PropertyId::Shorthand(id) => id.name().into(),
1665             PropertyId::LonghandAlias(id, _) |
1666             PropertyId::Longhand(id) => id.name().into(),
1667             PropertyId::Custom(ref name) => {
1668                 let mut s = String::new();
1669                 write!(&mut s, "--{}", name).unwrap();
1670                 s.into()
1671             }
1672         }
1673     }
1674 
non_custom_id(&self) -> Option<NonCustomPropertyId>1675     fn non_custom_id(&self) -> Option<NonCustomPropertyId> {
1676         Some(match *self {
1677             PropertyId::Custom(_) => return None,
1678             PropertyId::Shorthand(shorthand_id) => shorthand_id.into(),
1679             PropertyId::Longhand(longhand_id) => longhand_id.into(),
1680             PropertyId::ShorthandAlias(_, alias_id) => alias_id.into(),
1681             PropertyId::LonghandAlias(_, alias_id) => alias_id.into(),
1682         })
1683     }
1684 
1685     /// Whether the property is enabled for all content regardless of the
1686     /// stylesheet it was declared on (that is, in practice only checks prefs).
1687     #[inline]
enabled_for_all_content(&self) -> bool1688     pub fn enabled_for_all_content(&self) -> bool {
1689         let id = match self.non_custom_id() {
1690             // Custom properties are allowed everywhere
1691             None => return true,
1692             Some(id) => id,
1693         };
1694 
1695         id.enabled_for_all_content()
1696     }
1697 
allowed_in(&self, context: &ParserContext) -> bool1698     fn allowed_in(&self, context: &ParserContext) -> bool {
1699         let id = match self.non_custom_id() {
1700             // Custom properties are allowed everywhere
1701             None => return true,
1702             Some(id) => id,
1703         };
1704         id.allowed_in(context)
1705     }
1706 }
1707 
1708 /// A declaration using a CSS-wide keyword.
1709 #[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
1710 #[derive(Clone, PartialEq, ToCss)]
1711 pub struct WideKeywordDeclaration {
1712     #[css(skip)]
1713     id: LonghandId,
1714     keyword: CSSWideKeyword,
1715 }
1716 
1717 /// An unparsed declaration that contains `var()` functions.
1718 #[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
1719 #[derive(Clone, PartialEq, ToCss)]
1720 pub struct VariableDeclaration {
1721     #[css(skip)]
1722     id: LonghandId,
1723     #[cfg_attr(feature = "gecko", ignore_malloc_size_of = "XXX: how to handle this?")]
1724     value: Arc<UnparsedValue>,
1725 }
1726 
1727 /// A custom property declaration with the property name and the declared value.
1728 #[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
1729 #[derive(Clone, PartialEq, ToCss)]
1730 pub struct CustomDeclaration {
1731     /// The name of the custom property.
1732     #[css(skip)]
1733     pub name: ::custom_properties::Name,
1734     /// The value of the custom property.
1735     #[cfg_attr(feature = "gecko", ignore_malloc_size_of = "XXX: how to handle this?")]
1736     pub value: DeclaredValueOwned<Arc<::custom_properties::SpecifiedValue>>,
1737 }
1738 
1739 impl fmt::Debug for PropertyDeclaration {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1740     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1741         self.id().to_css(&mut CssWriter::new(f))?;
1742         f.write_str(": ")?;
1743 
1744         // Because PropertyDeclaration::to_css requires CssStringWriter, we can't write
1745         // it directly to f, and need to allocate an intermediate string. This is
1746         // fine for debug-only code.
1747         let mut s = CssString::new();
1748         self.to_css(&mut s)?;
1749         write!(f, "{}", s)
1750     }
1751 }
1752 
1753 impl PropertyDeclaration {
1754     /// Given a property declaration, return the property declaration id.
1755     #[inline]
id(&self) -> PropertyDeclarationId1756     pub fn id(&self) -> PropertyDeclarationId {
1757         match *self {
1758             PropertyDeclaration::Custom(ref declaration) => {
1759                 return PropertyDeclarationId::Custom(&declaration.name)
1760             }
1761             PropertyDeclaration::CSSWideKeyword(ref declaration) => {
1762                 return PropertyDeclarationId::Longhand(declaration.id);
1763             }
1764             PropertyDeclaration::WithVariables(ref declaration) => {
1765                 return PropertyDeclarationId::Longhand(declaration.id);
1766             }
1767             _ => {}
1768         }
1769         // This is just fine because PropertyDeclarationId and LonghandId
1770         // have corresponding discriminants.
1771         let id = unsafe { *(self as *const _ as *const LonghandId) };
1772         debug_assert_eq!(id, match *self {
1773             % for property in data.longhands:
1774             PropertyDeclaration::${property.camel_case}(..) => LonghandId::${property.camel_case},
1775             % endfor
1776             _ => id,
1777         });
1778         PropertyDeclarationId::Longhand(id)
1779     }
1780 
with_variables_from_shorthand(&self, shorthand: ShorthandId) -> Option< &str>1781     fn with_variables_from_shorthand(&self, shorthand: ShorthandId) -> Option< &str> {
1782         match *self {
1783             PropertyDeclaration::WithVariables(ref declaration) => {
1784                 let s = declaration.value.from_shorthand?;
1785                 if s != shorthand {
1786                     return None;
1787                 }
1788                 Some(&*declaration.value.css)
1789             },
1790             _ => None,
1791         }
1792     }
1793 
1794     /// Returns a CSS-wide keyword if the declaration's value is one.
get_css_wide_keyword(&self) -> Option<CSSWideKeyword>1795     pub fn get_css_wide_keyword(&self) -> Option<CSSWideKeyword> {
1796         match *self {
1797             PropertyDeclaration::CSSWideKeyword(ref declaration) => {
1798                 Some(declaration.keyword)
1799             },
1800             _ => None,
1801         }
1802     }
1803 
1804     /// Returns whether or not the property is set by a system font
1805     #[cfg(feature = "gecko")]
get_system(&self) -> Option<SystemFont>1806     pub fn get_system(&self) -> Option<SystemFont> {
1807         match *self {
1808             % for prop in SYSTEM_FONT_LONGHANDS:
1809                 PropertyDeclaration::${to_camel_case(prop)}(ref prop) => {
1810                     prop.get_system()
1811                 }
1812             % endfor
1813             _ => None,
1814         }
1815     }
1816 
1817     /// Is it the default value of line-height?
is_default_line_height(&self) -> bool1818     pub fn is_default_line_height(&self) -> bool {
1819         match *self {
1820             PropertyDeclaration::LineHeight(LineHeight::Normal) => true,
1821             _ => false
1822         }
1823     }
1824 
1825     #[cfg(feature = "servo")]
1826     /// Dummy method to avoid cfg()s
get_system(&self) -> Option<()>1827     pub fn get_system(&self) -> Option<()> {
1828         None
1829     }
1830 
1831     /// Returns whether the declaration may be serialized as part of a shorthand.
1832     ///
1833     /// This method returns false if this declaration contains variable or has a
1834     /// CSS-wide keyword value, since these values cannot be serialized as part
1835     /// of a shorthand.
1836     ///
1837     /// Caller should check `with_variables_from_shorthand()` and whether all
1838     /// needed declarations has the same CSS-wide keyword first.
1839     ///
1840     /// Note that, serialization of a shorthand may still fail because of other
1841     /// property-specific requirement even when this method returns true for all
1842     /// the longhand declarations.
may_serialize_as_part_of_shorthand(&self) -> bool1843     pub fn may_serialize_as_part_of_shorthand(&self) -> bool {
1844         match *self {
1845             PropertyDeclaration::CSSWideKeyword(..) |
1846             PropertyDeclaration::WithVariables(..) => false,
1847             PropertyDeclaration::Custom(..) =>
1848                 unreachable!("Serializing a custom property as part of shorthand?"),
1849             _ => true,
1850         }
1851     }
1852 
1853     /// Return whether the value is stored as it was in the CSS source,
1854     /// preserving whitespace (as opposed to being parsed into a more abstract
1855     /// data structure).
1856     ///
1857     /// This is the case of custom properties and values that contain
1858     /// unsubstituted variables.
value_is_unparsed(&self) -> bool1859     pub fn value_is_unparsed(&self) -> bool {
1860       match *self {
1861           PropertyDeclaration::WithVariables(..) => true,
1862           PropertyDeclaration::Custom(ref declaration) => {
1863             !matches!(declaration.value.borrow(), DeclaredValue::CSSWideKeyword(..))
1864           }
1865           _ => false,
1866       }
1867     }
1868 
1869     /// Returns true if this property declaration is for one of the animatable
1870     /// properties.
is_animatable(&self) -> bool1871     pub fn is_animatable(&self) -> bool {
1872         match self.id() {
1873             PropertyDeclarationId::Longhand(id) => id.is_animatable(),
1874             PropertyDeclarationId::Custom(..) => false,
1875         }
1876     }
1877 
1878     /// Returns true if this property is a custom property, false
1879     /// otherwise.
is_custom(&self) -> bool1880     pub fn is_custom(&self) -> bool {
1881         matches!(*self, PropertyDeclaration::Custom(..))
1882     }
1883 
1884     /// The `context` parameter controls this:
1885     ///
1886     /// <https://drafts.csswg.org/css-animations/#keyframes>
1887     /// > The <declaration-list> inside of <keyframe-block> accepts any CSS property
1888     /// > except those defined in this specification,
1889     /// > but does accept the `animation-play-state` property and interprets it specially.
1890     ///
1891     /// This will not actually parse Importance values, and will always set things
1892     /// to Importance::Normal. Parsing Importance values is the job of PropertyDeclarationParser,
1893     /// we only set them here so that we don't have to reallocate
parse_into<'i, 't>( declarations: &mut SourcePropertyDeclaration, id: PropertyId, name: CowRcStr<'i>, context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<(), ParseError<'i>>1894     pub fn parse_into<'i, 't>(
1895         declarations: &mut SourcePropertyDeclaration,
1896         id: PropertyId,
1897         name: CowRcStr<'i>,
1898         context: &ParserContext,
1899         input: &mut Parser<'i, 't>,
1900     ) -> Result<(), ParseError<'i>> {
1901         assert!(declarations.is_empty());
1902 
1903         if !id.allowed_in(context) {
1904             return Err(input.new_custom_error(
1905                 StyleParseErrorKind::UnknownProperty(name)
1906             ));
1907         }
1908 
1909         let start = input.state();
1910         match id {
1911             PropertyId::Custom(property_name) => {
1912                 // FIXME: fully implement https://github.com/w3c/csswg-drafts/issues/774
1913                 // before adding skip_whitespace here.
1914                 // This probably affects some test results.
1915                 let value = match input.try(|i| CSSWideKeyword::parse(i)) {
1916                     Ok(keyword) => DeclaredValueOwned::CSSWideKeyword(keyword),
1917                     Err(()) => match ::custom_properties::SpecifiedValue::parse(input) {
1918                         Ok(value) => DeclaredValueOwned::Value(value),
1919                         Err(e) => return Err(StyleParseErrorKind::new_invalid(name, e)),
1920                     }
1921                 };
1922                 declarations.push(PropertyDeclaration::Custom(CustomDeclaration {
1923                     name: property_name,
1924                     value,
1925                 }));
1926                 Ok(())
1927             }
1928             PropertyId::LonghandAlias(id, _) |
1929             PropertyId::Longhand(id) => {
1930                 input.skip_whitespace();  // Unnecessary for correctness, but may help try() rewind less.
1931                 input.try(|i| CSSWideKeyword::parse(i)).map(|keyword| {
1932                     PropertyDeclaration::CSSWideKeyword(
1933                         WideKeywordDeclaration { id, keyword },
1934                     )
1935                 }).or_else(|()| {
1936                     input.look_for_var_functions();
1937                     input.parse_entirely(|input| id.parse_value(context, input))
1938                     .or_else(|err| {
1939                         while let Ok(_) = input.next() {}  // Look for var() after the error.
1940                         if input.seen_var_functions() {
1941                             input.reset(&start);
1942                             let (first_token_type, css) =
1943                                 ::custom_properties::parse_non_custom_with_var(input).map_err(|e| {
1944                                     StyleParseErrorKind::new_invalid(name, e)
1945                                 })?;
1946                             Ok(PropertyDeclaration::WithVariables(VariableDeclaration {
1947                                 id,
1948                                 value: Arc::new(UnparsedValue {
1949                                 css: css.into_owned(),
1950                                 first_token_type: first_token_type,
1951                                 url_data: context.url_data.clone(),
1952                                 from_shorthand: None,
1953                                 }),
1954                             }))
1955                         } else {
1956                             Err(StyleParseErrorKind::new_invalid(name, err))
1957                         }
1958                     })
1959                 }).map(|declaration| {
1960                     declarations.push(declaration)
1961                 })
1962             }
1963             PropertyId::ShorthandAlias(id, _) |
1964             PropertyId::Shorthand(id) => {
1965                 input.skip_whitespace();  // Unnecessary for correctness, but may help try() rewind less.
1966                 if let Ok(keyword) = input.try(|i| CSSWideKeyword::parse(i)) {
1967                     if id == ShorthandId::All {
1968                         declarations.all_shorthand = AllShorthand::CSSWideKeyword(keyword)
1969                     } else {
1970                         for longhand in id.longhands() {
1971                             declarations.push(PropertyDeclaration::CSSWideKeyword(
1972                                 WideKeywordDeclaration {
1973                                     id: longhand,
1974                                     keyword,
1975                                 },
1976                             ))
1977                         }
1978                     }
1979                     Ok(())
1980                 } else {
1981                     input.look_for_var_functions();
1982                     // Not using parse_entirely here: each ${shorthand.ident}::parse_into function
1983                     // needs to do so *before* pushing to `declarations`.
1984                     id.parse_into(declarations, context, input).or_else(|err| {
1985                         while let Ok(_) = input.next() {}  // Look for var() after the error.
1986                         if input.seen_var_functions() {
1987                             input.reset(&start);
1988                             let (first_token_type, css) =
1989                                 ::custom_properties::parse_non_custom_with_var(input).map_err(|e| {
1990                                     StyleParseErrorKind::new_invalid(name, e)
1991                                 })?;
1992                             let unparsed = Arc::new(UnparsedValue {
1993                                 css: css.into_owned(),
1994                                 first_token_type: first_token_type,
1995                                 url_data: context.url_data.clone(),
1996                                 from_shorthand: Some(id),
1997                             });
1998                             if id == ShorthandId::All {
1999                                 declarations.all_shorthand = AllShorthand::WithVariables(unparsed)
2000                             } else {
2001                                 for id in id.longhands() {
2002                                     declarations.push(
2003                                         PropertyDeclaration::WithVariables(VariableDeclaration {
2004                                             id,
2005                                             value: unparsed.clone(),
2006                                         })
2007                                     )
2008                                 }
2009                             }
2010                             Ok(())
2011                         } else {
2012                             Err(StyleParseErrorKind::new_invalid(name, err))
2013                         }
2014                     })
2015                 }
2016             }
2017         }
2018     }
2019 }
2020 
2021 const MAX_SUB_PROPERTIES_PER_SHORTHAND_EXCEPT_ALL: usize =
2022     ${max(len(s.sub_properties) for s in data.shorthands_except_all())};
2023 
2024 type SourcePropertyDeclarationArray =
2025     [PropertyDeclaration; MAX_SUB_PROPERTIES_PER_SHORTHAND_EXCEPT_ALL];
2026 
2027 /// A stack-allocated vector of `PropertyDeclaration`
2028 /// large enough to parse one CSS `key: value` declaration.
2029 /// (Shorthands expand to multiple `PropertyDeclaration`s.)
2030 pub struct SourcePropertyDeclaration {
2031     declarations: ::arrayvec::ArrayVec<SourcePropertyDeclarationArray>,
2032 
2033     /// Stored separately to keep MAX_SUB_PROPERTIES_PER_SHORTHAND_EXCEPT_ALL smaller.
2034     all_shorthand: AllShorthand,
2035 }
2036 
2037 impl SourcePropertyDeclaration {
2038     /// Create one. It’s big, try not to move it around.
2039     #[inline]
new() -> Self2040     pub fn new() -> Self {
2041         SourcePropertyDeclaration {
2042             declarations: ::arrayvec::ArrayVec::new(),
2043             all_shorthand: AllShorthand::NotSet,
2044         }
2045     }
2046 
2047     /// Similar to Vec::drain: leaves this empty when the return value is dropped.
drain(&mut self) -> SourcePropertyDeclarationDrain2048     pub fn drain(&mut self) -> SourcePropertyDeclarationDrain {
2049         SourcePropertyDeclarationDrain {
2050             declarations: self.declarations.drain(..),
2051             all_shorthand: mem::replace(&mut self.all_shorthand, AllShorthand::NotSet),
2052         }
2053     }
2054 
2055     /// Reset to initial state
clear(&mut self)2056     pub fn clear(&mut self) {
2057         self.declarations.clear();
2058         self.all_shorthand = AllShorthand::NotSet;
2059     }
2060 
is_empty(&self) -> bool2061     fn is_empty(&self) -> bool {
2062         self.declarations.is_empty() && matches!(self.all_shorthand, AllShorthand::NotSet)
2063     }
2064 
push(&mut self, declaration: PropertyDeclaration)2065     fn push(&mut self, declaration: PropertyDeclaration) {
2066         let _result = self.declarations.try_push(declaration);
2067         debug_assert!(_result.is_ok());
2068     }
2069 }
2070 
2071 /// Return type of SourcePropertyDeclaration::drain
2072 pub struct SourcePropertyDeclarationDrain<'a> {
2073     declarations: ::arrayvec::Drain<'a, SourcePropertyDeclarationArray>,
2074     all_shorthand: AllShorthand,
2075 }
2076 
2077 enum AllShorthand {
2078     NotSet,
2079     CSSWideKeyword(CSSWideKeyword),
2080     WithVariables(Arc<UnparsedValue>)
2081 }
2082 
2083 #[cfg(feature = "gecko")]
2084 pub use gecko_properties::style_structs;
2085 
2086 /// The module where all the style structs are defined.
2087 #[cfg(feature = "servo")]
2088 pub mod style_structs {
2089     use fnv::FnvHasher;
2090     use super::longhands;
2091     use std::hash::{Hash, Hasher};
2092     use logical_geometry::WritingMode;
2093     use media_queries::Device;
2094     use values::computed::NonNegativeLength;
2095 
2096     % for style_struct in data.active_style_structs():
2097         % if style_struct.name == "Font":
2098         #[derive(Clone, Debug, MallocSizeOf)]
2099         % else:
2100         #[derive(Clone, Debug, MallocSizeOf, PartialEq)]
2101         % endif
2102         /// The ${style_struct.name} style struct.
2103         pub struct ${style_struct.name} {
2104             % for longhand in style_struct.longhands:
2105                 /// The ${longhand.name} computed value.
2106                 pub ${longhand.ident}: longhands::${longhand.ident}::computed_value::T,
2107             % endfor
2108             % if style_struct.name == "InheritedText":
2109                 /// The "used" text-decorations that apply to this box.
2110                 ///
2111                 /// FIXME(emilio): This is technically a box-tree concept, and
2112                 /// would be nice to move away from style.
2113                 pub text_decorations_in_effect: ::values::computed::text::TextDecorationsInEffect,
2114             % endif
2115             % if style_struct.name == "Font":
2116                 /// The font hash, used for font caching.
2117                 pub hash: u64,
2118             % endif
2119             % if style_struct.name == "Box":
2120                 /// The display value specified by the CSS stylesheets (without any style adjustments),
2121                 /// which is needed for hypothetical layout boxes.
2122                 pub original_display: longhands::display::computed_value::T,
2123             % endif
2124         }
2125         % if style_struct.name == "Font":
2126         impl PartialEq for Font {
eq(&self, other: &Font) -> bool2127             fn eq(&self, other: &Font) -> bool {
2128                 self.hash == other.hash
2129                 % for longhand in style_struct.longhands:
2130                     && self.${longhand.ident} == other.${longhand.ident}
2131                 % endfor
2132             }
2133         }
2134         % endif
2135 
2136         impl ${style_struct.name} {
2137             % for longhand in style_struct.longhands:
2138                 % if longhand.logical:
2139                     ${helpers.logical_setter(name=longhand.name)}
2140                 % else:
2141                     % if longhand.is_vector:
2142                         /// Set ${longhand.name}.
2143                         #[allow(non_snake_case)]
2144                         #[inline]
2145                         pub fn set_${longhand.ident}<I>(&mut self, v: I)
2146                             where I: IntoIterator<Item = longhands::${longhand.ident}
2147                                                                   ::computed_value::single_value::T>,
2148                                   I::IntoIter: ExactSizeIterator
2149                         {
2150                             self.${longhand.ident} = longhands::${longhand.ident}::computed_value
2151                                                               ::T(v.into_iter().collect());
2152                         }
2153                     % elif longhand.ident == "display":
2154                         /// Set `display`.
2155                         ///
2156                         /// We need to keep track of the original display for hypothetical boxes,
2157                         /// so we need to special-case this.
2158                         #[allow(non_snake_case)]
2159                         #[inline]
set_display(&mut self, v: longhands::display::computed_value::T)2160                         pub fn set_display(&mut self, v: longhands::display::computed_value::T) {
2161                             self.display = v;
2162                             self.original_display = v;
2163                         }
2164                     % else:
2165                         /// Set ${longhand.name}.
2166                         #[allow(non_snake_case)]
2167                         #[inline]
2168                         pub fn set_${longhand.ident}(&mut self, v: longhands::${longhand.ident}::computed_value::T) {
2169                             self.${longhand.ident} = v;
2170                         }
2171                     % endif
2172                     % if longhand.ident == "display":
2173                         /// Set `display` from other struct.
2174                         ///
2175                         /// Same as `set_display` above.
2176                         /// Thus, we need to special-case this.
2177                         #[allow(non_snake_case)]
2178                         #[inline]
copy_display_from(&mut self, other: &Self)2179                         pub fn copy_display_from(&mut self, other: &Self) {
2180                             self.display = other.display.clone();
2181                             self.original_display = other.display.clone();
2182                         }
2183                     % else:
2184                         /// Set ${longhand.name} from other struct.
2185                         #[allow(non_snake_case)]
2186                         #[inline]
2187                         pub fn copy_${longhand.ident}_from(&mut self, other: &Self) {
2188                             self.${longhand.ident} = other.${longhand.ident}.clone();
2189                         }
2190                     % endif
2191                     /// Reset ${longhand.name} from the initial struct.
2192                     #[allow(non_snake_case)]
2193                     #[inline]
2194                     pub fn reset_${longhand.ident}(&mut self, other: &Self) {
2195                         self.copy_${longhand.ident}_from(other)
2196                     }
2197 
2198                     /// Get the computed value for ${longhand.name}.
2199                     #[allow(non_snake_case)]
2200                     #[inline]
2201                     pub fn clone_${longhand.ident}(&self) -> longhands::${longhand.ident}::computed_value::T {
2202                         self.${longhand.ident}.clone()
2203                     }
2204                 % endif
2205                 % if longhand.need_index:
2206                     /// If this longhand is indexed, get the number of elements.
2207                     #[allow(non_snake_case)]
2208                     pub fn ${longhand.ident}_count(&self) -> usize {
2209                         self.${longhand.ident}.0.len()
2210                     }
2211 
2212                     /// If this longhand is indexed, get the element at given
2213                     /// index.
2214                     #[allow(non_snake_case)]
2215                     pub fn ${longhand.ident}_at(&self, index: usize)
2216                         -> longhands::${longhand.ident}::computed_value::SingleComputedValue {
2217                         self.${longhand.ident}.0[index].clone()
2218                     }
2219                 % endif
2220             % endfor
2221             % if style_struct.name == "Border":
2222                 % for side in ["top", "right", "bottom", "left"]:
2223                     /// Whether the border-${side} property has nonzero width.
2224                     #[allow(non_snake_case)]
2225                     pub fn border_${side}_has_nonzero_width(&self) -> bool {
2226                         self.border_${side}_width != NonNegativeLength::zero()
2227                     }
2228                 % endfor
2229             % elif style_struct.name == "Font":
2230                 /// Computes a font hash in order to be able to cache fonts
2231                 /// effectively in GFX and layout.
compute_font_hash(&mut self)2232                 pub fn compute_font_hash(&mut self) {
2233                     // Corresponds to the fields in
2234                     // `gfx::font_template::FontTemplateDescriptor`.
2235                     let mut hasher: FnvHasher = Default::default();
2236                     hasher.write_u16(self.font_weight.0);
2237                     self.font_stretch.hash(&mut hasher);
2238                     self.font_family.hash(&mut hasher);
2239                     self.hash = hasher.finish()
2240                 }
2241 
2242                 /// (Servo does not handle MathML, so this just calls copy_font_size_from)
inherit_font_size_from(&mut self, parent: &Self, _: Option<NonNegativeLength>, _: &Device)2243                 pub fn inherit_font_size_from(&mut self, parent: &Self,
2244                                               _: Option<NonNegativeLength>,
2245                                               _: &Device) {
2246                     self.copy_font_size_from(parent);
2247                 }
2248                 /// (Servo does not handle MathML, so this just calls set_font_size)
apply_font_size(&mut self, v: longhands::font_size::computed_value::T, _: &Self, _: &Device) -> Option<NonNegativeLength>2249                 pub fn apply_font_size(&mut self,
2250                                        v: longhands::font_size::computed_value::T,
2251                                        _: &Self,
2252                                        _: &Device) -> Option<NonNegativeLength> {
2253                     self.set_font_size(v);
2254                     None
2255                 }
2256                 /// (Servo does not handle MathML, so this does nothing)
apply_unconstrained_font_size(&mut self, _: NonNegativeLength)2257                 pub fn apply_unconstrained_font_size(&mut self, _: NonNegativeLength) {
2258                 }
2259 
2260             % elif style_struct.name == "Outline":
2261                 /// Whether the outline-width property is non-zero.
2262                 #[inline]
outline_has_nonzero_width(&self) -> bool2263                 pub fn outline_has_nonzero_width(&self) -> bool {
2264                     self.outline_width != NonNegativeLength::zero()
2265                 }
2266             % elif style_struct.name == "Text":
2267                 /// Whether the text decoration has an underline.
2268                 #[inline]
has_underline(&self) -> bool2269                 pub fn has_underline(&self) -> bool {
2270                     self.text_decoration_line.contains(longhands::text_decoration_line::SpecifiedValue::UNDERLINE)
2271                 }
2272 
2273                 /// Whether the text decoration has an overline.
2274                 #[inline]
has_overline(&self) -> bool2275                 pub fn has_overline(&self) -> bool {
2276                     self.text_decoration_line.contains(longhands::text_decoration_line::SpecifiedValue::OVERLINE)
2277                 }
2278 
2279                 /// Whether the text decoration has a line through.
2280                 #[inline]
has_line_through(&self) -> bool2281                 pub fn has_line_through(&self) -> bool {
2282                     self.text_decoration_line.contains(longhands::text_decoration_line::SpecifiedValue::LINE_THROUGH)
2283                 }
2284             % elif style_struct.name == "Box":
2285                 /// Sets the display property, but without touching original_display,
2286                 /// except when the adjustment comes from root or item display fixups.
set_adjusted_display( &mut self, dpy: longhands::display::computed_value::T, is_item_or_root: bool )2287                 pub fn set_adjusted_display(
2288                     &mut self,
2289                     dpy: longhands::display::computed_value::T,
2290                     is_item_or_root: bool
2291                 ) {
2292                     self.display = dpy;
2293                     if is_item_or_root {
2294                         self.original_display = dpy;
2295                     }
2296                 }
2297             % endif
2298         }
2299 
2300     % endfor
2301 }
2302 
2303 % for style_struct in data.active_style_structs():
2304     impl style_structs::${style_struct.name} {
2305         % for longhand in style_struct.longhands:
2306             % if longhand.need_index:
2307                 /// Iterate over the values of ${longhand.name}.
2308                 #[allow(non_snake_case)]
2309                 #[inline]
2310                 pub fn ${longhand.ident}_iter(&self) -> ${longhand.camel_case}Iter {
2311                     ${longhand.camel_case}Iter {
2312                         style_struct: self,
2313                         current: 0,
2314                         max: self.${longhand.ident}_count(),
2315                     }
2316                 }
2317 
2318                 /// Get a value mod `index` for the property ${longhand.name}.
2319                 #[allow(non_snake_case)]
2320                 #[inline]
2321                 pub fn ${longhand.ident}_mod(&self, index: usize)
2322                     -> longhands::${longhand.ident}::computed_value::SingleComputedValue {
2323                     self.${longhand.ident}_at(index % self.${longhand.ident}_count())
2324                 }
2325             % endif
2326         % endfor
2327 
2328         % if style_struct.name == "Box":
2329             /// Returns whether there is any animation specified with
2330             /// animation-name other than `none`.
specifies_animations(&self) -> bool2331             pub fn specifies_animations(&self) -> bool {
2332                 self.animation_name_iter().any(|name| name.0.is_some())
2333             }
2334 
2335             /// Returns whether there are any transitions specified.
2336             #[cfg(feature = "servo")]
specifies_transitions(&self) -> bool2337             pub fn specifies_transitions(&self) -> bool {
2338                 self.transition_duration_iter()
2339                     .take(self.transition_property_count())
2340                     .any(|t| t.seconds() > 0.)
2341             }
2342         % elif style_struct.name == "Column":
2343             /// Whether this is a multicol style.
2344             #[cfg(feature = "servo")]
is_multicol(&self) -> bool2345             pub fn is_multicol(&self) -> bool {
2346                 match self.column_width {
2347                     Either::First(_width) => true,
2348                     Either::Second(_auto) => !self.column_count.is_auto(),
2349                 }
2350             }
2351         % endif
2352     }
2353 
2354     % for longhand in style_struct.longhands:
2355         % if longhand.need_index:
2356             /// An iterator over the values of the ${longhand.name} properties.
2357             pub struct ${longhand.camel_case}Iter<'a> {
2358                 style_struct: &'a style_structs::${style_struct.name},
2359                 current: usize,
2360                 max: usize,
2361             }
2362 
2363             impl<'a> Iterator for ${longhand.camel_case}Iter<'a> {
2364                 type Item = longhands::${longhand.ident}::computed_value::SingleComputedValue;
2365 
next(&mut self) -> Option<Self::Item>2366                 fn next(&mut self) -> Option<Self::Item> {
2367                     self.current += 1;
2368                     if self.current <= self.max {
2369                         Some(self.style_struct.${longhand.ident}_at(self.current - 1))
2370                     } else {
2371                         None
2372                     }
2373                 }
2374             }
2375         % endif
2376     % endfor
2377 % endfor
2378 
2379 
2380 #[cfg(feature = "gecko")]
2381 pub use gecko_properties::{ComputedValues, ComputedValuesInner};
2382 
2383 #[cfg(feature = "servo")]
2384 #[cfg_attr(feature = "servo", derive(Clone, Debug))]
2385 /// Actual data of ComputedValues, to match up with Gecko
2386 pub struct ComputedValuesInner {
2387     % for style_struct in data.active_style_structs():
2388         ${style_struct.ident}: Arc<style_structs::${style_struct.name}>,
2389     % endfor
2390     custom_properties: Option<Arc<::custom_properties::CustomPropertiesMap>>,
2391     /// The writing mode of this computed values struct.
2392     pub writing_mode: WritingMode,
2393 
2394     /// A set of flags we use to store misc information regarding this style.
2395     pub flags: ComputedValueFlags,
2396 
2397     /// The rule node representing the ordered list of rules matched for this
2398     /// node.  Can be None for default values and text nodes.  This is
2399     /// essentially an optimization to avoid referencing the root rule node.
2400     pub rules: Option<StrongRuleNode>,
2401 
2402     /// The element's computed values if visited, only computed if there's a
2403     /// relevant link for this element. A element's "relevant link" is the
2404     /// element being matched if it is a link or the nearest ancestor link.
2405     visited_style: Option<Arc<ComputedValues>>,
2406 }
2407 
2408 /// The struct that Servo uses to represent computed values.
2409 ///
2410 /// This struct contains an immutable atomically-reference-counted pointer to
2411 /// every kind of style struct.
2412 ///
2413 /// When needed, the structs may be copied in order to get mutated.
2414 #[cfg(feature = "servo")]
2415 #[cfg_attr(feature = "servo", derive(Clone, Debug))]
2416 pub struct ComputedValues {
2417     /// The actual computed values
2418     ///
2419     /// In Gecko the outer ComputedValues is actually a style context,
2420     /// whereas ComputedValuesInner is the core set of computed values.
2421     ///
2422     /// We maintain this distinction in servo to reduce the amount of special casing.
2423     inner: ComputedValuesInner,
2424 }
2425 
2426 impl ComputedValues {
2427     /// Returns whether this style's display value is equal to contents.
is_display_contents(&self) -> bool2428     pub fn is_display_contents(&self) -> bool {
2429         self.get_box().clone_display().is_contents()
2430     }
2431 
2432     /// Whether we're a visited style.
is_style_if_visited(&self) -> bool2433     pub fn is_style_if_visited(&self) -> bool {
2434         self.flags.contains(ComputedValueFlags::IS_STYLE_IF_VISITED)
2435     }
2436 
2437     /// Gets a reference to the rule node. Panic if no rule node exists.
rules(&self) -> &StrongRuleNode2438     pub fn rules(&self) -> &StrongRuleNode {
2439         self.rules.as_ref().unwrap()
2440     }
2441 
2442     /// Returns the visited style, if any.
visited_style(&self) -> Option<<&ComputedValues>2443     pub fn visited_style(&self) -> Option<<&ComputedValues> {
2444         self.visited_style.as_ref().map(|s| &**s)
2445     }
2446 
2447     /// Returns the visited rules, if applicable.
visited_rules(&self) -> Option<<&StrongRuleNode>2448     pub fn visited_rules(&self) -> Option<<&StrongRuleNode> {
2449         self.visited_style.as_ref().and_then(|s| s.rules.as_ref())
2450     }
2451 
2452     /// Returns whether we're in a display: none subtree.
is_in_display_none_subtree(&self) -> bool2453     pub fn is_in_display_none_subtree(&self) -> bool {
2454         use properties::computed_value_flags::ComputedValueFlags;
2455 
2456         self.flags.contains(ComputedValueFlags::IS_IN_DISPLAY_NONE_SUBTREE)
2457     }
2458 
2459     /// Gets a reference to the custom properties map (if one exists).
custom_properties(&self) -> Option<<&Arc<::custom_properties::CustomPropertiesMap>>2460     pub fn custom_properties(&self) -> Option<<&Arc<::custom_properties::CustomPropertiesMap>> {
2461         self.custom_properties.as_ref()
2462     }
2463 }
2464 
2465 #[cfg(feature = "servo")]
2466 impl ComputedValues {
2467     /// Create a new refcounted `ComputedValues`
2468     pub fn new(
2469         _: &Device,
2470         _: Option<<&ComputedValues>,
2471         _: Option<<&PseudoElement>,
2472         custom_properties: Option<Arc<::custom_properties::CustomPropertiesMap>>,
2473         writing_mode: WritingMode,
2474         flags: ComputedValueFlags,
2475         rules: Option<StrongRuleNode>,
2476         visited_style: Option<Arc<ComputedValues>>,
2477         % for style_struct in data.active_style_structs():
2478         ${style_struct.ident}: Arc<style_structs::${style_struct.name}>,
2479         % endfor
2480     ) -> Arc<Self> {
2481         Arc::new(Self {
2482             inner: ComputedValuesInner {
2483                 custom_properties,
2484                 writing_mode,
2485                 rules,
2486                 visited_style,
2487                 flags,
2488             % for style_struct in data.active_style_structs():
2489                 ${style_struct.ident},
2490             % endfor
2491             }
2492         })
2493     }
2494 
2495     /// Get the initial computed values.
initial_values() -> &'static Self2496     pub fn initial_values() -> &'static Self { &*INITIAL_SERVO_VALUES }
2497 }
2498 
2499 #[cfg(feature = "servo")]
2500 impl ops::Deref for ComputedValues {
2501     type Target = ComputedValuesInner;
deref(&self) -> &ComputedValuesInner2502     fn deref(&self) -> &ComputedValuesInner {
2503         &self.inner
2504     }
2505 }
2506 
2507 #[cfg(feature = "servo")]
2508 impl ops::DerefMut for ComputedValues {
deref_mut(&mut self) -> &mut ComputedValuesInner2509     fn deref_mut(&mut self) -> &mut ComputedValuesInner {
2510         &mut self.inner
2511     }
2512 }
2513 
2514 #[cfg(feature = "servo")]
2515 impl ComputedValuesInner {
2516     % for style_struct in data.active_style_structs():
2517         /// Clone the ${style_struct.name} struct.
2518         #[inline]
2519         pub fn clone_${style_struct.name_lower}(&self) -> Arc<style_structs::${style_struct.name}> {
2520             self.${style_struct.ident}.clone()
2521         }
2522 
2523         /// Get a immutable reference to the ${style_struct.name} struct.
2524         #[inline]
2525         pub fn get_${style_struct.name_lower}(&self) -> &style_structs::${style_struct.name} {
2526             &self.${style_struct.ident}
2527         }
2528 
2529         /// Gets an immutable reference to the refcounted value that wraps
2530         /// `${style_struct.name}`.
2531         pub fn ${style_struct.name_lower}_arc(&self) -> &Arc<style_structs::${style_struct.name}> {
2532             &self.${style_struct.ident}
2533         }
2534 
2535         /// Get a mutable reference to the ${style_struct.name} struct.
2536         #[inline]
2537         pub fn mutate_${style_struct.name_lower}(&mut self) -> &mut style_structs::${style_struct.name} {
2538             Arc::make_mut(&mut self.${style_struct.ident})
2539         }
2540     % endfor
2541 
2542     /// Gets a reference to the rule node. Panic if no rule node exists.
rules(&self) -> &StrongRuleNode2543     pub fn rules(&self) -> &StrongRuleNode {
2544         self.rules.as_ref().unwrap()
2545     }
2546 
2547     /// Whether this style has a -moz-binding value. This is always false for
2548     /// Servo for obvious reasons.
has_moz_binding(&self) -> bool2549     pub fn has_moz_binding(&self) -> bool { false }
2550 
2551     #[inline]
2552     /// Returns whether the "content" property for the given style is completely
2553     /// ineffective, and would yield an empty `::before` or `::after`
2554     /// pseudo-element.
ineffective_content_property(&self) -> bool2555     pub fn ineffective_content_property(&self) -> bool {
2556         use properties::longhands::content::computed_value::T;
2557         match self.get_counters().content {
2558             T::Normal | T::None => true,
2559             T::Items(ref items) => items.is_empty(),
2560         }
2561     }
2562 
2563     /// Whether the current style or any of its ancestors is multicolumn.
2564     #[inline]
can_be_fragmented(&self) -> bool2565     pub fn can_be_fragmented(&self) -> bool {
2566         self.flags.contains(ComputedValueFlags::CAN_BE_FRAGMENTED)
2567     }
2568 
2569     /// Whether the current style is multicolumn.
2570     #[inline]
is_multicol(&self) -> bool2571     pub fn is_multicol(&self) -> bool {
2572         self.get_column().is_multicol()
2573     }
2574 
2575     /// Resolves the currentColor keyword.
2576     ///
2577     /// Any color value from computed values (except for the 'color' property
2578     /// itself) should go through this method.
2579     ///
2580     /// Usage example:
2581     /// let top_color = style.resolve_color(style.Border.border_top_color);
2582     #[inline]
resolve_color(&self, color: computed::Color) -> RGBA2583     pub fn resolve_color(&self, color: computed::Color) -> RGBA {
2584         color.to_rgba(self.get_color().color)
2585     }
2586 
2587     /// Get the logical computed inline size.
2588     #[inline]
content_inline_size(&self) -> computed::LengthOrPercentageOrAuto2589     pub fn content_inline_size(&self) -> computed::LengthOrPercentageOrAuto {
2590         let position_style = self.get_position();
2591         if self.writing_mode.is_vertical() {
2592             position_style.height
2593         } else {
2594             position_style.width
2595         }
2596     }
2597 
2598     /// Get the logical computed block size.
2599     #[inline]
content_block_size(&self) -> computed::LengthOrPercentageOrAuto2600     pub fn content_block_size(&self) -> computed::LengthOrPercentageOrAuto {
2601         let position_style = self.get_position();
2602         if self.writing_mode.is_vertical() { position_style.width } else { position_style.height }
2603     }
2604 
2605     /// Get the logical computed min inline size.
2606     #[inline]
min_inline_size(&self) -> computed::LengthOrPercentage2607     pub fn min_inline_size(&self) -> computed::LengthOrPercentage {
2608         let position_style = self.get_position();
2609         if self.writing_mode.is_vertical() { position_style.min_height } else { position_style.min_width }
2610     }
2611 
2612     /// Get the logical computed min block size.
2613     #[inline]
min_block_size(&self) -> computed::LengthOrPercentage2614     pub fn min_block_size(&self) -> computed::LengthOrPercentage {
2615         let position_style = self.get_position();
2616         if self.writing_mode.is_vertical() { position_style.min_width } else { position_style.min_height }
2617     }
2618 
2619     /// Get the logical computed max inline size.
2620     #[inline]
max_inline_size(&self) -> computed::LengthOrPercentageOrNone2621     pub fn max_inline_size(&self) -> computed::LengthOrPercentageOrNone {
2622         let position_style = self.get_position();
2623         if self.writing_mode.is_vertical() { position_style.max_height } else { position_style.max_width }
2624     }
2625 
2626     /// Get the logical computed max block size.
2627     #[inline]
max_block_size(&self) -> computed::LengthOrPercentageOrNone2628     pub fn max_block_size(&self) -> computed::LengthOrPercentageOrNone {
2629         let position_style = self.get_position();
2630         if self.writing_mode.is_vertical() { position_style.max_width } else { position_style.max_height }
2631     }
2632 
2633     /// Get the logical computed padding for this writing mode.
2634     #[inline]
logical_padding(&self) -> LogicalMargin<computed::LengthOrPercentage>2635     pub fn logical_padding(&self) -> LogicalMargin<computed::LengthOrPercentage> {
2636         let padding_style = self.get_padding();
2637         LogicalMargin::from_physical(self.writing_mode, SideOffsets2D::new(
2638             padding_style.padding_top.0,
2639             padding_style.padding_right.0,
2640             padding_style.padding_bottom.0,
2641             padding_style.padding_left.0,
2642         ))
2643     }
2644 
2645     /// Get the logical border width
2646     #[inline]
border_width_for_writing_mode(&self, writing_mode: WritingMode) -> LogicalMargin<Au>2647     pub fn border_width_for_writing_mode(&self, writing_mode: WritingMode) -> LogicalMargin<Au> {
2648         let border_style = self.get_border();
2649         LogicalMargin::from_physical(writing_mode, SideOffsets2D::new(
2650             Au::from(border_style.border_top_width),
2651             Au::from(border_style.border_right_width),
2652             Au::from(border_style.border_bottom_width),
2653             Au::from(border_style.border_left_width),
2654         ))
2655     }
2656 
2657     /// Gets the logical computed border widths for this style.
2658     #[inline]
logical_border_width(&self) -> LogicalMargin<Au>2659     pub fn logical_border_width(&self) -> LogicalMargin<Au> {
2660         self.border_width_for_writing_mode(self.writing_mode)
2661     }
2662 
2663     /// Gets the logical computed margin from this style.
2664     #[inline]
logical_margin(&self) -> LogicalMargin<computed::LengthOrPercentageOrAuto>2665     pub fn logical_margin(&self) -> LogicalMargin<computed::LengthOrPercentageOrAuto> {
2666         let margin_style = self.get_margin();
2667         LogicalMargin::from_physical(self.writing_mode, SideOffsets2D::new(
2668             margin_style.margin_top,
2669             margin_style.margin_right,
2670             margin_style.margin_bottom,
2671             margin_style.margin_left,
2672         ))
2673     }
2674 
2675     /// Gets the logical position from this style.
2676     #[inline]
logical_position(&self) -> LogicalMargin<computed::LengthOrPercentageOrAuto>2677     pub fn logical_position(&self) -> LogicalMargin<computed::LengthOrPercentageOrAuto> {
2678         // FIXME(SimonSapin): should be the writing mode of the containing block, maybe?
2679         let position_style = self.get_position();
2680         LogicalMargin::from_physical(self.writing_mode, SideOffsets2D::new(
2681             position_style.top,
2682             position_style.right,
2683             position_style.bottom,
2684             position_style.left,
2685         ))
2686     }
2687 
2688     /// Return true if the effects force the transform style to be Flat
overrides_transform_style(&self) -> bool2689     pub fn overrides_transform_style(&self) -> bool {
2690         use computed_values::mix_blend_mode::T as MixBlendMode;
2691 
2692         let effects = self.get_effects();
2693         // TODO(gw): Add clip-path, isolation, mask-image, mask-border-source when supported.
2694         effects.opacity < 1.0 ||
2695            !effects.filter.0.is_empty() ||
2696            !effects.clip.is_auto() ||
2697            effects.mix_blend_mode != MixBlendMode::Normal
2698     }
2699 
2700     /// <https://drafts.csswg.org/css-transforms/#grouping-property-values>
get_used_transform_style(&self) -> computed_values::transform_style::T2701     pub fn get_used_transform_style(&self) -> computed_values::transform_style::T {
2702         use computed_values::transform_style::T as TransformStyle;
2703 
2704         let box_ = self.get_box();
2705 
2706         if self.overrides_transform_style() {
2707             TransformStyle::Flat
2708         } else {
2709             // Return the computed value if not overridden by the above exceptions
2710             box_.transform_style
2711         }
2712     }
2713 
2714     /// Whether given this transform value, the compositor would require a
2715     /// layer.
transform_requires_layer(&self) -> bool2716     pub fn transform_requires_layer(&self) -> bool {
2717         use values::generics::transform::TransformOperation;
2718         // Check if the transform matrix is 2D or 3D
2719         for transform in &self.get_box().transform.0 {
2720             match *transform {
2721                 TransformOperation::Perspective(..) => {
2722                     return true;
2723                 }
2724                 TransformOperation::Matrix3D(m) => {
2725                     // See http://dev.w3.org/csswg/css-transforms/#2d-matrix
2726                     if m.m31 != 0.0 || m.m32 != 0.0 ||
2727                        m.m13 != 0.0 || m.m23 != 0.0 ||
2728                        m.m43 != 0.0 || m.m14 != 0.0 ||
2729                        m.m24 != 0.0 || m.m34 != 0.0 ||
2730                        m.m33 != 1.0 || m.m44 != 1.0 {
2731                         return true;
2732                     }
2733                 }
2734                 TransformOperation::Translate3D(_, _, z) |
2735                 TransformOperation::TranslateZ(z) => {
2736                     if z.px() != 0. {
2737                         return true;
2738                     }
2739                 }
2740                 _ => {}
2741             }
2742         }
2743 
2744         // Neither perspective nor transform present
2745         false
2746     }
2747 
2748     /// Serializes the computed value of this property as a string.
computed_value_to_string(&self, property: PropertyDeclarationId) -> String2749     pub fn computed_value_to_string(&self, property: PropertyDeclarationId) -> String {
2750         match property {
2751             % for style_struct in data.active_style_structs():
2752                 % for longhand in style_struct.longhands:
2753                     PropertyDeclarationId::Longhand(LonghandId::${longhand.camel_case}) => {
2754                         self.${style_struct.ident}.${longhand.ident}.to_css_string()
2755                     }
2756                 % endfor
2757             % endfor
2758             PropertyDeclarationId::Custom(name) => {
2759                 self.custom_properties
2760                     .as_ref()
2761                     .and_then(|map| map.get(name))
2762                     .map(|value| value.to_css_string())
2763                     .unwrap_or(String::new())
2764             }
2765         }
2766     }
2767 }
2768 
2769 % if product == "gecko":
2770     pub use ::servo_arc::RawOffsetArc as BuilderArc;
2771     /// Clone an arc, returning a regular arc
clone_arc<T: 'static>(x: &BuilderArc<T>) -> Arc<T>2772     fn clone_arc<T: 'static>(x: &BuilderArc<T>) -> Arc<T> {
2773         Arc::from_raw_offset(x.clone())
2774     }
2775 % else:
2776     pub use ::servo_arc::Arc as BuilderArc;
2777     /// Clone an arc, returning a regular arc
clone_arc<T: 'static>(x: &BuilderArc<T>) -> Arc<T>2778     fn clone_arc<T: 'static>(x: &BuilderArc<T>) -> Arc<T> {
2779         x.clone()
2780     }
2781 % endif
2782 
2783 /// A reference to a style struct of the parent, or our own style struct.
2784 pub enum StyleStructRef<'a, T: 'static> {
2785     /// A borrowed struct from the parent, for example, for inheriting style.
2786     Borrowed(&'a BuilderArc<T>),
2787     /// An owned struct, that we've already mutated.
2788     Owned(UniqueArc<T>),
2789     /// Temporarily vacated, will panic if accessed
2790     Vacated,
2791 }
2792 
2793 impl<'a, T: 'a> StyleStructRef<'a, T>
2794     where T: Clone,
2795 {
2796     /// Ensure a mutable reference of this value exists, either cloning the
2797     /// borrowed value, or returning the owned one.
mutate(&mut self) -> &mut T2798     pub fn mutate(&mut self) -> &mut T {
2799         if let StyleStructRef::Borrowed(v) = *self {
2800             *self = StyleStructRef::Owned(UniqueArc::new((**v).clone()));
2801         }
2802 
2803         match *self {
2804             StyleStructRef::Owned(ref mut v) => v,
2805             StyleStructRef::Borrowed(..) => unreachable!(),
2806             StyleStructRef::Vacated => panic!("Accessed vacated style struct")
2807         }
2808     }
2809 
2810     /// Extract a unique Arc from this struct, vacating it.
2811     ///
2812     /// The vacated state is a transient one, please put the Arc back
2813     /// when done via `put()`. This function is to be used to separate
2814     /// the struct being mutated from the computed context
take(&mut self) -> UniqueArc<T>2815     pub fn take(&mut self) -> UniqueArc<T> {
2816         use std::mem::replace;
2817         let inner = replace(self, StyleStructRef::Vacated);
2818 
2819         match inner {
2820             StyleStructRef::Owned(arc) => arc,
2821             StyleStructRef::Borrowed(arc) => UniqueArc::new((**arc).clone()),
2822             StyleStructRef::Vacated => panic!("Accessed vacated style struct"),
2823         }
2824     }
2825 
2826     /// Replace vacated ref with an arc
put(&mut self, arc: UniqueArc<T>)2827     pub fn put(&mut self, arc: UniqueArc<T>) {
2828         debug_assert!(matches!(*self, StyleStructRef::Vacated));
2829         *self = StyleStructRef::Owned(arc);
2830     }
2831 
2832     /// Get a mutable reference to the owned struct, or `None` if the struct
2833     /// hasn't been mutated.
get_if_mutated(&mut self) -> Option<<&mut T>2834     pub fn get_if_mutated(&mut self) -> Option<<&mut T> {
2835         match *self {
2836             StyleStructRef::Owned(ref mut v) => Some(v),
2837             StyleStructRef::Borrowed(..) => None,
2838             StyleStructRef::Vacated => panic!("Accessed vacated style struct")
2839         }
2840     }
2841 
2842     /// Returns an `Arc` to the internal struct, constructing one if
2843     /// appropriate.
build(self) -> Arc<T>2844     pub fn build(self) -> Arc<T> {
2845         match self {
2846             StyleStructRef::Owned(v) => v.shareable(),
2847             StyleStructRef::Borrowed(v) => clone_arc(v),
2848             StyleStructRef::Vacated => panic!("Accessed vacated style struct")
2849         }
2850     }
2851 }
2852 
2853 impl<'a, T: 'a> ops::Deref for StyleStructRef<'a, T> {
2854     type Target = T;
2855 
deref(&self) -> &T2856     fn deref(&self) -> &T {
2857         match *self {
2858             StyleStructRef::Owned(ref v) => &**v,
2859             StyleStructRef::Borrowed(v) => &**v,
2860             StyleStructRef::Vacated => panic!("Accessed vacated style struct")
2861         }
2862     }
2863 }
2864 
2865 /// A type used to compute a struct with minimal overhead.
2866 ///
2867 /// This allows holding references to the parent/default computed values without
2868 /// actually cloning them, until we either build the style, or mutate the
2869 /// inherited value.
2870 pub struct StyleBuilder<'a> {
2871     /// The device we're using to compute style.
2872     ///
2873     /// This provides access to viewport unit ratios, etc.
2874     pub device: &'a Device,
2875 
2876     /// The style we're inheriting from.
2877     ///
2878     /// This is effectively
2879     /// `parent_style.unwrap_or(device.default_computed_values())`.
2880     inherited_style: &'a ComputedValues,
2881 
2882     /// The style we're inheriting from for properties that don't inherit from
2883     /// ::first-line.  This is the same as inherited_style, unless
2884     /// inherited_style is a ::first-line style.
2885     inherited_style_ignoring_first_line: &'a ComputedValues,
2886 
2887     /// The style we're getting reset structs from.
2888     reset_style: &'a ComputedValues,
2889 
2890     /// The style we're inheriting from explicitly, or none if we're the root of
2891     /// a subtree.
2892     parent_style: Option<<&'a ComputedValues>,
2893 
2894     /// The rule node representing the ordered list of rules matched for this
2895     /// node.
2896     pub rules: Option<StrongRuleNode>,
2897 
2898     custom_properties: Option<Arc<::custom_properties::CustomPropertiesMap>>,
2899 
2900     /// The pseudo-element this style will represent.
2901     pub pseudo: Option<<&'a PseudoElement>,
2902 
2903     /// Whether we have mutated any reset structs since the the last time
2904     /// `clear_modified_reset` was called.  This is used to tell whether the
2905     /// `StyleAdjuster` did any work.
2906     modified_reset: bool,
2907 
2908     /// The writing mode flags.
2909     ///
2910     /// TODO(emilio): Make private.
2911     pub writing_mode: WritingMode,
2912     /// Flags for the computed value.
2913     pub flags: ComputedValueFlags,
2914     /// The element's style if visited, only computed if there's a relevant link
2915     /// for this element.  A element's "relevant link" is the element being
2916     /// matched if it is a link or the nearest ancestor link.
2917     visited_style: Option<Arc<ComputedValues>>,
2918     % for style_struct in data.active_style_structs():
2919         ${style_struct.ident}: StyleStructRef<'a, style_structs::${style_struct.name}>,
2920     % endfor
2921 }
2922 
2923 impl<'a> StyleBuilder<'a> {
2924     /// Trivially construct a `StyleBuilder`.
new( device: &'a Device, parent_style: Option<<&'a ComputedValues>, parent_style_ignoring_first_line: Option<<&'a ComputedValues>, pseudo: Option<<&'a PseudoElement>, cascade_flags: CascadeFlags, rules: Option<StrongRuleNode>, custom_properties: Option<Arc<::custom_properties::CustomPropertiesMap>>, visited_style: Option<Arc<ComputedValues>>, ) -> Self2925     fn new(
2926         device: &'a Device,
2927         parent_style: Option<<&'a ComputedValues>,
2928         parent_style_ignoring_first_line: Option<<&'a ComputedValues>,
2929         pseudo: Option<<&'a PseudoElement>,
2930         cascade_flags: CascadeFlags,
2931         rules: Option<StrongRuleNode>,
2932         custom_properties: Option<Arc<::custom_properties::CustomPropertiesMap>>,
2933         visited_style: Option<Arc<ComputedValues>>,
2934     ) -> Self {
2935         debug_assert_eq!(parent_style.is_some(), parent_style_ignoring_first_line.is_some());
2936         #[cfg(feature = "gecko")]
2937         debug_assert!(parent_style.is_none() ||
2938                       ::std::ptr::eq(parent_style.unwrap(),
2939                                      parent_style_ignoring_first_line.unwrap()) ||
2940                       parent_style.unwrap().pseudo() == Some(PseudoElement::FirstLine));
2941         let reset_style = device.default_computed_values();
2942         let inherited_style = parent_style.unwrap_or(reset_style);
2943         let inherited_style_ignoring_first_line = parent_style_ignoring_first_line.unwrap_or(reset_style);
2944         // FIXME(bz): INHERIT_ALL seems like a fundamentally broken idea.  I'm
2945         // 99% sure it should give incorrect behavior for table anonymous box
2946         // backgrounds, for example.  This code doesn't attempt to make it play
2947         // nice with inherited_style_ignoring_first_line.
2948         let reset_style = if cascade_flags.contains(CascadeFlags::INHERIT_ALL) {
2949             inherited_style
2950         } else {
2951             reset_style
2952         };
2953 
2954         let mut flags = inherited_style.flags.inherited();
2955         if cascade_flags.contains(CascadeFlags::VISITED_DEPENDENT_ONLY) {
2956             flags.insert(ComputedValueFlags::IS_STYLE_IF_VISITED);
2957         }
2958 
2959         StyleBuilder {
2960             device,
2961             parent_style,
2962             inherited_style,
2963             inherited_style_ignoring_first_line,
2964             reset_style,
2965             pseudo,
2966             rules,
2967             modified_reset: false,
2968             custom_properties,
2969             writing_mode: inherited_style.writing_mode,
2970             flags,
2971             visited_style,
2972             % for style_struct in data.active_style_structs():
2973             % if style_struct.inherited:
2974             ${style_struct.ident}: StyleStructRef::Borrowed(inherited_style.${style_struct.name_lower}_arc()),
2975             % else:
2976             ${style_struct.ident}: StyleStructRef::Borrowed(reset_style.${style_struct.name_lower}_arc()),
2977             % endif
2978             % endfor
2979         }
2980     }
2981 
2982     /// Whether we're a visited style.
is_style_if_visited(&self) -> bool2983     pub fn is_style_if_visited(&self) -> bool {
2984         self.flags.contains(ComputedValueFlags::IS_STYLE_IF_VISITED)
2985     }
2986 
2987     /// NOTE(emilio): This is done so we can compute relative units with respect
2988     /// to the parent style, but all the early properties / writing-mode / etc
2989     /// are already set to the right ones on the kid.
2990     ///
2991     /// Do _not_ actually call this to construct a style, this should mostly be
2992     /// used for animations.
for_animation( device: &'a Device, style_to_derive_from: &'a ComputedValues, parent_style: Option<<&'a ComputedValues>, ) -> Self2993     pub fn for_animation(
2994         device: &'a Device,
2995         style_to_derive_from: &'a ComputedValues,
2996         parent_style: Option<<&'a ComputedValues>,
2997     ) -> Self {
2998         let reset_style = device.default_computed_values();
2999         let inherited_style = parent_style.unwrap_or(reset_style);
3000         #[cfg(feature = "gecko")]
3001         debug_assert!(parent_style.is_none() ||
3002                       parent_style.unwrap().pseudo() != Some(PseudoElement::FirstLine));
3003         StyleBuilder {
3004             device,
3005             parent_style,
3006             inherited_style,
3007             // None of our callers pass in ::first-line parent styles.
3008             inherited_style_ignoring_first_line: inherited_style,
3009             reset_style,
3010             pseudo: None,
3011             modified_reset: false,
3012             rules: None,
3013             custom_properties: style_to_derive_from.custom_properties().cloned(),
3014             writing_mode: style_to_derive_from.writing_mode,
3015             flags: style_to_derive_from.flags,
3016             visited_style: None,
3017             % for style_struct in data.active_style_structs():
3018             ${style_struct.ident}: StyleStructRef::Borrowed(
3019                 style_to_derive_from.${style_struct.name_lower}_arc()
3020             ),
3021             % endfor
3022         }
3023     }
3024 
3025     /// Copy the reset properties from `style`.
copy_reset_from(&mut self, style: &'a ComputedValues)3026     pub fn copy_reset_from(&mut self, style: &'a ComputedValues) {
3027         % for style_struct in data.active_style_structs():
3028         % if not style_struct.inherited:
3029         self.${style_struct.ident} =
3030             StyleStructRef::Borrowed(style.${style_struct.name_lower}_arc());
3031         % endif
3032         % endfor
3033     }
3034 
3035     % for property in data.longhands:
3036     % if property.ident != "font_size":
3037     /// Inherit `${property.ident}` from our parent style.
3038     #[allow(non_snake_case)]
3039     pub fn inherit_${property.ident}(&mut self) {
3040         let inherited_struct =
3041         % if property.style_struct.inherited:
3042             self.inherited_style.get_${property.style_struct.name_lower}();
3043         % else:
3044             self.inherited_style_ignoring_first_line
3045                 .get_${property.style_struct.name_lower}();
3046         % endif
3047 
3048         % if not property.style_struct.inherited:
3049         self.flags.insert(ComputedValueFlags::INHERITS_RESET_STYLE);
3050         self.modified_reset = true;
3051         % endif
3052 
3053         % if property.ident == "content":
3054         self.flags.insert(ComputedValueFlags::INHERITS_CONTENT);
3055         % endif
3056 
3057         % if property.ident == "display":
3058         self.flags.insert(ComputedValueFlags::INHERITS_DISPLAY);
3059         % endif
3060 
3061         self.${property.style_struct.ident}.mutate()
3062             .copy_${property.ident}_from(
3063                 inherited_struct,
3064                 % if property.logical:
3065                 self.writing_mode,
3066                 % endif
3067             );
3068     }
3069 
3070     /// Reset `${property.ident}` to the initial value.
3071     #[allow(non_snake_case)]
3072     pub fn reset_${property.ident}(&mut self) {
3073         let reset_struct =
3074             self.reset_style.get_${property.style_struct.name_lower}();
3075 
3076         % if not property.style_struct.inherited:
3077         self.modified_reset = true;
3078         % endif
3079 
3080         self.${property.style_struct.ident}.mutate()
3081             .reset_${property.ident}(
3082                 reset_struct,
3083                 % if property.logical:
3084                 self.writing_mode,
3085                 % endif
3086             );
3087     }
3088 
3089     % if not property.is_vector:
3090     /// Set the `${property.ident}` to the computed value `value`.
3091     #[allow(non_snake_case)]
3092     pub fn set_${property.ident}(
3093         &mut self,
3094         value: longhands::${property.ident}::computed_value::T
3095     ) {
3096         % if not property.style_struct.inherited:
3097         self.modified_reset = true;
3098         % endif
3099 
3100         <% props_need_device = ["content", "list_style_type", "font_variant_alternates"] %>
3101         self.${property.style_struct.ident}.mutate()
3102             .set_${property.ident}(
3103                 value,
3104                 % if property.logical:
3105                 self.writing_mode,
3106                 % elif product == "gecko" and property.ident in props_need_device:
3107                 self.device,
3108                 % endif
3109             );
3110     }
3111     % endif
3112     % endif
3113     % endfor
3114 
3115     /// Inherits style from the parent element, accounting for the default
3116     /// computed values that need to be provided as well.
for_inheritance( device: &'a Device, parent: Option<<&'a ComputedValues>, pseudo: Option<<&'a PseudoElement>, ) -> Self3117     pub fn for_inheritance(
3118         device: &'a Device,
3119         parent: Option<<&'a ComputedValues>,
3120         pseudo: Option<<&'a PseudoElement>,
3121     ) -> Self {
3122         // Rebuild the visited style from the parent, ensuring that it will also
3123         // not have rules.  This matches the unvisited style that will be
3124         // produced by this builder.  This assumes that the caller doesn't need
3125         // to adjust or process visited style, so we can just build visited
3126         // style here for simplicity.
3127         let visited_style = parent.and_then(|parent| {
3128             parent.visited_style().map(|style| {
3129                 Self::for_inheritance(
3130                     device,
3131                     Some(style),
3132                     pseudo,
3133                 ).build()
3134             })
3135         });
3136         Self::new(
3137             device,
3138             parent,
3139             parent,
3140             pseudo,
3141             CascadeFlags::empty(),
3142             /* rules = */ None,
3143             parent.and_then(|p| p.custom_properties().cloned()),
3144             visited_style,
3145         )
3146     }
3147 
3148     /// Returns whether we have a visited style.
has_visited_style(&self) -> bool3149     pub fn has_visited_style(&self) -> bool {
3150         self.visited_style.is_some()
3151     }
3152 
3153     /// Returns whether we're a pseudo-elements style.
is_pseudo_element(&self) -> bool3154     pub fn is_pseudo_element(&self) -> bool {
3155         self.pseudo.map_or(false, |p| !p.is_anon_box())
3156     }
3157 
3158     /// Returns the style we're getting reset properties from.
default_style(&self) -> &'a ComputedValues3159     pub fn default_style(&self) -> &'a ComputedValues {
3160         self.reset_style
3161     }
3162 
3163     % for style_struct in data.active_style_structs():
3164         /// Gets an immutable view of the current `${style_struct.name}` style.
3165         pub fn get_${style_struct.name_lower}(&self) -> &style_structs::${style_struct.name} {
3166             &self.${style_struct.ident}
3167         }
3168 
3169         /// Gets a mutable view of the current `${style_struct.name}` style.
3170         pub fn mutate_${style_struct.name_lower}(&mut self) -> &mut style_structs::${style_struct.name} {
3171             % if not property.style_struct.inherited:
3172             self.modified_reset = true;
3173             % endif
3174             self.${style_struct.ident}.mutate()
3175         }
3176 
3177         /// Gets a mutable view of the current `${style_struct.name}` style.
3178         pub fn take_${style_struct.name_lower}(&mut self) -> UniqueArc<style_structs::${style_struct.name}> {
3179             % if not property.style_struct.inherited:
3180             self.modified_reset = true;
3181             % endif
3182             self.${style_struct.ident}.take()
3183         }
3184 
3185         /// Gets a mutable view of the current `${style_struct.name}` style.
3186         pub fn put_${style_struct.name_lower}(&mut self, s: UniqueArc<style_structs::${style_struct.name}>) {
3187             self.${style_struct.ident}.put(s)
3188         }
3189 
3190         /// Gets a mutable view of the current `${style_struct.name}` style,
3191         /// only if it's been mutated before.
3192         pub fn get_${style_struct.name_lower}_if_mutated(&mut self)
3193                                                          -> Option<<&mut style_structs::${style_struct.name}> {
3194             self.${style_struct.ident}.get_if_mutated()
3195         }
3196 
3197         /// Reset the current `${style_struct.name}` style to its default value.
3198         pub fn reset_${style_struct.name_lower}_struct(&mut self) {
3199             self.${style_struct.ident} =
3200                 StyleStructRef::Borrowed(self.reset_style.${style_struct.name_lower}_arc());
3201         }
3202     % endfor
3203 
3204     /// Returns whether this computed style represents a floated object.
floated(&self) -> bool3205     pub fn floated(&self) -> bool {
3206         self.get_box().clone_float() != longhands::float::computed_value::T::None
3207     }
3208 
3209     /// Returns whether this computed style represents an out of flow-positioned
3210     /// object.
out_of_flow_positioned(&self) -> bool3211     pub fn out_of_flow_positioned(&self) -> bool {
3212         use properties::longhands::position::computed_value::T as Position;
3213         matches!(self.get_box().clone_position(),
3214                  Position::Absolute | Position::Fixed)
3215     }
3216 
3217     /// Whether this style has a top-layer style. That's implemented in Gecko
3218     /// via the -moz-top-layer property, but servo doesn't have any concept of a
3219     /// top layer (yet, it's needed for fullscreen).
3220     #[cfg(feature = "servo")]
in_top_layer(&self) -> bool3221     pub fn in_top_layer(&self) -> bool { false }
3222 
3223     /// Whether this style has a top-layer style.
3224     #[cfg(feature = "gecko")]
in_top_layer(&self) -> bool3225     pub fn in_top_layer(&self) -> bool {
3226         matches!(self.get_box().clone__moz_top_layer(),
3227                  longhands::_moz_top_layer::computed_value::T::Top)
3228     }
3229 
3230     /// Clears the "have any reset structs been modified" flag.
clear_modified_reset(&mut self)3231     fn clear_modified_reset(&mut self) {
3232         self.modified_reset = false;
3233     }
3234 
3235     /// Returns whether we have mutated any reset structs since the the last
3236     /// time `clear_modified_reset` was called.
modified_reset(&self) -> bool3237     fn modified_reset(&self) -> bool {
3238         self.modified_reset
3239     }
3240 
3241     /// Turns this `StyleBuilder` into a proper `ComputedValues` instance.
build(self) -> Arc<ComputedValues>3242     pub fn build(self) -> Arc<ComputedValues> {
3243         ComputedValues::new(
3244             self.device,
3245             self.parent_style,
3246             self.pseudo,
3247             self.custom_properties,
3248             self.writing_mode,
3249             self.flags,
3250             self.rules,
3251             self.visited_style,
3252             % for style_struct in data.active_style_structs():
3253             self.${style_struct.ident}.build(),
3254             % endfor
3255         )
3256     }
3257 
3258     /// Get the custom properties map if necessary.
3259     ///
3260     /// Cloning the Arc here is fine because it only happens in the case where
3261     /// we have custom properties, and those are both rare and expensive.
custom_properties(&self) -> Option<<&Arc<::custom_properties::CustomPropertiesMap>>3262     fn custom_properties(&self) -> Option<<&Arc<::custom_properties::CustomPropertiesMap>> {
3263         self.custom_properties.as_ref()
3264     }
3265 
3266     /// Access to various information about our inherited styles.  We don't
3267     /// expose an inherited ComputedValues directly, because in the
3268     /// ::first-line case some of the inherited information needs to come from
3269     /// one ComputedValues instance and some from a different one.
3270 
3271     /// Inherited writing-mode.
inherited_writing_mode(&self) -> &WritingMode3272     pub fn inherited_writing_mode(&self) -> &WritingMode {
3273         &self.inherited_style.writing_mode
3274     }
3275 
3276     /// The computed value flags of our parent.
3277     #[inline]
get_parent_flags(&self) -> ComputedValueFlags3278     pub fn get_parent_flags(&self) -> ComputedValueFlags {
3279         self.inherited_style.flags
3280     }
3281 
3282     /// And access to inherited style structs.
3283     % for style_struct in data.active_style_structs():
3284         /// Gets our inherited `${style_struct.name}`.  We don't name these
3285         /// accessors `inherited_${style_struct.name_lower}` because we already
3286         /// have things like "box" vs "inherited_box" as struct names.  Do the
3287         /// next-best thing and call them `parent_${style_struct.name_lower}`
3288         /// instead.
3289         pub fn get_parent_${style_struct.name_lower}(&self) -> &style_structs::${style_struct.name} {
3290             % if style_struct.inherited:
3291             self.inherited_style.get_${style_struct.name_lower}()
3292             % else:
3293             self.inherited_style_ignoring_first_line.get_${style_struct.name_lower}()
3294             % endif
3295         }
3296     % endfor
3297 }
3298 
3299 #[cfg(feature = "servo")]
3300 pub use self::lazy_static_module::INITIAL_SERVO_VALUES;
3301 
3302 // Use a module to work around #[cfg] on lazy_static! not being applied to every generated item.
3303 #[cfg(feature = "servo")]
3304 #[allow(missing_docs)]
3305 mod lazy_static_module {
3306     use logical_geometry::WritingMode;
3307     use servo_arc::Arc;
3308     use super::{ComputedValues, ComputedValuesInner, longhands, style_structs};
3309     use super::computed_value_flags::ComputedValueFlags;
3310 
3311     /// The initial values for all style structs as defined by the specification.
3312     lazy_static! {
3313         pub static ref INITIAL_SERVO_VALUES: ComputedValues = ComputedValues {
3314             inner: ComputedValuesInner {
3315                 % for style_struct in data.active_style_structs():
3316                     ${style_struct.ident}: Arc::new(style_structs::${style_struct.name} {
3317                         % for longhand in style_struct.longhands:
3318                             ${longhand.ident}: longhands::${longhand.ident}::get_initial_value(),
3319                         % endfor
3320                         % if style_struct.name == "InheritedText":
3321                             text_decorations_in_effect: ::values::computed::text::TextDecorationsInEffect::default(),
3322                         % endif
3323                         % if style_struct.name == "Font":
3324                             hash: 0,
3325                         % endif
3326                         % if style_struct.name == "Box":
3327                             original_display: longhands::display::get_initial_value(),
3328                         % endif
3329                     }),
3330                 % endfor
3331                 custom_properties: None,
3332                 writing_mode: WritingMode::empty(),
3333                 rules: None,
3334                 visited_style: None,
3335                 flags: ComputedValueFlags::empty(),
3336             }
3337         };
3338     }
3339 }
3340 
3341 /// A per-longhand function that performs the CSS cascade for that longhand.
3342 pub type CascadePropertyFn =
3343     extern "Rust" fn(
3344         declaration: &PropertyDeclaration,
3345         context: &mut computed::Context,
3346     );
3347 
3348 /// A per-longhand array of functions to perform the CSS cascade on each of
3349 /// them, effectively doing virtual dispatch.
3350 static CASCADE_PROPERTY: [CascadePropertyFn; ${len(data.longhands)}] = [
3351     % for property in data.longhands:
3352         longhands::${property.ident}::cascade_property,
3353     % endfor
3354 ];
3355 
3356 bitflags! {
3357     /// A set of flags to tweak the behavior of the `cascade` function.
3358     pub struct CascadeFlags: u8 {
3359         /// Whether to inherit all styles from the parent. If this flag is not
3360         /// present, non-inherited styles are reset to their initial values.
3361         const INHERIT_ALL = 1;
3362 
3363         /// Whether to only cascade properties that are visited dependent.
3364         const VISITED_DEPENDENT_ONLY = 1 << 1;
3365     }
3366 }
3367 
3368 /// Performs the CSS cascade, computing new styles for an element from its parent style.
3369 ///
3370 /// The arguments are:
3371 ///
3372 ///   * `device`: Used to get the initial viewport and other external state.
3373 ///
3374 ///   * `rule_node`: The rule node in the tree that represent the CSS rules that
3375 ///   matched.
3376 ///
3377 ///   * `parent_style`: The parent style, if applicable; if `None`, this is the root node.
3378 ///
3379 /// Returns the computed values.
3380 ///   * `flags`: Various flags.
3381 ///
cascade<E>( device: &Device, pseudo: Option<<&PseudoElement>, rule_node: &StrongRuleNode, guards: &StylesheetGuards, parent_style: Option<<&ComputedValues>, parent_style_ignoring_first_line: Option<<&ComputedValues>, layout_parent_style: Option<<&ComputedValues>, visited_style: Option<Arc<ComputedValues>>, font_metrics_provider: &FontMetricsProvider, flags: CascadeFlags, quirks_mode: QuirksMode, rule_cache: Option<<&RuleCache>, rule_cache_conditions: &mut RuleCacheConditions, element: Option<E>, ) -> Arc<ComputedValues> where E: TElement,3382 pub fn cascade<E>(
3383     device: &Device,
3384     pseudo: Option<<&PseudoElement>,
3385     rule_node: &StrongRuleNode,
3386     guards: &StylesheetGuards,
3387     parent_style: Option<<&ComputedValues>,
3388     parent_style_ignoring_first_line: Option<<&ComputedValues>,
3389     layout_parent_style: Option<<&ComputedValues>,
3390     visited_style: Option<Arc<ComputedValues>>,
3391     font_metrics_provider: &FontMetricsProvider,
3392     flags: CascadeFlags,
3393     quirks_mode: QuirksMode,
3394     rule_cache: Option<<&RuleCache>,
3395     rule_cache_conditions: &mut RuleCacheConditions,
3396     element: Option<E>,
3397 ) -> Arc<ComputedValues>
3398 where
3399     E: TElement,
3400 {
3401     debug_assert_eq!(parent_style.is_some(), parent_style_ignoring_first_line.is_some());
3402     let empty = SmallBitVec::new();
3403 
3404     let property_restriction = pseudo.and_then(|p| p.property_restriction());
3405 
3406     let iter_declarations = || {
3407         rule_node.self_and_ancestors().flat_map(|node| {
3408             let cascade_level = node.cascade_level();
3409             let source = node.style_source();
3410 
3411             let declarations = if source.is_some() {
3412                 source.read(cascade_level.guard(guards)).declaration_importance_iter()
3413             } else {
3414                 // The root node has no style source.
3415                 DeclarationImportanceIterator::new(&[], &empty)
3416             };
3417             let node_importance = node.importance();
3418 
3419             declarations
3420                 // Yield declarations later in source order (with more precedence) first.
3421                 .rev()
3422                 .filter_map(move |(declaration, declaration_importance)| {
3423                     if let Some(property_restriction) = property_restriction {
3424                         // declaration.id() is either a longhand or a custom
3425                         // property.  Custom properties are always allowed, but
3426                         // longhands are only allowed if they have our
3427                         // property_restriction flag set.
3428                         if let PropertyDeclarationId::Longhand(id) = declaration.id() {
3429                             if !id.flags().contains(property_restriction) {
3430                                 return None
3431                             }
3432                         }
3433                     }
3434 
3435                     if declaration_importance == node_importance {
3436                         Some((declaration, cascade_level))
3437                     } else {
3438                         None
3439                     }
3440                 })
3441         })
3442     };
3443 
3444     apply_declarations(
3445         device,
3446         pseudo,
3447         rule_node,
3448         guards,
3449         iter_declarations,
3450         parent_style,
3451         parent_style_ignoring_first_line,
3452         layout_parent_style,
3453         visited_style,
3454         font_metrics_provider,
3455         flags,
3456         quirks_mode,
3457         rule_cache,
3458         rule_cache_conditions,
3459         element,
3460     )
3461 }
3462 
3463 /// NOTE: This function expects the declaration with more priority to appear
3464 /// first.
apply_declarations<'a, E, F, I>( device: &Device, pseudo: Option<<&PseudoElement>, rules: &StrongRuleNode, guards: &StylesheetGuards, iter_declarations: F, parent_style: Option<<&ComputedValues>, parent_style_ignoring_first_line: Option<<&ComputedValues>, layout_parent_style: Option<<&ComputedValues>, visited_style: Option<Arc<ComputedValues>>, font_metrics_provider: &FontMetricsProvider, flags: CascadeFlags, quirks_mode: QuirksMode, rule_cache: Option<<&RuleCache>, rule_cache_conditions: &mut RuleCacheConditions, element: Option<E>, ) -> Arc<ComputedValues> where E: TElement, F: Fn() -> I, I: Iterator<Item = (&'a PropertyDeclaration, CascadeLevel)>,3465 pub fn apply_declarations<'a, E, F, I>(
3466     device: &Device,
3467     pseudo: Option<<&PseudoElement>,
3468     rules: &StrongRuleNode,
3469     guards: &StylesheetGuards,
3470     iter_declarations: F,
3471     parent_style: Option<<&ComputedValues>,
3472     parent_style_ignoring_first_line: Option<<&ComputedValues>,
3473     layout_parent_style: Option<<&ComputedValues>,
3474     visited_style: Option<Arc<ComputedValues>>,
3475     font_metrics_provider: &FontMetricsProvider,
3476     flags: CascadeFlags,
3477     quirks_mode: QuirksMode,
3478     rule_cache: Option<<&RuleCache>,
3479     rule_cache_conditions: &mut RuleCacheConditions,
3480     element: Option<E>,
3481 ) -> Arc<ComputedValues>
3482 where
3483     E: TElement,
3484     F: Fn() -> I,
3485     I: Iterator<Item = (&'a PropertyDeclaration, CascadeLevel)>,
3486 {
3487     debug_assert!(layout_parent_style.is_none() || parent_style.is_some());
3488     debug_assert_eq!(parent_style.is_some(), parent_style_ignoring_first_line.is_some());
3489     #[cfg(feature = "gecko")]
3490     debug_assert!(parent_style.is_none() ||
3491                   ::std::ptr::eq(parent_style.unwrap(),
3492                                  parent_style_ignoring_first_line.unwrap()) ||
3493                   parent_style.unwrap().pseudo() == Some(PseudoElement::FirstLine));
3494     let (inherited_style, layout_parent_style) = match parent_style {
3495         Some(parent_style) => {
3496             (parent_style,
3497              layout_parent_style.unwrap_or(parent_style))
3498         },
3499         None => {
3500             (device.default_computed_values(),
3501              device.default_computed_values())
3502         }
3503     };
3504 
3505     let custom_properties = {
3506         let mut builder =
3507             CustomPropertiesBuilder::new(inherited_style.custom_properties());
3508 
3509         for (declaration, _cascade_level) in iter_declarations() {
3510             if let PropertyDeclaration::Custom(ref declaration) = *declaration {
3511                 builder.cascade(&declaration.name, declaration.value.borrow());
3512             }
3513         }
3514 
3515         builder.build()
3516     };
3517 
3518     let mut context = computed::Context {
3519         is_root_element: pseudo.is_none() && element.map_or(false, |e| e.is_root()),
3520         // We'd really like to own the rules here to avoid refcount traffic, but
3521         // animation's usage of `apply_declarations` make this tricky. See bug
3522         // 1375525.
3523         builder: StyleBuilder::new(
3524             device,
3525             parent_style,
3526             parent_style_ignoring_first_line,
3527             pseudo,
3528             flags,
3529             Some(rules.clone()),
3530             custom_properties,
3531             visited_style,
3532         ),
3533         cached_system_font: None,
3534         in_media_query: false,
3535         for_smil_animation: false,
3536         for_non_inherited_property: None,
3537         font_metrics_provider,
3538         quirks_mode,
3539         rule_cache_conditions: RefCell::new(rule_cache_conditions),
3540     };
3541 
3542     let ignore_colors = !device.use_document_colors();
3543 
3544     // Set computed values, overwriting earlier declarations for the same
3545     // property.
3546     let mut seen = LonghandIdSet::new();
3547 
3548     // Declaration blocks are stored in increasing precedence order, we want
3549     // them in decreasing order here.
3550     //
3551     // We could (and used to) use a pattern match here, but that bloats this
3552     // function to over 100K of compiled code!
3553     //
3554     // To improve i-cache behavior, we outline the individual functions and use
3555     // virtual dispatch instead.
3556     let mut apply_reset = true;
3557     % for category_to_cascade_now in ["early", "other"]:
3558         % if category_to_cascade_now == "early":
3559             // Pull these out so that we can compute them in a specific order
3560             // without introducing more iterations.
3561             let mut font_size = None;
3562             let mut font_family = None;
3563         % endif
3564         for (declaration, cascade_level) in iter_declarations() {
3565             let declaration_id = declaration.id();
3566             let longhand_id = match declaration_id {
3567                 PropertyDeclarationId::Longhand(id) => id,
3568                 PropertyDeclarationId::Custom(..) => continue,
3569             };
3570 
3571             // Only a few properties are allowed to depend on the visited state
3572             // of links.  When cascading visited styles, we can save time by
3573             // only processing these properties.
3574             if flags.contains(CascadeFlags::VISITED_DEPENDENT_ONLY) &&
3575                !longhand_id.is_visited_dependent() {
3576                 continue
3577             }
3578 
3579             if !apply_reset && !longhand_id.inherited() {
3580                 continue;
3581             }
3582 
3583             if
3584                 % if category_to_cascade_now == "early":
3585                     !
3586                 % endif
3587                 longhand_id.is_early_property()
3588             {
3589                 continue
3590             }
3591 
3592             <% maybe_to_physical = ".to_physical(writing_mode)" if category_to_cascade_now != "early" else "" %>
3593             let physical_longhand_id = longhand_id ${maybe_to_physical};
3594             if seen.contains(physical_longhand_id) {
3595                 continue
3596             }
3597 
3598             let mut declaration = match *declaration {
3599                 PropertyDeclaration::WithVariables(ref declaration) => {
3600                     if !declaration.id.inherited() {
3601                         context.rule_cache_conditions.borrow_mut()
3602                             .set_uncacheable();
3603                     }
3604                     Cow::Owned(declaration.value.substitute_variables(
3605                         declaration.id,
3606                         context.builder.custom_properties.as_ref(),
3607                         context.quirks_mode
3608                     ))
3609                 }
3610                 ref d => Cow::Borrowed(d)
3611             };
3612 
3613             // When document colors are disabled, skip properties that are
3614             // marked as ignored in that mode, unless they come from a UA or
3615             // user style sheet.
3616             if ignore_colors &&
3617                longhand_id.is_ignored_when_document_colors_disabled(
3618                    cascade_level,
3619                    context.builder.pseudo
3620                 )
3621             {
3622                 let non_transparent_background = match *declaration {
3623                     PropertyDeclaration::BackgroundColor(ref color) => {
3624                         // Treat background-color a bit differently.  If the specified
3625                         // color is anything other than a fully transparent color, convert
3626                         // it into the Device's default background color.
3627                         color.is_non_transparent()
3628                     }
3629                     _ => continue
3630                 };
3631 
3632                 // FIXME: moving this out of `match` is a work around for
3633                 // borrows being lexical.
3634                 if non_transparent_background {
3635                     let color = device.default_background_color();
3636                     declaration =
3637                         Cow::Owned(PropertyDeclaration::BackgroundColor(color.into()));
3638                 }
3639             }
3640 
3641             seen.insert(physical_longhand_id);
3642 
3643             % if category_to_cascade_now == "early":
3644                 if LonghandId::FontSize == longhand_id {
3645                     font_size = Some(declaration.clone());
3646                     continue;
3647                 }
3648                 if LonghandId::FontFamily == longhand_id {
3649                     font_family = Some(declaration.clone());
3650                     continue;
3651                 }
3652             % endif
3653 
3654             let discriminant = longhand_id as usize;
3655             (CASCADE_PROPERTY[discriminant])(&*declaration, &mut context);
3656         }
3657         % if category_to_cascade_now == "early":
3658             let writing_mode =
3659                 WritingMode::new(context.builder.get_inheritedbox());
3660             context.builder.writing_mode = writing_mode;
3661 
3662             let mut _skip_font_family = false;
3663 
3664             % if product == "gecko":
3665 
3666                 // <svg:text> is not affected by text zoom, and it uses a preshint to
3667                 // disable it. We fix up the struct when this happens by unzooming
3668                 // its contained font values, which will have been zoomed in the parent
3669                 if seen.contains(LonghandId::XTextZoom) {
3670                     let zoom = context.builder.get_font().gecko().mAllowZoom;
3671                     let parent_zoom = context.style().get_parent_font().gecko().mAllowZoom;
3672                     if  zoom != parent_zoom {
3673                         debug_assert!(!zoom,
3674                                       "We only ever disable text zoom (in svg:text), never enable it");
3675                         // can't borrow both device and font, use the take/put machinery
3676                         let mut font = context.builder.take_font();
3677                         font.unzoom_fonts(context.device());
3678                         context.builder.put_font(font);
3679                     }
3680                 }
3681 
3682                 // Whenever a single generic value is specified, gecko will do a bunch of
3683                 // recalculation walking up the rule tree, including handling the font-size stuff.
3684                 // It basically repopulates the font struct with the default font for a given
3685                 // generic and language. We handle the font-size stuff separately, so this boils
3686                 // down to just copying over the font-family lists (no other aspect of the default
3687                 // font can be configured).
3688 
3689                 if seen.contains(LonghandId::XLang) || font_family.is_some() {
3690                     // if just the language changed, the inherited generic is all we need
3691                     let mut generic = inherited_style.get_font().gecko().mGenericID;
3692                     if let Some(ref declaration) = font_family {
3693                         if let PropertyDeclaration::FontFamily(ref fam) = **declaration {
3694                             if let Some(id) = fam.single_generic() {
3695                                 generic = id;
3696                                 // In case of a specified font family with a single generic, we will
3697                                 // end up setting font family below, but its value would get
3698                                 // overwritten later in the pipeline when cascading.
3699                                 //
3700                                 // We instead skip cascading font-family in that case.
3701                                 //
3702                                 // In case of the language changing, we wish for a specified font-
3703                                 // family to override this, so we do not skip cascading then.
3704                                 _skip_font_family = true;
3705                             }
3706                         }
3707                     }
3708 
3709                     let pres_context = context.builder.device.pres_context();
3710                     let gecko_font = context.builder.mutate_font().gecko_mut();
3711                     gecko_font.mGenericID = generic;
3712                     unsafe {
3713                         bindings::Gecko_nsStyleFont_PrefillDefaultForGeneric(
3714                             gecko_font,
3715                             pres_context,
3716                             generic,
3717                         );
3718                     }
3719                 }
3720             % endif
3721 
3722             // It is important that font_size is computed before
3723             // the late properties (for em units), but after font-family
3724             // (for the base-font-size dependence for default and keyword font-sizes)
3725             // Additionally, when we support system fonts they will have to be
3726             // computed early, and *before* font_family, so I'm including
3727             // font_family here preemptively instead of keeping it within
3728             // the early properties.
3729             //
3730             // To avoid an extra iteration, we just pull out the property
3731             // during the early iteration and cascade them in order
3732             // after it.
3733             if !_skip_font_family {
3734                 if let Some(ref declaration) = font_family {
3735 
3736                     let discriminant = LonghandId::FontFamily as usize;
3737                     (CASCADE_PROPERTY[discriminant])(declaration, &mut context);
3738                     % if product == "gecko":
3739                         let device = context.builder.device;
3740                         if let PropertyDeclaration::FontFamily(ref val) = **declaration {
3741                             if val.get_system().is_some() {
3742                                 let default = context.cached_system_font
3743                                                      .as_ref().unwrap().default_font_type;
3744                                 context.builder.mutate_font().fixup_system(default);
3745                             } else {
3746                                 context.builder.mutate_font().fixup_none_generic(device);
3747                             }
3748                         }
3749                     % endif
3750                 }
3751             }
3752 
3753             if let Some(ref declaration) = font_size {
3754                 let discriminant = LonghandId::FontSize as usize;
3755                 (CASCADE_PROPERTY[discriminant])(declaration, &mut context);
3756             % if product == "gecko":
3757             // Font size must be explicitly inherited to handle lang changes and
3758             // scriptlevel changes.
3759             } else if seen.contains(LonghandId::XLang) ||
3760                       seen.contains(LonghandId::MozScriptLevel) ||
3761                       seen.contains(LonghandId::MozMinFontSizeRatio) ||
3762                       font_family.is_some() {
3763                 let discriminant = LonghandId::FontSize as usize;
3764                 let size = PropertyDeclaration::CSSWideKeyword(WideKeywordDeclaration {
3765                     id: LonghandId::FontSize,
3766                     keyword: CSSWideKeyword::Inherit,
3767                 });
3768 
3769                 (CASCADE_PROPERTY[discriminant])(&size, &mut context);
3770             % endif
3771             }
3772 
3773             if let Some(style) = rule_cache.and_then(|c| c.find(guards, &context.builder)) {
3774                 context.builder.copy_reset_from(style);
3775                 apply_reset = false;
3776             }
3777         % endif // category == "early"
3778     % endfor
3779 
3780     let mut builder = context.builder;
3781 
3782     % if product == "gecko":
3783         if let Some(ref mut bg) = builder.get_background_if_mutated() {
3784             bg.fill_arrays();
3785         }
3786 
3787         if let Some(ref mut svg) = builder.get_svg_if_mutated() {
3788             svg.fill_arrays();
3789         }
3790     % endif
3791 
3792     % if product == "servo":
3793         if seen.contains(LonghandId::FontStyle) ||
3794            seen.contains(LonghandId::FontWeight) ||
3795            seen.contains(LonghandId::FontStretch) ||
3796            seen.contains(LonghandId::FontFamily) {
3797             builder.mutate_font().compute_font_hash();
3798         }
3799     % endif
3800 
3801     builder.clear_modified_reset();
3802 
3803     StyleAdjuster::new(&mut builder).adjust(
3804         layout_parent_style,
3805         element,
3806         flags,
3807     );
3808 
3809     if builder.modified_reset() || !apply_reset {
3810         // If we adjusted any reset structs, we can't cache this ComputedValues.
3811         //
3812         // Also, if we re-used existing reset structs, don't bother caching it
3813         // back again. (Aside from being wasted effort, it will be wrong, since
3814         // context.rule_cache_conditions won't be set appropriately if we
3815         // didn't compute those reset properties.)
3816         context.rule_cache_conditions.borrow_mut()
3817             .set_uncacheable();
3818     }
3819 
3820     builder.build()
3821 }
3822 
3823 /// See StyleAdjuster::adjust_for_border_width.
adjust_border_width(style: &mut StyleBuilder)3824 pub fn adjust_border_width(style: &mut StyleBuilder) {
3825     % for side in ["top", "right", "bottom", "left"]:
3826         // Like calling to_computed_value, which wouldn't type check.
3827         if style.get_border().clone_border_${side}_style().none_or_hidden() &&
3828            style.get_border().border_${side}_has_nonzero_width() {
3829             style.set_border_${side}_width(NonNegativeLength::zero());
3830         }
3831     % endfor
3832 }
3833 
3834 /// An identifier for a given alias property.
3835 #[derive(Clone, Copy, Eq, PartialEq)]
3836 #[cfg_attr(feature = "servo", derive(MallocSizeOf))]
3837 pub enum AliasId {
3838     % for i, property in enumerate(data.all_aliases()):
3839         /// ${property.name}
3840         ${property.camel_case} = ${i},
3841     % endfor
3842 }
3843 
3844 impl fmt::Debug for AliasId {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result3845     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
3846         let name = match *self {
3847             % for property in data.all_aliases():
3848                 AliasId::${property.camel_case} => "${property.camel_case}",
3849             % endfor
3850         };
3851         formatter.write_str(name)
3852     }
3853 }
3854 
3855 // NOTE(emilio): Callers are responsible to deal with prefs.
3856 #[macro_export]
3857 macro_rules! css_properties_accessors {
3858     ($macro_name: ident) => {
3859         $macro_name! {
3860             % for kind, props in [("Longhand", data.longhands), ("Shorthand", data.shorthands)]:
3861                 % for property in props:
3862                     % if property.enabled_in_content():
3863                         % for name in [property.name] + property.alias:
3864                             % if '-' in name:
3865                                 [${to_rust_ident(name).capitalize()}, Set${to_rust_ident(name).capitalize()},
3866                                  PropertyId::${kind}(${kind}Id::${property.camel_case})],
3867                             % endif
3868                             [${to_camel_case(name)}, Set${to_camel_case(name)},
3869                              PropertyId::${kind}(${kind}Id::${property.camel_case})],
3870                         % endfor
3871                     % endif
3872                 % endfor
3873             % endfor
3874         }
3875     }
3876 }
3877 
3878 #[macro_export]
3879 macro_rules! longhand_properties_idents {
3880     ($macro_name: ident) => {
3881         $macro_name! {
3882             % for property in data.longhands:
3883                 { ${property.ident}, ${"true" if property.boxed else "false"} }
3884             % endfor
3885         }
3886     }
3887 }
3888 
3889 % if product == "servo":
3890 % for effect_name in ["repaint", "reflow_out_of_flow", "reflow", "rebuild_and_reflow_inline", "rebuild_and_reflow"]:
3891     macro_rules! restyle_damage_${effect_name} {
3892         ($old: ident, $new: ident, $damage: ident, [ $($effect:expr),* ]) => ({
3893             if
3894                 % for style_struct in data.active_style_structs():
3895                     % for longhand in style_struct.longhands:
3896                         % if effect_name in longhand.servo_restyle_damage.split() and not longhand.logical:
3897                             $old.get_${style_struct.name_lower}().${longhand.ident} !=
3898                             $new.get_${style_struct.name_lower}().${longhand.ident} ||
3899                         % endif
3900                     % endfor
3901                 % endfor
3902 
3903                 false {
3904                     $damage.insert($($effect)|*);
3905                     true
3906             } else {
3907                 false
3908             }
3909         })
3910     }
3911 % endfor
3912 % endif
3913