Bug 1299392 - stylo: Add safety glue for borrowed and owned types, use for nodes/documents/iterators; r?bholley, r?mystor draft
authorManish Goregaokar <manishearth@gmail.com>
Tue, 23 Aug 2016 18:41:02 +0530
changeset 409025 3c5a1d60cb1d7671136e406bee7fc4b278e8adc7
parent 407818 506facea63169a29e04eb140663da1730052db64
child 530245 1a3e103d5ecb6b9e76fea8bdf1db351cbcffaef4
push id28363
push userbmo:manishearth@gmail.com
push dateFri, 02 Sep 2016 02:34:54 +0000
reviewersbholley, mystor
bugs1299392
milestone51.0a1
Bug 1299392 - stylo: Add safety glue for borrowed and owned types, use for nodes/documents/iterators; r?bholley, r?mystor
layout/style/ServoBindingList.h
layout/style/ServoBindings.cpp
layout/style/ServoBindings.h
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -14,42 +14,42 @@
  * and the parameter list of the function.
  *
  * Users of this list should define a macro
  * SERVO_BINDING_FUNC(name_, return_, ...)
  * before including this file.
  */
 
 // Node data
-SERVO_BINDING_FUNC(Servo_NodeData_Drop, void, ServoNodeData* data)
+SERVO_BINDING_FUNC(Servo_NodeData_Drop, void, ServoNodeDataOwned data)
 
 // Styleset and Stylesheet management
 SERVO_BINDING_FUNC(Servo_StyleSheet_FromUTF8Bytes, RawServoStyleSheetStrong,
                    const uint8_t* bytes, uint32_t length,
                    mozilla::css::SheetParsingMode parsing_mode,
                    const uint8_t* base_bytes, uint32_t base_length,
                    ThreadSafeURIHolder* base,
                    ThreadSafeURIHolder* referrer,
                    ThreadSafePrincipalHolder* principal)
 SERVO_BINDING_FUNC(Servo_StyleSheet_AddRef, void,
                    RawServoStyleSheetBorrowed sheet)
 SERVO_BINDING_FUNC(Servo_StyleSheet_Release, void,
                    RawServoStyleSheetBorrowed sheet)
 SERVO_BINDING_FUNC(Servo_StyleSheet_HasRules, bool,
                    RawServoStyleSheetBorrowed sheet)
-SERVO_BINDING_FUNC(Servo_StyleSet_Init, RawServoStyleSet*)
-SERVO_BINDING_FUNC(Servo_StyleSet_Drop, void, RawServoStyleSet* set)
+SERVO_BINDING_FUNC(Servo_StyleSet_Init, RawServoStyleSetOwned)
+SERVO_BINDING_FUNC(Servo_StyleSet_Drop, void, RawServoStyleSetOwned set)
 SERVO_BINDING_FUNC(Servo_StyleSet_AppendStyleSheet, void,
-                   RawServoStyleSet* set, RawServoStyleSheetBorrowed sheet)
+                   RawServoStyleSetBorrowedMut set, RawServoStyleSheetBorrowed sheet)
 SERVO_BINDING_FUNC(Servo_StyleSet_PrependStyleSheet, void,
-                   RawServoStyleSet* set, RawServoStyleSheetBorrowed sheet)
+                   RawServoStyleSetBorrowedMut set, RawServoStyleSheetBorrowed sheet)
 SERVO_BINDING_FUNC(Servo_StyleSet_RemoveStyleSheet, void,
-                   RawServoStyleSet* set, RawServoStyleSheetBorrowed sheet)
+                   RawServoStyleSetBorrowedMut set, RawServoStyleSheetBorrowed sheet)
 SERVO_BINDING_FUNC(Servo_StyleSet_InsertStyleSheetBefore, void,
-                   RawServoStyleSet* set, RawServoStyleSheetBorrowed sheet,
+                   RawServoStyleSetBorrowedMut set, RawServoStyleSheetBorrowed sheet,
                    RawServoStyleSheetBorrowed reference)
 
 // Style attribute
 SERVO_BINDING_FUNC(Servo_ParseStyleAttribute, ServoDeclarationBlockStrong,
                    const uint8_t* bytes, uint32_t length,
                    nsHTMLCSSStyleSheet* cache)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_AddRef, void,
                    ServoDeclarationBlockBorrowed declarations)
