diff --git a/dom/html/HTMLAudioElement.cpp b/dom/html/HTMLAudioElement.cpp
index 69a2a60d40fe..2572f4011849 100644
--- a/dom/html/HTMLAudioElement.cpp
+++ b/dom/html/HTMLAudioElement.cpp
@@ -20,12 +20,31 @@
#include "mozilla/dom/TimeRanges.h"
#include "AudioStream.h"
-NS_IMPL_NS_NEW_HTML_ELEMENT(Audio)
+nsGenericHTMLElement* NS_NewHTMLAudioElement(
+ already_AddRefed&& aNodeInfo,
+ mozilla::dom::FromParser aFromParser) {
+ mozilla::dom::HTMLAudioElement* element =
+ new mozilla::dom::HTMLAudioElement(std::move(aNodeInfo));
+ element->Init();
+ return element;
+}
namespace mozilla {
namespace dom {
-NS_IMPL_ELEMENT_CLONE(HTMLAudioElement)
+nsresult HTMLAudioElement::Clone(mozilla::dom::NodeInfo* aNodeInfo,
+ nsINode** aResult) const {
+ *aResult = nullptr;
+ RefPtr ni(aNodeInfo);
+ HTMLAudioElement* it = new HTMLAudioElement(ni.forget());
+ it->Init();
+ nsCOMPtr kungFuDeathGrip = it;
+ nsresult rv = const_cast(this)->CopyInnerTo(it);
+ if (NS_SUCCEEDED(rv)) {
+ kungFuDeathGrip.swap(*aResult);
+ }
+ return rv;
+}
HTMLAudioElement::HTMLAudioElement(already_AddRefed&& aNodeInfo)
: HTMLMediaElement(std::move(aNodeInfo)) {
@@ -54,7 +73,8 @@ already_AddRefed HTMLAudioElement::Audio(
RefPtr nodeInfo = doc->NodeInfoManager()->GetNodeInfo(
nsGkAtoms::audio, nullptr, kNameSpaceID_XHTML, ELEMENT_NODE);
- RefPtr audio = new HTMLAudioElement(nodeInfo.forget());
+ RefPtr audio =
+ static_cast(NS_NewHTMLAudioElement(nodeInfo.forget()));
audio->SetHTMLAttr(nsGkAtoms::preload, NS_LITERAL_STRING("auto"), aRv);
if (aRv.Failed()) {
return nullptr;
diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp
index f305cdcb867b..e1b432c773d4 100644
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -3498,13 +3498,27 @@ HTMLMediaElement::HTMLMediaElement(
mShutdownObserver(new ShutdownObserver),
mPlayed(new TimeRanges(ToSupports(OwnerDoc()))),
mPaused(true, "HTMLMediaElement::mPaused"),
- mAudioTrackList(new AudioTrackList(OwnerDoc()->GetParentObject(), this)),
- mVideoTrackList(new VideoTrackList(OwnerDoc()->GetParentObject(), this)),
mErrorSink(new ErrorSink(this)),
mAudioChannelWrapper(new AudioChannelAgentCallback(this)),
mSink(MakePair(nsString(), RefPtr())) {
MOZ_ASSERT(mMainThreadEventTarget);
MOZ_ASSERT(mAbstractMainThread);
+ // Please don't add anything to this constructor or the initialization
+ // list that can cause AddRef to be called. This prevents subclasses
+ // from overriding AddRef in a way that works with our refcount
+ // logging mechanisms. Put these things inside of the ::Init method
+ // instead.
+}
+
+void HTMLMediaElement::Init() {
+ MOZ_ASSERT(mRefCnt == 0 && !mRefCnt.IsPurple(),
+ "HTMLMediaElement::Init called when AddRef has been called "
+ "at least once already, probably in the constructor. Please "
+ "see the documentation in the HTMLMediaElement constructor.");
+ MOZ_ASSERT(!mRefCnt.IsPurple());
+
+ mAudioTrackList = new AudioTrackList(OwnerDoc()->GetParentObject(), this);
+ mVideoTrackList = new VideoTrackList(OwnerDoc()->GetParentObject(), this);
DecoderDoctorLogger::LogConstruction(this);
@@ -3525,9 +3539,12 @@ HTMLMediaElement::HTMLMediaElement(
MediaShutdownManager::InitStatics();
mShutdownObserver->Subscribe(this);
+ mInitialized = true;
}
HTMLMediaElement::~HTMLMediaElement() {
+ MOZ_ASSERT(mInitialized,
+ "HTMLMediaElement must be initialized before it is destroyed.");
NS_ASSERTION(
!mHasSelfReference,
"How can we be destroyed if we're still holding a self reference?");
diff --git a/dom/html/HTMLMediaElement.h b/dom/html/HTMLMediaElement.h
index ac86a02b8c19..2aba76d77b13 100644
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -117,6 +117,7 @@ class HTMLMediaElement : public nsGenericHTMLElement,
explicit HTMLMediaElement(
already_AddRefed&& aNodeInfo);
+ void Init();
void ReportCanPlayTelemetry();
@@ -1750,6 +1751,9 @@ class HTMLMediaElement : public nsGenericHTMLElement,
// threshold.
void ReportPlayedTimeAfterBlockedTelemetry();
+ // True if Init() has been called after construction
+ bool mInitialized = false;
+
// True if user has called load(), seek() or element has started playing
// before. It's *only* use for checking autoplay policy
bool mIsBlessed = false;
diff --git a/dom/html/HTMLVideoElement.cpp b/dom/html/HTMLVideoElement.cpp
index 15b4fd89d307..9e60ce506a93 100644
--- a/dom/html/HTMLVideoElement.cpp
+++ b/dom/html/HTMLVideoElement.cpp
@@ -35,14 +35,33 @@
#include
#include
-NS_IMPL_NS_NEW_HTML_ELEMENT(Video)
+nsGenericHTMLElement* NS_NewHTMLVideoElement(
+ already_AddRefed&& aNodeInfo,
+ mozilla::dom::FromParser aFromParser) {
+ mozilla::dom::HTMLVideoElement* element =
+ new mozilla::dom::HTMLVideoElement(std::move(aNodeInfo));
+ element->Init();
+ return element;
+}
namespace mozilla {
namespace dom {
static bool sVideoStatsEnabled;
-NS_IMPL_ELEMENT_CLONE(HTMLVideoElement)
+nsresult HTMLVideoElement::Clone(mozilla::dom::NodeInfo* aNodeInfo,
+ nsINode** aResult) const {
+ *aResult = nullptr;
+ RefPtr ni(aNodeInfo);
+ HTMLVideoElement* it = new HTMLVideoElement(ni.forget());
+ it->Init();
+ nsCOMPtr kungFuDeathGrip = it;
+ nsresult rv = const_cast(this)->CopyInnerTo(it);
+ if (NS_SUCCEEDED(rv)) {
+ kungFuDeathGrip.swap(*aResult);
+ }
+ return rv;
+}
HTMLVideoElement::HTMLVideoElement(already_AddRefed&& aNodeInfo)
: HTMLMediaElement(std::move(aNodeInfo)), mIsOrientationLocked(false) {
@@ -308,7 +327,8 @@ void HTMLVideoElement::ReleaseVideoWakeLockIfExists() {
}
}
-void HTMLVideoElement::Init() {
+/* static */
+void HTMLVideoElement::InitStatics() {
Preferences::AddBoolVarCache(&sVideoStatsEnabled,
"media.video_stats.enabled");
}
diff --git a/dom/html/HTMLVideoElement.h b/dom/html/HTMLVideoElement.h
index 4e18fe68f638..e2acce0b3528 100644
--- a/dom/html/HTMLVideoElement.h
+++ b/dom/html/HTMLVideoElement.h
@@ -38,7 +38,7 @@ class HTMLVideoElement final : public HTMLMediaElement {
nsAttrValue& aResult) override;
NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* aAttribute) const override;
- static void Init();
+ static void InitStatics();
virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction()
const override;
diff --git a/layout/build/nsLayoutStatics.cpp b/layout/build/nsLayoutStatics.cpp
index e4b343ef7466..13ee34c9735c 100644
--- a/layout/build/nsLayoutStatics.cpp
+++ b/layout/build/nsLayoutStatics.cpp
@@ -255,7 +255,7 @@ nsresult nsLayoutStatics::Initialize() {
nsCookieService::AppClearDataObserverInit();
nsApplicationCacheService::AppClearDataObserverInit();
- HTMLVideoElement::Init();
+ HTMLVideoElement::InitStatics();
nsGenericHTMLFrameElement::InitStatics();
#ifdef MOZ_XUL