Bug 1421195 - Add weighted telemetry probes for parallel restyles ; r?emilio draft
authorManish Goregaokar <manishearth@gmail.com>
Tue, 28 Nov 2017 14:42:59 -0800
changeset 709302 e1cbaad39fb8fc52ad0e3f390ec0362aba6c88fd
parent 704240 0d911716d118add20cccee08ca5b6bd3d9bd523e
child 743387 46a8b30ca08021b52be84186f61f1e868d62475b
push id92606
push userbmo:manishearth@gmail.com
push dateThu, 07 Dec 2017 22:40:12 +0000
reviewersemilio
bugs1421195
milestone59.0a1
Bug 1421195 - Add weighted telemetry probes for parallel restyles ; r?emilio MozReview-Commit-ID: sVN7CWjgni
layout/style/ServoBindings.cpp
layout/style/ServoBindings.h
layout/style/ServoBindings.toml
servo/components/style/context.rs
servo/components/style/driver.rs
servo/components/style/gecko/data.rs
servo/components/style/gecko/generated/bindings.rs
servo/components/style/gecko/generated/structs.rs
servo/ports/geckolib/glue.rs
toolkit/components/telemetry/Histograms.json
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -119,23 +119,36 @@ ThreadSafeGetDefaultFontHelper(const nsP
 void
 AssertIsMainThreadOrServoLangFontPrefsCacheLocked()
 {
   MOZ_ASSERT(NS_IsMainThread() || sServoFFILock->LockedForWritingByCurrentThread());
 }
 
 
 void
-Gecko_RecordTraversalStatistics(uint32_t total, uint32_t parallel)
+Gecko_RecordTraversalStatistics(uint32_t total, uint32_t parallel,
+                                uint32_t total_t, uint32_t parallel_t,
+                                uint32_t total_s, uint32_t parallel_s)
 {
+
+#ifdef NIGHTLY_BUILD
   // we ignore cases where a page just didn't restyle a lot
   if (total > 30) {
     uint32_t percent = parallel * 100 / total;
     Telemetry::Accumulate(Telemetry::STYLO_PARALLEL_RESTYLE_FRACTION, percent);
   }
+  if (total_t > 0) {
+    uint32_t percent = parallel_t * 100 / total_t;
+    Telemetry::Accumulate(Telemetry::STYLO_PARALLEL_RESTYLE_FRACTION_WEIGHTED_TRAVERSED, percent);
+  }
+  if (total_s > 0) {
+    uint32_t percent = parallel_s * 100 / total_s;
+    Telemetry::Accumulate(Telemetry::STYLO_PARALLEL_RESTYLE_FRACTION_WEIGHTED_STYLED, percent);
+  }
+#endif
 }
 
 bool
 Gecko_IsInDocument(RawGeckoNodeBorrowed aNode)
 {
   return aNode->IsInComposedDoc();
 }
 
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -70,16 +70,22 @@ class nsSimpleContentList;
 struct nsStyleList;
 struct nsStyleImage;
 struct nsStyleGradientStop;
 class nsStyleGradient;
 class nsStyleCoord;
 struct nsStyleDisplay;
 class nsXBLBinding;
 
+#ifdef NIGHTLY_BUILD
+const bool GECKO_IS_NIGHTLY = true;
+#else
+const bool GECKO_IS_NIGHTLY = false;
+#endif
+
 namespace mozilla {
   #define STYLE_STRUCT(name_, checkdata_cb_) struct Gecko##name_ {nsStyle##name_ gecko;};
   #include "nsStyleStructList.h"
   #undef STYLE_STRUCT
 }
 
 #define STYLE_STRUCT(name_, checkdata_cb_) \
   const nsStyle##name_* ServoComputedData::GetStyle##name_() const { return &name_.mPtr->gecko; }
@@ -137,17 +143,19 @@ struct FontSizePrefs
   nscoord mDefaultSerifSize;
   nscoord mDefaultSansSerifSize;
   nscoord mDefaultMonospaceSize;
   nscoord mDefaultCursiveSize;
   nscoord mDefaultFantasySize;
 };
 
 // DOM Traversal.
-void Gecko_RecordTraversalStatistics(uint32_t total, uint32_t parallel);
+void Gecko_RecordTraversalStatistics(uint32_t total, uint32_t parallel,
+                                     uint32_t total_t, uint32_t parallel_t,
+                                     uint32_t total_s, uint32_t parallel_s);
 bool Gecko_IsInDocument(RawGeckoNodeBorrowed node);
 bool Gecko_FlattenedTreeParentIsParent(RawGeckoNodeBorrowed node);
 bool Gecko_IsSignificantChild(RawGeckoNodeBorrowed node,
                               bool text_is_significant,
                               bool whitespace_is_significant);
 RawGeckoNodeBorrowedOrNull Gecko_GetLastChild(RawGeckoNodeBorrowed node);
 RawGeckoNodeBorrowedOrNull Gecko_GetFlattenedTreeParentNode(RawGeckoNodeBorrowed node);
 RawGeckoElementBorrowedOrNull Gecko_GetBeforeOrAfterPseudo(RawGeckoElementBorrowed element, bool is_before);
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -201,16 +201,17 @@ whitelist-vars = [
     "BORDER_COLOR_.*",
     "BORDER_STYLE_.*",
     "mozilla::SERVO_PREF_.*",
     "CSS_PSEUDO_ELEMENT_.*",
     "SERVO_CSS_PSEUDO_ELEMENT_FLAGS_.*",
     "kNameSpaceID_.*",
     "kGenericFont_.*",
     "kPresContext_.*",
+    "GECKO_IS_NIGHTLY",
 ]
 whitelist-types = [
     "RawGecko.*",
     "mozilla::AnimationPropertySegment",
     "mozilla::AnonymousCounterStyle",
     "mozilla::AtomArray",
     "mozilla::ComputedTiming",
     "mozilla::ComputedTimingFunction",
--- a/servo/components/style/context.rs
+++ b/servo/components/style/context.rs
@@ -111,16 +111,31 @@ impl Default for StyleSystemOptions {
             disable_style_sharing_cache: get_env_bool("DISABLE_STYLE_SHARING_CACHE"),
             dump_style_statistics: get_env_bool("DUMP_STYLE_STATISTICS"),
             style_statistics_threshold: get_env_usize("STYLE_STATISTICS_THRESHOLD")
                                           .unwrap_or(DEFAULT_STATISTICS_THRESHOLD),
         }
     }
 }
 
