Merge inbound to mozilla-central. a=merge
authorCiure Andrei <aciure@mozilla.com>
Wed, 27 Mar 2019 18:36:44 +0200
changeset 466348 e94edf4ec19f11dce836449882d37d039773c68c
parent 466347 16f19322ec762261a5abe9e70c935e6e6bf90582 (current diff)
parent 466280 b9b1b4d013f5f32dd15c7d39cca87a8370101773 (diff)
child 466349 6e4c046bbac71dcceecdee932177d0fef04c7eaa
child 466365 00c5ef76d951a834ccf87c83d04e0878f6c2c515
child 466416 1735ced17de7faa90488d1e942184c9c6ca4f6c1
push id112577
push useraciure@mozilla.com
push dateWed, 27 Mar 2019 16:44:02 +0000
treeherdermozilla-inbound@6e4c046bbac7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone68.0a1
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
Merge inbound to mozilla-central. a=merge
layout/style/GeckoBindings.cpp
--- a/dom/animation/CSSPseudoElement.cpp
+++ b/dom/animation/CSSPseudoElement.cpp
@@ -18,17 +18,19 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CS
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(CSSPseudoElement, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(CSSPseudoElement, Release)
 
 CSSPseudoElement::CSSPseudoElement(dom::Element* aElement,
                                    PseudoStyleType aType)
     : mOriginatingElement(aElement), mPseudoType(aType) {
   MOZ_ASSERT(aElement);
   MOZ_ASSERT(
-      aType == PseudoStyleType::after || aType == PseudoStyleType::before,
+      aType == PseudoStyleType::after ||
+      aType == PseudoStyleType::before ||
+      aType == PseudoStyleType::marker,
       "Unexpected Pseudo Type");
 }
 
 CSSPseudoElement::~CSSPseudoElement() {
   // Element might have been unlinked already, so we have to do null check.
   if (mOriginatingElement) {
     mOriginatingElement->DeleteProperty(
         GetCSSPseudoElementPropertyAtom(mPseudoType));
@@ -101,18 +103,21 @@ nsAtom* CSSPseudoElement::GetCSSPseudoEl
     PseudoStyleType aType) {
   switch (aType) {
     case PseudoStyleType::before:
       return nsGkAtoms::cssPseudoElementBeforeProperty;
 
     case PseudoStyleType::after:
       return nsGkAtoms::cssPseudoElementAfterProperty;
 
+    case PseudoStyleType::marker:
+      return nsGkAtoms::cssPseudoElementMarkerProperty;
+
     default:
       MOZ_ASSERT_UNREACHABLE(
           "Should not try to get CSSPseudoElement "
-          "other than ::before or ::after");
+          "other than ::before, ::after or ::marker");
       return nullptr;
   }
 }
 
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/animation/CSSPseudoElement.h
+++ b/dom/animation/CSSPseudoElement.h
@@ -64,17 +64,17 @@ class CSSPseudoElement final : public ns
   // Given an element:pseudoType pair, returns the CSSPseudoElement stored as a
   // property on |aElement|. If there is no CSSPseudoElement for the specified
   // pseudo-type on element, a new CSSPseudoElement will be created and stored
   // on the element.
   static already_AddRefed<CSSPseudoElement> GetCSSPseudoElement(
       dom::Element* aElement, PseudoStyleType aType);
 
  private:
-  // Only ::before and ::after are supported.
+  // Only ::before, ::after and ::marker are supported.
   CSSPseudoElement(dom::Element* aElement, PseudoStyleType aType);
 
   static nsAtom* GetCSSPseudoElementPropertyAtom(PseudoStyleType aType);
 
   // mOriginatingElement needs to be an owning reference since if script is
   // holding on to the pseudo-element, it needs to continue to be able to refer
   // to the originating element.
   RefPtr<dom::Element> mOriginatingElement;
--- a/dom/animation/EffectCompositor.cpp
+++ b/dom/animation/EffectCompositor.cpp
@@ -330,28 +330,32 @@ void EffectCompositor::PostRestyleForThr
 
 void EffectCompositor::ClearRestyleRequestsFor(Element* aElement) {
   MOZ_ASSERT(aElement);
 
   auto& elementsToRestyle = mElementsToRestyle[CascadeLevel::Animations];
 
   PseudoStyleType pseudoType = aElement->GetPseudoElementType();
   if (pseudoType == PseudoStyleType::NotPseudo) {
-    PseudoElementHashEntry::KeyType notPseudoKey = {aElement,
-                                                    PseudoStyleType::NotPseudo};
-    PseudoElementHashEntry::KeyType beforePseudoKey = {aElement,
-                                                       PseudoStyleType::before};
-    PseudoElementHashEntry::KeyType afterPseudoKey = {aElement,
-                                                      PseudoStyleType::after};
+    PseudoElementHashEntry::KeyType notPseudoKey =
+      {aElement, PseudoStyleType::NotPseudo};
+    PseudoElementHashEntry::KeyType beforePseudoKey =
+      {aElement, PseudoStyleType::before};
+    PseudoElementHashEntry::KeyType afterPseudoKey =
+      {aElement, PseudoStyleType::after};
+    PseudoElementHashEntry::KeyType markerPseudoKey =
+      {aElement, PseudoStyleType::marker};
 
     elementsToRestyle.Remove(notPseudoKey);
     elementsToRestyle.Remove(beforePseudoKey);
     elementsToRestyle.Remove(afterPseudoKey);
+    elementsToRestyle.Remove(markerPseudoKey);
   } else if (pseudoType == PseudoStyleType::before ||
-             pseudoType == PseudoStyleType::after) {
+             pseudoType == PseudoStyleType::after ||
+             pseudoType == PseudoStyleType::marker) {
     Element* parentElement = aElement->GetParentElement();
     MOZ_ASSERT(parentElement);
     PseudoElementHashEntry::KeyType key = {parentElement, pseudoType};
     elementsToRestyle.Remove(key);
   }
 }
 
 void EffectCompositor::UpdateEffectProperties(const ComputedStyle* aStyle,
@@ -439,19 +443,23 @@ bool EffectCompositor::GetServoAnimation
   if (aPseudoType == PseudoStyleType::before) {
     return nsLayoutUtils::GetBeforePseudo(aElement);
   }
 
   if (aPseudoType == PseudoStyleType::after) {
     return nsLayoutUtils::GetAfterPseudo(aElement);
   }
 
+  if (aPseudoType == PseudoStyleType::marker) {
+    return nsLayoutUtils::GetMarkerPseudo(aElement);
+  }
+
   MOZ_ASSERT_UNREACHABLE(
       "Should not try to get the element to restyle for "
-      "a pseudo other that :before or :after");
+      "a pseudo other that :before, :after or ::marker");
   return nullptr;
 }
 
 bool EffectCompositor::HasPendingStyleUpdates() const {
   for (auto& elementSet : mElementsToRestyle) {
     if (elementSet.Count()) {
       return true;
     }
@@ -515,27 +523,29 @@ Maybe<NonOwningAnimationTarget>
 EffectCompositor::GetAnimationElementAndPseudoForFrame(const nsIFrame* aFrame) {
   // Always return the same object to benefit from return-value optimization.
   Maybe<NonOwningAnimationTarget> result;
 
   PseudoStyleType pseudoType = aFrame->Style()->GetPseudoType();
 
   if (pseudoType != PseudoStyleType::NotPseudo &&
       pseudoType != PseudoStyleType::before &&
-      pseudoType != PseudoStyleType::after) {
+      pseudoType != PseudoStyleType::after &&
+      pseudoType != PseudoStyleType::marker) {
     return result;
   }
 
   nsIContent* content = aFrame->GetContent();
   if (!content) {
     return result;
   }
 
   if (pseudoType == PseudoStyleType::before ||
-      pseudoType == PseudoStyleType::after) {
+      pseudoType == PseudoStyleType::after ||
+      pseudoType == PseudoStyleType::marker) {
     content = content->GetParent();
     if (!content) {
       return result;
     }
   }
 
   if (!content->IsElement()) {
     return result;
@@ -717,17 +727,18 @@ bool EffectCompositor::PreTraverseInSubt
              "Traversal root, if provided, should be bound to a display "
              "document");
 
   // Convert the root element to the parent element if the root element is
   // pseudo since we check each element in mElementsToRestyle is in the subtree
   // of the root element later in this function, but for pseudo elements the
   // element in mElementsToRestyle is the parent of the pseudo.
   if (aRoot && (aRoot->IsGeneratedContentContainerForBefore() ||
-                aRoot->IsGeneratedContentContainerForAfter())) {
+                aRoot->IsGeneratedContentContainerForAfter() ||
+                aRoot->IsGeneratedContentContainerForMarker())) {
     aRoot = aRoot->GetParentElement();
   }
 
   AutoRestore<bool> guard(mIsInPreTraverse);
   mIsInPreTraverse = true;
 
   // We need to force flush all throttled animations if we also have
   // non-animation restyles (since we'll want the up-to-date animation style
@@ -860,17 +871,18 @@ bool EffectCompositor::PreTraverse(dom::
   // should not run animations on it.
   if (!nsContentUtils::GetPresShellForContent(aElement)) {
     return false;
   }
 
   bool found = false;
   if (aPseudoType != PseudoStyleType::NotPseudo &&
       aPseudoType != PseudoStyleType::before &&
-      aPseudoType != PseudoStyleType::after) {
+      aPseudoType != PseudoStyleType::after &&
+      aPseudoType != PseudoStyleType::marker) {
     return found;
   }
 
   AutoRestore<bool> guard(mIsInPreTraverse);
   mIsInPreTraverse = true;
 
   PseudoElementHashEntry::KeyType key = {aElement, aPseudoType};
 
--- a/dom/animation/EffectCompositor.h
+++ b/dom/animation/EffectCompositor.h
@@ -99,17 +99,17 @@ class EffectCompositor {
                                CascadeLevel aCascadeLevel);
 
   // Posts an animation restyle for any elements whose animation style rule
   // is out of date but for which an animation restyle has not yet been
   // posted because updates on the main thread are throttled.
   void PostRestyleForThrottledAnimations();
 
   // Clear all pending restyle requests for the given (pseudo-) element (and its
-  // ::before and ::after elements if the given element is not pseudo).
+  // ::before, ::after and ::marker elements if the given element is not pseudo).
   void ClearRestyleRequestsFor(dom::Element* aElement);
 
   // Called when computed style on the specified (pseudo-) element might
   // have changed so that any context-sensitive values stored within
   // animation effects (e.g. em-based endpoints used in keyframe effects)
   // can be re-resolved to computed values.
   void UpdateEffectProperties(const ComputedStyle* aStyle,
                               dom::Element* aElement,
@@ -198,17 +198,17 @@ class EffectCompositor {
   bool PreTraverse(dom::Element* aElement, PseudoStyleType aPseudoType);
 
   // Similar to the above but for all elements in the subtree rooted
   // at aElement.
   bool PreTraverseInSubtree(ServoTraversalFlags aFlags, dom::Element* aRoot);
 
   // Returns the target element for restyling.
   //
-  // If |aPseudoType| is ::after or ::before, returns the generated content
+  // If |aPseudoType| is ::after, ::before or ::marker, returns the generated content
   // element of which |aElement| is the parent. If |aPseudoType| is any other
   // pseudo type (other than PseudoStyleType::NotPseudo) returns nullptr.
   // Otherwise, returns |aElement|.
   static dom::Element* GetElementToRestyle(dom::Element* aElement,
                                            PseudoStyleType aPseudoType);
 
   // Returns true if any type of compositor animations on |aFrame| allow
   // runnning on the compositor.
--- a/dom/animation/EffectSet.cpp
+++ b/dom/animation/EffectSet.cpp
@@ -145,37 +145,42 @@ void EffectSet::UpdateAnimationGeneratio
       aPresContext->RestyleManager()->GetAnimationGeneration();
 }
 
 /* static */
 nsAtom** EffectSet::GetEffectSetPropertyAtoms() {
   static nsAtom* effectSetPropertyAtoms[] = {
       nsGkAtoms::animationEffectsProperty,
       nsGkAtoms::animationEffectsForBeforeProperty,
-      nsGkAtoms::animationEffectsForAfterProperty, nullptr};
+      nsGkAtoms::animationEffectsForAfterProperty,
+      nsGkAtoms::animationEffectsForMarkerProperty,
+      nullptr};
 
   return effectSetPropertyAtoms;
 }
 
 /* static */
 nsAtom* EffectSet::GetEffectSetPropertyAtom(PseudoStyleType aPseudoType) {
   switch (aPseudoType) {
     case PseudoStyleType::NotPseudo:
       return nsGkAtoms::animationEffectsProperty;
 
     case PseudoStyleType::before:
       return nsGkAtoms::animationEffectsForBeforeProperty;
 
     case PseudoStyleType::after:
       return nsGkAtoms::animationEffectsForAfterProperty;
 
+    case PseudoStyleType::marker:
+      return nsGkAtoms::animationEffectsForMarkerProperty;
+
     default:
       MOZ_ASSERT_UNREACHABLE(
           "Should not try to get animation effects for "
-          "a pseudo other that :before or :after");
+          "a pseudo other that :before, :after or ::marker");
       return nullptr;
   }
 }
 
 void EffectSet::AddEffect(dom::KeyframeEffect& aEffect) {
   if (!mEffects.EnsureInserted(&aEffect)) {
     return;
   }
--- a/dom/animation/KeyframeEffect.cpp
+++ b/dom/animation/KeyframeEffect.cpp
@@ -937,16 +937,17 @@ void KeyframeEffect::GetTarget(
   if (!mTarget) {
     aRv.SetNull();
     return;
   }
 
   switch (mTarget->mPseudoType) {
     case PseudoStyleType::before:
     case PseudoStyleType::after:
+    case PseudoStyleType::marker:
       aRv.SetValue().SetAsCSSPseudoElement() =
           CSSPseudoElement::GetCSSPseudoElement(mTarget->mElement,
                                                 mTarget->mPseudoType);
       break;
 
     case PseudoStyleType::NotPseudo:
       aRv.SetValue().SetAsElement() = mTarget->mElement;
       break;
@@ -1384,16 +1385,18 @@ nsIFrame* KeyframeEffect::GetPrimaryFram
   if (!mTarget) {
     return frame;
   }
 
   if (mTarget->mPseudoType == PseudoStyleType::before) {
     frame = nsLayoutUtils::GetBeforeFrame(mTarget->mElement);
   } else if (mTarget->mPseudoType == PseudoStyleType::after) {
     frame = nsLayoutUtils::GetAfterFrame(mTarget->mElement);
+  } else if (mTarget->mPseudoType == PseudoStyleType::marker) {
+    frame = nsLayoutUtils::GetMarkerFrame(mTarget->mElement);
   } else {
     frame = mTarget->mElement->GetPrimaryFrame();
     MOZ_ASSERT(mTarget->mPseudoType == PseudoStyleType::NotPseudo,
                "unknown mTarget->mPseudoType");
   }
 
   return frame;
 }
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -1772,17 +1772,18 @@ nsresult Element::BindToTree(Document* a
   // the first place, we should style it properly eventually.
   //
   // Also, if this _is_ needed, then it's wrong and should use GetComposedDoc()
   // to account for Shadow DOM.
   if (aDocument && MayHaveAnimations()) {
     PseudoStyleType pseudoType = GetPseudoElementType();
     if ((pseudoType == PseudoStyleType::NotPseudo ||
          pseudoType == PseudoStyleType::before ||
-         pseudoType == PseudoStyleType::after) &&
+         pseudoType == PseudoStyleType::after ||
+         pseudoType == PseudoStyleType::marker) &&
         EffectSet::GetEffectSet(this, pseudoType)) {
       if (nsPresContext* presContext = aDocument->GetPresContext()) {
         presContext->EffectCompositor()->RequestRestyle(
             this, pseudoType, EffectCompositor::RestyleType::Standard,
             EffectCompositor::CascadeLevel::Animations);
       }
     }
   }
@@ -1908,19 +1909,21 @@ void Element::UnbindFromTree(bool aDeep,
   // different place in the tree (even if reinserted before next
   // animation refresh).
   // We need to delete the properties while we're still in document
   // (if we were in document).
   // FIXME (Bug 522599): Need a test for this.
   if (MayHaveAnimations()) {
     DeleteProperty(nsGkAtoms::transitionsOfBeforeProperty);
     DeleteProperty(nsGkAtoms::transitionsOfAfterProperty);
+    DeleteProperty(nsGkAtoms::transitionsOfMarkerProperty);
     DeleteProperty(nsGkAtoms::transitionsProperty);
     DeleteProperty(nsGkAtoms::animationsOfBeforeProperty);
     DeleteProperty(nsGkAtoms::animationsOfAfterProperty);
+    DeleteProperty(nsGkAtoms::animationsOfMarkerProperty);
     DeleteProperty(nsGkAtoms::animationsProperty);
     if (document) {
       if (nsPresContext* presContext = document->GetPresContext()) {
         // We have to clear all pending restyle requests for the animations on
         // this element to avoid unnecessary restyles when we re-attached this
         // element.
         presContext->EffectCompositor()->ClearRestyleRequestsFor(this);
       }
@@ -3488,49 +3491,57 @@ void Element::GetAnimations(const Animat
   // For animations on generated-content elements, the animations are stored
   // on the parent element.
   if (IsGeneratedContentContainerForBefore()) {
     elem = GetParentElement();
     pseudoType = PseudoStyleType::before;
   } else if (IsGeneratedContentContainerForAfter()) {
     elem = GetParentElement();
     pseudoType = PseudoStyleType::after;
+  } else if (IsGeneratedContentContainerForMarker()) {
+    elem = GetParentElement();
+    pseudoType = PseudoStyleType::marker;
   }
 
   if (!elem) {
     return;
   }
 
-  if (!filter.mSubtree || pseudoType == PseudoStyleType::before ||
-      pseudoType == PseudoStyleType::after) {
+  if (!filter.mSubtree ||
+      pseudoType == PseudoStyleType::before ||
+      pseudoType == PseudoStyleType::after ||
+      pseudoType == PseudoStyleType::marker) {
     GetAnimationsUnsorted(elem, pseudoType, aAnimations);
   } else {
     for (nsIContent* node = this; node; node = node->GetNextNode(this)) {
       if (!node->IsElement()) {
         continue;
       }
       Element* element = node->AsElement();
       Element::GetAnimationsUnsorted(element, PseudoStyleType::NotPseudo,
                                      aAnimations);
       Element::GetAnimationsUnsorted(element, PseudoStyleType::before,
                                      aAnimations);
       Element::GetAnimationsUnsorted(element, PseudoStyleType::after,
                                      aAnimations);
+      Element::GetAnimationsUnsorted(element, PseudoStyleType::marker,
+                                     aAnimations);
     }
   }
   aAnimations.Sort(AnimationPtrComparator<RefPtr<Animation>>());
 }
 
 /* static */
 void Element::GetAnimationsUnsorted(Element* aElement,
                                     PseudoStyleType aPseudoType,
                                     nsTArray<RefPtr<Animation>>& aAnimations) {
   MOZ_ASSERT(aPseudoType == PseudoStyleType::NotPseudo ||
                  aPseudoType == PseudoStyleType::after ||
-                 aPseudoType == PseudoStyleType::before,
+                 aPseudoType == PseudoStyleType::before ||
+                 aPseudoType == PseudoStyleType::marker,
              "Unsupported pseudo type");
   MOZ_ASSERT(aElement, "Null element");
 
   EffectSet* effects = EffectSet::GetEffectSet(aElement, aPseudoType);
   if (!effects) {
     return;
   }
 
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -1225,16 +1225,18 @@ void nsGlobalWindowInner::FreeInnerObjec
 
   mConsole = nullptr;
 
   mPaintWorklet = nullptr;
 
   mExternal = nullptr;
   mInstallTrigger = nullptr;
 
+  mLocalStorage = nullptr;
+  mSessionStorage = nullptr;
   mPerformance = nullptr;
 
   mSharedWorkers.Clear();
 
 #ifdef MOZ_WEBSPEECH
   mSpeechSynthesis = nullptr;
 #endif
 
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -1978,16 +1978,17 @@ RestyleManager::AnimationsWithDestroyedF
   mRestyleManager->mAnimationsWithDestroyedFrame = this;
 }
 
 void RestyleManager::AnimationsWithDestroyedFrame ::
     StopAnimationsForElementsWithoutFrames() {
   StopAnimationsWithoutFrame(mContents, PseudoStyleType::NotPseudo);
   StopAnimationsWithoutFrame(mBeforeContents, PseudoStyleType::before);
   StopAnimationsWithoutFrame(mAfterContents, PseudoStyleType::after);
+  StopAnimationsWithoutFrame(mAfterContents, PseudoStyleType::marker);
 }
 
 void RestyleManager::AnimationsWithDestroyedFrame ::StopAnimationsWithoutFrame(
     nsTArray<RefPtr<nsIContent>>& aArray, PseudoStyleType aPseudoType) {
   nsAnimationManager* animationManager =
       mRestyleManager->PresContext()->AnimationManager();
   nsTransitionManager* transitionManager =
       mRestyleManager->PresContext()->TransitionManager();
@@ -1999,16 +2000,20 @@ void RestyleManager::AnimationsWithDestr
     } else if (aPseudoType == PseudoStyleType::before) {
       if (nsLayoutUtils::GetBeforeFrame(content)) {
         continue;
       }
     } else if (aPseudoType == PseudoStyleType::after) {
       if (nsLayoutUtils::GetAfterFrame(content)) {
         continue;
       }
+    } else if (aPseudoType == PseudoStyleType::marker) {
+      if (nsLayoutUtils::GetMarkerFrame(content)) {
+        continue;
+      }
     }
     dom::Element* element = content->AsElement();
 
     animationManager->StopAnimationsForElement(element, aPseudoType);
     transitionManager->StopAnimationsForElement(element, aPseudoType);
 
     // All other animations should keep running but not running on the
     // *compositor* at this point.
--- a/layout/base/RestyleManager.h
+++ b/layout/base/RestyleManager.h
@@ -258,37 +258,42 @@ class RestyleManager {
       } else if (pseudoType == PseudoStyleType::before) {
         MOZ_ASSERT(aContent->NodeInfo()->NameAtom() ==
                    nsGkAtoms::mozgeneratedcontentbefore);
         mBeforeContents.AppendElement(aContent->GetParent());
       } else if (pseudoType == PseudoStyleType::after) {
         MOZ_ASSERT(aContent->NodeInfo()->NameAtom() ==
                    nsGkAtoms::mozgeneratedcontentafter);
         mAfterContents.AppendElement(aContent->GetParent());
+      } else if (pseudoType == PseudoStyleType::marker) {
+        MOZ_ASSERT(aContent->NodeInfo()->NameAtom() ==
+                   nsGkAtoms::mozgeneratedcontentmarker);
+        mMarkerContents.AppendElement(aContent->GetParent());
       }
     }
 
     void StopAnimationsForElementsWithoutFrames();
 
    private:
     void StopAnimationsWithoutFrame(nsTArray<RefPtr<nsIContent>>& aArray,
                                     PseudoStyleType aPseudoType);
 
     RestyleManager* mRestyleManager;
     AutoRestore<AnimationsWithDestroyedFrame*> mRestorePointer;
 
     // Below three arrays might include elements that have already had their
     // animations or transitions stopped.
     //
-    // mBeforeContents and mAfterContents hold the real element rather than
-    // the content node for the generated content (which might change during
-    // a reframe)
+    // mBeforeContents, mAfterContents and mMarkerContents hold the real element
+    // rather than the content node for the generated content (which might
+    // change during a reframe)
     nsTArray<RefPtr<nsIContent>> mContents;
     nsTArray<RefPtr<nsIContent>> mBeforeContents;
     nsTArray<RefPtr<nsIContent>> mAfterContents;
+    nsTArray<RefPtr<nsIContent>> mMarkerContents;
   };
 
   /**
    * Return the current AnimationsWithDestroyedFrame struct, or null if we're
    * not currently in a restyling operation.
    */
   AnimationsWithDestroyedFrame* GetAnimationsWithDestroyedFrame() {
     return mAnimationsWithDestroyedFrame;
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-animations/content-on-marker-pseudo-element-at-beginning-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+  <style>
+  #target::marker {
+    content: 'content';
+  }
+  #target {
+    display: list-item;
+    margin-left: 200px;
+  }
+  </style>
+  <div id='target'></div>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-animations/content-on-marker-pseudo-element-at-beginning.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+  <style>
+  @keyframes anim {
+    from { content: 'content'; }
+    to { content: ''; }
+  }
+  #target::marker {
+    content: 'initial';
+    animation: anim 100s paused;
+  }
+  #target {
+    display: list-item;
+    margin-left: 200px;
+  }
+  </style>
+  <div id='target'></div>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-animations/content-on-marker-pseudo-element-at-half.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+  <style>
+  @keyframes anim {
+    from { content: ''; }
+    to { content: 'content'; }
+  }
+  #target::marker {
+    content: 'initial';
+    animation: anim 100s linear -50s paused;
+  }
+  #target {
+    display: list-item;
+    margin-left: 200px;
+  }
+  </style>
+  <div id='target'></div>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-animations/in-visibility-hidden-animation-marker-pseudo-element-ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+<html>
+<title>In visibility hidden color animation on pseudo element</title>
+<style>
+
+div::marker {
+  visibility: visible;
+  color: blue;
+  content: "Color Animation";
+}
+
+div {
+  color: black;
+  visibility: hidden;
+  display: list-item;
+  list-style-position: inside;
+}
+
+</style>
+<div>color animation on visible psuedo element attached to invisible element</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-animations/in-visibility-hidden-animation-marker-pseudo-element.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<html class="reftest-wait">
+<title>In visibility hidden color animation on pseudo element</title>
+<style>
+
+@keyframes color {
+  0% { color: black }
+  1% { color: blue }
+  100% { color: blue }
+}
+
+div::marker {
+  visibility: visible;
+  content: "Color Animation";
+  animation: color 0.1s 1 forwards;
+}
+
+div {
+  color: black;
+  visibility: hidden;
+  display: list-item;
+  list-style-position: inside;
+}
+
+</style>
+<div id="target">color animation on visible pseudo element attached to invisible element</div>
+<script>
+
+document.getElementById("target").addEventListener("animationend", AnimationEndListener);
+
+function AnimationEndListener(event) {
+  setTimeout(RemoveReftestWait, 0);
+}
+
+function RemoveReftestWait() {
+  document.documentElement.classList.remove("reftest-wait");
+}
+
+</script>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-animations/marker-reframe-and-animation-starts-at-the-same-time-ref.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<style>
+#target::marker {
+  content: '';
+  background-color: rgb(255, 255, 255);
+  height: 100px;
+  width: 100px;
+  position: absolute;
+}
+#target {
+  display: list-item;
+  list-style-position: inside;
+}
+</style>
+<div id="target"></div>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-animations/marker-reframe-and-animation-starts-at-the-same-time.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<style>
+@keyframes anim {
+  from { background-color: rgb(255, 255, 255); }
+  to { background-color: rgb(255, 255, 255); }
+}
+#target::marker {
+  content: 'initial';
+  background-color: rgb(0, 0, 0);
+  height: 100px;
+  width: 100px;
+  position: absolute;
+}
+#target.hover::marker{
+  content: '';
+  animation: anim 100s steps(1, start);
+}
+#target {
+  display: list-item;
+  list-style-position: inside;
+}
+</style>
+<div id="target"></div>
+<script>
+window.addEventListener("load", () => {
+  target.className = 'hover';
+  target.addEventListener('animationstart', () => {
+    document.documentElement.classList.remove('reftest-wait');
+  });
+});
+</script>
+</html>
--- a/layout/reftests/css-animations/reftest.list
+++ b/layout/reftests/css-animations/reftest.list
@@ -3,16 +3,17 @@
 fails == print-no-animations.html print-no-animations-ref.html # reftest harness doesn't actually make pres context non-dynamic for reftest-paged tests.
 fails != print-no-animations.html print-no-animations-notref.html # reftest harness doesn't actually make pres context non-dynamic for reftest-paged tests.
 == animate-opacity.html animate-opacity-ref.html
 == animate-preserves3d.html animate-preserves3d-ref.html
 == animation-initially-out-of-view-with-delay.html animation-initially-out-of-view-with-delay-ref.html
 == animation-on-empty-height-frame.html about:blank
 == in-visibility-hidden-animation.html in-visibility-hidden-animation-ref.html
 == in-visibility-hidden-animation-pseudo-element.html in-visibility-hidden-animation-pseudo-element-ref.html