@@ -64,48 +64,48 @@ SERVO_BINDING_FUNC(Servo_DeclarationBloc
 
 // CSS supports()
 SERVO_BINDING_FUNC(Servo_CSSSupports, bool,
                    const uint8_t* name, uint32_t name_length,
                    const uint8_t* value, uint32_t value_length)
 
 // Computed style data
 SERVO_BINDING_FUNC(Servo_ComputedValues_Get, ServoComputedValuesStrong,
-                   RawGeckoNode* node)
+                   RawGeckoNodeBorrowed node)
 SERVO_BINDING_FUNC(Servo_ComputedValues_GetForAnonymousBox,
                    ServoComputedValuesStrong,
-                   ServoComputedValuesBorrowed parent_style_or_null,
-                   nsIAtom* pseudoTag, RawServoStyleSet* set)
+                   ServoComputedValuesBorrowedOrNull parent_style_or_null,
+                   nsIAtom* pseudoTag, RawServoStyleSetBorrowedMut set)
 SERVO_BINDING_FUNC(Servo_ComputedValues_GetForPseudoElement,
                    ServoComputedValuesStrong,
                    ServoComputedValuesBorrowed parent_style,
-                   RawGeckoElement* match_element, nsIAtom* pseudo_tag,
-                   RawServoStyleSet* set, bool is_probe)
+                   RawGeckoElementBorrowed match_element, nsIAtom* pseudo_tag,
+                   RawServoStyleSetBorrowedMut set, bool is_probe)
 SERVO_BINDING_FUNC(Servo_ComputedValues_Inherit, ServoComputedValuesStrong,
-                   ServoComputedValuesBorrowed parent_style)
+                   ServoComputedValuesBorrowedOrNull parent_style)
 SERVO_BINDING_FUNC(Servo_ComputedValues_AddRef, void,
                    ServoComputedValuesBorrowed computed_values)
 SERVO_BINDING_FUNC(Servo_ComputedValues_Release, void,
                    ServoComputedValuesBorrowed computed_values)
 
 // Initialize Servo components. Should be called exactly once at startup.
 SERVO_BINDING_FUNC(Servo_Initialize, void)
 // Shut down Servo components. Should be called exactly once at shutdown.
 SERVO_BINDING_FUNC(Servo_Shutdown, void)
 
 // Restyle hints
 SERVO_BINDING_FUNC(Servo_ComputeRestyleHint, nsRestyleHint,
                    RawGeckoElement* element, ServoElementSnapshot* snapshot,
-                   RawServoStyleSet* set)
+                   RawServoStyleSetBorrowed set)
 
 // Restyle the given document or subtree
 SERVO_BINDING_FUNC(Servo_RestyleDocument, void,
-                   RawGeckoDocument* doc, RawServoStyleSet* set)
+                   RawGeckoDocumentBorrowed doc, RawServoStyleSetBorrowedMut set)
 SERVO_BINDING_FUNC(Servo_RestyleSubtree, void,
-                   RawGeckoNode* node, RawServoStyleSet* set)
+                   RawGeckoNodeBorrowed node, RawServoStyleSetBorrowedMut set)
 
 // Style-struct management.
 #define STYLE_STRUCT(name, checkdata_cb)                            \
   struct nsStyle##name;                                             \
   SERVO_BINDING_FUNC(Servo_GetStyle##name, const nsStyle##name*,  \
                      ServoComputedValuesBorrowed computed_values)
 #include "nsStyleStructList.h"
 #undef STYLE_STRUCT
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -44,202 +44,202 @@ using namespace mozilla::dom;
 
 IMPL_STRONG_REF_TYPE_FOR(ServoComputedValues)
 IMPL_STRONG_REF_TYPE_FOR(RawServoStyleSheet)
 IMPL_STRONG_REF_TYPE_FOR(ServoDeclarationBlock)
 
 #undef IMPL_STRONG_REF_TYPE_FOR
 
 uint32_t
-Gecko_ChildrenCount(RawGeckoNode* aNode)
+Gecko_ChildrenCount(RawGeckoNodeBorrowed aNode)
 {
   return aNode->GetChildCount();
 }
 
 bool
-Gecko_NodeIsElement(RawGeckoNode* aNode)
+Gecko_NodeIsElement(RawGeckoNodeBorrowed aNode)
 {
   return aNode->IsElement();
 }
 
-RawGeckoNode*
-Gecko_GetParentNode(RawGeckoNode* aNode)
+RawGeckoNodeBorrowedOrNull
+Gecko_GetParentNode(RawGeckoNodeBorrowed aNode)
 {
   return aNode->GetFlattenedTreeParentNode();
 }
 
-RawGeckoNode*
-Gecko_GetFirstChild(RawGeckoNode* aNode)
+RawGeckoNodeBorrowedOrNull
+Gecko_GetFirstChild(RawGeckoNodeBorrowed aNode)
 {
   return aNode->GetFirstChild();
 }
 
-RawGeckoNode*
-Gecko_GetLastChild(RawGeckoNode* aNode)
+RawGeckoNodeBorrowedOrNull
+Gecko_GetLastChild(RawGeckoNodeBorrowed aNode)
 {
   return aNode->GetLastChild();
 }
 
-RawGeckoNode*
-Gecko_GetPrevSibling(RawGeckoNode* aNode)
+RawGeckoNodeBorrowedOrNull
+Gecko_GetPrevSibling(RawGeckoNodeBorrowed aNode)
 {
   return aNode->GetPreviousSibling();
 }
 
-RawGeckoNode*
-Gecko_GetNextSibling(RawGeckoNode* aNode)
+RawGeckoNodeBorrowedOrNull
+Gecko_GetNextSibling(RawGeckoNodeBorrowed aNode)
 {
   return aNode->GetNextSibling();
 }
 
-RawGeckoElement*
-Gecko_GetParentElement(RawGeckoElement* aElement)
+RawGeckoElementBorrowedOrNull
+Gecko_GetParentElement(RawGeckoElementBorrowed aElement)
 {
   nsINode* parentNode = aElement->GetFlattenedTreeParentNode();
   return parentNode->IsElement() ? parentNode->AsElement() : nullptr;
 }
 
