Backed out 5 changesets (bug 1292618) for !mImageTracked assertion failures
authorPhil Ringnalda <philringnalda@gmail.com>
Fri, 19 Aug 2016 00:23:42 -0700
changeset 351529 43689d56cbf6891d3fb4cb3a3fff687884049313
parent 351528 581e898152d059ed2c2f9ba38c36f14291328e83
child 351530 24f8fbe46850d572c36f8f6dbfa10e962c38a7d7
push id6570
push userraliiev@mozilla.com
push dateMon, 14 Nov 2016 12:26:13 +0000
treeherdermozilla-beta@f455459b2ae5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1292618
milestone51.0a1
backs out1d767147e160b9f2c8b070b604d939cd76d92051
e6034e58efe42d575dba117c596d4d0c8a9a4a82
928dd363efa0f375e5c35e3a40a660fb9d44d4a1
8e274c66ae7f157df79b029c48dd4b434c2bc38e
6c347701d343570f7c71b0f8875756e490a17d7a
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out 5 changesets (bug 1292618) for !mImageTracked assertion failures CLOSED TREE Backed out changeset 1d767147e160 (bug 1292618) Backed out changeset e6034e58efe4 (bug 1292618) Backed out changeset 928dd363efa0 (bug 1292618) Backed out changeset 8e274c66ae7f (bug 1292618) Backed out changeset 6c347701d343 (bug 1292618)
layout/base/ServoRestyleManager.cpp
layout/base/ServoRestyleManager.h
layout/base/nsCounterManager.cpp
layout/base/nsCounterManager.h
layout/style/ServoBindings.cpp
layout/style/ServoBindings.h
layout/style/ServoStyleSet.cpp
layout/style/nsComputedDOMStyle.cpp
layout/style/nsRuleNode.cpp
layout/style/nsStyleStruct.cpp
layout/style/nsStyleStruct.h
xpcom/glue/nsTArray.h
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -1,19 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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/. */
 
 #include "mozilla/ServoRestyleManager.h"
 #include "mozilla/ServoStyleSet.h"