+== in-visibility-hidden-animation-marker-pseudo-element.html in-visibility-hidden-animation-marker-pseudo-element-ref.html
 == partially-out-of-view-animation.html partially-out-of-view-animation-ref.html
 == animate-display-table-opacity.html animate-display-table-opacity-ref.html
 # We need to run 100% opacity test case when OMTA is disabled to check that the animation creates a stacking context even if the animation is not running on the compositor
 test-pref(layers.offmainthreadcomposition.async-animations,false) == stacking-context-opacity-1-animation.html stacking-context-animation-ref.html
 # We need to run transform:none test case when OMTA is disabled to check that the animation creates a stacking context even if the animation is not running on the compositor
 test-pref(layers.offmainthreadcomposition.async-animations,false) == stacking-context-transform-none-animation.html stacking-context-animation-ref.html
 == no-stacking-context-opacity-removing-animation-in-delay.html no-stacking-context-animation-ref.html
 == no-stacking-context-transform-removing-animation-in-delay.html no-stacking-context-animation-ref.html
@@ -52,19 +53,23 @@ fails-if(layerChecksEnabled) == backgrou
 == mask-size-after-finish-1a.html mask-anim-ref.html
 == mask-size-after-finish-1b.html mask-anim-ref.html
 == mask-size-in-delay-1a.html mask-anim-ref.html
 == mask-size-in-delay-1b.html mask-anim-ref.html
 
 == stop-animation-on-discarded-pseudo-element.html about:blank
 
 == updating-animation-on-pseudo-element.html updating-animation-on-pseudo-element-ref.html