-RawGeckoElement*
-Gecko_GetFirstChildElement(RawGeckoElement* aElement)
+RawGeckoElementBorrowedOrNull
+Gecko_GetFirstChildElement(RawGeckoElementBorrowed aElement)
 {
   return aElement->GetFirstElementChild();
 }
 
-RawGeckoElement* Gecko_GetLastChildElement(RawGeckoElement* aElement)
+RawGeckoElementBorrowedOrNull Gecko_GetLastChildElement(RawGeckoElementBorrowed aElement)
 {
   return aElement->GetLastElementChild();
 }
 
-RawGeckoElement*
-Gecko_GetPrevSiblingElement(RawGeckoElement* aElement)
+RawGeckoElementBorrowedOrNull
+Gecko_GetPrevSiblingElement(RawGeckoElementBorrowed aElement)
 {
   return aElement->GetPreviousElementSibling();
 }
 
-RawGeckoElement*
-Gecko_GetNextSiblingElement(RawGeckoElement* aElement)
+RawGeckoElementBorrowedOrNull
+Gecko_GetNextSiblingElement(RawGeckoElementBorrowed aElement)
 {
   return aElement->GetNextElementSibling();
 }
 
-RawGeckoElement*
-Gecko_GetDocumentElement(RawGeckoDocument* aDoc)
+RawGeckoElementBorrowedOrNull
+Gecko_GetDocumentElement(RawGeckoDocumentBorrowed aDoc)
 {
   return aDoc->GetDocumentElement();
 }
 
-StyleChildrenIterator*
-Gecko_MaybeCreateStyleChildrenIterator(RawGeckoNode* aNode)
+StyleChildrenIteratorOwnedOrNull
+Gecko_MaybeCreateStyleChildrenIterator(RawGeckoNodeBorrowed aNode)
 {
   if (!aNode->IsElement()) {
     return nullptr;
   }
 
   Element* el = aNode->AsElement();
   return StyleChildrenIterator::IsNeeded(el) ? new StyleChildrenIterator(el)
                                              : nullptr;
 }
 
 void
-Gecko_DropStyleChildrenIterator(StyleChildrenIterator* aIterator)
+Gecko_DropStyleChildrenIterator(StyleChildrenIteratorOwned aIterator)
 {
   MOZ_ASSERT(aIterator);
   delete aIterator;
 }
 
-RawGeckoNode*
-Gecko_GetNextStyleChild(StyleChildrenIterator* aIterator)
+RawGeckoNodeBorrowed
+Gecko_GetNextStyleChild(StyleChildrenIteratorBorrowed aIterator)
 {
   MOZ_ASSERT(aIterator);
   return aIterator->GetNextChild();
 }
 
 EventStates::ServoType
-Gecko_ElementState(RawGeckoElement* aElement)
+Gecko_ElementState(RawGeckoElementBorrowed aElement)
 {
   return aElement->StyleState().ServoValue();
 }
 
 bool
-Gecko_IsHTMLElementInHTMLDocument(RawGeckoElement* aElement)
+Gecko_IsHTMLElementInHTMLDocument(RawGeckoElementBorrowed aElement)
 {
   return aElement->IsHTMLElement() && aElement->OwnerDoc()->IsHTMLDocument();
 }
 
 bool
-Gecko_IsLink(RawGeckoElement* aElement)
+Gecko_IsLink(RawGeckoElementBorrowed aElement)
 {
   return nsCSSRuleProcessor::IsLink(aElement);
 }
 
 bool
-Gecko_IsTextNode(RawGeckoNode* aNode)
+Gecko_IsTextNode(RawGeckoNodeBorrowed aNode)
 {
   return aNode->NodeInfo()->NodeType() == nsIDOMNode::TEXT_NODE;
 }
 
 bool
-Gecko_IsVisitedLink(RawGeckoElement* aElement)
+Gecko_IsVisitedLink(RawGeckoElementBorrowed aElement)
 {
   return aElement->StyleState().HasState(NS_EVENT_STATE_VISITED);
 }
 
 bool
-Gecko_IsUnvisitedLink(RawGeckoElement* aElement)
+Gecko_IsUnvisitedLink(RawGeckoElementBorrowed aElement)
 {
   return aElement->StyleState().HasState(NS_EVENT_STATE_UNVISITED);
 }
 
 bool
-Gecko_IsRootElement(RawGeckoElement* aElement)
+Gecko_IsRootElement(RawGeckoElementBorrowed aElement)
 {
   return aElement->OwnerDoc()->GetRootElement() == aElement;
 }
 
 nsIAtom*
-Gecko_LocalName(RawGeckoElement* aElement)
+Gecko_LocalName(RawGeckoElementBorrowed aElement)
 {
   return aElement->NodeInfo()->NameAtom();
 }
 
 nsIAtom*
-Gecko_Namespace(RawGeckoElement* aElement)
+Gecko_Namespace(RawGeckoElementBorrowed aElement)
 {
   int32_t id = aElement->NodeInfo()->NamespaceID();
   return nsContentUtils::NameSpaceManager()->NameSpaceURIAtomForServo(id);
 }
 
 nsIAtom*