-#include "mozilla/dom/ChildIterator.h"
-#include "nsContentUtils.h"
-#include "nsStyleChangeList.h"
 
 using namespace mozilla::dom;
 
 namespace mozilla {
 
 ServoRestyleManager::ServoRestyleManager(nsPresContext* aPresContext)
   : RestyleManagerBase(aPresContext)
 {
@@ -77,20 +74,20 @@ ServoRestyleManager::RecreateStyleContex
     return;
   }
 
   if (aContent->IsDirtyForServo()) {
     RefPtr<ServoComputedValues> computedValues =
       Servo_GetComputedValues(aContent).Consume();
     MOZ_ASSERT(computedValues);
 
-    nsChangeHint changeHint = nsChangeHint(0);
     // NB: Change hint processing only applies to elements, at least until we
     // support display: contents.
     if (aContent->IsElement()) {
+      nsChangeHint changeHint = nsChangeHint(0);
       Element* element = aContent->AsElement();
 
       // Add an explicit change hint if appropriate.
       ServoElementSnapshot* snapshot;
       if (mModifiedElements.Get(element, &snapshot)) {
         changeHint |= snapshot->ExplicitChangeHint();
       }
 
@@ -138,46 +135,16 @@ ServoRestyleManager::RecreateStyleContex
     // XXX This could not always work as expected: there are kinds of content
     // with the first split and the last sharing style, but others not. We
     // should handle those properly.
     for (nsIFrame* f = primaryFrame; f;
          f = GetNextContinuationWithSameStyle(f, oldStyleContext)) {
       f->SetStyleContext(newContext);
     }
 
-    // Update pseudo-elements state if appropriate.
-    if (aContent->IsElement()) {
-      Element* aElement = aContent->AsElement();
-      const static CSSPseudoElementType pseudosToRestyle[] = {
-        CSSPseudoElementType::before, CSSPseudoElementType::after,
-      };
-
-      for (CSSPseudoElementType pseudoType : pseudosToRestyle) {
-        nsIAtom* pseudoTag =
-          nsCSSPseudoElements::GetPseudoAtom(pseudoType);
-        if (nsIFrame* pseudoFrame =
-              FrameForPseudoElement(aElement, pseudoTag)) {
-          // TODO: we could maybe make this more performant via calling into
-          // Servo just once to know which pseudo-elements we've got to restyle?
-          RefPtr<nsStyleContext> pseudoContext =
-            aStyleSet->ProbePseudoElementStyle(aElement, pseudoType,
-                                               newContext);
-
-          // If pseudoContext is null here, it means the frame is going away, so
-          // our change hint computation should have already indicated we need
-          // to reframe.
-          MOZ_ASSERT_IF(!pseudoContext,
-                        changeHint & nsChangeHint_ReconstructFrame);
-          if (pseudoContext) {
-            pseudoFrame->SetStyleContext(pseudoContext);
-          }
-        }
-      }
-    }
-
     // TODO: There are other continuations we still haven't restyled, mostly
     // pseudo-elements. We have to deal with those, and with anonymous boxes.
     aContent->UnsetFlags(NODE_IS_DIRTY_FOR_SERVO);
   }
 
   if (aContent->HasDirtyDescendantsForServo()) {
     MOZ_ASSERT(primaryFrame,
                "Frame construction should be scheduled, and it takes the "
@@ -215,47 +182,17 @@ MarkChildrenAsDirtyForServo(nsIContent* 
     n->SetIsDirtyForServo();
   }
 
   if (hadChildren) {
     aContent->SetHasDirtyDescendantsForServo();
   }
 }
 
-/* static */ nsIFrame*
-ServoRestyleManager::FrameForPseudoElement(nsIContent* aContent,
-                                           nsIAtom* aPseudoTagOrNull)
-{
-  MOZ_ASSERT_IF(aPseudoTagOrNull, aContent->IsElement());
-  nsIFrame* primaryFrame = aContent->GetPrimaryFrame();
-
-  if (!aPseudoTagOrNull) {
-    return primaryFrame;
-  }
-
-  if (!primaryFrame) {
-    return nullptr;
-  }
-
-  // NOTE: we probably need to special-case display: contents here. Gecko's
-  // RestyleManager passes the primary frame of the parent instead.
-  if (aPseudoTagOrNull == nsCSSPseudoElements::before) {
-    return nsLayoutUtils::GetBeforeFrameForContent(primaryFrame, aContent);
-  }
-
-  if (aPseudoTagOrNull == nsCSSPseudoElements::after) {
-    return nsLayoutUtils::GetAfterFrameForContent(primaryFrame, aContent);
-  }
-
-  MOZ_CRASH("Unkown pseudo-element given to "
-            "ServoRestyleManager::FrameForPseudoElement");
-  return nullptr;
-}
-
-/* static */ void
+void
 ServoRestyleManager::NoteRestyleHint(Element* aElement, nsRestyleHint aHint)
 {
   const nsRestyleHint HANDLED_RESTYLE_HINTS = eRestyle_Self |
                                               eRestyle_Subtree |
                                               eRestyle_LaterSiblings |
                                               eRestyle_SomeDescendants;
   // NB: For Servo, at least for now, restyling and running selector-matching
   // against the subtree is necessary as part of restyling the element, so
--- a/layout/base/ServoRestyleManager.h
+++ b/layout/base/ServoRestyleManager.h
@@ -72,25 +72,16 @@ public:
   {
     MOZ_ASSERT(SnapshotForElement(aElement)->HasAttrs());
   }
 
   nsresult ReparentStyleContext(nsIFrame* aFrame);
 
   bool HasPendingRestyles() { return !mModifiedElements.IsEmpty(); }
 
-  /**
-   * Gets the appropriate frame given a content and a pseudo-element tag.
-   *
-   * Right now only supports a null tag, before or after. If the pseudo-element
-   * is not null, the content needs to be an element.
-   */
-  static nsIFrame* FrameForPseudoElement(nsIContent* aContent,
-                                         nsIAtom* aPseudoTagOrNull);
-
 protected:
   ~ServoRestyleManager() {}
 
 private:
   ServoElementSnapshot* SnapshotForElement(Element* aElement);
 
   /**
    * The element-to-element snapshot table to compute restyle hints.
--- a/layout/base/nsCounterManager.cpp
+++ b/layout/base/nsCounterManager.cpp
@@ -221,41 +221,42 @@ nsCounterManager::AddCounterResetsAndInc
         !styleContent->CounterResetCount())
         return false;
 
     // Add in order, resets first, so all the comparisons will be optimized
     // for addition at the end of the list.
     int32_t i, i_end;
     bool dirty = false;
     for (i = 0, i_end = styleContent->CounterResetCount(); i != i_end; ++i)
-      dirty |= AddResetOrIncrement(aFrame, i, styleContent->CounterResetAt(i),
-                                   nsCounterChangeNode::RESET);
+        dirty |= AddResetOrIncrement(aFrame, i,
+                                     styleContent->GetCounterResetAt(i),
+                                     nsCounterChangeNode::RESET);
     for (i = 0, i_end = styleContent->CounterIncrementCount(); i != i_end; ++i)
-      dirty |=
-        AddResetOrIncrement(aFrame, i, styleContent->CounterIncrementAt(i),
-                            nsCounterChangeNode::INCREMENT);
+        dirty |= AddResetOrIncrement(aFrame, i,
+                                     styleContent->GetCounterIncrementAt(i),
+                                     nsCounterChangeNode::INCREMENT);
     return dirty;
 }
 
 bool
-nsCounterManager::AddResetOrIncrement(nsIFrame* aFrame, int32_t aIndex,
-                                      const nsStyleCounterData& aCounterData,
+nsCounterManager::AddResetOrIncrement(nsIFrame *aFrame, int32_t aIndex,
+                                      const nsStyleCounterData *aCounterData,
                                       nsCounterNode::Type aType)
 {
-  nsCounterChangeNode* node =
-    new nsCounterChangeNode(aFrame, aType, aCounterData.mValue, aIndex);
+    nsCounterChangeNode *node =
+        new nsCounterChangeNode(aFrame, aType, aCounterData->mValue, aIndex);
 
-  nsCounterList* counterList = CounterListFor(aCounterData.mCounter);
+    nsCounterList *counterList = CounterListFor(aCounterData->mCounter);
 
-  counterList->Insert(node);
-  if (!counterList->IsLast(node)) {
-    // Tell the caller it's responsible for recalculating the entire
-    // list.
-    counterList->SetDirty();
-    return true;
+    counterList->Insert(node);
+    if (!counterList->IsLast(node)) {
+        // Tell the caller it's responsible for recalculating the entire
+        // list.
+        counterList->SetDirty();
+        return true;
     }
 
     // Don't call Calc() if the list is already dirty -- it'll be recalculated
     // anyway, and trying to calculate with a dirty list doesn't work.
     if (MOZ_LIKELY(!counterList->IsDirty())) {
         node->Calc(counterList);
     }
     return false;
--- a/layout/base/nsCounterManager.h
+++ b/layout/base/nsCounterManager.h
@@ -266,16 +266,16 @@ public:
         if ((aIncrement > 0) != (newValue > aOldValue)) {
           newValue = aOldValue;
         }
         return newValue;
     }
 
 private:
     // for |AddCounterResetsAndIncrements| only
-  bool AddResetOrIncrement(nsIFrame* aFrame, int32_t aIndex,
-                           const nsStyleCounterData& aCounterData,
-                           nsCounterNode::Type aType);
+    bool AddResetOrIncrement(nsIFrame *aFrame, int32_t aIndex,
+                               const nsStyleCounterData *aCounterData,
+                               nsCounterNode::Type aType);
 
-  nsClassHashtable<nsStringHashKey, nsCounterList> mNames;
+    nsClassHashtable<nsStringHashKey, nsCounterList> mNames;
 };
 
 #endif /* nsCounterManager_h_ */
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -9,32 +9,28 @@
 #include "StyleStructContext.h"
 #include "gfxFontFamilyList.h"
 #include "nsAttrValueInlines.h"
 #include "nsCSSRuleProcessor.h"
 #include "nsContentUtils.h"
 #include "nsDOMTokenList.h"
 #include "nsIDOMNode.h"
 #include "nsIDocument.h"
-#include "nsIFrame.h"
 #include "nsINode.h"
 #include "nsIPrincipal.h"
 #include "nsNameSpaceManager.h"
 #include "nsString.h"
 #include "nsStyleStruct.h"
 #include "nsStyleUtil.h"
 #include "nsTArray.h"
 
 #include "mozilla/EventStates.h"
 #include "mozilla/ServoElementSnapshot.h"
-#include "mozilla/ServoRestyleManager.h"
 #include "mozilla/dom/Element.h"
 
-using namespace mozilla;
-
 #define IMPL_STRONG_REF_TYPE(name, T)           \
   already_AddRefed<T> name::Consume() {         \
     RefPtr<T> result = dont_AddRef(mPtr);       \
     mPtr = nullptr;                             \
     return result.forget();                     \
   };
 
 
@@ -195,27 +191,25 @@ Gecko_SetNodeFlags(RawGeckoNode* aNode, 
 
 void
 Gecko_UnsetNodeFlags(RawGeckoNode* aNode, uint32_t aFlags)
 {
   aNode->UnsetFlags(aFlags);
 }
 
 nsStyleContext*
-Gecko_GetStyleContext(RawGeckoNode* aNode, nsIAtom* aPseudoTagOrNull)
+Gecko_GetStyleContext(RawGeckoNode* aNode)
 {
   MOZ_ASSERT(aNode->IsContent());
-  nsIFrame* relevantFrame =
-    ServoRestyleManager::FrameForPseudoElement(aNode->AsContent(),
-                                               aPseudoTagOrNull);
-  if (!relevantFrame) {
+  nsIFrame* primaryFrame = aNode->AsContent()->GetPrimaryFrame();
+  if (!primaryFrame) {
     return nullptr;
   }
 
-  return relevantFrame->StyleContext();
+  return primaryFrame->StyleContext();
 }
 
 nsChangeHint
 Gecko_CalcStyleDifference(nsStyleContext* aOldStyleContext,
                           ServoComputedValuesBorrowed aComputedValues)
 {
   MOZ_ASSERT(aOldStyleContext);
   MOZ_ASSERT(aComputedValues);
@@ -710,53 +704,21 @@ Gecko_CreateGradient(uint8_t aShape,
   }
 
   return result;
 }
 
 void
 Gecko_EnsureTArrayCapacity(void* aArray, size_t aCapacity, size_t aElemSize)
 {
-  auto base =
-    reinterpret_cast<nsTArray_base<nsTArrayInfallibleAllocator,
-                                   nsTArray_CopyWithMemutils> *>(aArray);
-
+  auto base = reinterpret_cast<nsTArray_base<nsTArrayInfallibleAllocator, nsTArray_CopyWithMemutils> *>(aArray);
   base->EnsureCapacity<nsTArrayInfallibleAllocator>(aCapacity, aElemSize);
 }
 
 void
-Gecko_ClearPODTArray(void* aArray, size_t aElementSize, size_t aElementAlign)
-{
-  auto base =
-    reinterpret_cast<nsTArray_base<nsTArrayInfallibleAllocator,
-                                   nsTArray_CopyWithMemutils> *>(aArray);
-
-  base->template ShiftData<nsTArrayInfallibleAllocator>(0, base->Length(), 0,
-                                                        aElementSize, aElementAlign);
-}
-
-void
-Gecko_ClearStyleContents(nsStyleContent* aContent)
-{
-  aContent->AllocateContents(0);
-}
-
-void
-Gecko_CopyStyleContentsFrom(nsStyleContent* aContent, const nsStyleContent* aOther)
-{
-  uint32_t count = aOther->ContentCount();
-
-  aContent->AllocateContents(count);
-
-  for (uint32_t i = 0; i < count; ++i) {
-    aContent->ContentAt(i) = aOther->ContentAt(i);
-  }
-}
-
-void
 Gecko_EnsureImageLayersLength(nsStyleImageLayers* aLayers, size_t aLen)
 {
   aLayers->mLayers.EnsureLengthAtLeast(aLen);
 }
 
 void
 Gecko_InitializeImageLayer(nsStyleImageLayers::Layer* aLayer,
                                 nsStyleImageLayers::LayerType aLayerType)
@@ -816,17 +778,17 @@ void
 Servo_DropNodeData(ServoNodeData* data)
 {
   MOZ_CRASH("stylo: shouldn't be calling Servo_DropNodeData in a "
             "non-MOZ_STYLO build");
 }
 
 RawServoStyleSheetStrong
 Servo_StylesheetFromUTF8Bytes(const uint8_t* bytes, uint32_t length,
-                              css::SheetParsingMode mode,
+                              mozilla::css::SheetParsingMode mode,
                               const uint8_t* base_bytes, uint32_t base_length,
                               ThreadSafeURIHolder* base,
                               ThreadSafeURIHolder* referrer,
                               ThreadSafePrincipalHolder* principal)
 {
   MOZ_CRASH("stylo: shouldn't be calling Servo_StylesheetFromUTF8Bytes in a "
             "non-MOZ_STYLO build");
 }
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -210,38 +210,26 @@ void Gecko_UnsetNodeFlags(RawGeckoNode* 
 
 // 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,
-                                      nsIAtom* aPseudoTagOrNull);
+nsStyleContext* Gecko_GetStyleContext(RawGeckoNode* node);
 nsChangeHint Gecko_CalcStyleDifference(nsStyleContext* oldstyle,
                                        ServoComputedValuesBorrowed newstyle);
 void Gecko_StoreStyleDifference(RawGeckoNode* 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.
-//
-// Important note: Only valid for POD types, since destructors won't be run
-// otherwise. This is ensured with rust traits for the relevant structs.
-void Gecko_ClearPODTArray(void* array, size_t elem_size, size_t elem_align);
-
-// Clear the mContents field in nsStyleContent. This is needed to run the
-// destructors, otherwise we'd leak the images (though we still don't support
-// those), strings, and whatnot.
-void Gecko_ClearStyleContents(nsStyleContent* content);
-void Gecko_CopyStyleContentsFrom(nsStyleContent* content, const nsStyleContent* other);
 
 void Gecko_EnsureImageLayersLength(nsStyleImageLayers* layers, size_t len);
 
 void Gecko_InitializeImageLayer(nsStyleImageLayers::Layer* layer,
                                 nsStyleImageLayers::LayerType layer_type);
 
 // Clean up pointer-based coordinates
 void Gecko_ResetStyleCoord(nsStyleUnit* unit, nsStyleUnion* value);
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -91,18 +91,17 @@ ServoStyleSet::ResolveStyleFor(Element* 
 }
 
 already_AddRefed<nsStyleContext>
 ServoStyleSet::GetContext(nsIContent* aContent,
                           nsStyleContext* aParentContext,
                           nsIAtom* aPseudoTag,
                           CSSPseudoElementType aPseudoType)
 {
-  RefPtr<ServoComputedValues> computedValues =
-    Servo_GetComputedValues(aContent).Consume();
+  RefPtr<ServoComputedValues> computedValues = Servo_GetComputedValues(aContent).Consume();
   MOZ_ASSERT(computedValues);
   return GetContext(computedValues.forget(), aParentContext, aPseudoTag, aPseudoType);
 }
 
 already_AddRefed<nsStyleContext>
 ServoStyleSet::GetContext(already_AddRefed<ServoComputedValues> aComputedValues,
                           nsStyleContext* aParentContext,
                           nsIAtom* aPseudoTag,
@@ -110,17 +109,18 @@ ServoStyleSet::GetContext(already_AddRef
 {
   // XXXbholley: nsStyleSet does visited handling here.
 
   // XXXbholley: Figure out the correct thing to pass here. Does this fixup
   // duplicate something that servo already does?
   bool skipFixup = false;
 
   return NS_NewStyleContext(aParentContext, mPresContext, aPseudoTag,
-                            aPseudoType, Move(aComputedValues), skipFixup);
+                            aPseudoType,
+                            Move(aComputedValues), skipFixup);
 }
 
 already_AddRefed<nsStyleContext>
 ServoStyleSet::ResolveStyleFor(Element* aElement,
                                nsStyleContext* aParentContext,
                                TreeMatchContext& aTreeMatchContext)
 {
   // aTreeMatchContext is used to speed up selector matching,
@@ -129,61 +129,28 @@ ServoStyleSet::ResolveStyleFor(Element* 
   return ResolveStyleFor(aElement, aParentContext);
 }
 
 already_AddRefed<nsStyleContext>
 ServoStyleSet::ResolveStyleForText(nsIContent* aTextNode,
                                    nsStyleContext* aParentContext)
 {
   MOZ_ASSERT(aTextNode && aTextNode->IsNodeOfType(nsINode::eTEXT));
-  MOZ_ASSERT(aTextNode->GetParent());
-
-  nsIContent* parent = aTextNode->GetParent();
-  nsIAtom* parentName = parent->NodeInfo()->NameAtom();
-
-  // If this text node is a child of a generated content node, it'll never have
-  // been traversed by Servo, and thus isn't styled.
-  //
-  // We inherit the style from the parent here, but also taking into account
-  // that only the frame of the parent has the correct style, given we take it
-  // from the map, and the content hasn't also being traversed from Servo.
-  //
-  // Otherwise, we rely on the fact that this text node should have been
-  // traversed by servo to just grab the computed values as appropriate.
-  //
-  // TODO: We might want to just do this and skip styling nodes entirely from
-  // Servo. This would accidentally fix the issue of having to stash
-  // change-hints from children in the parent element just because of inherited
-  // style struct changes.
-  RefPtr<ServoComputedValues> computedValues;
-  if (parent->IsRootOfAnonymousSubtree() &&
-      (parentName == nsGkAtoms::mozgeneratedcontentbefore ||
-       parentName == nsGkAtoms::mozgeneratedcontentafter)) {
-    MOZ_ASSERT(aParentContext);
-    ServoComputedValues* parentComputedValues =
-      aParentContext->StyleSource().AsServoComputedValues();
-    computedValues =
-      Servo_InheritComputedValues(parentComputedValues).Consume();
-  } else {
-    computedValues = Servo_GetComputedValues(aTextNode).Consume();
-  }
-
-  return GetContext(computedValues.forget(), aParentContext,
-                    nsCSSAnonBoxes::mozText, CSSPseudoElementType::AnonBox);
+  return GetContext(aTextNode, aParentContext, nsCSSAnonBoxes::mozText,
+                    CSSPseudoElementType::AnonBox);
 }
 
 already_AddRefed<nsStyleContext>
 ServoStyleSet::ResolveStyleForOtherNonElement(nsStyleContext* aParentContext)
 {
   // The parent context can be null if the non-element share a style context
   // with the root of an anonymous subtree.
   ServoComputedValues* parent =
     aParentContext ? aParentContext->StyleSource().AsServoComputedValues() : nullptr;
-  RefPtr<ServoComputedValues> computedValues =
-    Servo_InheritComputedValues(parent).Consume();
+  RefPtr<ServoComputedValues> computedValues = Servo_InheritComputedValues(parent).Consume();
   MOZ_ASSERT(computedValues);
 
   return GetContext(computedValues.forget(), aParentContext,
                     nsCSSAnonBoxes::mozOtherNonElement,
                     CSSPseudoElementType::AnonBox);
 }
 
 already_AddRefed<nsStyleContext>
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -1192,21 +1192,21 @@ nsComputedDOMStyle::DoGetCounterIncremen
   }
 
   RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
 
   for (uint32_t i = 0, i_end = content->CounterIncrementCount(); i < i_end; ++i) {
     RefPtr<nsROCSSPrimitiveValue> name = new nsROCSSPrimitiveValue;
     RefPtr<nsROCSSPrimitiveValue> value = new nsROCSSPrimitiveValue;
 
-    const nsStyleCounterData& data = content->CounterIncrementAt(i);
+    const nsStyleCounterData *data = content->GetCounterIncrementAt(i);
     nsAutoString escaped;
-    nsStyleUtil::AppendEscapedCSSIdent(data.mCounter, escaped);
+    nsStyleUtil::AppendEscapedCSSIdent(data->mCounter, escaped);
     name->SetString(escaped);
-    value->SetNumber(data.mValue); // XXX This should really be integer
+    value->SetNumber(data->mValue); // XXX This should really be integer
 
     valueList->AppendCSSValue(name.forget());
     valueList->AppendCSSValue(value.forget());
   }
 
   return valueList.forget();
 }
 
@@ -1436,21 +1436,21 @@ nsComputedDOMStyle::DoGetCounterReset()
   }
 
   RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
 
   for (uint32_t i = 0, i_end = content->CounterResetCount(); i < i_end; ++i) {
     RefPtr<nsROCSSPrimitiveValue> name = new nsROCSSPrimitiveValue;
     RefPtr<nsROCSSPrimitiveValue> value = new nsROCSSPrimitiveValue;
 
-    const nsStyleCounterData& data = content->CounterResetAt(i);
+    const nsStyleCounterData *data = content->GetCounterResetAt(i);
     nsAutoString escaped;
-    nsStyleUtil::AppendEscapedCSSIdent(data.mCounter, escaped);
+    nsStyleUtil::AppendEscapedCSSIdent(data->mCounter, escaped);
     name->SetString(escaped);
-    value->SetNumber(data.mValue); // XXX This should really be integer
+    value->SetNumber(data->mValue); // XXX This should really be integer
 
     valueList->AppendCSSValue(name.forget());
     valueList->AppendCSSValue(value.forget());
   }
 
   return valueList.forget();
 }
 
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -8858,91 +8858,96 @@ nsRuleNode::ComputeContentData(void* aSt
   case eCSSUnit_Unset:
     // "normal", "none", "initial" and "unset" all mean no content
     content->AllocateContents(0);
     break;
 
   case eCSSUnit_Inherit:
     conditions.SetUncacheable();
     count = parentContent->ContentCount();
-    content->AllocateContents(count);
-    while (0 < count--) {
-      content->ContentAt(count) = parentContent->ContentAt(count);
+    if (NS_SUCCEEDED(content->AllocateContents(count))) {
+      while (0 < count--) {
+        content->ContentAt(count) = parentContent->ContentAt(count);
+      }
     }
     break;
 
   case eCSSUnit_Enumerated: {
     MOZ_ASSERT(contentValue->GetIntValue() == NS_STYLE_CONTENT_ALT_CONTENT,
                "unrecognized solitary content keyword");
     content->AllocateContents(1);
     nsStyleContentData& data = content->ContentAt(0);
     data.mType = eStyleContentType_AltContent;
     data.mContent.mString = nullptr;
     break;
   }
 
   case eCSSUnit_List:
   case eCSSUnit_ListDep: {
     const nsCSSValueList* contentValueList = contentValue->GetListValue();
-    count = 0;
-    while (contentValueList) {
-      count++;
-      contentValueList = contentValueList->mNext;
-    }
-    content->AllocateContents(count);
-    const nsAutoString nullStr;
-    count = 0;
-    contentValueList = contentValue->GetListValue();
-    while (contentValueList) {
-      const nsCSSValue& value = contentValueList->mValue;
-      nsCSSUnit unit = value.GetUnit();
-      nsStyleContentType type;
-      nsStyleContentData &data = content->ContentAt(count++);
-      switch (unit) {
-      case eCSSUnit_String:   type = eStyleContentType_String;    break;
-      case eCSSUnit_Image:    type = eStyleContentType_Image;     break;
-      case eCSSUnit_Attr:     type = eStyleContentType_Attr;      break;
-      case eCSSUnit_Counter:  type = eStyleContentType_Counter;   break;
-      case eCSSUnit_Counters: type = eStyleContentType_Counters;  break;
-      case eCSSUnit_Enumerated:
-        switch (value.GetIntValue()) {
-        case NS_STYLE_CONTENT_OPEN_QUOTE:
-          type = eStyleContentType_OpenQuote;     break;
-        case NS_STYLE_CONTENT_CLOSE_QUOTE:
-          type = eStyleContentType_CloseQuote;    break;
-        case NS_STYLE_CONTENT_NO_OPEN_QUOTE:
-          type = eStyleContentType_NoOpenQuote;   break;
-        case NS_STYLE_CONTENT_NO_CLOSE_QUOTE:
-          type = eStyleContentType_NoCloseQuote;  break;
-        default:
-          NS_ERROR("bad content value");
-          type = eStyleContentType_Uninitialized;
+      count = 0;
+      while (contentValueList) {
+        count++;
+        contentValueList = contentValueList->mNext;
+      }
+      if (NS_SUCCEEDED(content->AllocateContents(count))) {
+        const nsAutoString  nullStr;
+        count = 0;
+        contentValueList = contentValue->GetListValue();
+        while (contentValueList) {
+          const nsCSSValue& value = contentValueList->mValue;
+          nsCSSUnit unit = value.GetUnit();
+          nsStyleContentType type;
+          nsStyleContentData &data = content->ContentAt(count++);
+          switch (unit) {
+          case eCSSUnit_String:   type = eStyleContentType_String;    break;
+          case eCSSUnit_Image:    type = eStyleContentType_Image;     break;
+          case eCSSUnit_Attr:     type = eStyleContentType_Attr;      break;
+          case eCSSUnit_Counter:  type = eStyleContentType_Counter;   break;
+          case eCSSUnit_Counters: type = eStyleContentType_Counters;  break;
+          case eCSSUnit_Enumerated:
+            switch (value.GetIntValue()) {
+            case NS_STYLE_CONTENT_OPEN_QUOTE:
+              type = eStyleContentType_OpenQuote;     break;
+            case NS_STYLE_CONTENT_CLOSE_QUOTE:
+              type = eStyleContentType_CloseQuote;    break;
+            case NS_STYLE_CONTENT_NO_OPEN_QUOTE:
+              type = eStyleContentType_NoOpenQuote;   break;
+            case NS_STYLE_CONTENT_NO_CLOSE_QUOTE:
+              type = eStyleContentType_NoCloseQuote;  break;
+            default:
+              NS_ERROR("bad content value");
+              type = eStyleContentType_Uninitialized;
+            }
+            break;
+          default:
+            NS_ERROR("bad content type");
+            type = eStyleContentType_Uninitialized;
+          }
+          data.mType = type;
+          if (type == eStyleContentType_Image) {
+            SetImageRequest([&](imgRequestProxy* req) {
+              data.SetImage(req);
+            }, mPresContext, value);
+          }
+          else if (type <= eStyleContentType_Attr) {
+            value.GetStringValue(buffer);
+            data.mContent.mString = NS_strdup(buffer.get());
+          }
+          else if (type <= eStyleContentType_Counters) {
+            data.mContent.mCounters = value.GetArrayValue();
+            data.mContent.mCounters->AddRef();
+          }
+          else {
+            data.mContent.mString = nullptr;
+          }
+          contentValueList = contentValueList->mNext;
         }
-        break;
-      default:
-        NS_ERROR("bad content type");
-        type = eStyleContentType_Uninitialized;
-      }
-      data.mType = type;
-      if (type == eStyleContentType_Image) {
-        SetImageRequest([&](imgRequestProxy* req) {
-          data.SetImage(req);
-        }, mPresContext, value);
-      } else if (type <= eStyleContentType_Attr) {
-        value.GetStringValue(buffer);
-        data.mContent.mString = NS_strdup(buffer.get());
-      } else if (type <= eStyleContentType_Counters) {
-        data.mContent.mCounters = value.GetArrayValue();
-        data.mContent.mCounters->AddRef();
-      } else {
-        data.mContent.mString = nullptr;
-      }
-      contentValueList = contentValueList->mNext;
-    }
-    break;
+      }
+      break;
   }
 
   default:
     MOZ_ASSERT(false, "unrecognized content unit");
   }
 
   // counter-increment: [string [int]]+, none, inherit
   const nsCSSValue* counterIncrementValue =
@@ -8955,31 +8960,35 @@ nsRuleNode::ComputeContentData(void* aSt
   case eCSSUnit_Initial:
   case eCSSUnit_Unset:
     content->AllocateCounterIncrements(0);
     break;
 
   case eCSSUnit_Inherit:
     conditions.SetUncacheable();
     count = parentContent->CounterIncrementCount();
-    content->AllocateCounterIncrements(count);
-    while (count--) {
-      const nsStyleCounterData& data = parentContent->CounterIncrementAt(count);
-      content->SetCounterIncrementAt(count, data.mCounter, data.mValue);
+    if (NS_SUCCEEDED(content->AllocateCounterIncrements(count))) {
+      while (0 < count--) {
+        const nsStyleCounterData *data =
+          parentContent->GetCounterIncrementAt(count);
+        content->SetCounterIncrementAt(count, data->mCounter, data->mValue);
+      }
     }
     break;
 
   case eCSSUnit_PairList:
   case eCSSUnit_PairListDep: {
     const nsCSSValuePairList* ourIncrement =
       counterIncrementValue->GetPairListValue();
     MOZ_ASSERT(ourIncrement->mXValue.GetUnit() == eCSSUnit_Ident,
                "unexpected value unit");
     count = ListLength(ourIncrement);
-    content->AllocateCounterIncrements(count);
+    if (NS_FAILED(content->AllocateCounterIncrements(count))) {
+      break;
+    }
 
     count = 0;
     for (const nsCSSValuePairList* p = ourIncrement; p; p = p->mNext, count++) {
       int32_t increment;
       if (p->mYValue.GetUnit() == eCSSUnit_Integer) {
         increment = p->mYValue.GetIntValue();
       } else {
         increment = 1;
@@ -9004,31 +9013,36 @@ nsRuleNode::ComputeContentData(void* aSt
   case eCSSUnit_Initial:
   case eCSSUnit_Unset:
     content->AllocateCounterResets(0);
     break;
 
   case eCSSUnit_Inherit:
     conditions.SetUncacheable();
     count = parentContent->CounterResetCount();
-    content->AllocateCounterResets(count);
-    while (0 < count--) {
-      const nsStyleCounterData& data = parentContent->CounterResetAt(count);
-      content->SetCounterResetAt(count, data.mCounter, data.mValue);
+    if (NS_SUCCEEDED(content->AllocateCounterResets(count))) {
+      while (0 < count--) {
+        const nsStyleCounterData *data =
+          parentContent->GetCounterResetAt(count);
+        content->SetCounterResetAt(count, data->mCounter, data->mValue);
+      }
     }
     break;
 
   case eCSSUnit_PairList:
   case eCSSUnit_PairListDep: {
     const nsCSSValuePairList* ourReset =
       counterResetValue->GetPairListValue();
     MOZ_ASSERT(ourReset->mXValue.GetUnit() == eCSSUnit_Ident,
                "unexpected value unit");
     count = ListLength(ourReset);
-    content->AllocateCounterResets(count);
+    if (NS_FAILED(content->AllocateCounterResets(count))) {
+      break;
+    }
+
     count = 0;
     for (const nsCSSValuePairList* p = ourReset; p; p = p->mNext, count++) {
       int32_t reset;
       if (p->mYValue.GetUnit() == eCSSUnit_Integer) {
         reset = p->mYValue.GetIntValue();
       } else {
         reset = 0;
       }
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -3384,55 +3384,50 @@ nsStyleVisibility::CalcDifference(const 
       hint |= nsChangeHint_NeutralChange;
     }
   }
   return hint;
 }
 
 nsStyleContentData::~nsStyleContentData()
 {
-  MOZ_COUNT_DTOR(nsStyleContentData);
   MOZ_ASSERT(!mImageTracked,
              "nsStyleContentData being destroyed while still tracking image!");
   if (mType == eStyleContentType_Image) {
     NS_IF_RELEASE(mContent.mImage);
   } else if (mType == eStyleContentType_Counter ||
              mType == eStyleContentType_Counters) {
     mContent.mCounters->Release();
   } else if (mContent.mString) {
     free(mContent.mString);
   }
 }
 
-nsStyleContentData::nsStyleContentData(const nsStyleContentData& aOther)
+nsStyleContentData&
+nsStyleContentData::operator=(const nsStyleContentData& aOther)
 {
+  if (this == &aOther) {
+    return *this;
+  }
+  this->~nsStyleContentData();
+  new (this) nsStyleContentData();
+
   mType = aOther.mType;
   if (mType == eStyleContentType_Image) {
     mContent.mImage = aOther.mContent.mImage;
     NS_IF_ADDREF(mContent.mImage);
   } else if (mType == eStyleContentType_Counter ||
              mType == eStyleContentType_Counters) {
     mContent.mCounters = aOther.mContent.mCounters;
     mContent.mCounters->AddRef();
   } else if (aOther.mContent.mString) {
     mContent.mString = NS_strdup(aOther.mContent.mString);
   } else {
     mContent.mString = nullptr;
   }
-}
-
-nsStyleContentData&
-nsStyleContentData::operator=(const nsStyleContentData& aOther)
-{
-  if (this == &aOther) {
-    return *this;
-  }
-  this->~nsStyleContentData();
-  new (this) nsStyleContentData(aOther);
-
   return *this;
 }
 
 bool
 nsStyleContentData::operator==(const nsStyleContentData& aOther) const
 {
   if (mType != aOther.mType) {
     return false;
@@ -3503,46 +3498,84 @@ nsStyleContentData::UntrackImage(nsPresC
 
 
 //-----------------------
 // nsStyleContent
 //
 
 nsStyleContent::nsStyleContent(StyleStructContext aContext)
   : mMarkerOffset(eStyleUnit_Auto)
+  , mContents(nullptr)
+  , mIncrements(nullptr)
+  , mResets(nullptr)
+  , mContentCount(0)
+  , mIncrementCount(0)
+  , mResetCount(0)
 {
   MOZ_COUNT_CTOR(nsStyleContent);
 }
 
 nsStyleContent::~nsStyleContent()
 {
   MOZ_COUNT_DTOR(nsStyleContent);
+  DELETE_ARRAY_IF(mContents);
+  DELETE_ARRAY_IF(mIncrements);
+  DELETE_ARRAY_IF(mResets);
 }
 
 void
 nsStyleContent::Destroy(nsPresContext* aContext)
 {
   // Unregister any images we might have with the document.
-  for (auto& content : mContents) {
-    if (content.mType == eStyleContentType_Image && content.mContent.mImage) {
-      content.UntrackImage(aContext);
+  for (uint32_t i = 0; i < mContentCount; ++i) {
+    if ((mContents[i].mType == eStyleContentType_Image) &&
+        mContents[i].mContent.mImage) {
+      mContents[i].UntrackImage(aContext);
     }
   }
 
   this->~nsStyleContent();
-  aContext->PresShell()->FreeByObjectID(eArenaObjectID_nsStyleContent, this);
+  aContext->PresShell()->
+    FreeByObjectID(eArenaObjectID_nsStyleContent, this);
 }
 
 nsStyleContent::nsStyleContent(const nsStyleContent& aSource)
   : mMarkerOffset(aSource.mMarkerOffset)
-  , mContents(aSource.mContents)
-  , mIncrements(aSource.mIncrements)
-  , mResets(aSource.mResets)
+  , mContents(nullptr)
+  , mIncrements(nullptr)
+  , mResets(nullptr)
+  , mContentCount(0)
+  , mIncrementCount(0)
+  , mResetCount(0)
+
 {
   MOZ_COUNT_CTOR(nsStyleContent);
+
+  uint32_t index;
+  if (NS_SUCCEEDED(AllocateContents(aSource.ContentCount()))) {
+    for (index = 0; index < mContentCount; index++) {
+      ContentAt(index) = aSource.ContentAt(index);
+    }
+  }
+
+  if (NS_SUCCEEDED(AllocateCounterIncrements(aSource.CounterIncrementCount()))) {
+    for (index = 0; index < mIncrementCount; index++) {
+      const nsStyleCounterData *data = aSource.GetCounterIncrementAt(index);
+      mIncrements[index].mCounter = data->mCounter;
+      mIncrements[index].mValue = data->mValue;
+    }
+  }
+
+  if (NS_SUCCEEDED(AllocateCounterResets(aSource.CounterResetCount()))) {
+    for (index = 0; index < mResetCount; index++) {
+      const nsStyleCounterData *data = aSource.GetCounterResetAt(index);
+      mResets[index].mCounter = data->mCounter;
+      mResets[index].mValue = data->mValue;
+    }
+  }
 }
 
 nsChangeHint
 nsStyleContent::CalcDifference(const nsStyleContent& aNewData) const
 {
   // In ReResolveStyleContext we assume that if there's no existing
   // ::before or ::after and we don't have to restyle children of the
   // node then we can't end up with a ::before or ::after due to the
@@ -3550,32 +3583,72 @@ nsStyleContent::CalcDifference(const nsS
   // exception to the above is when the 'content' property of the node
   // changes and the pseudo-element inherits the changed value.  Since
   // the code here triggers a frame change on the node in that case,
   // the optimization in ReResolveStyleContext is ok.  But if we ever
   // change this code to not reconstruct frames on changes to the
   // 'content' property, then we will need to revisit the optimization
   // in ReResolveStyleContext.
 
-  // Unfortunately we need to reframe even if the content lengths are the same;
-  // a simple reflow will not pick up different text or different image URLs,
-  // since we set all that up in the CSSFrameConstructor
-  if (mContents != aNewData.mContents ||
-      mIncrements != aNewData.mIncrements ||
-      mResets != aNewData.mResets) {
+  if (mContentCount != aNewData.mContentCount ||
+      mIncrementCount != aNewData.mIncrementCount ||
+      mResetCount != aNewData.mResetCount) {
     return nsChangeHint_ReconstructFrame;
   }
 
+  uint32_t ix = mContentCount;
+  while (0 < ix--) {
+    if (mContents[ix] != aNewData.mContents[ix]) {
+      // Unfortunately we need to reframe here; a simple reflow
+      // will not pick up different text or different image URLs,
+      // since we set all that up in the CSSFrameConstructor
+      return nsChangeHint_ReconstructFrame;
+    }
+  }
+  ix = mIncrementCount;
+  while (0 < ix--) {
+    if ((mIncrements[ix].mValue != aNewData.mIncrements[ix].mValue) ||
+        (mIncrements[ix].mCounter != aNewData.mIncrements[ix].mCounter)) {
+      return nsChangeHint_ReconstructFrame;
+    }
+  }
+  ix = mResetCount;
+  while (0 < ix--) {
+    if ((mResets[ix].mValue != aNewData.mResets[ix].mValue) ||
+        (mResets[ix].mCounter != aNewData.mResets[ix].mCounter)) {
+      return nsChangeHint_ReconstructFrame;
+    }
+  }
   if (mMarkerOffset != aNewData.mMarkerOffset) {
     return NS_STYLE_HINT_REFLOW;
   }
-
   return nsChangeHint(0);
 }
 
+nsresult
+nsStyleContent::AllocateContents(uint32_t aCount)
+{
+  // We need to run the destructors of the elements of mContents, so we
+  // delete and reallocate even if aCount == mContentCount.  (If
+  // nsStyleContentData had its members private and managed their
+  // ownership on setting, we wouldn't need this, but that seems
+  // unnecessary at this point.)
+  DELETE_ARRAY_IF(mContents);
+  if (aCount) {
+    mContents = new nsStyleContentData[aCount];
+    if (! mContents) {
+      mContentCount = 0;
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+  }
+  mContentCount = aCount;
+  return NS_OK;
+}
+
+
 // --------------------
 // nsStyleTextReset
 //
 
 nsStyleTextReset::nsStyleTextReset(StyleStructContext aContext)
   : mTextDecorationLine(NS_STYLE_TEXT_DECORATION_LINE_NONE)
   , mUnicodeBidi(NS_STYLE_UNICODE_BIDI_NORMAL)
   , mInitialLetterSink(0)
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -3156,21 +3156,17 @@ struct nsStyleContentData
   bool mImageTracked;
 #endif
 
   nsStyleContentData()
     : mType(eStyleContentType_Uninitialized)
 #ifdef DEBUG
     , mImageTracked(false)
 #endif
-  {
-    MOZ_COUNT_CTOR(nsStyleContentData);
-    mContent.mString = nullptr;
-  }
-  nsStyleContentData(const nsStyleContentData&);
+  { mContent.mString = nullptr; }
 
   ~nsStyleContentData();
   nsStyleContentData& operator=(const nsStyleContentData& aOther);
   bool operator==(const nsStyleContentData& aOther) const;
 
   bool operator!=(const nsStyleContentData& aOther) const {
     return !(*this == aOther);
   }
@@ -3180,32 +3176,29 @@ struct nsStyleContentData
 
   void SetImage(imgRequestProxy* aRequest)
   {
     MOZ_ASSERT(!mImageTracked,
                "Setting a new image without untracking the old one!");
     MOZ_ASSERT(mType == eStyleContentType_Image, "Wrong type!");
     NS_IF_ADDREF(mContent.mImage = aRequest);
   }
+private:
+  nsStyleContentData(const nsStyleContentData&); // not to be implemented
 };
 
 struct nsStyleCounterData
 {
   nsString  mCounter;
   int32_t   mValue;
-
-  bool operator==(const nsStyleCounterData& aOther) const {
-    return mValue == aOther.mValue && mCounter == aOther.mCounter;
-  }
-
-  bool operator!=(const nsStyleCounterData& aOther) const {
-    return !(*this == aOther);
-  }
 };
 
+
+#define DELETE_ARRAY_IF(array)  if (array) { delete[] array; array = nullptr; }
+
 struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleContent
 {
   explicit nsStyleContent(StyleStructContext aContext);
   nsStyleContent(const nsStyleContent& aContent);
   ~nsStyleContent();
 
   void* operator new(size_t sz, nsStyleContent* aSelf) { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) {
@@ -3222,70 +3215,100 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
   static nsChangeHint DifferenceAlwaysHandledForDescendants() {
     // CalcDifference never returns the reflow hints that are sometimes
     // handled for descendants as hints not handled for descendants.
     return nsChangeHint_NeedReflow |
            nsChangeHint_ReflowChangesSizeOrPosition |
            nsChangeHint_ClearAncestorIntrinsics;
   }
 
-  uint32_t ContentCount() const { return mContents.Length(); } // [reset]
+  uint32_t  ContentCount() const  { return mContentCount; } // [reset]
 
   const nsStyleContentData& ContentAt(uint32_t aIndex) const {
+    NS_ASSERTION(aIndex < mContentCount, "out of range");
     return mContents[aIndex];
   }
 
-  nsStyleContentData& ContentAt(uint32_t aIndex) { return mContents[aIndex]; }
-
-  void AllocateContents(uint32_t aCount) {
-    // We need to run the destructors of the elements of mContents, so we
-    // delete and reallocate even if aCount == mContentCount.  (If
-    // nsStyleContentData had its members private and managed their
-    // ownership on setting, we wouldn't need this, but that seems
-    // unnecessary at this point.)
-    mContents.Clear();
-    mContents.SetLength(aCount);
-  }
-
-  uint32_t CounterIncrementCount() const { return mIncrements.Length(); }  // [reset]
-  const nsStyleCounterData& CounterIncrementAt(uint32_t aIndex) const {
-    return mIncrements[aIndex];
-  }
-
-  void AllocateCounterIncrements(uint32_t aCount) {
-    mIncrements.Clear();
-    mIncrements.SetLength(aCount);
-  }
-
-  void SetCounterIncrementAt(uint32_t aIndex, const nsString& aCounter, int32_t aIncrement) {
-    mIncrements[aIndex].mCounter = aCounter;
-    mIncrements[aIndex].mValue = aIncrement;
-  }
-
-  uint32_t CounterResetCount() const { return mResets.Length(); }  // [reset]
-  const nsStyleCounterData& CounterResetAt(uint32_t aIndex) const {
-    return mResets[aIndex];
-  }
-
-  void AllocateCounterResets(uint32_t aCount) {
-    mResets.Clear();
-    mResets.SetLength(aCount);
-  }
-
-  void SetCounterResetAt(uint32_t aIndex, const nsString& aCounter, int32_t aValue) {
-    mResets[aIndex].mCounter = aCounter;
-    mResets[aIndex].mValue = aValue;
+  nsStyleContentData& ContentAt(uint32_t aIndex) {
+    NS_ASSERTION(aIndex < mContentCount, "out of range");
+    return mContents[aIndex];
+  }
+
+  nsresult AllocateContents(uint32_t aCount);
+
+  uint32_t  CounterIncrementCount() const { return mIncrementCount; }  // [reset]
+  const nsStyleCounterData* GetCounterIncrementAt(uint32_t aIndex) const {
+    NS_ASSERTION(aIndex < mIncrementCount, "out of range");
+    return &mIncrements[aIndex];
+  }
+
+  nsresult  AllocateCounterIncrements(uint32_t aCount) {
+    if (aCount != mIncrementCount) {
+      DELETE_ARRAY_IF(mIncrements);
+      if (aCount) {
+        mIncrements = new nsStyleCounterData[aCount];
+        if (! mIncrements) {
+          mIncrementCount = 0;
+          return NS_ERROR_OUT_OF_MEMORY;
+        }
+      }
+      mIncrementCount = aCount;
+    }
+    return NS_OK;
+  }
+
+  nsresult  SetCounterIncrementAt(uint32_t aIndex, const nsString& aCounter, int32_t aIncrement) {
+    if (aIndex < mIncrementCount) {
+      mIncrements[aIndex].mCounter = aCounter;
+      mIncrements[aIndex].mValue = aIncrement;
+      return NS_OK;
+    }
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+
+  uint32_t  CounterResetCount() const { return mResetCount; }  // [reset]
+  const nsStyleCounterData* GetCounterResetAt(uint32_t aIndex) const {
+    NS_ASSERTION(aIndex < mResetCount, "out of range");
+    return &mResets[aIndex];
+  }
+
+  nsresult  AllocateCounterResets(uint32_t aCount) {
+    if (aCount != mResetCount) {
+      DELETE_ARRAY_IF(mResets);
+      if (aCount) {
+        mResets = new nsStyleCounterData[aCount];
+        if (! mResets) {
+          mResetCount = 0;
+          return NS_ERROR_OUT_OF_MEMORY;
+        }
+      }
+      mResetCount = aCount;
+    }
+    return NS_OK;
+  }
+
+  nsresult  SetCounterResetAt(uint32_t aIndex, const nsString& aCounter, int32_t aValue) {
+    if (aIndex < mResetCount) {
+      mResets[aIndex].mCounter = aCounter;
+      mResets[aIndex].mValue = aValue;
+      return NS_OK;
+    }
+    return NS_ERROR_ILLEGAL_VALUE;
   }
 
   nsStyleCoord  mMarkerOffset;  // [reset] coord, auto
 
 protected:
-  nsTArray<nsStyleContentData> mContents;
-  nsTArray<nsStyleCounterData> mIncrements;
-  nsTArray<nsStyleCounterData> mResets;
+  nsStyleContentData* mContents;
+  nsStyleCounterData* mIncrements;
+  nsStyleCounterData* mResets;
+
+  uint32_t            mContentCount;
+  uint32_t            mIncrementCount;
+  uint32_t            mResetCount;
 };
 
 struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleUIReset
 {
   explicit nsStyleUIReset(StyleStructContext aContext);
   nsStyleUIReset(const nsStyleUIReset& aOther);
   ~nsStyleUIReset();
 
--- a/xpcom/glue/nsTArray.h
+++ b/xpcom/glue/nsTArray.h
@@ -323,23 +323,17 @@ struct nsTArray_SafeElementAtHelper<mozi
   {
     if (aIndex < static_cast<const Derived*>(this)->Length()) {
       return static_cast<const Derived*>(this)->ElementAt(aIndex);
     }
     return nullptr;
   }
 };
 
-// Servo bindings.
-extern "C" void Gecko_EnsureTArrayCapacity(void* aArray,
-                                           size_t aCapacity,
-                                           size_t aElementSize);
-extern "C" void Gecko_ClearPODTArray(void* aArray,
-                                     size_t aElementSize,
-                                     size_t aElementAlign);
+extern "C" void Gecko_EnsureTArrayCapacity(void* aArray, size_t aCapacity, size_t aElemSize);
 
 MOZ_NORETURN MOZ_COLD void
 InvalidArrayIndex_CRASH(size_t aIndex, size_t aLength);
 
 //
 // This class serves as a base class for nsTArray.  It shouldn't be used
 // directly.  It holds common implementation code that does not depend on the
 // element type of the nsTArray.
@@ -347,20 +341,17 @@ InvalidArrayIndex_CRASH(size_t aIndex, s
 template<class Alloc, class Copy>
 class nsTArray_base
 {
   // Allow swapping elements with |nsTArray_base|s created using a
   // different allocator.  This is kosher because all allocators use
   // the same free().
   template<class Allocator, class Copier>
   friend class nsTArray_base;
-  friend void Gecko_EnsureTArrayCapacity(void* aArray, size_t aCapacity,
-                                         size_t aElemSize);
-  friend void Gecko_ClearPODTArray(void* aTArray, size_t aElementSize,
-                                   size_t aElementAlign);
+  friend void Gecko_EnsureTArrayCapacity(void* aArray, size_t aCapacity, size_t aElemSize);
 
 protected:
   typedef nsTArrayHeader Header;
 
 public:
   typedef size_t size_type;
   typedef size_t index_type;