+== updating-animation-on-marker-pseudo-element.html updating-animation-on-marker-pseudo-element-ref.html
 == content-on-pseudo-element-at-beginning.html content-on-pseudo-element-ref.html
 == content-on-pseudo-element-at-half.html content-on-pseudo-element-ref.html
+== content-on-marker-pseudo-element-at-beginning.html content-on-marker-pseudo-element-at-beginning-ref.html
+== content-on-marker-pseudo-element-at-half.html content-on-marker-pseudo-element-at-beginning-ref.html
 == reframe-and-animation-starts-at-the-same-time.html reframe-and-animation-starts-at-the-same-time-ref.html
+== marker-reframe-and-animation-starts-at-the-same-time.html marker-reframe-and-animation-starts-at-the-same-time-ref.html
 == change-animation-name-to-none-in-rule.html change-animation-name-in-rule-ref.html
 == change-animation-name-to-other-in-rule.html change-animation-name-in-rule-ref.html
 == change-animation-name-to-non-existent-in-rule.html change-animation-name-in-rule-ref.html
 == no-style-sharing-with-animations.html no-style-sharing-with-animations-ref.html
 
 == continuation-opacity.html continuation-opacity-ref.html
 == ib-split-sibling-opacity.html about:blank
 
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-animations/updating-animation-on-marker-pseudo-element-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<style>
+#target::marker {
+  content: 'marker';
+  margin-left: 10em;
+  font-size: 20px;
+}
+#target {
+  display: list-item;
+  margin-left: 200px;
+}
+</style>
+<div id="target"></div>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-animations/updating-animation-on-marker-pseudo-element.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<style>
+@keyframes anim {
+  from { margin-left: 10em; }
+  to { margin-left: 10em; }
+}
+#target::marker {
+  content: 'marker';
+}
+#target.anim::marker {
+  animation: anim 100s infinite;
+  font-size: 10px;
+}
+#target.bigger-font::marker {
+  font-size: 20px;
+}
+#target {
+  display: list-item;
+  margin-left: 200px;
+}
+</style>
+<div id="target"></div>
+<script>
+addEventListener('DOMContentLoaded', () => {
+  var target = document.getElementById('target');
+
+  // Start an animation on pseudo element.
+  target.classList.add('anim');
+
+  requestAnimationFrame(() => {
+    // The animation on pseudo element should be updated
+    // when the target element classes are modified.
+    target.classList.add('bigger-font');
+
+    requestAnimationFrame(() => {
+      document.documentElement.classList.remove('reftest-wait');
+    });
+  });
+});
+</script>
+</html>
--- a/layout/style/AnimationCollection.cpp
+++ b/layout/style/AnimationCollection.cpp
@@ -112,16 +112,18 @@ AnimationCollection<AnimationType>::GetP
   nsAtom* propName = nullptr;
 
   if (aPseudoType == PseudoStyleType::NotPseudo) {
     propName = TraitsType::ElementPropertyAtom();
   } else if (aPseudoType == PseudoStyleType::before) {
     propName = TraitsType::BeforePropertyAtom();
   } else if (aPseudoType == PseudoStyleType::after) {
     propName = TraitsType::AfterPropertyAtom();
+  } else if (aPseudoType == PseudoStyleType::marker) {
+    propName = TraitsType::MarkerPropertyAtom();
   }
 
   return propName;
 }
 
 // Explicit class instantiations
 
 template class AnimationCollection<dom::CSSAnimation>;