-Gecko_GetElementId(RawGeckoElement* aElement)
+Gecko_GetElementId(RawGeckoElementBorrowed aElement)
 {
   const nsAttrValue* attr = aElement->GetParsedAttr(nsGkAtoms::id);
   return attr ? attr->GetAtomValue() : nullptr;
 }
 
 // Dirtiness tracking.
 uint32_t
-Gecko_GetNodeFlags(RawGeckoNode* aNode)
+Gecko_GetNodeFlags(RawGeckoNodeBorrowed aNode)
 {
   return aNode->GetFlags();
 }
 
 void
-Gecko_SetNodeFlags(RawGeckoNode* aNode, uint32_t aFlags)
+Gecko_SetNodeFlags(RawGeckoNodeBorrowed aNode, uint32_t aFlags)
 {
   aNode->SetFlags(aFlags);
 }
 
 void
-Gecko_UnsetNodeFlags(RawGeckoNode* aNode, uint32_t aFlags)
+Gecko_UnsetNodeFlags(RawGeckoNodeBorrowed aNode, uint32_t aFlags)
 {
   aNode->UnsetFlags(aFlags);
 }
 
 nsStyleContext*
-Gecko_GetStyleContext(RawGeckoNode* aNode, nsIAtom* aPseudoTagOrNull)
+Gecko_GetStyleContext(RawGeckoNodeBorrowed aNode, nsIAtom* aPseudoTagOrNull)
 {
   MOZ_ASSERT(aNode->IsContent());
   nsIFrame* relevantFrame =
     ServoRestyleManager::FrameForPseudoElement(aNode->AsContent(),
                                                aPseudoTagOrNull);
   if (!relevantFrame) {
     return nullptr;
   }
@@ -267,17 +267,17 @@ Gecko_CalcStyleDifference(nsStyleContext
                                           forDescendants,
                                           &equalStructs,
                                           &samePointerStructs);
 
   return result;
 }
 
 void
-Gecko_StoreStyleDifference(RawGeckoNode* aNode, nsChangeHint aChangeHintToStore)
+Gecko_StoreStyleDifference(RawGeckoNodeBorrowed aNode, nsChangeHint aChangeHintToStore)
 {
 #ifdef MOZ_STYLO
   MOZ_ASSERT(aNode->IsContent());
   MOZ_ASSERT(aNode->IsDirtyForServo(),
              "Change hint stored in a not-dirty node");
 
   // For elements, we need to store the change hint in the proper style context.
   // For text nodes, we want to store the change hint in the parent element,
@@ -310,17 +310,17 @@ Gecko_StoreStyleDifference(RawGeckoNode*
   primaryFrame->StyleContext()->StoreChangeHint(aChangeHintToStore);
 #else
   MOZ_CRASH("stylo: Shouldn't call Gecko_StoreStyleDifference in "
             "non-stylo build");
 #endif
 }
 
 ServoDeclarationBlock*
-Gecko_GetServoDeclarationBlock(RawGeckoElement* aElement)
+Gecko_GetServoDeclarationBlock(RawGeckoElementBorrowed aElement)
 {
   const nsAttrValue* attr = aElement->GetParsedAttr(nsGkAtoms::style);
   if (!attr || attr->Type() != nsAttrValue::eServoCSSDeclaration) {
     return nullptr;
   }
   return attr->GetServoCSSDeclarationValue();
 }
 
@@ -511,73 +511,73 @@ ClassOrClassList(Implementor* aElement, 
 
   nsCOMPtr<nsIAtom>* elements = atomArray->Elements();
   nsIAtom** rawElements = reinterpret_cast<nsIAtom**>(elements);
   *aClassList = rawElements;
   return atomArray->Length();
 }
 
 #define SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS(prefix_, implementor_)      \
-  nsIAtom* prefix_##AtomAttrValue(implementor_* aElement, nsIAtom* aName)      \
+  nsIAtom* prefix_##AtomAttrValue(implementor_ aElement, nsIAtom* aName)       \
   {                                                                            \
     return AtomAttrValue(aElement, aName);                                     \
   }                                                                            \
-  bool prefix_##HasAttr(implementor_* aElement, nsIAtom* aNS, nsIAtom* aName)  \
+  bool prefix_##HasAttr(implementor_ aElement, nsIAtom* aNS, nsIAtom* aName)   \
   {                                                                            \
     return HasAttr(aElement, aNS, aName);                                      \
   }                                                                            \
-  bool prefix_##AttrEquals(implementor_* aElement, nsIAtom* aNS,               \
+  bool prefix_##AttrEquals(implementor_ aElement, nsIAtom* aNS,                \
                            nsIAtom* aName, nsIAtom* aStr, bool aIgnoreCase)    \
   {                                                                            \
     return AttrEquals(aElement, aNS, aName, aStr, aIgnoreCase);                \
   }                                                                            \
-  bool prefix_##AttrDashEquals(implementor_* aElement, nsIAtom* aNS,           \
+  bool prefix_##AttrDashEquals(implementor_ aElement, nsIAtom* aNS,            \
                                nsIAtom* aName, nsIAtom* aStr)                  \
   {                                                                            \
     return AttrDashEquals(aElement, aNS, aName, aStr);                         \
   }                                                                            \
