Bug 1367904 - Part 4: stylo: Replace real ComputedValues with bindgenned ComputedValues2; r?bholley draft
authorManish Goregaokar <manishearth@gmail.com>
Thu, 15 Jun 2017 22:49:50 -0700
changeset 609393 800c7605c752bab0d2d4b5bb9d78683605619351
parent 609392 b562033c87bce4bc5aa5a334f6cccdc178fe9d91
child 609394 e5910aa0c8331241356edecc3d9e9f6784281ba8
push id68565
push userbmo:manishearth@gmail.com
push dateSun, 16 Jul 2017 03:07:34 +0000
reviewersbholley
bugs1367904
milestone56.0a1
Bug 1367904 - Part 4: stylo: Replace real ComputedValues with bindgenned ComputedValues2; r?bholley MozReview-Commit-ID: GRkycXueUVr
layout/style/ServoBindings.h
layout/style/ServoBindings.toml
layout/style/ServoTypes.h
layout/style/generate-stylestructlist.py
servo/components/servo_arc/lib.rs
servo/components/style/properties/gecko.mako.rs
servo/components/style/properties/properties.mako.rs
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -62,16 +62,22 @@ struct nsMediaFeature;
 struct nsStyleList;
 struct nsStyleImage;
 struct nsStyleGradientStop;
 class nsStyleGradient;
 class nsStyleCoord;
 struct nsStyleDisplay;
 class nsXBLBinding;
 
+namespace mozilla {
+  #define STYLE_STRUCT(name_, checkdata_cb_) struct Gecko##name_ {nsStyle##name_ gecko;};
+  #include "nsStyleStructList.h"
+  #undef STYLE_STRUCT
+}
+
 #define NS_DECL_THREADSAFE_FFI_REFCOUNTING(class_, name_)                     \
   void Gecko_AddRef##name_##ArbitraryThread(class_* aPtr);                    \
   void Gecko_Release##name_##ArbitraryThread(class_* aPtr);
 #define NS_IMPL_THREADSAFE_FFI_REFCOUNTING(class_, name_)                     \
   static_assert(class_::HasThreadSafeRefCnt::value,                           \
                 "NS_DECL_THREADSAFE_FFI_REFCOUNTING can only be used with "   \
                 "classes that have thread-safe refcounting");                 \
   void Gecko_AddRef##name_##ArbitraryThread(class_* aPtr)                     \
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -309,17 +309,19 @@ opaque-types = [
 ]
 mapped-generic-types = [
     { generic = true, gecko = "mozilla::ServoUnsafeCell", servo = "::std::cell::UnsafeCell" },
     { generic = true, gecko = "mozilla::ServoCell", servo = "::std::cell::Cell" },
     { generic = false, gecko = "ServoNodeData", servo = "AtomicRefCell<ElementData>" },
     { generic = false, gecko = "mozilla::ServoWritingMode", servo = "::logical_geometry::WritingMode" },
     { generic = false, gecko = "mozilla::ServoFontComputationData", servo = "::properties::FontComputationData" },
     { generic = false, gecko = "mozilla::ServoCustomPropertiesMap", servo = "Option<::stylearc::Arc<::custom_properties::CustomPropertiesMap>>" },
+    { generic = false, gecko = "mozilla::ServoRuleNode", servo = "Option<::rule_tree::StrongRuleNode>" },
     { generic = false, gecko = "mozilla::ServoVisitedStyle", servo = "Option<::stylearc::Arc<ServoComputedValues2>>" },
+    { generic = false, gecko = "mozilla::ServoComputedValueFlags", servo = "::properties::computed_value_flags::ComputedValueFlags" },
     { generic = true, gecko = "mozilla::ServoRawOffsetArc", servo = "::stylearc::RawOffsetArc" },
 ]
 fixups = [
     { pat = "root::nsString", rep = "::nsstring::nsStringRepr" },
 ]
 
 [bindings]
 headers = ["mozilla/ServoBindings.h"]
--- a/layout/style/ServoTypes.h
+++ b/layout/style/ServoTypes.h
@@ -137,41 +137,66 @@ struct ServoFontComputationData {
   uint32_t mFour;
   uint32_t mFour2;
 };
 
 struct ServoCustomPropertiesMap {
   uintptr_t mPtr;
 };
 