--- a/layout/style/AnimationCommon.h
+++ b/layout/style/AnimationCommon.h
@@ -42,17 +42,17 @@ class CommonAnimationManager {
     RemoveAllElementCollections();
 
     mPresContext = nullptr;
   }
 
   /**
    * Stop animations on the element. This method takes the real element
    * rather than the element for the generated content for animations on
-   * ::before and ::after.
+   * ::before, ::after and ::marker.
    */
   void StopAnimationsForElement(dom::Element* aElement,
                                 PseudoStyleType aPseudoType) {
     MOZ_ASSERT(aElement);
     AnimationCollection<AnimationType>* collection =
         AnimationCollection<AnimationType>::GetAnimationCollection(aElement,
                                                                    aPseudoType);
     if (!collection) {
@@ -118,16 +118,20 @@ class OwningElementRef final {
     if (mTarget.mElement != aOther.mTarget.mElement) {
       return nsContentUtils::PositionIsBefore(mTarget.mElement,
                                               aOther.mTarget.mElement,
                                               &aChildIndex, &aOtherChildIndex);
     }
 
     return mTarget.mPseudoType == PseudoStyleType::NotPseudo ||
            (mTarget.mPseudoType == PseudoStyleType::before &&
+            aOther.mTarget.mPseudoType == PseudoStyleType::after) ||
+           (mTarget.mPseudoType == PseudoStyleType::marker &&
+            aOther.mTarget.mPseudoType == PseudoStyleType::before) ||
+           (mTarget.mPseudoType == PseudoStyleType::marker &&
             aOther.mTarget.mPseudoType == PseudoStyleType::after);
   }
 
   bool IsSet() const { return !!mTarget.mElement; }
 
   void GetElement(dom::Element*& aElement, PseudoStyleType& aPseudoType) const {
     aElement = mTarget.mElement;
     aPseudoType = mTarget.mPseudoType;
--- a/layout/style/GeckoBindings.cpp
+++ b/layout/style/GeckoBindings.cpp
@@ -465,16 +465,21 @@ static PseudoStyleType GetPseudoTypeFrom
     return PseudoStyleType::before;
   }
 
   if (aElementOrPseudo->IsGeneratedContentContainerForAfter()) {
     aElementOrPseudo = aElementOrPseudo->GetParent()->AsElement();
     return PseudoStyleType::after;
   }
 
+  if (aElementOrPseudo->IsGeneratedContentContainerForMarker()) {
+    aElementOrPseudo = aElementOrPseudo->GetParent()->AsElement();
+    return PseudoStyleType::marker;
+  }
+
   return PseudoStyleType::NotPseudo;
 }
 
 bool Gecko_GetAnimationRule(const Element* aElement,
                             EffectCompositor::CascadeLevel aCascadeLevel,
                             RawServoAnimationValueMap* aAnimationValues) {
   MOZ_ASSERT(aElement);
 
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -1223,16 +1223,21 @@ already_AddRefed<ComputedStyle> ServoSty
       elementForStyleResolution = pseudo;
       pseudoTypeForStyleResolution = PseudoStyleType::NotPseudo;
     }
   } else if (aPseudoType == PseudoStyleType::after) {
     if (Element* pseudo = nsLayoutUtils::GetAfterPseudo(aElement)) {
       elementForStyleResolution = pseudo;
       pseudoTypeForStyleResolution = PseudoStyleType::NotPseudo;
     }
+  } else if (aPseudoType == PseudoStyleType::marker) {
+    if (Element* pseudo = nsLayoutUtils::GetMarkerPseudo(aElement)) {
+      elementForStyleResolution = pseudo;
+      pseudoTypeForStyleResolution = PseudoStyleType::NotPseudo;
+    }
   }
 
   RefPtr<ComputedStyle> computedValues =
       Servo_ResolveStyleLazily(elementForStyleResolution,
                                pseudoTypeForStyleResolution, aRuleInclusion,
                                &Snapshots(), mRawSet.get())
           .Consume();
 