-  bool prefix_##AttrIncludes(implementor_* aElement, nsIAtom* aNS,             \
+  bool prefix_##AttrIncludes(implementor_ aElement, nsIAtom* aNS,              \
                              nsIAtom* aName, nsIAtom* aStr)                    \
   {                                                                            \
     return AttrIncludes(aElement, aNS, aName, aStr);                           \
   }                                                                            \
-  bool prefix_##AttrHasSubstring(implementor_* aElement, nsIAtom* aNS,         \
+  bool prefix_##AttrHasSubstring(implementor_ aElement, nsIAtom* aNS,          \
                                  nsIAtom* aName, nsIAtom* aStr)                \
   {                                                                            \
     return AttrHasSubstring(aElement, aNS, aName, aStr);                       \
   }                                                                            \
-  bool prefix_##AttrHasPrefix(implementor_* aElement, nsIAtom* aNS,            \
+  bool prefix_##AttrHasPrefix(implementor_ aElement, nsIAtom* aNS,             \
                               nsIAtom* aName, nsIAtom* aStr)                   \
   {                                                                            \
     return AttrHasPrefix(aElement, aNS, aName, aStr);                          \
   }                                                                            \
-  bool prefix_##AttrHasSuffix(implementor_* aElement, nsIAtom* aNS,            \
+  bool prefix_##AttrHasSuffix(implementor_ aElement, nsIAtom* aNS,             \
                               nsIAtom* aName, nsIAtom* aStr)                   \
   {                                                                            \
     return AttrHasSuffix(aElement, aNS, aName, aStr);                          \
   }                                                                            \
-  uint32_t prefix_##ClassOrClassList(implementor_* aElement, nsIAtom** aClass, \
+  uint32_t prefix_##ClassOrClassList(implementor_ aElement, nsIAtom** aClass,  \
                                      nsIAtom*** aClassList)                    \
   {                                                                            \
     return ClassOrClassList(aElement, aClass, aClassList);                     \
   }
 
-SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_, RawGeckoElement)
-SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_Snapshot, ServoElementSnapshot)
+SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_, RawGeckoElementBorrowed)
+SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_Snapshot, ServoElementSnapshot*)
 
 #undef SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS
 
-ServoNodeData*
-Gecko_GetNodeData(RawGeckoNode* aNode)
+ServoNodeDataBorrowedOrNull
+Gecko_GetNodeData(RawGeckoNodeBorrowed aNode)
 {
   return aNode->ServoData().get();
 }
 
 void