+impl StyleSystemOptions {
+    #[cfg(feature = "servo")]
+    /// On Gecko's nightly build?
+    pub fn is_nightly(&self) -> bool {
+        false
+    }
+
+    #[cfg(feature = "gecko")]
+    /// On Gecko's nightly build?
+    #[inline]
+    pub fn is_nightly(&self) -> bool {
+        structs::GECKO_IS_NIGHTLY
+    }
+}
+
 /// A shared style context.
 ///
 /// There's exactly one of these during a given restyle traversal, and it's
 /// shared among the worker threads.
 pub struct SharedStyleContext<'a> {
     /// The CSS selector stylist.
     pub stylist: &'a Stylist,
 
--- a/servo/components/style/driver.rs
+++ b/servo/components/style/driver.rs
@@ -2,17 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Implements traversal over the DOM tree. The traversal starts in sequential
 //! mode, and optionally parallelizes as it discovers work.
 
 #![deny(missing_docs)]
 
-use context::{StyleContext, ThreadLocalStyleContext};
+use context::{StyleContext, ThreadLocalStyleContext, TraversalStatistics};
 use dom::{SendNode, TElement, TNode};
 use parallel;
 use parallel::{DispatchMode, WORK_UNIT_MAX};
 use rayon;
 use scoped_tls::ScopedTLS;
 use std::collections::VecDeque;
 use std::mem;
 use time;
@@ -21,30 +21,33 @@ use traversal::{DomTraversal, PerLevelTr
 /// Do a DOM traversal for top-down and (optionally) bottom-up processing,
 /// generic over `D`.
 ///
 /// We use an adaptive traversal strategy. We start out with simple sequential
 /// processing, until we arrive at a wide enough level in the DOM that the
 /// parallel traversal would parallelize it. If a thread pool is provided, we
 /// then transfer control over to the parallel traversal.
 ///
-/// Returns true if the traversal was parallel
+/// Returns true if the traversal was parallel, and also returns the statistics
+/// object containing information on nodes traversed (on nightly only). Not
+/// all of its fields will be initialized since we don't call finish().
 pub fn traverse_dom<E, D>(
     traversal: &D,
     token: PreTraverseToken<E>,
     pool: Option<&rayon::ThreadPool>
-) -> bool
+) -> (bool, Option<TraversalStatistics>)
 where
     E: TElement,
     D: DomTraversal<E>,
 {
     let root =
         token.traversal_root().expect("Should've ensured we needed to traverse");
 
     let dump_stats = traversal.shared_context().options.dump_style_statistics;
+    let is_nightly  = traversal.shared_context().options.is_nightly();
     let mut used_parallel = false;
     let start_time = if dump_stats { Some(time::precise_time_s()) } else { None };
 
     // Declare the main-thread context, as well as the worker-thread contexts,
     // which we may or may not instantiate. It's important to declare the worker-
     // thread contexts first, so that they get dropped second. This matters because:
     //   * ThreadLocalContexts borrow AtomicRefCells in TLS.
     //   * Dropping a ThreadLocalContext can run SequentialTasks.
@@ -107,31 +110,34 @@ where
                         );
                     });
                 });
                 break;
             }
             nodes_remaining_at_current_depth = discovered.len();
         }
     }
-
-    // Dump statistics to stdout if requested.
-    if dump_stats {
+    let mut maybe_stats = None;
+    // Accumulate statistics
+    if dump_stats || is_nightly {
         let mut aggregate =
             mem::replace(&mut context.thread_local.statistics, Default::default());
         let parallel = maybe_tls.is_some();
         if let Some(ref mut tls) = maybe_tls {
             let slots = unsafe { tls.unsafe_get() };
             aggregate = slots.iter().fold(aggregate, |acc, t| {
                 match *t.borrow() {
                     None => acc,
                     Some(ref cx) => &cx.statistics + &acc,
                 }
             });
         }
-        aggregate.finish(traversal, parallel, start_time.unwrap());
-        if aggregate.is_large_traversal() {
-            println!("{}", aggregate);
+
+        // dump to stdout if requested
+        if dump_stats && aggregate.is_large_traversal() {
+            aggregate.finish(traversal, parallel, start_time.unwrap());
+             println!("{}", aggregate);
         }
+        maybe_stats = Some(aggregate);
     }
 
-    used_parallel
+    (used_parallel, maybe_stats)
 }
--- a/servo/components/style/gecko/data.rs
+++ b/servo/components/style/gecko/data.rs
@@ -1,15 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Data needed to style a Gecko document.
 
 use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
+use context::TraversalStatistics;
 use dom::TElement;
 use gecko_bindings::bindings::{self, RawServoStyleSet};
 use gecko_bindings::structs::{RawGeckoPresContextOwned, ServoStyleSetSizes, ServoStyleSheet};
 use gecko_bindings::structs::{StyleSheetInfo, ServoStyleSheetInner, nsIDocument, self};
 use gecko_bindings::sugar::ownership::{HasArcFFI, HasBoxFFI, HasFFI, HasSimpleFFI};
 use invalidation::media_queries::{MediaListKey, ToMediaListKey};
 use malloc_size_of::MallocSizeOfOps;
 use media_queries::{Device, MediaList};
@@ -103,25 +104,50 @@ impl StylesheetInDocument for GeckoStyle
 
     // All the stylesheets Servo knows about are enabled, because that state is
     // handled externally by Gecko.
     fn enabled(&self) -> bool {
         true
     }
 }
 