--- a/layout/style/nsAnimationManager.h
+++ b/layout/style/nsAnimationManager.h
@@ -250,16 +250,19 @@ template <>
 struct AnimationTypeTraits<dom::CSSAnimation> {
   static nsAtom* ElementPropertyAtom() { return nsGkAtoms::animationsProperty; }
   static nsAtom* BeforePropertyAtom() {
     return nsGkAtoms::animationsOfBeforeProperty;
   }
   static nsAtom* AfterPropertyAtom() {
     return nsGkAtoms::animationsOfAfterProperty;
   }
+  static nsAtom* MarkerPropertyAtom() {
+    return nsGkAtoms::animationsOfMarkerProperty;
+  }
 };
 
 } /* namespace mozilla */
 
 class nsAnimationManager final
     : public mozilla::CommonAnimationManager<mozilla::dom::CSSAnimation> {
  public:
   explicit nsAnimationManager(nsPresContext* aPresContext)
--- a/layout/style/nsCSSPseudoElements.cpp
+++ b/layout/style/nsCSSPseudoElements.cpp
@@ -114,16 +114,18 @@ bool nsCSSPseudoElements::PseudoElementS
 
 /* static */
 nsString nsCSSPseudoElements::PseudoTypeAsString(Type aPseudoType) {
   switch (aPseudoType) {
     case PseudoStyleType::before:
       return NS_LITERAL_STRING("::before");
     case PseudoStyleType::after:
       return NS_LITERAL_STRING("::after");
+    case PseudoStyleType::marker:
+      return NS_LITERAL_STRING("::marker");
     default:
       MOZ_ASSERT(aPseudoType == PseudoStyleType::NotPseudo,
                  "Unexpected pseudo type");
       return EmptyString();
   }
 }
 
 #ifdef DEBUG
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -130,16 +130,20 @@ static bool DocumentNeedsRestyle(const D
     if (aPseudo == nsCSSPseudoElements::before()) {
       if (EffectSet::GetEffectSet(aElement, PseudoStyleType::before)) {
         return true;
       }
     } else if (aPseudo == nsCSSPseudoElements::after()) {
       if (EffectSet::GetEffectSet(aElement, PseudoStyleType::after)) {
         return true;
       }
+    } else if (aPseudo == nsCSSPseudoElements::marker()) {
+      if (EffectSet::GetEffectSet(aElement, PseudoStyleType::marker)) {
+        return true;
+      }
     }
   }
 
   // For Servo, we need to process the restyle-hint-invalidations first, to
   // expand LaterSiblings hint, so that we can look whether ancestors need
   // restyling.
   RestyleManager* restyleManager = presContext->RestyleManager();
   restyleManager->ProcessAllPendingAttributeAndStateInvalidations();
--- a/layout/style/nsTransitionManager.h
+++ b/layout/style/nsTransitionManager.h
@@ -271,16 +271,19 @@ struct AnimationTypeTraits<dom::CSSTrans
     return nsGkAtoms::transitionsProperty;
   }
   static nsAtom* BeforePropertyAtom() {
     return nsGkAtoms::transitionsOfBeforeProperty;
   }
   static nsAtom* AfterPropertyAtom() {
     return nsGkAtoms::transitionsOfAfterProperty;
   }