-Gecko_SetNodeData(RawGeckoNode* aNode, ServoNodeData* aData)
+Gecko_SetNodeData(RawGeckoNodeBorrowed aNode, ServoNodeDataOwned aData)
 {
   MOZ_ASSERT(!aNode->ServoData());
   aNode->ServoData().reset(aData);
 }
 
 nsIAtom*
 Gecko_Atomize(const char* aString, uint32_t aLength)
 {
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -56,29 +56,88 @@ struct nsStyleDisplay;
 struct ServoDeclarationBlock;
 
 namespace mozilla {
 namespace dom {
 class StyleChildrenIterator;
 }
 }
 
-#define DECL_REF_TYPE_FOR(type_)          \
-  typedef type_* type_##Borrowed;         \
-  struct MOZ_MUST_USE_TYPE type_##Strong  \
-  {                                       \
-    type_* mPtr;                          \
-    already_AddRefed<type_> Consume();    \
+using mozilla::dom::StyleChildrenIterator;
+
+// We have these helper types so that we can directly generate
+// things like &T or Borrowed<T> on the Rust side in the function, providing
+// additional safety benefits.
+//
+// FFI has a problem with templated types, so we just use raw pointers here.
+//
+// The "Borrowed" types generate &T or Borrowed<T> in the nullable case.
+//
+// The "Owned" types generate Owned<T> or OwnedOrNull<T>. Some of these
+// are Servo-managed and can be converted to Box<ServoType> on the
+// Servo side.
+//
+// The "Arc" types are Servo-managed Arc<ServoType>s, which are passed
+// over FFI as Strong<T> (which is nullable).
+// Note that T != ServoType, rather T is ArcInner<ServoType>
+#define DECL_BORROWED_REF_TYPE_FOR(type_) typedef type_* type_##Borrowed;
+#define DECL_NULLABLE_BORROWED_REF_TYPE_FOR(type_) typedef type_* type_##BorrowedOrNull;
+#define DECL_BORROWED_MUT_REF_TYPE_FOR(type_) typedef type_* type_##BorrowedMut;
+#define DECL_NULLABLE_BORROWED_MUT_REF_TYPE_FOR(type_) typedef type_* type_##BorrowedMutOrNull;
+
+#define DECL_ARC_REF_TYPE_FOR(type_)         \
+  DECL_NULLABLE_BORROWED_REF_TYPE_FOR(type_) \
+  DECL_BORROWED_REF_TYPE_FOR(type_)          \
+  struct MOZ_MUST_USE_TYPE type_##Strong     \
+  {                                          \
+    type_* mPtr;                             \
+    already_AddRefed<type_> Consume();       \
   };
 
-DECL_REF_TYPE_FOR(ServoComputedValues)
-DECL_REF_TYPE_FOR(RawServoStyleSheet)
-DECL_REF_TYPE_FOR(ServoDeclarationBlock)
+#define DECL_OWNED_REF_TYPE_FOR(type_)    \
+  typedef type_* type_##Owned;            \
+  DECL_BORROWED_REF_TYPE_FOR(type_)       \
+  DECL_BORROWED_MUT_REF_TYPE_FOR(type_)
+
+#define DECL_NULLABLE_OWNED_REF_TYPE_FOR(type_)    \
+  typedef type_* type_##OwnedOrNull;               \
+  DECL_NULLABLE_BORROWED_REF_TYPE_FOR(type_)       \
+  DECL_NULLABLE_BORROWED_MUT_REF_TYPE_FOR(type_)
+
+DECL_ARC_REF_TYPE_FOR(ServoComputedValues)
+DECL_ARC_REF_TYPE_FOR(RawServoStyleSheet)
+DECL_ARC_REF_TYPE_FOR(ServoDeclarationBlock)
+
+DECL_OWNED_REF_TYPE_FOR(RawServoStyleSet)
+DECL_NULLABLE_OWNED_REF_TYPE_FOR(ServoNodeData)
+DECL_OWNED_REF_TYPE_FOR(ServoNodeData)
+DECL_NULLABLE_OWNED_REF_TYPE_FOR(StyleChildrenIterator)
+DECL_OWNED_REF_TYPE_FOR(StyleChildrenIterator)
 
-#undef DECL_REF_TYPE_FOR
+// We don't use BorrowedMut because the nodes may alias
+// Servo itself doesn't directly read or mutate these;
+// it only asks Gecko to do so. In case we wish to in
+// the future, we should ensure that things being mutated
+// are protected from noalias violations by a cell type
+DECL_BORROWED_REF_TYPE_FOR(RawGeckoNode)
+DECL_NULLABLE_BORROWED_REF_TYPE_FOR(RawGeckoNode)
+DECL_BORROWED_REF_TYPE_FOR(RawGeckoElement)
+DECL_NULLABLE_BORROWED_REF_TYPE_FOR(RawGeckoElement)
+DECL_BORROWED_REF_TYPE_FOR(RawGeckoDocument)
+DECL_NULLABLE_BORROWED_REF_TYPE_FOR(RawGeckoDocument)
+DECL_BORROWED_MUT_REF_TYPE_FOR(StyleChildrenIterator)
+
+#undef DECL_ARC_REF_TYPE_FOR
+#undef DECL_OWNED_REF_TYPE_FOR
+#undef DECL_NULLABLE_OWNED_REF_TYPE_FOR
+#undef DECL_BORROWED_REF_TYPE_FOR
+#undef DECL_NULLABLE_BORROWED_REF_TYPE_FOR
+#undef DECL_BORROWED_MUT_REF_TYPE_FOR
+#undef DECL_NULLABLE_BORROWED_MUT_REF_TYPE_FOR
+
 
 #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");                 \
@@ -95,83 +154,83 @@ DECL_REF_TYPE_FOR(ServoDeclarationBlock)
   void Gecko_AddRef##name_##ArbitraryThread(ThreadSafe##name_##Holder* aPtr)  \
   { NS_ADDREF(aPtr); }                                                        \
   void Gecko_Release##name_##ArbitraryThread(ThreadSafe##name_##Holder* aPtr) \
   { NS_RELEASE(aPtr); }                                                       \
 
 extern "C" {
 
 // DOM Traversal.
-uint32_t Gecko_ChildrenCount(RawGeckoNode* node);
-bool Gecko_NodeIsElement(RawGeckoNode* node);
-RawGeckoNode* Gecko_GetParentNode(RawGeckoNode* node);
-RawGeckoNode* Gecko_GetFirstChild(RawGeckoNode* node);
-RawGeckoNode* Gecko_GetLastChild(RawGeckoNode* node);
-RawGeckoNode* Gecko_GetPrevSibling(RawGeckoNode* node);
-RawGeckoNode* Gecko_GetNextSibling(RawGeckoNode* node);
-RawGeckoElement* Gecko_GetParentElement(RawGeckoElement* element);
-RawGeckoElement* Gecko_GetFirstChildElement(RawGeckoElement* element);
-RawGeckoElement* Gecko_GetLastChildElement(RawGeckoElement* element);
-RawGeckoElement* Gecko_GetPrevSiblingElement(RawGeckoElement* element);
-RawGeckoElement* Gecko_GetNextSiblingElement(RawGeckoElement* element);
-RawGeckoElement* Gecko_GetDocumentElement(RawGeckoDocument* document);
+uint32_t Gecko_ChildrenCount(RawGeckoNodeBorrowed node);
+bool Gecko_NodeIsElement(RawGeckoNodeBorrowed node);
+RawGeckoNodeBorrowedOrNull Gecko_GetParentNode(RawGeckoNodeBorrowed node);
+RawGeckoNodeBorrowedOrNull Gecko_GetFirstChild(RawGeckoNodeBorrowed node);
+RawGeckoNodeBorrowedOrNull Gecko_GetLastChild(RawGeckoNodeBorrowed node);
+RawGeckoNodeBorrowedOrNull Gecko_GetPrevSibling(RawGeckoNodeBorrowed node);
+RawGeckoNodeBorrowedOrNull Gecko_GetNextSibling(RawGeckoNodeBorrowed node);
+RawGeckoElementBorrowedOrNull Gecko_GetParentElement(RawGeckoElementBorrowed element);
+RawGeckoElementBorrowedOrNull Gecko_GetFirstChildElement(RawGeckoElementBorrowed element);
+RawGeckoElementBorrowedOrNull Gecko_GetLastChildElement(RawGeckoElementBorrowed element);
+RawGeckoElementBorrowedOrNull Gecko_GetPrevSiblingElement(RawGeckoElementBorrowed element);
+RawGeckoElementBorrowedOrNull Gecko_GetNextSiblingElement(RawGeckoElementBorrowed element);
+RawGeckoElementBorrowedOrNull Gecko_GetDocumentElement(RawGeckoDocumentBorrowed document);
 
 // By default, Servo walks the DOM by traversing the siblings of the DOM-view
 // first child. This generally works, but misses anonymous children, which we
 // want to traverse during styling. To support these cases, we create an
 // optional heap-allocated iterator for nodes that need it. If the creation
 // method returns null, Servo falls back to the aforementioned simpler (and
 // faster) sibling traversal.
-mozilla::dom::StyleChildrenIterator* Gecko_MaybeCreateStyleChildrenIterator(RawGeckoNode* node);
-void Gecko_DropStyleChildrenIterator(mozilla::dom::StyleChildrenIterator* it);
-RawGeckoNode* Gecko_GetNextStyleChild(mozilla::dom::StyleChildrenIterator* it);
+StyleChildrenIteratorOwnedOrNull Gecko_MaybeCreateStyleChildrenIterator(RawGeckoNodeBorrowed node);
+void Gecko_DropStyleChildrenIterator(StyleChildrenIteratorOwned it);
+RawGeckoNodeBorrowedOrNull Gecko_GetNextStyleChild(StyleChildrenIteratorBorrowed it);
 
 // Selector Matching.
-uint8_t Gecko_ElementState(RawGeckoElement* element);
-bool Gecko_IsHTMLElementInHTMLDocument(RawGeckoElement* element);
-bool Gecko_IsLink(RawGeckoElement* element);
-bool Gecko_IsTextNode(RawGeckoNode* node);
-bool Gecko_IsVisitedLink(RawGeckoElement* element);
-bool Gecko_IsUnvisitedLink(RawGeckoElement* element);
-bool Gecko_IsRootElement(RawGeckoElement* element);
-nsIAtom* Gecko_LocalName(RawGeckoElement* element);
-nsIAtom* Gecko_Namespace(RawGeckoElement* element);
-nsIAtom* Gecko_GetElementId(RawGeckoElement* element);
+uint8_t Gecko_ElementState(RawGeckoElementBorrowed element);
+bool Gecko_IsHTMLElementInHTMLDocument(RawGeckoElementBorrowed element);
+bool Gecko_IsLink(RawGeckoElementBorrowed element);
+bool Gecko_IsTextNode(RawGeckoNodeBorrowed node);
+bool Gecko_IsVisitedLink(RawGeckoElementBorrowed element);
+bool Gecko_IsUnvisitedLink(RawGeckoElementBorrowed element);
+bool Gecko_IsRootElement(RawGeckoElementBorrowed element);
+nsIAtom* Gecko_LocalName(RawGeckoElementBorrowed element);
+nsIAtom* Gecko_Namespace(RawGeckoElementBorrowed element);
+nsIAtom* Gecko_GetElementId(RawGeckoElementBorrowed element);
 
 // Attributes.
-#define SERVO_DECLARE_ELEMENT_ATTR_MATCHING_FUNCTIONS(prefix_, implementor_)   \
-  nsIAtom* prefix_##AtomAttrValue(implementor_* element, nsIAtom* attribute);  \
-  bool prefix_##HasAttr(implementor_* element, nsIAtom* ns, nsIAtom* name);    \
-  bool prefix_##AttrEquals(implementor_* element, nsIAtom* ns, nsIAtom* name,  \
-                           nsIAtom* str, bool ignoreCase);                     \
-  bool prefix_##AttrDashEquals(implementor_* element, nsIAtom* ns,             \
-                               nsIAtom* name, nsIAtom* str);                   \
-  bool prefix_##AttrIncludes(implementor_* element, nsIAtom* ns,               \
-                             nsIAtom* name, nsIAtom* str);                     \
-  bool prefix_##AttrHasSubstring(implementor_* element, nsIAtom* ns,           \
-                                 nsIAtom* name, nsIAtom* str);                 \
-  bool prefix_##AttrHasPrefix(implementor_* element, nsIAtom* ns,              \
-                              nsIAtom* name, nsIAtom* str);                    \
-  bool prefix_##AttrHasSuffix(implementor_* element, nsIAtom* ns,              \
-                              nsIAtom* name, nsIAtom* str);                    \
-  uint32_t prefix_##ClassOrClassList(implementor_* element, nsIAtom** class_,  \
+#define SERVO_DECLARE_ELEMENT_ATTR_MATCHING_FUNCTIONS(prefix_, implementor_)  \
+  nsIAtom* prefix_##AtomAttrValue(implementor_ element, nsIAtom* attribute);  \
+  bool prefix_##HasAttr(implementor_ element, nsIAtom* ns, nsIAtom* name);    \
+  bool prefix_##AttrEquals(implementor_ element, nsIAtom* ns, nsIAtom* name,  \
+                           nsIAtom* str, bool ignoreCase);                    \
+  bool prefix_##AttrDashEquals(implementor_ element, nsIAtom* ns,             \
+                               nsIAtom* name, nsIAtom* str);                  \
+  bool prefix_##AttrIncludes(implementor_ element, nsIAtom* ns,               \
+                             nsIAtom* name, nsIAtom* str);                    \
+  bool prefix_##AttrHasSubstring(implementor_ element, nsIAtom* ns,           \
+                                 nsIAtom* name, nsIAtom* str);                \
+  bool prefix_##AttrHasPrefix(implementor_ element, nsIAtom* ns,              \
+                              nsIAtom* name, nsIAtom* str);                   \
+  bool prefix_##AttrHasSuffix(implementor_ element, nsIAtom* ns,              \
+                              nsIAtom* name, nsIAtom* str);                   \
+  uint32_t prefix_##ClassOrClassList(implementor_ element, nsIAtom** class_,  \
                                      nsIAtom*** classList);
 