+struct ServoRuleNode {
+  uintptr_t mPtr;
+};
+
 struct ServoVisitedStyle {
   uintptr_t mPtr;
 };
 
 template <typename T>
 struct ServoRawOffsetArc {
   T* mPtr;
 };
 
+struct ServoComputedValueFlags {
+  uint8_t mFlags;
+};
+
+#define STYLE_STRUCT(name_, checkdata_cb_) struct Gecko##name_;
+#define STYLE_STRUCT_LIST_IGNORE_VARIABLES
+#include "nsStyleStructList.h"
+#undef STYLE_STRUCT
+#undef STYLE_STRUCT_LIST_IGNORE_VARIABLES
+
+
 /**
  * We want C++ to be abe to read the style struct fields of ComputedValues
  * so we define this type on the C++ side and use the bindgenned version
  * on the Rust side.
  *
  * C++ just sees pointers and opaque types here, so bindgen will attempt to generate a Copy
  * impl. This will fail because the bindgenned version contains owned types. Opt out.
  *
  * <div rustbindgen nocopy></div>
  */
 struct ServoComputedValues2 {
-#define STYLE_STRUCT(name_, checkdata_cb_) ServoRawOffsetArc<nsStyle##name_> name_;
+#define STYLE_STRUCT(name_, checkdata_cb_) ServoRawOffsetArc<Gecko##name_> name_;
+  #define STYLE_STRUCT_LIST_IGNORE_VARIABLES
 #include "nsStyleStructList.h"
 #undef STYLE_STRUCT
+  #undef STYLE_STRUCT_LIST_IGNORE_VARIABLES
   ServoCustomPropertiesMap custom_properties;
   ServoWritingMode writing_mode;
   ServoFontComputationData font_computation_data;
+  /// The rule node representing the ordered list of rules matched for this
+  /// node.  Can be None for default values and text nodes.  This is
+  /// essentially an optimization to avoid referencing the root rule node.
+  ServoRuleNode rules;
+  /// The element's computed values if visited, only computed if there's a
+  /// relevant link for this element. A element's "relevant link" is the
+  /// element being matched if it is a link or the nearest ancestor link.
   ServoVisitedStyle visited_style;
+  ServoComputedValueFlags flags;
   ~ServoComputedValues2() {} // do nothing, but prevent Copy from being impl'd by bindgen
 };
 
 } // namespace mozilla
 
 #endif // mozilla_ServoTypes_h
--- a/layout/style/generate-stylestructlist.py
+++ b/layout/style/generate-stylestructlist.py
@@ -83,20 +83,24 @@ for i in range(count):
         print("Resolved items:", " ".join(resolved_items), file=sys.stderr)
         unsolved_items = [name for _, name, _, _ in STYLE_STRUCTS
                           if name not in resolved_items]
         print("There exist cyclic dependencies between " +
                   "the following structs:", " ".join(unsolved_items), file=sys.stderr)
         exit(1)
 
 def printEntry(header, i):
+    if STYLE_STRUCTS[i][1] == "Variables":
+        print("#ifndef STYLE_STRUCT_LIST_IGNORE_VARIABLES", file=header)
     print("STYLE_STRUCT_%s(%s, %s)" % STYLE_STRUCTS[i][:3], file=header)
     for dep in STYLE_STRUCTS[i][3]:
         print("STYLE_STRUCT_DEP(%s)" % (dep,), file=header)
     print("STYLE_STRUCT_END()", file=header)