+#[derive(Default)]
+/// Helper struct for counting traversals
+pub struct TraversalCount {
+    /// Total number of events
+    pub total_count: AtomicUsize,
+    /// Number of events which were parallel
+    pub parallel_count: AtomicUsize
+}
+
+impl TraversalCount {
+    fn record(&self, parallel: bool, count: u32) {
+        self.total_count.fetch_add(count as usize, Ordering::Relaxed);
+        if parallel {
+            self.parallel_count.fetch_add(count as usize, Ordering::Relaxed);
+        }
+    }
+
+    fn get(&self) -> (u32, u32) {
+        (self.total_count.load(Ordering::Relaxed) as u32,
+         self.parallel_count.load(Ordering::Relaxed) as u32)
+    }
+}
+
 /// The container for data that a Servo-backed Gecko document needs to style
 /// itself.
 pub struct PerDocumentStyleDataImpl {
     /// Rule processor.
     pub stylist: Stylist,
-    /// Total number of traversals that could have been parallel, for telemetry
-    pub total_traversal_count: AtomicUsize,
-    /// Number of parallel traversals
-    pub parallel_traversal_count: AtomicUsize,
+    /// Counter for traversals that could have been parallel, for telemetry
+    pub traversal_count: TraversalCount,
+    /// Counter for traversals, weighted by elements traversed,
+    pub traversal_count_traversed: TraversalCount,
+    /// Counter for traversals, weighted by elements styled,
+    pub traversal_count_styled: TraversalCount,
 }
 
 /// The data itself is an `AtomicRefCell`, which guarantees the proper semantics
 /// and unexpected races while trying to mutate it.
 pub struct PerDocumentStyleData(AtomicRefCell<PerDocumentStyleDataImpl>);
 
 impl PerDocumentStyleData {
     /// Create a dummy `PerDocumentStyleData`.
@@ -133,37 +159,45 @@ impl PerDocumentStyleData {
         //
         // Should we just force XBL Stylists to be NoQuirks?
         let quirks_mode = unsafe {
             (*device.pres_context().mDocument.raw::<nsIDocument>()).mCompatMode
         };
 
         PerDocumentStyleData(AtomicRefCell::new(PerDocumentStyleDataImpl {
             stylist: Stylist::new(device, quirks_mode.into()),
-            total_traversal_count: Default::default(),
-            parallel_traversal_count: Default::default(),
+            traversal_count: Default::default(),
+            traversal_count_traversed: Default::default(),
+            traversal_count_styled: Default::default(),
         }))
     }
 
     /// Get an immutable reference to this style data.
     pub fn borrow(&self) -> AtomicRef<PerDocumentStyleDataImpl> {
         self.0.borrow()
     }
 
     /// Get an mutable reference to this style data.
     pub fn borrow_mut(&self) -> AtomicRefMut<PerDocumentStyleDataImpl> {
         self.0.borrow_mut()
     }
 }
 
 impl Drop for PerDocumentStyleDataImpl {
     fn drop(&mut self) {
-        let total = self.total_traversal_count.load(Ordering::Relaxed) as u32;
-        let parallel = self.parallel_traversal_count.load(Ordering::Relaxed) as u32;
-        unsafe { bindings::Gecko_RecordTraversalStatistics(total, parallel) }
+        if !structs::GECKO_IS_NIGHTLY {
+            return
+        }
+        let (total, parallel)  = self.traversal_count.get();
+        let (total_t, parallel_t)  = self.traversal_count_traversed.get();
+        let (total_s, parallel_s)  = self.traversal_count_styled.get();
+
+        unsafe { bindings::Gecko_RecordTraversalStatistics(total, parallel,
+                                                           total_t, parallel_t,
+                                                           total_s, parallel_s) }
     }
 }
 
 impl PerDocumentStyleDataImpl {
     /// Recreate the style data if the stylesheets have changed.
     pub fn flush_stylesheets<E>(
         &mut self,
         guard: &SharedRwLockReadGuard,
@@ -200,20 +234,21 @@ impl PerDocumentStyleDataImpl {
     }
 
     /// Measure heap usage.
     pub fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
         self.stylist.add_size_of(ops, sizes);
     }
 
     /// Record that a traversal happened for later collection as telemetry
-    pub fn record_traversal(&self, was_parallel: bool) {
-        self.total_traversal_count.fetch_add(1, Ordering::Relaxed);
-        if was_parallel {
-            self.parallel_traversal_count.fetch_add(1, Ordering::Relaxed);
+    pub fn record_traversal(&self, was_parallel: bool, stats: Option<TraversalStatistics>) {
+        self.traversal_count.record(was_parallel, 1);
+        if let Some(stats) = stats {
+            self.traversal_count_traversed.record(was_parallel, stats.elements_traversed);
+            self.traversal_count_styled.record(was_parallel, stats.elements_styled);
         }
     }
 }
 
 unsafe impl HasFFI for PerDocumentStyleData {
     type FFIType = RawServoStyleSet;
 }
 unsafe impl HasSimpleFFI for PerDocumentStyleData {}
--- a/servo/components/style/gecko/generated/bindings.rs
+++ b/servo/components/style/gecko/generated/bindings.rs
@@ -493,16 +493,18 @@ extern "C" {
  pub fn Servo_RuleNode_Release ( ptr : RawServoRuleNodeBorrowed , ) ; 
 } extern "C" {
  pub fn Servo_StyleSet_Drop ( ptr : RawServoStyleSetOwned , ) ; 
 } extern "C" {
  pub fn Servo_SelectorList_Drop ( ptr : RawServoSelectorListOwned , ) ; 
 } extern "C" {
  pub fn Servo_SourceSizeList_Drop ( ptr : RawServoSourceSizeListOwned , ) ; 
 } extern "C" {
+ pub fn Gecko_RecordTraversalStatistics ( total : u32 , parallel : u32 , total_t : u32 , parallel_t : u32 , total_s : u32 , parallel_s : u32 , ) ; 
+} extern "C" {
  pub fn Gecko_IsInDocument ( node : RawGeckoNodeBorrowed , ) -> bool ; 
 } extern "C" {
  pub fn Gecko_FlattenedTreeParentIsParent ( node : RawGeckoNodeBorrowed , ) -> bool ; 
 } extern "C" {
  pub fn Gecko_IsSignificantChild ( node : RawGeckoNodeBorrowed , text_is_significant : bool , whitespace_is_significant : bool , ) -> bool ; 
 } extern "C" {
  pub fn Gecko_GetLastChild ( node : RawGeckoNodeBorrowed , ) -> RawGeckoNodeBorrowedOrNull ; 
 } extern "C" {
--- a/servo/components/style/gecko/generated/structs.rs
+++ b/servo/components/style/gecko/generated/structs.rs
@@ -1612,17 +1612,17 @@ pub type ServoStyleContextStrong = ::gec
  /// PLDHashEntryHdr implementation for nsAttrKey. 
  # [ repr ( C ) ] # [ derive ( Debug ) ] pub struct nsAttrHashKey { pub _base : root :: PLDHashEntryHdr , pub mKey : root :: nsAttrKey , } pub type nsAttrHashKey_KeyType = * const root :: nsAttrKey ; pub type nsAttrHashKey_KeyTypePointer = * const root :: nsAttrKey ; pub const nsAttrHashKey_ALLOW_MEMMOVE : root :: nsAttrHashKey__bindgen_ty_1 = 1 ; pub type nsAttrHashKey__bindgen_ty_1 = :: std :: os :: raw :: c_uint ; # [ test ] fn bindgen_test_layout_nsAttrHashKey ( ) { assert_eq ! ( :: std :: mem :: size_of :: < nsAttrHashKey > ( ) , 24usize , concat ! ( "Size of: " , stringify ! ( nsAttrHashKey ) ) ) ; assert_eq ! ( :: std :: mem :: align_of :: < nsAttrHashKey > ( ) , 8usize , concat ! ( "Alignment of " , stringify ! ( nsAttrHashKey ) ) ) ; assert_eq ! ( unsafe { & ( * ( 0 as * const nsAttrHashKey ) ) . mKey as * const _ as usize } , 8usize , concat ! ( "Alignment of field: " , stringify ! ( nsAttrHashKey ) , "::" , stringify ! ( mKey ) ) ) ; } # [ repr ( C ) ] pub struct nsDOMAttributeMap { pub _base : root :: nsIDOMMozNamedAttrMap , pub _base_1 : root :: nsWrapperCache , pub mRefCnt : root :: nsCycleCollectingAutoRefCnt , pub mContent : root :: nsCOMPtr , 
  /// Cache of Attrs. 
  pub mAttributeCache : root :: nsDOMAttributeMap_AttrCache , } pub type nsDOMAttributeMap_Attr = root :: mozilla :: dom :: Attr ; pub type nsDOMAttributeMap_Element = root :: mozilla :: dom :: Element ; pub type nsDOMAttributeMap_HasThreadSafeRefCnt = root :: mozilla :: FalseType ; # [ repr ( C ) ] # [ derive ( Debug , Copy ) ] pub struct nsDOMAttributeMap_cycleCollection { pub _base : root :: nsXPCOMCycleCollectionParticipant , } # [ test ] fn bindgen_test_layout_nsDOMAttributeMap_cycleCollection ( ) { assert_eq ! ( :: std :: mem :: size_of :: < nsDOMAttributeMap_cycleCollection > ( ) , 16usize , concat ! ( "Size of: " , stringify ! ( nsDOMAttributeMap_cycleCollection ) ) ) ; assert_eq ! ( :: std :: mem :: align_of :: < nsDOMAttributeMap_cycleCollection > ( ) , 8usize , concat ! ( "Alignment of " , stringify ! ( nsDOMAttributeMap_cycleCollection ) ) ) ; } impl Clone for nsDOMAttributeMap_cycleCollection { fn clone ( & self ) -> Self { * self } } pub type nsDOMAttributeMap_AttrCache = [ u64 ; 4usize ] ; extern "C" {
  # [ link_name = "\u{1}_ZN17nsDOMAttributeMap21_cycleCollectorGlobalE" ] 
  pub static mut  nsDOMAttributeMap__cycleCollectorGlobal  :  root :: nsDOMAttributeMap_cycleCollection ;
 } # [ test ] fn bindgen_test_layout_nsDOMAttributeMap ( ) { assert_eq ! ( :: std :: mem :: size_of :: < nsDOMAttributeMap > ( ) , 80usize , concat ! ( "Size of: " , stringify ! ( nsDOMAttributeMap ) ) ) ; assert_eq ! ( :: std :: mem :: align_of :: < nsDOMAttributeMap > ( ) , 8usize , concat ! ( "Alignment of " , stringify ! ( nsDOMAttributeMap ) ) ) ; } # [ repr ( C ) ] pub struct nsISMILAttr__bindgen_vtable ( :: std :: os :: raw :: c_void ) ; 
  /// 
- # [ repr ( C ) ] # [ derive ( Debug ) ] pub struct nsISMILAttr { pub vtable_ : * const nsISMILAttr__bindgen_vtable , } # [ test ] fn bindgen_test_layout_nsISMILAttr ( ) { assert_eq ! ( :: std :: mem :: size_of :: < nsISMILAttr > ( ) , 8usize , concat ! ( "Size of: " , stringify ! ( nsISMILAttr ) ) ) ; assert_eq ! ( :: std :: mem :: align_of :: < nsISMILAttr > ( ) , 8usize , concat ! ( "Alignment of " , stringify ! ( nsISMILAttr ) ) ) ; } pub const ELEMENT_SHARED_RESTYLE_BIT_1 : root :: _bindgen_ty_74 = 8388608 ; pub const ELEMENT_SHARED_RESTYLE_BIT_2 : root :: _bindgen_ty_74 = 16777216 ; pub const ELEMENT_SHARED_RESTYLE_BIT_3 : root :: _bindgen_ty_74 = 33554432 ; pub const ELEMENT_SHARED_RESTYLE_BIT_4 : root :: _bindgen_ty_74 = 67108864 ; pub const ELEMENT_SHARED_RESTYLE_BITS : root :: _bindgen_ty_74 = 125829120 ; pub const ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO : root :: _bindgen_ty_74 = 8388608 ; pub const ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO : root :: _bindgen_ty_74 = 16777216 ; pub const ELEMENT_HAS_SNAPSHOT : root :: _bindgen_ty_74 = 33554432 ; pub const ELEMENT_HANDLED_SNAPSHOT : root :: _bindgen_ty_74 = 67108864 ; pub const ELEMENT_HAS_PENDING_RESTYLE : root :: _bindgen_ty_74 = 8388608 ; pub const ELEMENT_IS_POTENTIAL_RESTYLE_ROOT : root :: _bindgen_ty_74 = 16777216 ; pub const ELEMENT_HAS_PENDING_ANIMATION_ONLY_RESTYLE : root :: _bindgen_ty_74 = 33554432 ; pub const ELEMENT_IS_POTENTIAL_ANIMATION_ONLY_RESTYLE_ROOT : root :: _bindgen_ty_74 = 67108864 ; pub const ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR : root :: _bindgen_ty_74 = 134217728 ; pub const ELEMENT_HAS_CHILD_WITH_LATER_SIBLINGS_HINT : root :: _bindgen_ty_74 = 268435456 ; pub const ELEMENT_PENDING_RESTYLE_FLAGS : root :: _bindgen_ty_74 = 41943040 ; pub const ELEMENT_POTENTIAL_RESTYLE_ROOT_FLAGS : root :: _bindgen_ty_74 = 83886080 ; pub const ELEMENT_ALL_RESTYLE_FLAGS : root :: _bindgen_ty_74 = 260046848 ; pub const ELEMENT_TYPE_SPECIFIC_BITS_OFFSET : root :: _bindgen_ty_74 = 27 ; pub type _bindgen_ty_74 = :: std :: os :: raw :: c_uint ; # [ repr ( C ) ] # [ derive ( Debug , Copy ) ] pub struct ServoBundledURI { pub mURLString : * const u8 , pub mURLStringLength : u32 , pub mExtraData : * mut root :: mozilla :: URLExtraData , } # [ test ] fn bindgen_test_layout_ServoBundledURI ( ) { assert_eq ! ( :: std :: mem :: size_of :: < ServoBundledURI > ( ) , 24usize , concat ! ( "Size of: " , stringify ! ( ServoBundledURI ) ) ) ; assert_eq ! ( :: std :: mem :: align_of :: < ServoBundledURI > ( ) , 8usize , concat ! ( "Alignment of " , stringify ! ( ServoBundledURI ) ) ) ; assert_eq ! ( unsafe { & ( * ( 0 as * const ServoBundledURI ) ) . mURLString as * const _ as usize } , 0usize , concat ! ( "Alignment of field: " , stringify ! ( ServoBundledURI ) , "::" , stringify ! ( mURLString ) ) ) ; assert_eq ! ( unsafe { & ( * ( 0 as * const ServoBundledURI ) ) . mURLStringLength as * const _ as usize } , 8usize , concat ! ( "Alignment of field: " , stringify ! ( ServoBundledURI ) , "::" , stringify ! ( mURLStringLength ) ) ) ; assert_eq ! ( unsafe { & ( * ( 0 as * const ServoBundledURI ) ) . mExtraData as * const _ as usize } , 16usize , concat ! ( "Alignment of field: " , stringify ! ( ServoBundledURI ) , "::" , stringify ! ( mExtraData ) ) ) ; } impl Clone for ServoBundledURI { fn clone ( & self ) -> Self { * self } } # [ repr ( C ) ] # [ derive ( Debug , Copy ) ] pub struct FontSizePrefs { pub mDefaultVariableSize : root :: nscoord , pub mDefaultFixedSize : root :: nscoord , pub mDefaultSerifSize : root :: nscoord , pub mDefaultSansSerifSize : root :: nscoord , pub mDefaultMonospaceSize : root :: nscoord , pub mDefaultCursiveSize : root :: nscoord , pub mDefaultFantasySize : root :: nscoord , } # [ test ] fn bindgen_test_layout_FontSizePrefs ( ) { assert_eq ! ( :: std :: mem :: size_of :: < FontSizePrefs > ( ) , 28usize , concat ! ( "Size of: " , stringify ! ( FontSizePrefs ) ) ) ; assert_eq ! ( :: std :: mem :: align_of :: < FontSizePrefs > ( ) , 4usize , concat ! ( "Alignment of " , stringify ! ( FontSizePrefs ) ) ) ; assert_eq ! ( unsafe { & ( * ( 0 as * const FontSizePrefs ) ) . mDefaultVariableSize as * const _ as usize } , 0usize , concat ! ( "Alignment of field: " , stringify ! ( FontSizePrefs ) , "::" , stringify ! ( mDefaultVariableSize ) ) ) ; assert_eq ! ( unsafe { & ( * ( 0 as * const FontSizePrefs ) ) . mDefaultFixedSize as * const _ as usize } , 4usize , concat ! ( "Alignment of field: " , stringify ! ( FontSizePrefs ) , "::" , stringify ! ( mDefaultFixedSize ) ) ) ; assert_eq ! ( unsafe { & ( * ( 0 as * const FontSizePrefs ) ) . mDefaultSerifSize as * const _ as usize } , 8usize , concat ! ( "Alignment of field: " , stringify ! ( FontSizePrefs ) , "::" , stringify ! ( mDefaultSerifSize ) ) ) ; assert_eq ! ( unsafe { & ( * ( 0 as * const FontSizePrefs ) ) . mDefaultSansSerifSize as * const _ as usize } , 12usize , concat ! ( "Alignment of field: " , stringify ! ( FontSizePrefs ) , "::" , stringify ! ( mDefaultSansSerifSize ) ) ) ; assert_eq ! ( unsafe { & ( * ( 0 as * const FontSizePrefs ) ) . mDefaultMonospaceSize as * const _ as usize } , 16usize , concat ! ( "Alignment of field: " , stringify ! ( FontSizePrefs ) , "::" , stringify ! ( mDefaultMonospaceSize ) ) ) ; assert_eq ! ( unsafe { & ( * ( 0 as * const FontSizePrefs ) ) . mDefaultCursiveSize as * const _ as usize } , 20usize , concat ! ( "Alignment of field: " , stringify ! ( FontSizePrefs ) , "::" , stringify ! ( mDefaultCursiveSize ) ) ) ; assert_eq ! ( unsafe { & ( * ( 0 as * const FontSizePrefs ) ) . mDefaultFantasySize as * const _ as usize } , 24usize , concat ! ( "Alignment of field: " , stringify ! ( FontSizePrefs ) , "::" , stringify ! ( mDefaultFantasySize ) ) ) ; } impl Clone for FontSizePrefs { fn clone ( & self ) -> Self { * self } } # [ repr ( C ) ] # [ derive ( Debug , Copy ) ] pub struct GeckoFontMetrics { pub mChSize : root :: nscoord , pub mXSize : root :: nscoord , } # [ test ] fn bindgen_test_layout_GeckoFontMetrics ( ) { assert_eq ! ( :: std :: mem :: size_of :: < GeckoFontMetrics > ( ) , 8usize , concat ! ( "Size of: " , stringify ! ( GeckoFontMetrics ) ) ) ; assert_eq ! ( :: std :: mem :: align_of :: < GeckoFontMetrics > ( ) , 4usize , concat ! ( "Alignment of " , stringify ! ( GeckoFontMetrics ) ) ) ; assert_eq ! ( unsafe { & ( * ( 0 as * const GeckoFontMetrics ) ) . mChSize as * const _ as usize } , 0usize , concat ! ( "Alignment of field: " , stringify ! ( GeckoFontMetrics ) , "::" , stringify ! ( mChSize ) ) ) ; assert_eq ! ( unsafe { & ( * ( 0 as * const GeckoFontMetrics ) ) . mXSize as * const _ as usize } , 4usize , concat ! ( "Alignment of field: " , stringify ! ( GeckoFontMetrics ) , "::" , stringify ! ( mXSize ) ) ) ; } impl Clone for GeckoFontMetrics { fn clone ( & self ) -> Self { * self } } pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_after : u32 = 65 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_before : u32 = 65 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_backdrop : u32 = 0 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_cue : u32 = 36 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_firstLetter : u32 = 3 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_firstLine : u32 = 3 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozSelection : u32 = 2 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozFocusInner : u32 = 0 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozFocusOuter : u32 = 0 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozListBullet : u32 = 0 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozListNumber : u32 = 0 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozMathAnonymous : u32 = 0 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozNumberWrapper : u32 = 24 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozNumberText : u32 = 24 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozNumberSpinBox : u32 = 24 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozNumberSpinUp : u32 = 24 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozNumberSpinDown : u32 = 24 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozProgressBar : u32 = 8 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozRangeTrack : u32 = 8 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozRangeProgress : u32 = 8 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozRangeThumb : u32 = 8 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozMeterBar : u32 = 8 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozPlaceholder : u32 = 8 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_placeholder : u32 = 8 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozColorSwatch : u32 = 12 ; # [ repr ( C ) ] # [ derive ( Debug , Copy ) ] pub struct nsIDOMMediaList { pub _base : root :: nsISupports , } # [ repr ( C ) ] # [ derive ( Debug , Copy , Clone ) ] pub struct nsIDOMMediaList_COMTypeInfo { pub _address : u8 , } # [ test ] fn bindgen_test_layout_nsIDOMMediaList ( ) { assert_eq ! ( :: std :: mem :: size_of :: < nsIDOMMediaList > ( ) , 8usize , concat ! ( "Size of: " , stringify ! ( nsIDOMMediaList ) ) ) ; assert_eq ! ( :: std :: mem :: align_of :: < nsIDOMMediaList > ( ) , 8usize , concat ! ( "Alignment of " , stringify ! ( nsIDOMMediaList ) ) ) ; } impl Clone for nsIDOMMediaList { fn clone ( & self ) -> Self { * self } } pub type nsCSSAnonBoxes_NonInheritingBase = u8 ; pub const nsCSSAnonBoxes_NonInheriting_oofPlaceholder : root :: nsCSSAnonBoxes_NonInheriting = 0 ; pub const nsCSSAnonBoxes_NonInheriting_horizontalFramesetBorder : root :: nsCSSAnonBoxes_NonInheriting = 1 ; pub const nsCSSAnonBoxes_NonInheriting_verticalFramesetBorder : root :: nsCSSAnonBoxes_NonInheriting = 2 ; pub const nsCSSAnonBoxes_NonInheriting_framesetBlank : root :: nsCSSAnonBoxes_NonInheriting = 3 ; pub const nsCSSAnonBoxes_NonInheriting_tableColGroup : root :: nsCSSAnonBoxes_NonInheriting = 4 ; pub const nsCSSAnonBoxes_NonInheriting_tableCol : root :: nsCSSAnonBoxes_NonInheriting = 5 ; pub const nsCSSAnonBoxes_NonInheriting_pageBreak : root :: nsCSSAnonBoxes_NonInheriting = 6 ; pub const nsCSSAnonBoxes_NonInheriting__Count : root :: nsCSSAnonBoxes_NonInheriting = 7 ; pub type nsCSSAnonBoxes_NonInheriting = root :: nsCSSAnonBoxes_NonInheritingBase ; 
+ # [ repr ( C ) ] # [ derive ( Debug ) ] pub struct nsISMILAttr { pub vtable_ : * const nsISMILAttr__bindgen_vtable , } # [ test ] fn bindgen_test_layout_nsISMILAttr ( ) { assert_eq ! ( :: std :: mem :: size_of :: < nsISMILAttr > ( ) , 8usize , concat ! ( "Size of: " , stringify ! ( nsISMILAttr ) ) ) ; assert_eq ! ( :: std :: mem :: align_of :: < nsISMILAttr > ( ) , 8usize , concat ! ( "Alignment of " , stringify ! ( nsISMILAttr ) ) ) ; } pub const ELEMENT_SHARED_RESTYLE_BIT_1 : root :: _bindgen_ty_74 = 8388608 ; pub const ELEMENT_SHARED_RESTYLE_BIT_2 : root :: _bindgen_ty_74 = 16777216 ; pub const ELEMENT_SHARED_RESTYLE_BIT_3 : root :: _bindgen_ty_74 = 33554432 ; pub const ELEMENT_SHARED_RESTYLE_BIT_4 : root :: _bindgen_ty_74 = 67108864 ; pub const ELEMENT_SHARED_RESTYLE_BITS : root :: _bindgen_ty_74 = 125829120 ; pub const ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO : root :: _bindgen_ty_74 = 8388608 ; pub const ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO : root :: _bindgen_ty_74 = 16777216 ; pub const ELEMENT_HAS_SNAPSHOT : root :: _bindgen_ty_74 = 33554432 ; pub const ELEMENT_HANDLED_SNAPSHOT : root :: _bindgen_ty_74 = 67108864 ; pub const ELEMENT_HAS_PENDING_RESTYLE : root :: _bindgen_ty_74 = 8388608 ; pub const ELEMENT_IS_POTENTIAL_RESTYLE_ROOT : root :: _bindgen_ty_74 = 16777216 ; pub const ELEMENT_HAS_PENDING_ANIMATION_ONLY_RESTYLE : root :: _bindgen_ty_74 = 33554432 ; pub const ELEMENT_IS_POTENTIAL_ANIMATION_ONLY_RESTYLE_ROOT : root :: _bindgen_ty_74 = 67108864 ; pub const ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR : root :: _bindgen_ty_74 = 134217728 ; pub const ELEMENT_HAS_CHILD_WITH_LATER_SIBLINGS_HINT : root :: _bindgen_ty_74 = 268435456 ; pub const ELEMENT_PENDING_RESTYLE_FLAGS : root :: _bindgen_ty_74 = 41943040 ; pub const ELEMENT_POTENTIAL_RESTYLE_ROOT_FLAGS : root :: _bindgen_ty_74 = 83886080 ; pub const ELEMENT_ALL_RESTYLE_FLAGS : root :: _bindgen_ty_74 = 260046848 ; pub const ELEMENT_TYPE_SPECIFIC_BITS_OFFSET : root :: _bindgen_ty_74 = 27 ; pub type _bindgen_ty_74 = :: std :: os :: raw :: c_uint ; pub const GECKO_IS_NIGHTLY : bool = true ; # [ repr ( C ) ] # [ derive ( Debug , Copy ) ] pub struct ServoBundledURI { pub mURLString : * const u8 , pub mURLStringLength : u32 , pub mExtraData : * mut root :: mozilla :: URLExtraData , } # [ test ] fn bindgen_test_layout_ServoBundledURI ( ) { assert_eq ! ( :: std :: mem :: size_of :: < ServoBundledURI > ( ) , 24usize , concat ! ( "Size of: " , stringify ! ( ServoBundledURI ) ) ) ; assert_eq ! ( :: std :: mem :: align_of :: < ServoBundledURI > ( ) , 8usize , concat ! ( "Alignment of " , stringify ! ( ServoBundledURI ) ) ) ; assert_eq ! ( unsafe { & ( * ( 0 as * const ServoBundledURI ) ) . mURLString as * const _ as usize } , 0usize , concat ! ( "Alignment of field: " , stringify ! ( ServoBundledURI ) , "::" , stringify ! ( mURLString ) ) ) ; assert_eq ! ( unsafe { & ( * ( 0 as * const ServoBundledURI ) ) . mURLStringLength as * const _ as usize } , 8usize , concat ! ( "Alignment of field: " , stringify ! ( ServoBundledURI ) , "::" , stringify ! ( mURLStringLength ) ) ) ; assert_eq ! ( unsafe { & ( * ( 0 as * const ServoBundledURI ) ) . mExtraData as * const _ as usize } , 16usize , concat ! ( "Alignment of field: " , stringify ! ( ServoBundledURI ) , "::" , stringify ! ( mExtraData ) ) ) ; } impl Clone for ServoBundledURI { fn clone ( & self ) -> Self { * self } } # [ repr ( C ) ] # [ derive ( Debug , Copy ) ] pub struct FontSizePrefs { pub mDefaultVariableSize : root :: nscoord , pub mDefaultFixedSize : root :: nscoord , pub mDefaultSerifSize : root :: nscoord , pub mDefaultSansSerifSize : root :: nscoord , pub mDefaultMonospaceSize : root :: nscoord , pub mDefaultCursiveSize : root :: nscoord , pub mDefaultFantasySize : root :: nscoord , } # [ test ] fn bindgen_test_layout_FontSizePrefs ( ) { assert_eq ! ( :: std :: mem :: size_of :: < FontSizePrefs > ( ) , 28usize , concat ! ( "Size of: " , stringify ! ( FontSizePrefs ) ) ) ; assert_eq ! ( :: std :: mem :: align_of :: < FontSizePrefs > ( ) , 4usize , concat ! ( "Alignment of " , stringify ! ( FontSizePrefs ) ) ) ; assert_eq ! ( unsafe { & ( * ( 0 as * const FontSizePrefs ) ) . mDefaultVariableSize as * const _ as usize } , 0usize , concat ! ( "Alignment of field: " , stringify ! ( FontSizePrefs ) , "::" , stringify ! ( mDefaultVariableSize ) ) ) ; assert_eq ! ( unsafe { & ( * ( 0 as * const FontSizePrefs ) ) . mDefaultFixedSize as * const _ as usize } , 4usize , concat ! ( "Alignment of field: " , stringify ! ( FontSizePrefs ) , "::" , stringify ! ( mDefaultFixedSize ) ) ) ; assert_eq ! ( unsafe { & ( * ( 0 as * const FontSizePrefs ) ) . mDefaultSerifSize as * const _ as usize } , 8usize , concat ! ( "Alignment of field: " , stringify ! ( FontSizePrefs ) , "::" , stringify ! ( mDefaultSerifSize ) ) ) ; assert_eq ! ( unsafe { & ( * ( 0 as * const FontSizePrefs ) ) . mDefaultSansSerifSize as * const _ as usize } , 12usize , concat ! ( "Alignment of field: " , stringify ! ( FontSizePrefs ) , "::" , stringify ! ( mDefaultSansSerifSize ) ) ) ; assert_eq ! ( unsafe { & ( * ( 0 as * const FontSizePrefs ) ) . mDefaultMonospaceSize as * const _ as usize } , 16usize , concat ! ( "Alignment of field: " , stringify ! ( FontSizePrefs ) , "::" , stringify ! ( mDefaultMonospaceSize ) ) ) ; assert_eq ! ( unsafe { & ( * ( 0 as * const FontSizePrefs ) ) . mDefaultCursiveSize as * const _ as usize } , 20usize , concat ! ( "Alignment of field: " , stringify ! ( FontSizePrefs ) , "::" , stringify ! ( mDefaultCursiveSize ) ) ) ; assert_eq ! ( unsafe { & ( * ( 0 as * const FontSizePrefs ) ) . mDefaultFantasySize as * const _ as usize } , 24usize , concat ! ( "Alignment of field: " , stringify ! ( FontSizePrefs ) , "::" , stringify ! ( mDefaultFantasySize ) ) ) ; } impl Clone for FontSizePrefs { fn clone ( & self ) -> Self { * self } } # [ repr ( C ) ] # [ derive ( Debug , Copy ) ] pub struct GeckoFontMetrics { pub mChSize : root :: nscoord , pub mXSize : root :: nscoord , } # [ test ] fn bindgen_test_layout_GeckoFontMetrics ( ) { assert_eq ! ( :: std :: mem :: size_of :: < GeckoFontMetrics > ( ) , 8usize , concat ! ( "Size of: " , stringify ! ( GeckoFontMetrics ) ) ) ; assert_eq ! ( :: std :: mem :: align_of :: < GeckoFontMetrics > ( ) , 4usize , concat ! ( "Alignment of " , stringify ! ( GeckoFontMetrics ) ) ) ; assert_eq ! ( unsafe { & ( * ( 0 as * const GeckoFontMetrics ) ) . mChSize as * const _ as usize } , 0usize , concat ! ( "Alignment of field: " , stringify ! ( GeckoFontMetrics ) , "::" , stringify ! ( mChSize ) ) ) ; assert_eq ! ( unsafe { & ( * ( 0 as * const GeckoFontMetrics ) ) . mXSize as * const _ as usize } , 4usize , concat ! ( "Alignment of field: " , stringify ! ( GeckoFontMetrics ) , "::" , stringify ! ( mXSize ) ) ) ; } impl Clone for GeckoFontMetrics { fn clone ( & self ) -> Self { * self } } pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_after : u32 = 65 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_before : u32 = 65 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_backdrop : u32 = 0 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_cue : u32 = 36 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_firstLetter : u32 = 3 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_firstLine : u32 = 3 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozSelection : u32 = 2 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozFocusInner : u32 = 0 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozFocusOuter : u32 = 0 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozListBullet : u32 = 0 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozListNumber : u32 = 0 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozMathAnonymous : u32 = 0 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozNumberWrapper : u32 = 24 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozNumberText : u32 = 24 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozNumberSpinBox : u32 = 24 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozNumberSpinUp : u32 = 24 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozNumberSpinDown : u32 = 24 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozProgressBar : u32 = 8 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozRangeTrack : u32 = 8 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozRangeProgress : u32 = 8 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozRangeThumb : u32 = 8 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozMeterBar : u32 = 8 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozPlaceholder : u32 = 8 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_placeholder : u32 = 8 ; pub const SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozColorSwatch : u32 = 12 ; # [ repr ( C ) ] # [ derive ( Debug , Copy ) ] pub struct nsIDOMMediaList { pub _base : root :: nsISupports , } # [ repr ( C ) ] # [ derive ( Debug , Copy , Clone ) ] pub struct nsIDOMMediaList_COMTypeInfo { pub _address : u8 , } # [ test ] fn bindgen_test_layout_nsIDOMMediaList ( ) { assert_eq ! ( :: std :: mem :: size_of :: < nsIDOMMediaList > ( ) , 8usize , concat ! ( "Size of: " , stringify ! ( nsIDOMMediaList ) ) ) ; assert_eq ! ( :: std :: mem :: align_of :: < nsIDOMMediaList > ( ) , 8usize , concat ! ( "Alignment of " , stringify ! ( nsIDOMMediaList ) ) ) ; } impl Clone for nsIDOMMediaList { fn clone ( & self ) -> Self { * self } } pub type nsCSSAnonBoxes_NonInheritingBase = u8 ; pub const nsCSSAnonBoxes_NonInheriting_oofPlaceholder : root :: nsCSSAnonBoxes_NonInheriting = 0 ; pub const nsCSSAnonBoxes_NonInheriting_horizontalFramesetBorder : root :: nsCSSAnonBoxes_NonInheriting = 1 ; pub const nsCSSAnonBoxes_NonInheriting_verticalFramesetBorder : root :: nsCSSAnonBoxes_NonInheriting = 2 ; pub const nsCSSAnonBoxes_NonInheriting_framesetBlank : root :: nsCSSAnonBoxes_NonInheriting = 3 ; pub const nsCSSAnonBoxes_NonInheriting_tableColGroup : root :: nsCSSAnonBoxes_NonInheriting = 4 ; pub const nsCSSAnonBoxes_NonInheriting_tableCol : root :: nsCSSAnonBoxes_NonInheriting = 5 ; pub const nsCSSAnonBoxes_NonInheriting_pageBreak : root :: nsCSSAnonBoxes_NonInheriting = 6 ; pub const nsCSSAnonBoxes_NonInheriting__Count : root :: nsCSSAnonBoxes_NonInheriting = 7 ; pub type nsCSSAnonBoxes_NonInheriting = root :: nsCSSAnonBoxes_NonInheritingBase ; 
  /// templated hashtable class maps keys to interface pointers.
     /// See nsBaseHashtable for complete declaration.
     /// @param KeyClass a wrapper-class for the hashtable key, see nsHashKeys.h
     /// for a complete specification.
     /// @param Interface the interface-type being wrapped
     /// @see nsDataHashtable, nsClassHashtable 
  # [ repr ( C ) ] # [ derive ( Debug , Copy , Clone ) ] pub struct nsInterfaceHashtable { pub _address : u8 , } pub type nsInterfaceHashtable_KeyType = [ u8 ; 0usize ] ; pub type nsInterfaceHashtable_UserDataType < Interface > = * mut Interface ; pub type nsInterfaceHashtable_base_type = u8 ; pub type nsBindingList = root :: nsTArray < root :: RefPtr < root :: nsXBLBinding > > ; # [ repr ( C ) ] pub struct nsBindingManager { pub _base : root :: nsStubMutationObserver , pub mRefCnt : root :: nsCycleCollectingAutoRefCnt , pub mBoundContentSet : u64 , pub mWrapperTable : root :: nsAutoPtr < root :: nsBindingManager_WrapperHashtable > , pub mDocumentTable : u64 , pub mLoadingDocTable : u64 , pub mAttachedStack : root :: nsBindingList , pub mProcessingAttachedStack : bool , pub mDestroyed : bool , pub mAttachedStackSizeOnOutermost : u32 , pub mProcessAttachedQueueEvent : u64 , pub mDocument : * mut root :: nsIDocument , } pub type nsBindingManager_HasThreadSafeRefCnt = root :: mozilla :: FalseType ; pub const nsBindingManager_DestructorHandling_eRunDtor : root :: nsBindingManager_DestructorHandling = 0 ; pub const nsBindingManager_DestructorHandling_eDoNotRunDtor : root :: nsBindingManager_DestructorHandling = 1 ; pub type nsBindingManager_DestructorHandling = :: std :: os :: raw :: c_uint ; # [ repr ( C ) ] # [ derive ( Debug , Copy ) ] pub struct nsBindingManager_cycleCollection { pub _base : root :: nsXPCOMCycleCollectionParticipant , } # [ test ] fn bindgen_test_layout_nsBindingManager_cycleCollection ( ) { assert_eq ! ( :: std :: mem :: size_of :: < nsBindingManager_cycleCollection > ( ) , 16usize , concat ! ( "Size of: " , stringify ! ( nsBindingManager_cycleCollection ) ) ) ; assert_eq ! ( :: std :: mem :: align_of :: < nsBindingManager_cycleCollection > ( ) , 8usize , concat ! ( "Alignment of " , stringify ! ( nsBindingManager_cycleCollection ) ) ) ; } impl Clone for nsBindingManager_cycleCollection { fn clone ( & self ) -> Self { * self } } pub type nsBindingManager_BoundContentBindingCallback = root :: std :: function ; pub type nsBindingManager_WrapperHashtable = u8 ; extern "C" {
  # [ link_name = "\u{1}_ZN16nsBindingManager21_cycleCollectorGlobalE" ] 
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -261,25 +261,25 @@ fn traverse_subtree(
         thread_pool_holder.style_thread_pool.as_ref()
     } else {
         None
     };
 
     let is_restyle = element.get_data().is_some();
 
     let traversal = RecalcStyleOnly::new(shared_style_context);
-    let used_parallel = driver::traverse_dom(&traversal, token, thread_pool);
+    let (used_parallel, stats) = driver::traverse_dom(&traversal, token, thread_pool);
 
     if traversal_flags.contains(TraversalFlags::ParallelTraversal) &&
        !traversal_flags.contains(TraversalFlags::AnimationOnly) &&
        is_restyle && !element.is_native_anonymous() {
        // We turn off parallel traversal for background tabs; this
        // shouldn't count in telemetry. We're also focusing on restyles so
        // we ensure that it's a restyle.
-       per_doc_data.record_traversal(used_parallel);
+       per_doc_data.record_traversal(used_parallel, stats);
     }
 }
 
 /// Traverses the subtree rooted at `root` for restyling.
 ///
 /// Returns whether the root was restyled. Whether anything else was restyled or
 /// not can be inferred from the dirty bits in the rest of the tree.
 #[no_mangle]
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -13870,12 +13870,32 @@
   },
   "STYLO_PARALLEL_RESTYLE_FRACTION": {
     "record_in_processes": ["content"],
     "alert_emails": ["manish@mozilla.com"],
     "expires_in_version": "60",
     "kind": "linear",
     "high": 100,
     "n_buckets": 50,
-    "description": "Fraction of restyles on a single page that were parallel",
+    "description": "Percentage of restyles on a single page that were parallel",
+    "bug_numbers": [1421195]
+  },
+  "STYLO_PARALLEL_RESTYLE_FRACTION_WEIGHTED_TRAVERSED": {
+    "record_in_processes": ["content"],
+    "alert_emails": ["manish@mozilla.com"],
+    "expires_in_version": "60",
+    "kind": "linear",
+    "high": 100,
+    "n_buckets": 50,
+    "description": "Percentage of restyles on a single page that were parallel, weighted by elements traversed",
+    "bug_numbers": [1421195]
+  },
+  "STYLO_PARALLEL_RESTYLE_FRACTION_WEIGHTED_STYLED": {
+    "record_in_processes": ["content"],
+    "alert_emails": ["manish@mozilla.com"],
+    "expires_in_version": "60",
+    "kind": "linear",
+    "high": 100,
+    "n_buckets": 50,
+    "description": "Percentage of restyles on a single page that were parallel, weighted by elements styled",
     "bug_numbers": [1421195]
   }
 }