-SERVO_DECLARE_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_, RawGeckoElement)
+SERVO_DECLARE_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_, RawGeckoElementBorrowed)
 SERVO_DECLARE_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_Snapshot,
-                                              ServoElementSnapshot)
+                                              ServoElementSnapshot*)
 
 #undef SERVO_DECLARE_ELEMENT_ATTR_MATCHING_FUNCTIONS
 
 // Style attributes.
-ServoDeclarationBlockBorrowed Gecko_GetServoDeclarationBlock(RawGeckoElement* element);
+ServoDeclarationBlockBorrowedOrNull Gecko_GetServoDeclarationBlock(RawGeckoElementBorrowed element);
 
 // Node data.
-ServoNodeData* Gecko_GetNodeData(RawGeckoNode* node);
-void Gecko_SetNodeData(RawGeckoNode* node, ServoNodeData* data);
+ServoNodeDataBorrowedOrNull Gecko_GetNodeData(RawGeckoNodeBorrowed node);
+void Gecko_SetNodeData(RawGeckoNodeBorrowed node, ServoNodeDataOwned data);
 
 // Atoms.
 nsIAtom* Gecko_Atomize(const char* aString, uint32_t aLength);
 void Gecko_AddRefAtom(nsIAtom* aAtom);
 void Gecko_ReleaseAtom(nsIAtom* aAtom);
 const uint16_t* Gecko_GetAtomAsUTF16(nsIAtom* aAtom, uint32_t* aLength);
 bool Gecko_AtomEqualsUTF8(nsIAtom* aAtom, const char* aString, uint32_t aLength);
 bool Gecko_AtomEqualsUTF8IgnoreCase(nsIAtom* aAtom, const char* aString, uint32_t aLength);