+    if STYLE_STRUCTS[i][1] == "Variables":
+        print("#endif", file=header)
 
 HEADER = """/* THIS FILE IS AUTOGENERATED BY generate-stylestructlist.py - DO NOT EDIT */
 
 // IWYU pragma: private, include "nsStyleStructFwd.h"
 
 /*
  * list of structs that contain the data provided by nsStyleContext, the
  * internal API for computed style data for an element
--- a/servo/components/servo_arc/lib.rs
+++ b/servo/components/servo_arc/lib.rs
@@ -766,29 +766,49 @@ impl<T: 'static> RawOffsetArc<T> {
         // Forget the transient Arc to leave the refcount untouched.
         // XXXManishearth this can be removed when unions stabilize,
         // since then NoDrop becomes zero overhead
         mem::forget(transient);
 
         // Forward the result.
         result
     }
+
+    /// If uniquely owned, provide a mutable reference
+    /// Else create a copy, and mutate that
+    pub fn make_mut(&mut self) -> &mut T where T: Clone {
+        unsafe {
+            // extract the RawOffsetArc as an owned variable
+            let this = ptr::read(self);
+            // treat it as a real Arc
+            let mut arc = Arc::from_raw_offset(this);
+            // obtain the mutable reference. Cast away the lifetime
+            // This may mutate `arc`
+            let ret = Arc::make_mut(&mut arc) as *mut _;
+            // Store the possibly-mutated arc back inside, after converting
+            // it to a RawOffsetArc again
+            ptr::write(self, Arc::into_raw_offset(arc));
+            &mut *ret
+        }
+    }
 }
 
 impl<T: 'static> Arc<T> {
     /// Converts an Arc into a RawOffsetArc. This consumes the Arc, so the refcount
     /// is not modified.
+    #[inline]
     pub fn into_raw_offset(a: Self) -> RawOffsetArc<T> {
         RawOffsetArc {
             ptr: NonZeroPtrMut::new(Arc::into_raw(a) as *mut T),
         }
     }
 
     /// Converts a RawOffsetArc into an Arc. This consumes the RawOffsetArc, so the refcount
     /// is not modified.
+    #[inline]
     pub fn from_raw_offset(a: RawOffsetArc<T>) -> Self {
         let ptr = a.ptr.ptr();
         mem::forget(a);
         unsafe { Arc::from_raw(ptr) }
     }
 }
 
 #[cfg(test)]
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -53,52 +53,49 @@ use gecko::values::GeckoStyleCoordConver
 use gecko::values::round_border_to_device_pixels;
 use logical_geometry::WritingMode;
 use media_queries::Device;
 use properties::animated_properties::TransitionProperty;
 use properties::computed_value_flags::ComputedValueFlags;
 use properties::{longhands, FontComputationData, Importance, LonghandId};
 use properties::{PropertyDeclaration, PropertyDeclarationBlock, PropertyDeclarationId};
 use rule_tree::StrongRuleNode;
-use std::fmt::{self, Debug};
 use std::mem::{forget, transmute, zeroed};
 use std::ptr;
-use stylearc::Arc;
+use stylearc::{Arc, RawOffsetArc};
 use std::cmp;
 use values::{Auto, CustomIdent, Either, KeyframesName};
 use values::computed::ToComputedValue;
 use values::computed::effects::{BoxShadow, Filter, SimpleShadow};
 use values::specified::length::Percentage;
 use computed_values::border_style;
 
 pub mod style_structs {
     % for style_struct in data.style_structs:
     pub use super::${style_struct.gecko_struct_name} as ${style_struct.name};
     % endfor
 }
 
-// FIXME(emilio): Unify both definitions, since they're equal now.
-#[derive(Clone)]
-pub struct ComputedValues {
-    % for style_struct in data.style_structs:
-    ${style_struct.ident}: Arc<style_structs::${style_struct.name}>,
-    % endfor
-    custom_properties: Option<Arc<CustomPropertiesMap>>,
-    pub writing_mode: WritingMode,
-    pub font_computation_data: FontComputationData,
-    pub flags: ComputedValueFlags,
-
-    /// The rule node representing the ordered list of rules matched for this
-    /// node.  Can be None for default values and text nodes.  This is
-    /// essentially an optimization to avoid referencing the root rule node.
-    pub rules: Option<StrongRuleNode>,
-    /// The element's computed values if visited, only computed if there's a
-    /// relevant link for this element. A element's "relevant link" is the
-    /// element being matched if it is a link or the nearest ancestor link.
-    visited_style: Option<Arc<ComputedValues>>,
+
+pub use ::gecko_bindings::structs::mozilla::ServoComputedValues2 as ComputedValues;
+
+impl Clone for ComputedValues {
+    fn clone(&self) -> Self {
+        ComputedValues {
+            % for style_struct in data.style_structs:
+                ${style_struct.gecko_name}: self.${style_struct.gecko_name}.clone(),
+            % endfor
+            custom_properties: self.custom_properties.clone(),
+            writing_mode: self.writing_mode.clone(),
+            font_computation_data: self.font_computation_data.clone(),
+            flags: self.flags.clone(),
+            rules: self.rules.clone(),
+            visited_style: self.visited_style.clone(),
+        }
+    }
 }
 
 impl ComputedValues {
     pub fn new(custom_properties: Option<Arc<CustomPropertiesMap>>,
                writing_mode: WritingMode,
                font_size_keyword: Option<(longhands::font_size::KeywordSize, f32)>,
                flags: ComputedValueFlags,
                rules: Option<StrongRuleNode>,
@@ -110,31 +107,31 @@ impl ComputedValues {
         ComputedValues {
             custom_properties,
             writing_mode,
             font_computation_data: FontComputationData::new(font_size_keyword),
             flags,
             rules,
             visited_style: visited_style,
             % for style_struct in data.style_structs:
-            ${style_struct.ident},
+            ${style_struct.gecko_name}: Arc::into_raw_offset(${style_struct.ident}),
             % endfor
         }
     }
 
     pub fn default_values(pres_context: RawGeckoPresContextBorrowed) -> Arc<Self> {
         Arc::new(ComputedValues {
             custom_properties: None,
             writing_mode: WritingMode::empty(), // FIXME(bz): This seems dubious
             font_computation_data: FontComputationData::default_values(),
             flags: ComputedValueFlags::empty(),
             rules: None,
             visited_style: None,
             % for style_struct in data.style_structs:
-                ${style_struct.ident}: style_structs::${style_struct.name}::default(pres_context),
+                ${style_struct.gecko_name}: Arc::into_raw_offset(style_structs::${style_struct.name}::default(pres_context)),
             % endfor
         })
     }
 
     #[inline]
     pub fn is_display_contents(&self) -> bool {
         self.get_box().clone_display() == longhands::display::computed_value::T::contents
     }
@@ -144,30 +141,31 @@ impl ComputedValues {
     #[inline]
     pub fn ineffective_content_property(&self) -> bool {
         self.get_counters().ineffective_content_property()
     }
 
     % for style_struct in data.style_structs:
     #[inline]
     pub fn clone_${style_struct.name_lower}(&self) -> Arc<style_structs::${style_struct.name}> {
-        self.${style_struct.ident}.clone()
+        Arc::from_raw_offset(self.${style_struct.gecko_name}.clone())
     }
     #[inline]
     pub fn get_${style_struct.name_lower}(&self) -> &style_structs::${style_struct.name} {
-        &self.${style_struct.ident}
-    }
-
-    pub fn ${style_struct.name_lower}_arc(&self) -> &Arc<style_structs::${style_struct.name}> {
-        &self.${style_struct.ident}
+        &self.${style_struct.gecko_name}
+    }
+
+
+    pub fn ${style_struct.name_lower}_arc(&self) -> &RawOffsetArc<style_structs::${style_struct.name}> {
+        &self.${style_struct.gecko_name}
     }
 
     #[inline]
     pub fn mutate_${style_struct.name_lower}(&mut self) -> &mut style_structs::${style_struct.name} {
-        Arc::make_mut(&mut self.${style_struct.ident})
+        RawOffsetArc::make_mut(&mut self.${style_struct.gecko_name})
     }
     % endfor
 
     /// Gets a reference to the rule node. Panic if no rule node exists.
     pub fn rules(&self) -> &StrongRuleNode {
         self.rules.as_ref().unwrap()
     }
 
@@ -233,19 +231,17 @@ impl ComputedValues {
             % endfor
             PropertyDeclarationId::Custom(_name) => unimplemented!(),
             _ => unimplemented!()
         }
     }
 }
 
 <%def name="declare_style_struct(style_struct)">
-pub struct ${style_struct.gecko_struct_name} {
-    gecko: ${style_struct.gecko_ffi_name},
-}
+pub use ::gecko_bindings::structs::mozilla::Gecko${style_struct.gecko_name} as ${style_struct.gecko_struct_name};
 impl ${style_struct.gecko_struct_name} {
     pub fn gecko(&self) -> &${style_struct.gecko_ffi_name} {
         &self.gecko
     }
     pub fn gecko_mut(&mut self) -> &mut ${style_struct.gecko_ffi_name} {
         &mut self.gecko
     }
 }
@@ -732,30 +728,16 @@ impl Clone for ${style_struct.gecko_stru
         unsafe {
             let mut result = ${style_struct.gecko_struct_name} { gecko: zeroed() };
             Gecko_CopyConstruct_${style_struct.gecko_ffi_name}(&mut result.gecko, &self.gecko);
             result
         }
     }
 }
 
-// FIXME(bholley): Make bindgen generate Debug for all types.
-%if style_struct.gecko_ffi_name in ("nsStyle" + x for x in "Border Display List Background Font SVGReset".split()):
-impl Debug for ${style_struct.gecko_struct_name} {
-    // FIXME(bholley): Generate this.
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "Gecko style struct: ${style_struct.gecko_struct_name}")
-    }
-}
-%else:
-impl Debug for ${style_struct.gecko_struct_name} {
-    // FIXME(bholley): Generate this.
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.gecko.fmt(f) }
-}
-%endif
 </%def>
 
 <%def name="impl_simple_type_with_conversion(ident, gecko_ffi_name=None)">
     <%
     if gecko_ffi_name is None:
         gecko_ffi_name = "m" + to_camel_case(ident)
     %>
 
--- a/servo/components/style/properties/properties.mako.rs
+++ b/servo/components/style/properties/properties.mako.rs
@@ -2232,24 +2232,16 @@ impl ComputedValues {
                     .and_then(|map| map.get_computed_value(name))
                     .map(|value| value.to_css_string())
                     .unwrap_or(String::new())
             }
         }
     }
 }
 
-// We manually implement Debug for ComputedValues so that we can avoid the
-// verbose stringification of every property and instead focus on a few values.
-impl fmt::Debug for ComputedValues {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "ComputedValues {{ rules: {:?}, .. }}", self.rules)
-    }
-}
-
 /// Return a WritingMode bitflags from the relevant CSS properties.
 pub fn get_writing_mode(inheritedbox_style: &style_structs::InheritedBox) -> WritingMode {
     use logical_geometry;
     let mut flags = WritingMode::empty();
     match inheritedbox_style.clone_direction() {
         computed_values::direction::T::ltr => {},
         computed_values::direction::T::rtl => {
             flags.insert(logical_geometry::FLAG_RTL);
@@ -2291,20 +2283,34 @@ pub fn get_writing_mode(inheritedbox_sty
                 flags.insert(logical_geometry::FLAG_SIDEWAYS);
             },
         }
     }
     % endif
     flags
 }
 
+% if product == "gecko":
+    pub use ::stylearc::RawOffsetArc as BuilderArc;
+    /// Clone an arc, returning a regular arc
+    fn clone_arc<T: 'static>(x: &BuilderArc<T>) -> Arc<T> {
+        Arc::from_raw_offset(x.clone())
+    }
+% else:
+    pub use Arc as BuilderArc;
+    /// Clone an arc, returning a regular arc
+    fn clone_arc<T: 'static>(x: &BuilderArc<T>) -> Arc<T> {
+        x.clone()
+    }
+% endif
+
 /// A reference to a style struct of the parent, or our own style struct.
 pub enum StyleStructRef<'a, T: 'static> {
     /// A borrowed struct from the parent, for example, for inheriting style.
-    Borrowed(&'a Arc<T>),
+    Borrowed(&'a BuilderArc<T>),
     /// An owned struct, that we've already mutated.
     Owned(UniqueArc<T>),
     /// Temporarily vacated, will panic if accessed
     Vacated,
 }
 
 impl<'a, T: 'a> StyleStructRef<'a, T>
     where T: Clone,
@@ -2355,17 +2361,17 @@ impl<'a, T: 'a> StyleStructRef<'a, T>
         }
     }
 
     /// Returns an `Arc` to the internal struct, constructing one if
     /// appropriate.
     pub fn build(self) -> Arc<T> {
         match self {
             StyleStructRef::Owned(v) => v.shareable(),
-            StyleStructRef::Borrowed(v) => v.clone(),
+            StyleStructRef::Borrowed(v) => clone_arc(v),
             StyleStructRef::Vacated => panic!("Accessed vacated style struct")
         }
     }
 }
 
 impl<'a, T: 'a> Deref for StyleStructRef<'a, T> {
     type Target = T;