+  static nsAtom* MarkerPropertyAtom() {
+    return nsGkAtoms::transitionsOfMarkerProperty;
+  }
 };
 
 }  // namespace mozilla
 
 class nsTransitionManager final
     : public mozilla::CommonAnimationManager<mozilla::dom::CSSTransition> {
  public:
   explicit nsTransitionManager(nsPresContext* aPresContext)
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-animations/animationevent-marker-pseudoelement.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Animations Test: AnimationEvent pseudoElement</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<link rel="help" href="https://drafts.csswg.org/css-animations/#interface-animationevent">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+  #target::marker {
+    content: "";
+    animation: move 1s;
+  }
+
+  @keyframes move {
+    to { transform: translate(100px); }
+  }
+
+  #target {
+    display: list-item;
+    list-style-position: inside;
+  }
+</style>
+<div id='target'></div>
+<script>
+  async_test(function(t) {
+    var target = document.getElementById('target');
+    target.addEventListener("animationstart", t.step_func(function(evt) {
+      assert_true(evt instanceof window.AnimationEvent);
+      assert_equals(evt.pseudoElement, "::marker");
+
+      t.done();
+    }), true);
+  }, "AnimationEvent should have the correct pseudoElement memeber");
+</script>
+
--- a/testing/web-platform/tests/web-animations/interfaces/Animatable/animate.html
+++ b/testing/web-platform/tests/web-animations/interfaces/Animatable/animate.html
@@ -239,16 +239,30 @@ promise_test(async t => {
 
 test(t => {
   const pseudoTarget = getPseudoElement(t, 'before');
   const anim = pseudoTarget.animate(null);
   assert_class_string(anim, 'Animation', 'The returned object is an Animation');
 }, 'CSSPseudoElement.animate() creates an Animation object');
 
 test(t => {
+  const pseudoTarget = getPseudoElement(t, 'marker');
+  const anim = pseudoTarget.animate(null);
+  assert_class_string(anim, 'Animation', 'The returned object is an Animation for ::marker');
+}, 'CSSPseudoElement.animate() creates an Animation object for ::marker');
+
+test(t => {
   const pseudoTarget = getPseudoElement(t, 'before');
   const anim = pseudoTarget.animate(null);
   assert_equals(anim.effect.target, pseudoTarget,
                 'The returned Animation targets to the correct object');
 }, 'CSSPseudoElement.animate() creates an Animation object targeting ' +
    'to the correct CSSPseudoElement object');
+
+test(t => {
+  const pseudoTarget = getPseudoElement(t, 'marker');
+  const anim = pseudoTarget.animate(null);
+  assert_equals(anim.effect.target, pseudoTarget,
+                'The returned Animation targets to the correct object for ::marker');
+}, 'CSSPseudoElement.animate() creates an Animation object targeting ' +
+   'to the correct CSSPseudoElement object for ::marker');
 </script>
 </body>
--- a/testing/web-platform/tests/web-animations/testcommon.js
+++ b/testing/web-platform/tests/web-animations/testcommon.js
@@ -88,16 +88,19 @@ function createStyle(test, rules, doc) {
 }
 
 // Create a pseudo element
 function getPseudoElement(test, type) {
   createStyle(test, { '@keyframes anim': '',
                       [`.pseudo::${type}`]: 'animation: anim 10s; ' +
                                             'content: \'\';'  });
   const div = createDiv(test);
+  if (type == 'marker') {
+    div.style.display = 'list-item';
+  }
   div.classList.add('pseudo');
   const anims = document.getAnimations();
   assert_true(anims.length >= 1);
   const anim = anims[anims.length - 1];
   anim.cancel();
   return anim.effect.target;
 }
 
--- a/xpcom/ds/StaticAtoms.py
+++ b/xpcom/ds/StaticAtoms.py
@@ -2044,25 +2044,29 @@ STATIC_ATOMS = [
     Atom("ongamepaddisconnected", "ongamepaddisconnected"),
     Atom("onfetch", "onfetch"),
 
     # Content property names
     Atom("afterPseudoProperty", "afterPseudoProperty"),  # nsXMLElement*
     Atom("animationsProperty", "AnimationsProperty"),        # FrameAnimations*
     Atom("animationsOfBeforeProperty", "AnimationsOfBeforeProperty"),  # FrameAnimations*
     Atom("animationsOfAfterProperty", "AnimationsOfAfterProperty"),  # FrameAnimations*
+    Atom("animationsOfMarkerProperty", "AnimationsOfMarkerProperty"),  # FrameAnimations*
     Atom("animationEffectsProperty", "AnimationEffectsProperty"),  # EffectSet*
     Atom("animationEffectsForBeforeProperty", "AnimationsEffectsForBeforeProperty"),  # EffectSet*
     Atom("animationEffectsForAfterProperty", "AnimationsEffectsForAfterProperty"),  # EffectSet*
+    Atom("animationEffectsForMarkerProperty", "AnimationsEffectsForMarkerProperty"),  # EffectSet*
     Atom("beforePseudoProperty", "beforePseudoProperty"),  # nsXMLElement*
     Atom("cssPseudoElementBeforeProperty", "CSSPseudoElementBeforeProperty"),  # CSSPseudoElement*
     Atom("cssPseudoElementAfterProperty", "CSSPseudoElementAfterProperty"),  # CSSPseudoElement*
+    Atom("cssPseudoElementMarkerProperty", "CSSPseudoElementMarkerProperty"),  # CSSPseudoElement*
     Atom("transitionsProperty", "TransitionsProperty"),        # FrameTransitions*
     Atom("transitionsOfBeforeProperty", "TransitionsOfBeforeProperty"),  # FrameTransitions*
     Atom("transitionsOfAfterProperty", "TransitionsOfAfterProperty"),  # FrameTransitions*
+    Atom("transitionsOfMarkerProperty", "TransitionsOfMarkerProperty"),  # FrameTransitions*
     Atom("genConInitializerProperty", "QuoteNodeProperty"),
     Atom("labelMouseDownPtProperty", "LabelMouseDownPtProperty"),
     Atom("lockedStyleStates", "lockedStyleStates"),
     Atom("apzCallbackTransform", "apzCallbackTransform"),
     Atom("restylableAnonymousNode", "restylableAnonymousNode"),  # bool
     Atom("docLevelNativeAnonymousContent", "docLevelNativeAnonymousContent"),  # bool
     Atom("paintRequestTime", "PaintRequestTime"),
     Atom("pseudoProperty", "PseudoProperty"),  # PseudoStyleType