@@ -206,32 +265,32 @@ NS_DECL_HOLDER_FFI_REFCOUNTING(nsIURI, U
 void Gecko_SetMozBinding(nsStyleDisplay* style_struct,
                          const uint8_t* string_bytes, uint32_t string_length,
                          ThreadSafeURIHolder* base_uri,
                          ThreadSafeURIHolder* referrer,
                          ThreadSafePrincipalHolder* principal);
 void Gecko_CopyMozBindingFrom(nsStyleDisplay* des, const nsStyleDisplay* src);
 
 // Dirtiness tracking.
-uint32_t Gecko_GetNodeFlags(RawGeckoNode* node);
-void Gecko_SetNodeFlags(RawGeckoNode* node, uint32_t flags);
-void Gecko_UnsetNodeFlags(RawGeckoNode* node, uint32_t flags);
+uint32_t Gecko_GetNodeFlags(RawGeckoNodeBorrowed node);
+void Gecko_SetNodeFlags(RawGeckoNodeBorrowed node, uint32_t flags);
+void Gecko_UnsetNodeFlags(RawGeckoNodeBorrowed node, uint32_t flags);
 
 // Incremental restyle.
 // TODO: We would avoid a few ffi calls if we decide to make an API like the
 // former CalcAndStoreStyleDifference, but that would effectively mean breaking
 // some safety guarantees in the servo side.
 //
 // Also, we might want a ComputedValues to ComputedValues API for animations?
 // Not if we do them in Gecko...
-nsStyleContext* Gecko_GetStyleContext(RawGeckoNode* node,
+nsStyleContext* Gecko_GetStyleContext(RawGeckoNodeBorrowed node,
                                       nsIAtom* aPseudoTagOrNull);
 nsChangeHint Gecko_CalcStyleDifference(nsStyleContext* oldstyle,
                                        ServoComputedValuesBorrowed newstyle);
-void Gecko_StoreStyleDifference(RawGeckoNode* node, nsChangeHint change);
+void Gecko_StoreStyleDifference(RawGeckoNodeBorrowed node, nsChangeHint change);
 
 // `array` must be an nsTArray
 // If changing this signature, please update the
 // friend function declaration in nsTArray.h
 void Gecko_EnsureTArrayCapacity(void* array, size_t capacity, size_t elem_size);
 
 // Same here, `array` must be an nsTArray<T>, for some T.
 //