Bug 1329093 - Part 1: stylo: Handle SVG presentation attributes; r?bz draft
authorManish Goregaokar <manishearth@gmail.com>
Wed, 22 Feb 2017 17:19:04 -0800
changeset 496350 6093c6e56de6127074ce485bcdad475dcc2ffa3d
parent 496349 4aa128f4b262917b813d35088ef9fd9621f5cfdf
child 496351 24718fd4e0e2a3a6e4d181cf5a9b8794cfab8d82
push id48571
push userbmo:manishearth@gmail.com
push dateFri, 10 Mar 2017 01:48:52 +0000
reviewersbz
bugs1329093
milestone55.0a1
Bug 1329093 - Part 1: stylo: Handle SVG presentation attributes; r?bz MozReview-Commit-ID: 9cymo3c9HIn
dom/animation/KeyframeUtils.cpp
dom/svg/nsSVGElement.cpp
dom/svg/nsSVGElement.h
layout/style/ServoBindingList.h
layout/style/ServoBindings.cpp
layout/style/ServoBindings.h
layout/style/ServoDeclarationBlock.h
layout/style/nsDOMCSSDeclaration.cpp
--- a/dom/animation/KeyframeUtils.cpp
+++ b/dom/animation/KeyframeUtils.cpp
@@ -1023,29 +1023,26 @@ MakePropertyValuePair(nsCSSPropertyID aP
   PropertyValuePair result;
 
   result.mProperty = aProperty;
 
   if (aDocument->GetStyleBackendType() == StyleBackendType::Servo) {
     nsCString name = nsCSSProps::GetStringValue(aProperty);
 
     NS_ConvertUTF16toUTF8 value(aStringValue);
-    RefPtr<ThreadSafeURIHolder> base =
-      new ThreadSafeURIHolder(aDocument->GetDocumentURI());
-    RefPtr<ThreadSafeURIHolder> referrer =
-      new ThreadSafeURIHolder(aDocument->GetDocumentURI());
-    RefPtr<ThreadSafePrincipalHolder> principal =
-      new ThreadSafePrincipalHolder(aDocument->NodePrincipal());
 
     nsCString baseString;
+    // FIXME this is using the wrong base uri (bug 1343919)
+    GeckoParserExtraData data(aDocument->GetDocumentURI(),
+                              aDocument->GetDocumentURI(),
+                              aDocument->NodePrincipal());
     aDocument->GetDocumentURI()->GetSpec(baseString);
 
     RefPtr<RawServoDeclarationBlock> servoDeclarationBlock =
-      Servo_ParseProperty(&name, &value, &baseString,
-                          base, referrer, principal).Consume();
+      Servo_ParseProperty(&name, &value, &baseString, &data).Consume();
 
     if (servoDeclarationBlock) {
       result.mServoDeclarationBlock = servoDeclarationBlock.forget();
       return result;
     }
   }
 
   nsCSSValue value;
--- a/dom/svg/nsSVGElement.cpp
+++ b/dom/svg/nsSVGElement.cpp
@@ -298,16 +298,20 @@ nsSVGElement::AfterSetAttr(int32_t aName
              "Unexpected use of nsMappedAttributes within SVG");
 
   // If this is an svg presentation attribute we need to map it into
   // the content declaration block.
   // XXX For some reason incremental mapping doesn't work, so for now
   // just delete the style rule and lazily reconstruct it as needed).
   if (aNamespaceID == kNameSpaceID_None && IsAttributeMapped(aName)) {
     mContentDeclarationBlock = nullptr;
+    // TODO we should be doing this lazily by caching these on the styleset
+    if (OwnerDoc()->GetStyleBackendType() == StyleBackendType::Servo) {
+      UpdateContentDeclarationBlock(StyleBackendType::Servo);
+    }
   }
 
   if (IsEventAttributeName(aName) && aValue) {
     MOZ_ASSERT(aValue->Type() == nsAttrValue::eString,
                "Expected string value for script body");
     nsresult rv = SetEventHandler(GetEventNameForAttr(aName),
                                   aValue->GetStringValue());
     NS_ENSURE_SUCCESS(rv, rv);
@@ -905,17 +909,17 @@ nsSVGElement::IsNodeOfType(uint32_t aFla
 
 NS_IMETHODIMP
 nsSVGElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
 {
 #ifdef DEBUG
 //  printf("nsSVGElement(%p)::WalkContentStyleRules()\n", this);
 #endif
   if (!mContentDeclarationBlock) {
-    UpdateContentDeclarationBlock();
+    UpdateContentDeclarationBlock(StyleBackendType::Gecko);
   }
 
   if (mContentDeclarationBlock) {
     css::Declaration* declaration = mContentDeclarationBlock->AsGecko();
     declaration->SetImmutable();
     aRuleWalker->Forward(declaration);
   }
 
@@ -1171,77 +1175,97 @@ nsSVGElement::IsFocusableInternal(int32_
 
 namespace {
 
 class MOZ_STACK_CLASS MappedAttrParser {
 public:
   MappedAttrParser(css::Loader* aLoader,
                    nsIURI* aDocURI,
                    already_AddRefed<nsIURI> aBaseURI,
-                   nsSVGElement* aElement);
+                   nsSVGElement* aElement,
+                   StyleBackendType aBackend);
   ~MappedAttrParser();
 
   // Parses a mapped attribute value.
   void ParseMappedAttrValue(nsIAtom* aMappedAttrName,
                             const nsAString& aMappedAttrValue);
 
   // If we've parsed any values for mapped attributes, this method returns the
   // already_AddRefed css::Declaration that incorporates the parsed
   // values. Otherwise, this method returns null.
-  already_AddRefed<css::Declaration> GetDeclarationBlock();
+  already_AddRefed<DeclarationBlock> GetDeclarationBlock();
 
 private:
   // MEMBER DATA
   // -----------
   nsCSSParser       mParser;
 
   // Arguments for nsCSSParser::ParseProperty
   nsIURI*           mDocURI;
   nsCOMPtr<nsIURI>  mBaseURI;
 
   // Declaration for storing parsed values (lazily initialized)
-  RefPtr<css::Declaration> mDecl;
+  RefPtr<DeclarationBlock> mDecl;
 
   // For reporting use counters
   nsSVGElement*     mElement;
+
+  StyleBackendType mBackend;
 };
 
 MappedAttrParser::MappedAttrParser(css::Loader* aLoader,
                                    nsIURI* aDocURI,
                                    already_AddRefed<nsIURI> aBaseURI,
-                                   nsSVGElement* aElement)
+                                   nsSVGElement* aElement,
+                                   StyleBackendType aBackend)
   : mParser(aLoader), mDocURI(aDocURI), mBaseURI(aBaseURI),
-    mElement(aElement)
+    mElement(aElement), mBackend(aBackend)
 {
 }
 
 MappedAttrParser::~MappedAttrParser()
 {
   MOZ_ASSERT(!mDecl,
              "If mDecl was initialized, it should have been returned via "
              "GetDeclarationBlock (and had its pointer cleared)");
 }
 
 void
 MappedAttrParser::ParseMappedAttrValue(nsIAtom* aMappedAttrName,
                                        const nsAString& aMappedAttrValue)
 {
   if (!mDecl) {
-    mDecl = new css::Declaration();
-    mDecl->InitializeEmpty();
+    if (mBackend == StyleBackendType::Gecko) {
+      mDecl = new css::Declaration();
+      mDecl->AsGecko()->InitializeEmpty();
+    } else {
+      mDecl = new ServoDeclarationBlock();
+    }
   }
 
   // Get the nsCSSPropertyID ID for our mapped attribute.
   nsCSSPropertyID propertyID =
     nsCSSProps::LookupProperty(nsDependentAtomString(aMappedAttrName),
                                CSSEnabledState::eForAllContent);
   if (propertyID != eCSSProperty_UNKNOWN) {
     bool changed = false; // outparam for ParseProperty.
-    mParser.ParseProperty(propertyID, aMappedAttrValue, mDocURI, mBaseURI,
-                          mElement->NodePrincipal(), mDecl, &changed, false, true);
+    if (mBackend == StyleBackendType::Gecko) {
+      mParser.ParseProperty(propertyID, aMappedAttrValue, mDocURI, mBaseURI,
+                            mElement->NodePrincipal(), mDecl->AsGecko(), &changed, false, true);
+    } else {
+      NS_ConvertUTF16toUTF8 value(aMappedAttrValue);
+      // FIXME (bug 1343964): Figure out a better solution for sending the base uri to servo
+      nsCString baseString;
+      GeckoParserExtraData data(mBaseURI, mDocURI, mElement->NodePrincipal());
+      mBaseURI->GetSpec(baseString);
+      // FIXME (bug 1342559): Set SVG parsing mode for lengths
+      changed = Servo_DeclarationBlock_SetPropertyById(mDecl->AsServo()->Raw(), propertyID,
+                                                       &value, false, &baseString, &data);
+    }
+
     if (changed) {
       // The normal reporting of use counters by the nsCSSParser won't happen
       // since it doesn't have a sheet.
       if (nsCSSProps::IsShorthand(propertyID)) {
         CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(subprop, propertyID,
                                              CSSEnabledState::eForAllContent) {
           UseCounter useCounter = nsCSSProps::UseCounterFor(*subprop);
           if (useCounter != eUseCounter_UNKNOWN) {
@@ -1257,51 +1281,56 @@ MappedAttrParser::ParseMappedAttrValue(n
     }
     return;
   }
   MOZ_ASSERT(aMappedAttrName == nsGkAtoms::lang,
              "Only 'lang' should be unrecognized!");
   // nsCSSParser doesn't know about 'lang', so we need to handle it specially.
   if (aMappedAttrName == nsGkAtoms::lang) {
     propertyID = eCSSProperty__x_lang;
-    nsCSSExpandedDataBlock block;
-    mDecl->ExpandTo(&block);
-    nsCSSValue cssValue(PromiseFlatString(aMappedAttrValue), eCSSUnit_Ident);
-    block.AddLonghandProperty(propertyID, cssValue);
-    mDecl->ValueAppended(propertyID);
-    mDecl->CompressFrom(&block);
+    if (mBackend == StyleBackendType::Gecko) {
+      nsCSSExpandedDataBlock block;
+      mDecl->AsGecko()->ExpandTo(&block);
+      nsCSSValue cssValue(PromiseFlatString(aMappedAttrValue), eCSSUnit_Ident);
+      block.AddLonghandProperty(propertyID, cssValue);
+      mDecl->AsGecko()->ValueAppended(propertyID);
+      mDecl->AsGecko()->CompressFrom(&block);
+    } else {
+      nsCOMPtr<nsIAtom> atom = NS_Atomize(aMappedAttrValue);
+      Servo_DeclarationBlock_SetIdentStringValue(mDecl->AsServo()->Raw(), propertyID, atom);
+    }
   }
 }
 
-already_AddRefed<css::Declaration>
+already_AddRefed<DeclarationBlock>
 MappedAttrParser::GetDeclarationBlock()
 {
   return mDecl.forget();
 }
 
 } // namespace
 
 //----------------------------------------------------------------------
 // Implementation Helpers:
 
 void
-nsSVGElement::UpdateContentDeclarationBlock()
+nsSVGElement::UpdateContentDeclarationBlock(mozilla::StyleBackendType aBackend)
 {
   NS_ASSERTION(!mContentDeclarationBlock,
                "we already have a content declaration block");
 
   uint32_t attrCount = mAttrsAndChildren.AttrCount();
   if (!attrCount) {
     // nothing to do
     return;
   }
 
   nsIDocument* doc = OwnerDoc();
   MappedAttrParser mappedAttrParser(doc->CSSLoader(), doc->GetDocumentURI(),
-                                    GetBaseURI(), this);
+                                    GetBaseURI(), this, aBackend);
 
   for (uint32_t i = 0; i < attrCount; ++i) {
     const nsAttrName* attrName = mAttrsAndChildren.AttrNameAt(i);
     if (!attrName->IsAtom() || !IsAttributeMapped(attrName->Atom()))
       continue;
 
     if (attrName->NamespaceID() != kNameSpaceID_None &&
         !attrName->Equals(nsGkAtoms::lang, kNameSpaceID_XML)) {
@@ -1333,16 +1362,22 @@ nsSVGElement::UpdateContentDeclarationBl
 
     nsAutoString value;
     mAttrsAndChildren.AttrAt(i)->ToString(value);
     mappedAttrParser.ParseMappedAttrValue(attrName->Atom(), value);
   }
   mContentDeclarationBlock = mappedAttrParser.GetDeclarationBlock();
 }
 
+const DeclarationBlock*
+nsSVGElement::GetContentDeclarationBlock() const
+{
+  return mContentDeclarationBlock;
+}
+
 static void
 ParseMappedAttrAnimValueCallback(void*    aObject,
                                  nsIAtom* aPropertyName,
                                  void*    aPropertyValue,
                                  void*    aData)
 {
   MOZ_ASSERT(aPropertyName != SMIL_MAPPED_ATTR_STYLEDECL_ATOM,
              "animated content style rule should have been removed "
@@ -1381,18 +1416,19 @@ nsSVGElement::UpdateAnimatedContentDecla
              "Animated content declaration block already set");
 
   nsIDocument* doc = OwnerDoc();
   if (!doc) {
     NS_ERROR("SVG element without owner document");
     return;
   }
 
+  // FIXME (bug 1342557): Support SMIL in Servo
   MappedAttrParser mappedAttrParser(doc->CSSLoader(), doc->GetDocumentURI(),
-                                    GetBaseURI(), this);
+                                    GetBaseURI(), this, StyleBackendType::Gecko);
   doc->PropertyTable(SMIL_MAPPED_ATTR_ANIMVAL)->
     Enumerate(this, ParseMappedAttrAnimValueCallback, &mappedAttrParser);
  
   RefPtr<DeclarationBlock> animContentDeclBlock =
     mappedAttrParser.GetDeclarationBlock();
 
   if (animContentDeclBlock) {
 #ifdef DEBUG
--- a/dom/svg/nsSVGElement.h
+++ b/dom/svg/nsSVGElement.h
@@ -131,16 +131,18 @@ public:
   static const MappedAttributeEntry sFEFloodMap[];
   static const MappedAttributeEntry sLightingEffectsMap[];
   static const MappedAttributeEntry sMaskMap[];
 
   NS_FORWARD_NSIDOMNODE_TO_NSINODE
   NS_FORWARD_NSIDOMELEMENT_TO_GENERIC
   NS_DECL_NSIDOMSVGELEMENT
 
+  NS_IMPL_FROMCONTENT(nsSVGElement, kNameSpaceID_SVG)
+
   // Gets the element that establishes the rectangular viewport against which
   // we should resolve percentage lengths (our "coordinate context"). Returns
   // nullptr for outer <svg> or SVG without an <svg> parent (invalid SVG).
   mozilla::dom::SVGSVGElement* GetCtx() const;
 
   /**
    * Returns aMatrix pre-multiplied by (explicit or implicit) transforms that
    * are introduced by attributes on this element.
@@ -317,16 +319,19 @@ public:
   // WebIDL
   mozilla::dom::SVGSVGElement* GetOwnerSVGElement();
   nsSVGElement* GetViewportElement();
   already_AddRefed<mozilla::dom::SVGAnimatedString> ClassName();
 
   virtual bool IsSVGFocusable(bool* aIsFocusable, int32_t* aTabIndex);
   virtual bool IsFocusableInternal(int32_t* aTabIndex, bool aWithMouse) override;
 
+  void UpdateContentDeclarationBlock(mozilla::StyleBackendType aBackend);
+  const mozilla::DeclarationBlock* GetContentDeclarationBlock() const;
+
 protected:
   virtual JSObject* WrapNode(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
 
 #ifdef DEBUG
   // We define BeforeSetAttr here and mark it final to ensure it is NOT used
   // by SVG elements.
   // This is because we're not currently passing the correct value for aValue to
   // BeforeSetAttr since it would involve allocating extra SVG value types.
@@ -341,17 +346,16 @@ protected:
   virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
                                 const nsAttrValue* aValue, bool aNotify) override;
   virtual bool ParseAttribute(int32_t aNamespaceID, nsIAtom* aAttribute,
                                 const nsAString& aValue, nsAttrValue& aResult) override;
   static nsresult ReportAttributeParseFailure(nsIDocument* aDocument,
                                               nsIAtom* aAttribute,
                                               const nsAString& aValue);
 
-  void UpdateContentDeclarationBlock();
   void UpdateAnimatedContentDeclarationBlock();
   mozilla::DeclarationBlock* GetAnimatedContentDeclarationBlock();
 
   nsAttrValue WillChangeValue(nsIAtom* aName);
   // aNewValue is set to the old value. This value may be invalid if
   // !StoresOwnData.
   void DidChangeValue(nsIAtom* aName, const nsAttrValue& aEmptyOrOldValue,
                       nsAttrValue& aNewValue);
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -97,19 +97,18 @@ SERVO_BINDING_FUNC(Servo_StyleRule_GetCs
                    RawServoStyleRuleBorrowed rule, nsAString* result)
 SERVO_BINDING_FUNC(Servo_StyleRule_GetSelectorText, void,
                    RawServoStyleRuleBorrowed rule, nsAString* result)
 
 // Animations API
 SERVO_BINDING_FUNC(Servo_ParseProperty,
                    RawServoDeclarationBlockStrong,
                    const nsACString* property, const nsACString* value,
-                   const nsACString* base_url, ThreadSafeURIHolder* base,
-                   ThreadSafeURIHolder* referrer,
-                   ThreadSafePrincipalHolder* principal)
+                   const nsACString* base,
+                   const GeckoParserExtraData* data)
 SERVO_BINDING_FUNC(Servo_GetComputedKeyframeValues, void,
                    RawGeckoKeyframeListBorrowed keyframes,
                    ServoComputedValuesBorrowed style,
                    ServoComputedValuesBorrowedOrNull parent_style,
                    RawGeckoPresContextBorrowed pres_context,
                    RawGeckoComputedKeyframeValuesListBorrowedMut result)
 
 // AnimationValues handling
@@ -162,21 +161,25 @@ SERVO_BINDING_FUNC(Servo_DeclarationBloc
                    RawServoDeclarationBlockBorrowed declarations,
                    nsCSSPropertyID property, nsAString* value)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_GetPropertyIsImportant, bool,
                    RawServoDeclarationBlockBorrowed declarations,
                    const nsACString* property)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_SetProperty, bool,
                    RawServoDeclarationBlockBorrowed declarations,
                    const nsACString* property,
-                   nsACString* value, bool is_important)
+                   const nsACString* value, bool is_important,
+                   const nsACString* base,
+                   const GeckoParserExtraData* data)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_SetPropertyById, bool,
                    RawServoDeclarationBlockBorrowed declarations,
                    nsCSSPropertyID property,
-                   nsACString* value, bool is_important)
+                   const nsACString* value, bool is_important,
+                   const nsACString* base,
+                   const GeckoParserExtraData* data)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_RemoveProperty, void,
                    RawServoDeclarationBlockBorrowed declarations,
                    const nsACString* property)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_RemovePropertyById, void,
                    RawServoDeclarationBlockBorrowed declarations,
                    nsCSSPropertyID property)
 
 // presentation attributes
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -357,28 +357,33 @@ Gecko_GetStyleAttrDeclarationBlock(RawGe
     return nullptr;
   }
   if (decl->IsGecko()) {
     // XXX This can happen when nodes are adopted from a Gecko-style-backend
     //     document into a Servo-style-backend document.  See bug 1330051.
     NS_WARNING("stylo: requesting a Gecko declaration block?");
     return nullptr;
   }
-  return reinterpret_cast<const RawServoDeclarationBlockStrong*>
-    (decl->AsServo()->RefRaw());
+  return decl->AsServo()->RefRawStrong();
 }
 
 RawServoDeclarationBlockStrongBorrowedOrNull
 Gecko_GetHTMLPresentationAttrDeclarationBlock(RawGeckoElementBorrowed aElement)
 {
   static_assert(sizeof(RefPtr<RawServoDeclarationBlock>) ==
                 sizeof(RawServoDeclarationBlockStrong),
                 "RefPtr should just be a pointer");
   const nsMappedAttributes* attrs = aElement->GetMappedAttributes();
   if (!attrs) {
+    auto* svg = nsSVGElement::FromContentOrNull(const_cast<dom::Element*>(aElement));
+    if (svg) {
+      if (auto decl = svg->GetContentDeclarationBlock()) {
+        return decl->AsServo()->RefRawStrong();
+      }
+    }
     return nullptr;
   }
 
   const RefPtr<RawServoDeclarationBlock>& servo = attrs->GetServoStyle();
   return reinterpret_cast<const RawServoDeclarationBlockStrong*>(&servo);
 }
 
 RawServoDeclarationBlockStrong
@@ -779,16 +784,25 @@ ServoBundledURI::IntoCssUrl()
 
   RefPtr<css::URLValue> urlValue = new css::URLValue(urlBuffer,
                                                      do_AddRef(mBaseURI),
                                                      do_AddRef(mReferrer),
                                                      do_AddRef(mPrincipal));
   return urlValue.forget();
 }
 
+GeckoParserExtraData::GeckoParserExtraData(nsIURI* aBaseURI,
+                                           nsIURI* aReferrer,
+                                           nsIPrincipal* aPrincipal)
+    : mBaseURI(new ThreadSafeURIHolder(aBaseURI)),
+      mReferrer(new ThreadSafeURIHolder(aReferrer)),
+      mPrincipal(new ThreadSafePrincipalHolder(aPrincipal))
+{
+}
+
 void
 Gecko_SetNullImageValue(nsStyleImage* aImage)
 {
   MOZ_ASSERT(aImage);
   aImage->SetNull();
 }
 
 void
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -94,16 +94,27 @@ public:
   already_AddRefed<mozilla::css::URLValue> IntoCssUrl();
   const uint8_t* mURLString;
   uint32_t mURLStringLength;
   ThreadSafeURIHolder* mBaseURI;
   ThreadSafeURIHolder* mReferrer;
   ThreadSafePrincipalHolder* mPrincipal;
 };
 
+class GeckoParserExtraData
+{
+public:
+  GeckoParserExtraData(nsIURI* aBaseURI,
+                       nsIURI* aReferrer,
+                       nsIPrincipal* aPrincipal);
+  RefPtr<ThreadSafeURIHolder> mBaseURI;
+  RefPtr<ThreadSafeURIHolder> mReferrer;
+  RefPtr<ThreadSafePrincipalHolder> mPrincipal;
+};
+
 // DOM Traversal.
 uint32_t Gecko_ChildrenCount(RawGeckoNodeBorrowed node);
 bool Gecko_NodeIsElement(RawGeckoNodeBorrowed node);
 bool Gecko_IsInDocument(RawGeckoNodeBorrowed node);
 bool Gecko_FlattenedTreeParentIsParent(RawGeckoNodeBorrowed node);
 RawGeckoNodeBorrowedOrNull Gecko_GetParentNode(RawGeckoNodeBorrowed node);
 RawGeckoNodeBorrowedOrNull Gecko_GetFirstChild(RawGeckoNodeBorrowed node);
 RawGeckoNodeBorrowedOrNull Gecko_GetLastChild(RawGeckoNodeBorrowed node);
--- a/layout/style/ServoDeclarationBlock.h
+++ b/layout/style/ServoDeclarationBlock.h
@@ -20,29 +20,40 @@ public:
 
   ServoDeclarationBlock()
     : ServoDeclarationBlock(Servo_DeclarationBlock_CreateEmpty().Consume()) {}
 
   ServoDeclarationBlock(const ServoDeclarationBlock& aCopy)
     : DeclarationBlock(aCopy)
     , mRaw(Servo_DeclarationBlock_Clone(aCopy.mRaw).Consume()) {}
 
-  NS_INLINE_DECL_REFCOUNTING(ServoDeclarationBlock)
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ServoDeclarationBlock)
 
   static already_AddRefed<ServoDeclarationBlock>
   FromCssText(const nsAString& aCssText);
 
   RawServoDeclarationBlock* Raw() const { return mRaw; }
   RawServoDeclarationBlock* const* RefRaw() const {
     static_assert(sizeof(RefPtr<RawServoDeclarationBlock>) ==
                   sizeof(RawServoDeclarationBlock*),
                   "RefPtr should just be a pointer");
     return reinterpret_cast<RawServoDeclarationBlock* const*>(&mRaw);
   }
 
+  const RawServoDeclarationBlockStrong* RefRawStrong() const
+  {
+    static_assert(sizeof(RefPtr<RawServoDeclarationBlock>) ==
+                  sizeof(RawServoDeclarationBlock*),
+                  "RefPtr should just be a pointer");
+    static_assert(sizeof(RefPtr<RawServoDeclarationBlock>) ==
+                  sizeof(RawServoDeclarationBlockStrong),
+                  "RawServoDeclarationBlockStrong should be the same as RefPtr");
+    return reinterpret_cast<const RawServoDeclarationBlockStrong*>(&mRaw);
+  }
+
   void ToString(nsAString& aResult) const {
     Servo_DeclarationBlock_GetCssText(mRaw, &aResult);
   }
 
   uint32_t Count() const {
     return Servo_DeclarationBlock_Count(mRaw);
   }
   bool GetNthProperty(uint32_t aIndex, nsAString& aReturn) const {
--- a/layout/style/nsDOMCSSDeclaration.cpp
+++ b/layout/style/nsDOMCSSDeclaration.cpp
@@ -301,18 +301,22 @@ nsDOMCSSDeclaration::ParsePropertyValue(
   bool changed;
   if (decl->IsGecko()) {
     nsCSSParser cssParser(env.mCSSLoader);
     cssParser.ParseProperty(aPropID, aPropValue,
                             env.mSheetURI, env.mBaseURI, env.mPrincipal,
                             decl->AsGecko(), &changed, aIsImportant);
   } else {
     NS_ConvertUTF16toUTF8 value(aPropValue);
+    GeckoParserExtraData data(env.mBaseURI, env.mSheetURI, env.mPrincipal);
+    nsCString baseString;
+    // FIXME (bug 1343964): Figure out a better solution for sending the base uri to servo
+    env.mBaseURI->GetSpec(baseString);
     changed = Servo_DeclarationBlock_SetPropertyById(
-      decl->AsServo()->Raw(), aPropID, &value, aIsImportant);
+      decl->AsServo()->Raw(), aPropID, &value, aIsImportant, &baseString, &data);
   }
   if (!changed) {
     // Parsing failed -- but we don't throw an exception for that.
     return NS_OK;
   }
 
   return SetCSSDeclaration(decl);
 }
@@ -348,18 +352,21 @@ nsDOMCSSDeclaration::ParseCustomProperty
     nsCSSParser cssParser(env.mCSSLoader);
     auto propName = Substring(aPropertyName, CSS_CUSTOM_NAME_PREFIX_LENGTH);
     cssParser.ParseVariable(propName, aPropValue, env.mSheetURI,
                             env.mBaseURI, env.mPrincipal, decl->AsGecko(),
                             &changed, aIsImportant);
   } else {
     NS_ConvertUTF16toUTF8 property(aPropertyName);
     NS_ConvertUTF16toUTF8 value(aPropValue);
+    GeckoParserExtraData data(env.mBaseURI, env.mSheetURI, env.mPrincipal);
+    nsCString baseString;
+    env.mBaseURI->GetSpec(baseString);
     changed = Servo_DeclarationBlock_SetProperty(
-      decl->AsServo()->Raw(), &property, &value, aIsImportant);
+      decl->AsServo()->Raw(), &property, &value, aIsImportant, &baseString, &data);
   }
   if (!changed) {
     // Parsing failed -- but we don't throw an exception for that.
     return NS_OK;
   }
 
   return SetCSSDeclaration(decl);
 }