diff options
author | wicknix <39230578+wicknix@users.noreply.github.com> | 2019-04-15 18:58:07 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-04-15 18:58:07 -0500 |
commit | 5a1843c9f9e323627f9c35529e6a8c853d4dbb0d (patch) | |
tree | 62de3cd7cb8a6f75e568863bb73ca2deb80d87a9 /dom | |
parent | 065f6f9e5ebc1ed6cfaadaf7851b6021fa94a013 (diff) | |
parent | 095ea556855b38138e39e713f482eb440f7da9b2 (diff) | |
download | UXP-5a1843c9f9e323627f9c35529e6a8c853d4dbb0d.tar UXP-5a1843c9f9e323627f9c35529e6a8c853d4dbb0d.tar.gz UXP-5a1843c9f9e323627f9c35529e6a8c853d4dbb0d.tar.lz UXP-5a1843c9f9e323627f9c35529e6a8c853d4dbb0d.tar.xz UXP-5a1843c9f9e323627f9c35529e6a8c853d4dbb0d.zip |
Merge pull request #1 from MoonchildProductions/master
keep up with mc
Diffstat (limited to 'dom')
358 files changed, 2967 insertions, 11376 deletions
diff --git a/dom/animation/AnimationEffectReadOnly.cpp b/dom/animation/AnimationEffectReadOnly.cpp index bf2e2197d..63d633c2f 100644 --- a/dom/animation/AnimationEffectReadOnly.cpp +++ b/dom/animation/AnimationEffectReadOnly.cpp @@ -23,7 +23,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AnimationEffectReadOnly) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument, mTiming, mAnimation) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(AnimationEffectReadOnly) diff --git a/dom/animation/AnimationTimeline.cpp b/dom/animation/AnimationTimeline.cpp index 643106807..f4a1ecc9a 100644 --- a/dom/animation/AnimationTimeline.cpp +++ b/dom/animation/AnimationTimeline.cpp @@ -21,7 +21,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AnimationTimeline) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow, mAnimations) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(AnimationTimeline) diff --git a/dom/base/Attr.cpp b/dom/base/Attr.cpp index 6eb3b49fd..71b559392 100644 --- a/dom/base/Attr.cpp +++ b/dom/base/Attr.cpp @@ -59,8 +59,6 @@ Attr::Attr(nsDOMAttributeMap *aAttrMap, NS_IMPL_CYCLE_COLLECTION_CLASS(Attr) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Attr) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS - if (!nsINode::Traverse(tmp, cb)) { return NS_SUCCESS_INTERRUPTED_TRAVERSE; } diff --git a/dom/base/CustomElementRegistry.cpp b/dom/base/CustomElementRegistry.cpp index 00ee3d42f..3f202d33b 100644 --- a/dom/base/CustomElementRegistry.cpp +++ b/dom/base/CustomElementRegistry.cpp @@ -138,7 +138,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CustomElementRegistry) } NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWhenDefinedPromiseMap) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(CustomElementRegistry) diff --git a/dom/base/DOMException.cpp b/dom/base/DOMException.cpp index dfda47316..9fbb2f242 100644 --- a/dom/base/DOMException.cpp +++ b/dom/base/DOMException.cpp @@ -165,7 +165,6 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(Exception) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Exception) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mData) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Exception) diff --git a/dom/base/DOMIntersectionObserver.cpp b/dom/base/DOMIntersectionObserver.cpp index e39abf1a6..389b93071 100644 --- a/dom/base/DOMIntersectionObserver.cpp +++ b/dom/base/DOMIntersectionObserver.cpp @@ -43,16 +43,17 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMIntersectionObserver) NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER + tmp->Disconnect(); NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument) NS_IMPL_CYCLE_COLLECTION_UNLINK(mCallback) NS_IMPL_CYCLE_COLLECTION_UNLINK(mRoot) NS_IMPL_CYCLE_COLLECTION_UNLINK(mQueuedEntries) - tmp->Disconnect(); NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMIntersectionObserver) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCallback) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRoot) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mQueuedEntries) @@ -153,30 +154,34 @@ DOMIntersectionObserver::Observe(Element& aTarget) return; } aTarget.RegisterIntersectionObserver(this); - mObservationTargets.PutEntry(&aTarget); + mObservationTargets.AppendElement(&aTarget); Connect(); } void DOMIntersectionObserver::Unobserve(Element& aTarget) { - if (UnlinkTarget(aTarget)) { - aTarget.UnregisterIntersectionObserver(this); + if (!mObservationTargets.Contains(&aTarget)) { + // You're not on the list, buddy! + return; } + + if (mObservationTargets.Length() == 1) { + Disconnect(); + return; + } + + mObservationTargets.RemoveElement(&aTarget); + aTarget.UnregisterIntersectionObserver(this); } -bool +void DOMIntersectionObserver::UnlinkTarget(Element& aTarget) { - if (!mObservationTargets.Contains(&aTarget)) { - return false; - } - if (mObservationTargets.Count() == 1) { - Disconnect(); - return false; - } - mObservationTargets.RemoveEntry(&aTarget); - return true; + mObservationTargets.RemoveElement(&aTarget); + if (mObservationTargets.Length() == 0) { + Disconnect(); + } } void @@ -185,10 +190,11 @@ DOMIntersectionObserver::Connect() if (mConnected) { return; } + mConnected = true; - - nsIDocument* document = mOwner->GetExtantDoc(); - document->AddIntersectionObserver(this); + if (mDocument) { + mDocument->AddIntersectionObserver(this); + } } void @@ -197,18 +203,17 @@ DOMIntersectionObserver::Disconnect() if (!mConnected) { return; } - for (auto iter = mObservationTargets.Iter(); !iter.Done(); iter.Next()) { - Element* target = iter.Get()->GetKey(); + + mConnected = false; + + for (size_t i = 0; i < mObservationTargets.Length(); ++i) { + Element* target = mObservationTargets.ElementAt(i); target->UnregisterIntersectionObserver(this); } mObservationTargets.Clear(); - if (mOwner) { - nsIDocument* document = mOwner->GetExtantDoc(); - if (document) { - document->RemoveIntersectionObserver(this); - } + if (mDocument) { + mDocument->RemoveIntersectionObserver(this); } - mConnected = false; } void @@ -269,17 +274,21 @@ DOMIntersectionObserver::Update(nsIDocument* aDocument, DOMHighResTimeStamp time root = mRoot; rootFrame = root->GetPrimaryFrame(); if (rootFrame) { + nsRect rootRectRelativeToRootFrame; if (rootFrame->GetType() == nsGkAtoms::scrollFrame) { + // rootRectRelativeToRootFrame should be the content rect of rootFrame, not including the scrollbars. nsIScrollableFrame* scrollFrame = do_QueryFrame(rootFrame); - rootRect = nsLayoutUtils::TransformFrameRectToAncestor( - rootFrame, - rootFrame->GetContentRectRelativeToSelf(), - scrollFrame->GetScrolledFrame()); + rootRectRelativeToRootFrame = scrollFrame->GetScrollPortRect(); } else { - rootRect = nsLayoutUtils::GetAllInFlowRectsUnion(rootFrame, - nsLayoutUtils::GetContainingBlockForClientRect(rootFrame), - nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS); + // rootRectRelativeToRootFrame should be the border rect of rootFrame. + rootRectRelativeToRootFrame = rootFrame->GetRectRelativeToSelf(); } + nsIFrame* containingBlock = + nsLayoutUtils::GetContainingBlockForClientRect(rootFrame); + rootRect = + nsLayoutUtils::TransformFrameRectToAncestor(rootFrame, + rootRectRelativeToRootFrame, + containingBlock); } } else { nsCOMPtr<nsIPresShell> presShell = aDocument->GetShell(); @@ -288,12 +297,25 @@ DOMIntersectionObserver::Update(nsIDocument* aDocument, DOMHighResTimeStamp time if (rootFrame) { nsPresContext* presContext = rootFrame->PresContext(); while (!presContext->IsRootContentDocument()) { - presContext = rootFrame->PresContext()->GetParentPresContext(); - rootFrame = presContext->PresShell()->GetRootScrollFrame(); + // Walk up the tree + presContext = presContext->GetParentPresContext(); + if (!presContext) { + break; + } + nsIFrame* rootScrollFrame = presContext->PresShell()->GetRootScrollFrame(); + if (rootScrollFrame) { + rootFrame = rootScrollFrame; + } else { + break; + } } root = rootFrame->GetContent()->AsElement(); nsIScrollableFrame* scrollFrame = do_QueryFrame(rootFrame); - rootRect = scrollFrame->GetScrollPortRect(); + // If we end up with a null root frame for some reason, we'll proceed + // with an empty root intersection rect. + if (scrollFrame) { + rootRect = scrollFrame->GetScrollPortRect(); + } } } } @@ -314,11 +336,12 @@ DOMIntersectionObserver::Update(nsIDocument* aDocument, DOMHighResTimeStamp time rootMargin.Side(side) = nsLayoutUtils::ComputeCBDependentValue(basis, coord); } - for (auto iter = mObservationTargets.Iter(); !iter.Done(); iter.Next()) { - Element* target = iter.Get()->GetKey(); + for (size_t i = 0; i < mObservationTargets.Length(); ++i) { + Element* target = mObservationTargets.ElementAt(i); nsIFrame* targetFrame = target->GetPrimaryFrame(); nsRect targetRect; Maybe<nsRect> intersectionRect; + bool isSameDoc = root && root->GetComposedDoc() == target->GetComposedDoc(); if (rootFrame && targetFrame) { // If mRoot is set we are testing intersection with a container element @@ -327,7 +350,7 @@ DOMIntersectionObserver::Update(nsIDocument* aDocument, DOMHighResTimeStamp time // Skip further processing of this target if it is not in the same // Document as the intersection root, e.g. if root is an element of // the main document and target an element from an embedded iframe. - if (target->GetComposedDoc() != root->GetComposedDoc()) { + if (!isSameDoc) { continue; } // Skip further processing of this target if is not a descendant of the @@ -344,7 +367,7 @@ DOMIntersectionObserver::Update(nsIDocument* aDocument, DOMHighResTimeStamp time nsLayoutUtils::GetContainingBlockForClientRect(targetFrame), nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS ); - intersectionRect = Some(targetFrame->GetVisualOverflowRect()); + intersectionRect = Some(targetFrame->GetRectRelativeToSelf()); nsIFrame* containerFrame = nsLayoutUtils::GetCrossDocParentFrame(targetFrame); while (containerFrame && containerFrame != rootFrame) { @@ -399,29 +422,37 @@ DOMIntersectionObserver::Update(nsIDocument* aDocument, DOMHighResTimeStamp time intersectionRectRelativeToRoot, rootIntersectionRect ); - if (intersectionRect.isSome()) { - intersectionRect = Some(nsLayoutUtils::TransformFrameRectToAncestor( - nsLayoutUtils::GetContainingBlockForClientRect(rootFrame), - intersectionRect.value(), - targetFrame->PresContext()->PresShell()->GetRootScrollFrame() - )); + if (intersectionRect.isSome() && !isSameDoc) { + nsRect rect = intersectionRect.value(); + nsPresContext* presContext = targetFrame->PresContext(); + nsLayoutUtils::TransformRect(rootFrame, + presContext->PresShell()->GetRootScrollFrame(), rect); + intersectionRect = Some(rect); } } - double targetArea = targetRect.width * targetRect.height; - double intersectionArea = !intersectionRect ? - 0 : intersectionRect->width * intersectionRect->height; - double intersectionRatio = targetArea > 0.0 ? intersectionArea / targetArea : 0.0; + int64_t targetArea = + (int64_t) targetRect.Width() * (int64_t) targetRect.Height(); + int64_t intersectionArea = !intersectionRect ? 0 : + (int64_t) intersectionRect->Width() * + (int64_t) intersectionRect->Height(); + + double intersectionRatio; + if (targetArea > 0.0) { + intersectionRatio = (double) intersectionArea / (double) targetArea; + } else { + intersectionRatio = intersectionRect.isSome() ? 1.0 : 0.0; + } - size_t threshold = -1; + int32_t threshold = -1; if (intersectionRatio > 0.0) { if (intersectionRatio >= 1.0) { intersectionRatio = 1.0; - threshold = mThresholds.Length(); + threshold = (int32_t)mThresholds.Length(); } else { for (size_t k = 0; k < mThresholds.Length(); ++k) { if (mThresholds[k] <= intersectionRatio) { - threshold = k + 1; + threshold = (int32_t)k + 1; } else { break; } @@ -468,6 +499,7 @@ DOMIntersectionObserver::QueueIntersectionObserverEntry(Element* aTarget, rootBounds.forget(), boundingClientRect.forget(), intersectionRect.forget(), + aIntersectionRect.isSome(), aTarget, aIntersectionRatio); mQueuedEntries.AppendElement(entry.forget()); } @@ -480,7 +512,7 @@ DOMIntersectionObserver::Notify() } mozilla::dom::Sequence<mozilla::OwningNonNull<DOMIntersectionObserverEntry>> entries; if (entries.SetCapacity(mQueuedEntries.Length(), mozilla::fallible)) { - for (uint32_t i = 0; i < mQueuedEntries.Length(); ++i) { + for (size_t i = 0; i < mQueuedEntries.Length(); ++i) { RefPtr<DOMIntersectionObserverEntry> next = mQueuedEntries[i]; *entries.AppendElement(mozilla::fallible) = next; } diff --git a/dom/base/DOMIntersectionObserver.h b/dom/base/DOMIntersectionObserver.h index 8144fc5c5..8674fe25d 100644 --- a/dom/base/DOMIntersectionObserver.h +++ b/dom/base/DOMIntersectionObserver.h @@ -30,6 +30,7 @@ public: RefPtr<DOMRect> aRootBounds, RefPtr<DOMRect> aBoundingClientRect, RefPtr<DOMRect> aIntersectionRect, + bool aIsIntersecting, Element* aTarget, double aIntersectionRatio) : mOwner(aOwner), @@ -37,6 +38,7 @@ public: mRootBounds(aRootBounds), mBoundingClientRect(aBoundingClientRect), mIntersectionRect(aIntersectionRect), + mIsIntersecting(aIsIntersecting), mTarget(aTarget), mIntersectionRatio(aIntersectionRatio) { @@ -74,6 +76,11 @@ public: return mIntersectionRect; } + bool IsIntersecting() + { + return mIsIntersecting; + } + double IntersectionRatio() { return mIntersectionRatio; @@ -90,6 +97,7 @@ protected: RefPtr<DOMRect> mRootBounds; RefPtr<DOMRect> mBoundingClientRect; RefPtr<DOMRect> mIntersectionRect; + bool mIsIntersecting; RefPtr<Element> mTarget; double mIntersectionRatio; }; @@ -101,12 +109,17 @@ protected: class DOMIntersectionObserver final : public nsISupports, public nsWrapperCache { - virtual ~DOMIntersectionObserver() { } + virtual ~DOMIntersectionObserver() { + Disconnect(); + } public: DOMIntersectionObserver(already_AddRefed<nsPIDOMWindowInner>&& aOwner, mozilla::dom::IntersectionCallback& aCb) - : mOwner(aOwner), mCallback(&aCb), mConnected(false) + : mOwner(aOwner) + , mDocument(mOwner->GetExtantDoc()) + , mCallback(&aCb) + , mConnected(false) { } NS_DECL_CYCLE_COLLECTING_ISUPPORTS @@ -142,7 +155,7 @@ public: void Observe(Element& aTarget); void Unobserve(Element& aTarget); - bool UnlinkTarget(Element& aTarget); + void UnlinkTarget(Element& aTarget); void Disconnect(); void TakeRecords(nsTArray<RefPtr<DOMIntersectionObserverEntry>>& aRetVal); @@ -164,11 +177,15 @@ protected: double aIntersectionRatio); nsCOMPtr<nsPIDOMWindowInner> mOwner; + RefPtr<nsIDocument> mDocument; RefPtr<mozilla::dom::IntersectionCallback> mCallback; RefPtr<Element> mRoot; nsCSSRect mRootMargin; nsTArray<double> mThresholds; - nsTHashtable<nsPtrHashKey<Element>> mObservationTargets; + + // Holds raw pointers which are explicitly cleared by UnlinkTarget(). + nsTArray<Element*> mObservationTargets; + nsTArray<RefPtr<DOMIntersectionObserverEntry>> mQueuedEntries; bool mConnected; }; diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index 79b36a314..5c3277e84 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -145,7 +145,6 @@ #include "mozilla/dom/KeyframeEffectBinding.h" #include "mozilla/dom/WindowBinding.h" #include "mozilla/dom/ElementBinding.h" -#include "mozilla/dom/VRDisplay.h" #include "mozilla/IntegerPrintfMacros.h" #include "mozilla/Preferences.h" #include "nsComputedDOMStyle.h" @@ -688,19 +687,23 @@ Element::GetScrollFrame(nsIFrame **aStyledFrame, bool aFlushLayout) } void -Element::ScrollIntoView() +Element::ScrollIntoView(const BooleanOrScrollIntoViewOptions& aObject) { - ScrollIntoView(ScrollIntoViewOptions()); -} + if (aObject.IsScrollIntoViewOptions()) { + return ScrollIntoView(aObject.GetAsScrollIntoViewOptions()); + } + + MOZ_DIAGNOSTIC_ASSERT(aObject.IsBoolean()); -void -Element::ScrollIntoView(bool aTop) -{ ScrollIntoViewOptions options; - if (!aTop) { + if (aObject.GetAsBoolean()) { + options.mBlock = ScrollLogicalPosition::Start; + options.mInline = ScrollLogicalPosition::Nearest; + } else { options.mBlock = ScrollLogicalPosition::End; + options.mInline = ScrollLogicalPosition::Nearest; } - ScrollIntoView(options); + return ScrollIntoView(options); } void @@ -717,9 +720,41 @@ Element::ScrollIntoView(const ScrollIntoViewOptions &aOptions) return; } - int16_t vpercent = (aOptions.mBlock == ScrollLogicalPosition::Start) - ? nsIPresShell::SCROLL_TOP - : nsIPresShell::SCROLL_BOTTOM; + int16_t vpercent = nsIPresShell::SCROLL_CENTER; + switch (aOptions.mBlock) { + case ScrollLogicalPosition::Start: + vpercent = nsIPresShell::SCROLL_TOP; + break; + case ScrollLogicalPosition::Center: + vpercent = nsIPresShell::SCROLL_CENTER; + break; + case ScrollLogicalPosition::End: + vpercent = nsIPresShell::SCROLL_BOTTOM; + break; + case ScrollLogicalPosition::Nearest: + vpercent = nsIPresShell::SCROLL_MINIMUM; + break; + default: + MOZ_ASSERT_UNREACHABLE("Unexpected ScrollLogicalPosition value"); + } + + int16_t hpercent = nsIPresShell::SCROLL_CENTER; + switch (aOptions.mInline) { + case ScrollLogicalPosition::Start: + hpercent = nsIPresShell::SCROLL_LEFT; + break; + case ScrollLogicalPosition::Center: + hpercent = nsIPresShell::SCROLL_CENTER; + break; + case ScrollLogicalPosition::End: + hpercent = nsIPresShell::SCROLL_RIGHT; + break; + case ScrollLogicalPosition::Nearest: + hpercent = nsIPresShell::SCROLL_MINIMUM; + break; + default: + MOZ_ASSERT_UNREACHABLE("Unexpected ScrollLogicalPosition value"); + } uint32_t flags = nsIPresShell::SCROLL_OVERFLOW_HIDDEN; if (aOptions.mBehavior == ScrollBehavior::Smooth) { @@ -732,7 +767,9 @@ Element::ScrollIntoView(const ScrollIntoViewOptions &aOptions) nsIPresShell::ScrollAxis( vpercent, nsIPresShell::SCROLL_ALWAYS), - nsIPresShell::ScrollAxis(), + nsIPresShell::ScrollAxis( + hpercent, + nsIPresShell::SCROLL_ALWAYS), flags); } @@ -3948,7 +3985,7 @@ Element::ClearDataset() slots->mDataset = nullptr; } -nsDataHashtable<nsPtrHashKey<DOMIntersectionObserver>, int32_t>* +nsDataHashtable<nsRefPtrHashKey<DOMIntersectionObserver>, int32_t>* Element::RegisteredIntersectionObservers() { nsDOMSlots* slots = DOMSlots(); @@ -3963,7 +4000,7 @@ enum nsPreviousIntersectionThreshold { void Element::RegisterIntersectionObserver(DOMIntersectionObserver* aObserver) { - nsDataHashtable<nsPtrHashKey<DOMIntersectionObserver>, int32_t>* observers = + nsDataHashtable<nsRefPtrHashKey<DOMIntersectionObserver>, int32_t>* observers = RegisteredIntersectionObservers(); if (observers->Contains(aObserver)) { return; @@ -3980,7 +4017,7 @@ Element::RegisterIntersectionObserver(DOMIntersectionObserver* aObserver) void Element::UnregisterIntersectionObserver(DOMIntersectionObserver* aObserver) { - nsDataHashtable<nsPtrHashKey<DOMIntersectionObserver>, int32_t>* observers = + nsDataHashtable<nsRefPtrHashKey<DOMIntersectionObserver>, int32_t>* observers = RegisteredIntersectionObservers(); observers->Remove(aObserver); } @@ -3988,7 +4025,7 @@ Element::UnregisterIntersectionObserver(DOMIntersectionObserver* aObserver) bool Element::UpdateIntersectionObservation(DOMIntersectionObserver* aObserver, int32_t aThreshold) { - nsDataHashtable<nsPtrHashKey<DOMIntersectionObserver>, int32_t>* observers = + nsDataHashtable<nsRefPtrHashKey<DOMIntersectionObserver>, int32_t>* observers = RegisteredIntersectionObservers(); if (!observers->Contains(aObserver)) { return false; diff --git a/dom/base/Element.h b/dom/base/Element.h index c269ab14a..ce84b74fb 100644 --- a/dom/base/Element.h +++ b/dom/base/Element.h @@ -818,9 +818,10 @@ public: return slots ? slots->mShadowRoot.get() : nullptr; } - void ScrollIntoView(); - void ScrollIntoView(bool aTop); +private: void ScrollIntoView(const ScrollIntoViewOptions &aOptions); +public: + void ScrollIntoView(const BooleanOrScrollIntoViewOptions& aObject); void Scroll(double aXScroll, double aYScroll); void Scroll(const ScrollToOptions& aOptions); void ScrollTo(double aXScroll, double aYScroll); @@ -1382,7 +1383,8 @@ protected: nsDOMTokenList* GetTokenList(nsIAtom* aAtom, const DOMTokenListSupportedTokenArray aSupportedTokens = nullptr); - nsDataHashtable<nsPtrHashKey<DOMIntersectionObserver>, int32_t>* RegisteredIntersectionObservers(); + nsDataHashtable<nsRefPtrHashKey<DOMIntersectionObserver>, int32_t>* + RegisteredIntersectionObservers(); private: /** diff --git a/dom/base/File.cpp b/dom/base/File.cpp index 7d86dfe8a..1d5ab73e7 100755 --- a/dom/base/File.cpp +++ b/dom/base/File.cpp @@ -138,7 +138,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Blob) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Blob) diff --git a/dom/base/FormData.cpp b/dom/base/FormData.cpp index 6095286be..52bdd9210 100644 --- a/dom/base/FormData.cpp +++ b/dom/base/FormData.cpp @@ -84,7 +84,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(FormData) "mFormData[i].GetAsBlob()", 0); } - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(FormData) diff --git a/dom/base/FragmentOrElement.cpp b/dom/base/FragmentOrElement.cpp index fde983e7c..9106778df 100644 --- a/dom/base/FragmentOrElement.cpp +++ b/dom/base/FragmentOrElement.cpp @@ -585,6 +585,12 @@ FragmentOrElement::nsDOMSlots::Traverse(nsCycleCollectionTraversalCallback &cb, mCustomElementData->mCallbackQueue[i]->Traverse(cb); } } + + for (auto iter = mRegisteredIntersectionObservers.Iter(); !iter.Done(); iter.Next()) { + DOMIntersectionObserver* observer = iter.Key(); + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mRegisteredIntersectionObservers[i]"); + cb.NoteXPCOMChild(observer); + } } void @@ -1872,10 +1878,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(FragmentOrElement) NS_IMPL_CYCLE_COLLECTION_DESCRIBE(FragmentOrElement, tmp->mRefCnt.get()) } - // Always need to traverse script objects, so do that before we check - // if we're uncollectable. - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS - if (!nsINode::Traverse(tmp, cb)) { return NS_SUCCESS_INTERRUPTED_TRAVERSE; } diff --git a/dom/base/FragmentOrElement.h b/dom/base/FragmentOrElement.h index 7c74e9cd4..f0cc29f22 100644 --- a/dom/base/FragmentOrElement.h +++ b/dom/base/FragmentOrElement.h @@ -354,7 +354,8 @@ public: /** * Registered Intersection Observers on the element. */ - nsDataHashtable<nsPtrHashKey<DOMIntersectionObserver>, int32_t> mRegisteredIntersectionObservers; + nsDataHashtable<nsRefPtrHashKey<DOMIntersectionObserver>, int32_t> + mRegisteredIntersectionObservers; }; protected: diff --git a/dom/base/Location.cpp b/dom/base/Location.cpp index 7b3722f09..1483c32f9 100644 --- a/dom/base/Location.cpp +++ b/dom/base/Location.cpp @@ -33,6 +33,7 @@ #include "nsCycleCollectionParticipant.h" #include "nsNullPrincipal.h" #include "ScriptSettings.h" +#include "mozilla/Unused.h" #include "mozilla/dom/LocationBinding.h" namespace mozilla { @@ -79,7 +80,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Location) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInnerWindow) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(Location) @@ -716,9 +716,15 @@ Location::SetProtocol(const nsAString& aProtocol) return rv; } - rv = uri->SetScheme(NS_ConvertUTF16toUTF8(aProtocol)); + nsAString::const_iterator start, end; + aProtocol.BeginReading(start); + aProtocol.EndReading(end); + nsAString::const_iterator iter(start); + Unused << FindCharInReadable(':', iter, end); + + rv = uri->SetScheme(NS_ConvertUTF16toUTF8(Substring(start, iter))); if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; + return NS_ERROR_DOM_SYNTAX_ERR; } nsAutoCString newSpec; rv = uri->GetSpec(newSpec); @@ -728,9 +734,29 @@ Location::SetProtocol(const nsAString& aProtocol) // We may want a new URI class for the new URI, so recreate it: rv = NS_NewURI(getter_AddRefs(uri), newSpec); if (NS_FAILED(rv)) { + if (rv == NS_ERROR_MALFORMED_URI) { + rv = NS_ERROR_DOM_SYNTAX_ERR; + } + return rv; + } + + bool isHttp; + rv = uri->SchemeIs("http", &isHttp); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + bool isHttps; + rv = uri->SchemeIs("https", &isHttps); + if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } + if (!isHttp && !isHttps) { + // No-op, per spec. + return NS_OK; + } + return SetURI(uri); } @@ -763,10 +789,6 @@ Location::GetSearch(nsAString& aSearch) NS_IMETHODIMP Location::SetSearch(const nsAString& aSearch) { - if (aSearch.IsEmpty()) { - return NS_OK; // Ignore empty string - } - nsresult rv = SetSearchInternal(aSearch); if (NS_FAILED(rv)) { return rv; diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp index ed96ee23b..fdf151b6c 100644 --- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp @@ -44,7 +44,6 @@ #include "mozilla/dom/ServiceWorkerContainer.h" #include "mozilla/dom/StorageManager.h" #include "mozilla/dom/TCPSocket.h" -#include "mozilla/dom/VRDisplay.h" #include "mozilla/dom/workers/RuntimeService.h" #include "mozilla/Hal.h" #include "nsISiteSpecificUserAgent.h" @@ -224,7 +223,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGamepadServiceTest) #endif NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVRGetDisplaysPromises) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(Navigator) @@ -684,8 +682,6 @@ Navigator::GetDoNotTrack(nsAString &aResult) bool Navigator::JavaEnabled(ErrorResult& aRv) { - Telemetry::AutoTimer<Telemetry::CHECK_JAVA_ENABLED> telemetryTimer; - // Return true if we have a handler for the java mime nsAdoptingString javaMIME = Preferences::GetString("plugin.java.mime"); NS_ENSURE_TRUE(!javaMIME.IsEmpty(), false); @@ -1473,83 +1469,6 @@ Navigator::RequestGamepadServiceTest() } #endif -already_AddRefed<Promise> -Navigator::GetVRDisplays(ErrorResult& aRv) -{ - if (!mWindow || !mWindow->GetDocShell()) { - aRv.Throw(NS_ERROR_UNEXPECTED); - return nullptr; - } - - nsGlobalWindow* win = nsGlobalWindow::Cast(mWindow); - win->NotifyVREventListenerAdded(); - - nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(mWindow); - RefPtr<Promise> p = Promise::Create(go, aRv); - if (aRv.Failed()) { - return nullptr; - } - - // We pass mWindow's id to RefreshVRDisplays, so NotifyVRDisplaysUpdated will - // be called asynchronously, resolving the promises in mVRGetDisplaysPromises. - if (!VRDisplay::RefreshVRDisplays(win->WindowID())) { - p->MaybeReject(NS_ERROR_FAILURE); - return p.forget(); - } - - mVRGetDisplaysPromises.AppendElement(p); - return p.forget(); -} - -void -Navigator::GetActiveVRDisplays(nsTArray<RefPtr<VRDisplay>>& aDisplays) const -{ - /** - * Get only the active VR displays. - * Callers do not wish to VRDisplay::RefreshVRDisplays, as the enumeration may - * activate hardware that is not yet intended to be used. - */ - if (!mWindow || !mWindow->GetDocShell()) { - return; - } - nsGlobalWindow* win = nsGlobalWindow::Cast(mWindow); - win->NotifyVREventListenerAdded(); - nsTArray<RefPtr<VRDisplay>> displays; - if (win->UpdateVRDisplays(displays)) { - for (auto display : displays) { - if (display->IsPresenting()) { - aDisplays.AppendElement(display); - } - } - } -} - -void -Navigator::NotifyVRDisplaysUpdated() -{ - // Synchronize the VR devices and resolve the promises in - // mVRGetDisplaysPromises - nsGlobalWindow* win = nsGlobalWindow::Cast(mWindow); - - nsTArray<RefPtr<VRDisplay>> vrDisplays; - if (win->UpdateVRDisplays(vrDisplays)) { - for (auto p : mVRGetDisplaysPromises) { - p->MaybeResolve(vrDisplays); - } - } else { - for (auto p : mVRGetDisplaysPromises) { - p->MaybeReject(NS_ERROR_FAILURE); - } - } - mVRGetDisplaysPromises.Clear(); -} - -void -Navigator::NotifyActiveVRDisplaysChanged() -{ - NavigatorBinding::ClearCachedActiveVRDisplaysValue(this); -} - //***************************************************************************** // Navigator::nsIMozNavigatorNetwork //***************************************************************************** diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h index d47a80bc1..91b7fc15c 100644 --- a/dom/base/Navigator.h +++ b/dom/base/Navigator.h @@ -76,7 +76,6 @@ class Connection; class PowerManager; class Presentation; class LegacyMozTCPSocket; -class VRDisplay; class StorageManager; namespace time { @@ -204,8 +203,6 @@ public: void GetGamepads(nsTArray<RefPtr<Gamepad> >& aGamepads, ErrorResult& aRv); GamepadServiceTest* RequestGamepadServiceTest(); #endif // MOZ_GAMEPAD - already_AddRefed<Promise> GetVRDisplays(ErrorResult& aRv); - void GetActiveVRDisplays(nsTArray<RefPtr<VRDisplay>>& aDisplays) const; #ifdef MOZ_TIME_MANAGER time::TimeManager* GetMozTime(ErrorResult& aRv); #endif // MOZ_TIME_MANAGER @@ -269,10 +266,6 @@ private: RefPtr<MediaKeySystemAccessManager> mMediaKeySystemAccessManager; #endif -public: - void NotifyVRDisplaysUpdated(); - void NotifyActiveVRDisplaysChanged(); - private: virtual ~Navigator(); diff --git a/dom/base/Pose.cpp b/dom/base/Pose.cpp index 1eab4c173..5bc4ca6de 100644 --- a/dom/base/Pose.cpp +++ b/dom/base/Pose.cpp @@ -26,7 +26,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Pose) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Pose) diff --git a/dom/base/ProcessGlobal.cpp b/dom/base/ProcessGlobal.cpp index 641f49f98..6cd29ab7c 100644 --- a/dom/base/ProcessGlobal.cpp +++ b/dom/base/ProcessGlobal.cpp @@ -52,7 +52,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ProcessGlobal) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageManager) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal) tmp->TraverseHostObjectURIs(cb); - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ProcessGlobal) diff --git a/dom/base/nsAttrAndChildArray.cpp b/dom/base/nsAttrAndChildArray.cpp index b285ee003..9fd27262b 100644 --- a/dom/base/nsAttrAndChildArray.cpp +++ b/dom/base/nsAttrAndChildArray.cpp @@ -78,15 +78,8 @@ GetIndexFromCache(const nsAttrAndChildArray* aArray) } -/** - * Due to a compiler bug in VisualAge C++ for AIX, we need to return the - * address of the first index into mBuffer here, instead of simply returning - * mBuffer itself. - * - * See Bug 231104 for more information. - */ #define ATTRS(_impl) \ - reinterpret_cast<InternalAttr*>(&((_impl)->mBuffer[0])) + reinterpret_cast<InternalAttr*>((_impl)->mBuffer) #define NS_IMPL_EXTRA_SIZE \ diff --git a/dom/base/nsCCUncollectableMarker.cpp b/dom/base/nsCCUncollectableMarker.cpp index 861cda521..db4d0d351 100644 --- a/dom/base/nsCCUncollectableMarker.cpp +++ b/dom/base/nsCCUncollectableMarker.cpp @@ -188,23 +188,20 @@ MarkMessageManagers() } void -MarkContentViewer(nsIContentViewer* aViewer, bool aCleanupJS, - bool aPrepareForCC) +MarkDocument(nsIDocument* aDoc, bool aCleanupJS, bool aPrepareForCC) { - if (!aViewer) { + if (!aDoc) { return; } - nsIDocument *doc = aViewer->GetDocument(); - if (doc && - doc->GetMarkedCCGeneration() != nsCCUncollectableMarker::sGeneration) { - doc->MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration); + if (aDoc->GetMarkedCCGeneration() != nsCCUncollectableMarker::sGeneration) { + aDoc->MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration); if (aCleanupJS) { - EventListenerManager* elm = doc->GetExistingListenerManager(); + EventListenerManager* elm = aDoc->GetExistingListenerManager(); if (elm) { elm->MarkForCC(); } - nsCOMPtr<EventTarget> win = do_QueryInterface(doc->GetInnerWindow()); + nsCOMPtr<EventTarget> win = do_QueryInterface(aDoc->GetInnerWindow()); if (win) { elm = win->GetExistingListenerManager(); if (elm) { @@ -215,18 +212,27 @@ MarkContentViewer(nsIContentViewer* aViewer, bool aCleanupJS, } else if (aPrepareForCC) { // Unfortunately we need to still mark user data just before running CC so // that it has the right generation. - doc->PropertyTable(DOM_USER_DATA)-> + aDoc->PropertyTable(DOM_USER_DATA)-> EnumerateAll(MarkUserData, &nsCCUncollectableMarker::sGeneration); } } - if (doc) { - if (nsPIDOMWindowInner* inner = doc->GetInnerWindow()) { - inner->MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration); - } - if (nsPIDOMWindowOuter* outer = doc->GetWindow()) { - outer->MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration); - } + if (nsPIDOMWindowInner* inner = aDoc->GetInnerWindow()) { + inner->MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration); + } + if (nsPIDOMWindowOuter* outer = aDoc->GetWindow()) { + outer->MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration); + } +} + +void +MarkContentViewer(nsIContentViewer* aViewer, bool aCleanupJS, + bool aPrepareForCC) +{ + if (!aViewer) { + return; } + + MarkDocument(aViewer->GetDocument(), aCleanupJS, aPrepareForCC); } void MarkDocShell(nsIDocShellTreeItem* aNode, bool aCleanupJS, diff --git a/dom/base/nsContentList.cpp b/dom/base/nsContentList.cpp index 43e65777d..c98859ee3 100644 --- a/dom/base/nsContentList.cpp +++ b/dom/base/nsContentList.cpp @@ -54,7 +54,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsBaseContentList) NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsBaseContentList) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mElements) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(nsBaseContentList) diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 34c7d23b8..3696195dd 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -7597,6 +7597,24 @@ nsContentUtils::IsFileImage(nsIFile* aFile, nsACString& aType) } nsresult +nsContentUtils::CalculateBufferSizeForImage(const uint32_t& aStride, + const IntSize& aImageSize, + const SurfaceFormat& aFormat, + size_t* aMaxBufferSize, + size_t* aUsedBufferSize) +{ + CheckedInt32 requiredBytes = + CheckedInt32(aStride) * CheckedInt32(aImageSize.height); + if (!requiredBytes.isValid()) { + return NS_ERROR_FAILURE; + } + *aMaxBufferSize = requiredBytes.value(); + *aUsedBufferSize = *aMaxBufferSize - aStride + + (aImageSize.width * BytesPerPixel(aFormat)); + return NS_OK; +} + +nsresult nsContentUtils::DataTransferItemToImage(const IPCDataTransferItem& aItem, imgIContainer** aContainer) { @@ -7611,6 +7629,22 @@ nsContentUtils::DataTransferItemToImage(const IPCDataTransferItem& aItem, Shmem data = aItem.data().get_Shmem(); + // Validate shared memory buffer size + size_t imageBufLen = 0; + size_t maxBufLen = 0; + nsresult rv = CalculateBufferSizeForImage(imageDetails.stride(), + size, + static_cast<SurfaceFormat>( + imageDetails.format()), + &maxBufLen, + &imageBufLen); + if (NS_FAILED(rv)) { + return rv; + } + if (imageBufLen > data.Size<uint8_t>()) { + return NS_ERROR_FAILURE; + } + RefPtr<DataSourceSurface> image = CreateDataSourceSurfaceFromData(size, static_cast<SurfaceFormat>(imageDetails.format()), @@ -7950,20 +7984,19 @@ GetSurfaceDataImpl(mozilla::gfx::DataSourceSurface* aSurface, return GetSurfaceDataContext::NullValue(); } - mozilla::gfx::IntSize size = aSurface->GetSize(); - mozilla::CheckedInt32 requiredBytes = - mozilla::CheckedInt32(map.mStride) * mozilla::CheckedInt32(size.height); - if (!requiredBytes.isValid()) { + size_t bufLen = 0; + size_t maxBufLen = 0; + nsresult rv = nsContentUtils::CalculateBufferSizeForImage(map.mStride, + aSurface->GetSize(), + aSurface->GetFormat(), + &maxBufLen, + &bufLen); + if (NS_FAILED(rv)) { + // Release mapped memory + aSurface->Unmap(); return GetSurfaceDataContext::NullValue(); } - size_t maxBufLen = requiredBytes.value(); - mozilla::gfx::SurfaceFormat format = aSurface->GetFormat(); - - // Surface data handling is totally nuts. This is the magic one needs to - // know to access the data. - size_t bufLen = maxBufLen - map.mStride + (size.width * BytesPerPixel(format)); - // nsDependentCString wants null-terminated string. typename GetSurfaceDataContext::ReturnType surfaceData = aContext.Allocate(maxBufLen + 1); if (GetSurfaceDataContext::GetBuffer(surfaceData)) { @@ -9787,3 +9820,19 @@ nsContentUtils::AttemptLargeAllocationLoad(nsIHttpChannel* aChannel) return reloadSucceeded; } + +/* static */ bool +nsContentUtils::IsLocalRefURL(const nsString& aString) +{ + // Find the first non-"C0 controls + space" character. + const char16_t* current = aString.get(); + for (; *current != '\0'; current++) { + if (*current > 0x20) { + // if the first non-"C0 controls + space" character is '#', this is a + // local-ref URL. + return *current == '#'; + } + } + + return false; +}
\ No newline at end of file diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index 9ae6d2155..299a8e859 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -13,10 +13,6 @@ #include <float.h> #endif -#if defined(SOLARIS) -#include <ieeefp.h> -#endif - #include "js/TypeDecls.h" #include "js/Value.h" #include "js/RootingAPI.h" @@ -975,11 +971,17 @@ public: static bool PrefetchEnabled(nsIDocShell* aDocShell); + static nsresult CalculateBufferSizeForImage(const uint32_t& aStride, + const mozilla::gfx::IntSize& aImageSize, + const mozilla::gfx::SurfaceFormat& aFormat, + size_t* aMaxBufferSize, + size_t* aUsedBufferSize); + +private: /** * Fill (with the parameters given) the localized string named |aKey| in * properties file |aFile|. */ -private: static nsresult FormatLocalizedString(PropertiesFile aFile, const char* aKey, const char16_t** aParams, @@ -2730,6 +2732,13 @@ public: static bool AttemptLargeAllocationLoad(nsIHttpChannel* aChannel); + /** + * Detect whether a string is a (CSS) local-url. + * https://drafts.csswg.org/css-values/#local-urls + */ + static bool + IsLocalRefURL(const nsString& aString); + private: static bool InitializeEventTable(); diff --git a/dom/base/nsDOMAttributeMap.cpp b/dom/base/nsDOMAttributeMap.cpp index 381f267cd..2a90df7e4 100644 --- a/dom/base/nsDOMAttributeMap.cpp +++ b/dom/base/nsDOMAttributeMap.cpp @@ -65,7 +65,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMAttributeMap) for (auto iter = tmp->mAttributeCache.Iter(); !iter.Done(); iter.Next()) { cb.NoteXPCOMChild(static_cast<nsINode*>(iter.Data().get())); } - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContent) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index d125e5ad1..1cfde6e1b 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -49,7 +49,6 @@ #include "nsContentUtils.h" #include "nsIDOMGlobalPropertyInitializer.h" #include "mozilla/Attributes.h" -#include "mozilla/Telemetry.h" // Window scriptable helper includes #include "nsScriptNameSpaceManager.h" @@ -1903,9 +1902,6 @@ LookupComponentsShim(JSContext *cx, JS::Handle<JSObject*> global, nsPIDOMWindowInner *win, JS::MutableHandle<JS::PropertyDescriptor> desc) { - // Keep track of how often this happens. - Telemetry::Accumulate(Telemetry::COMPONENTS_SHIM_ACCESSED_BY_CONTENT, true); - // Warn once. nsCOMPtr<nsIDocument> doc = win->GetExtantDoc(); if (doc) { diff --git a/dom/base/nsDOMMutationObserver.cpp b/dom/base/nsDOMMutationObserver.cpp index 024ce5e2e..858a30ce5 100644 --- a/dom/base/nsDOMMutationObserver.cpp +++ b/dom/base/nsDOMMutationObserver.cpp @@ -506,7 +506,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMMutationObserver) NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMMutationObserver) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReceivers) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFirstPendingMutation) diff --git a/dom/base/nsDOMNavigationTiming.cpp b/dom/base/nsDOMNavigationTiming.cpp index 32ce8a8cb..9c732f2d8 100644 --- a/dom/base/nsDOMNavigationTiming.cpp +++ b/dom/base/nsDOMNavigationTiming.cpp @@ -15,7 +15,6 @@ #include "nsPrintfCString.h" #include "mozilla/dom/PerformanceNavigation.h" #include "mozilla/TimeStamp.h" -#include "mozilla/Telemetry.h" using namespace mozilla; @@ -203,12 +202,6 @@ nsDOMNavigationTiming::NotifyNonBlankPaintForRootContentDocument() mDocShellHasBeenActiveSinceNavigationStart ? "foreground tab" : "this tab was inactive some of the time between navigation start and first non-blank paint"); PROFILER_MARKER(marker.get()); } - - if (mDocShellHasBeenActiveSinceNavigationStart) { - Telemetry::AccumulateTimeDelta(Telemetry::TIME_TO_NON_BLANK_PAINT_MS, - mNavigationStart, - mNonBlankPaint); - } } void diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index 291df5f27..2ab5937ac 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -4033,8 +4033,6 @@ nsDOMWindowUtils::ForceUseCounterFlush(nsIDOMNode *aNode) if (nsCOMPtr<nsIDocument> doc = do_QueryInterface(aNode)) { mozilla::css::ImageLoader* loader = doc->StyleImageLoader(); loader->FlushUseCounters(); - - static_cast<nsDocument*>(doc.get())->ReportUseCounters(); return NS_OK; } diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index 8acfd901a..a6ed419df 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -25,7 +25,6 @@ #include "plstr.h" #include "mozilla/Sprintf.h" -#include "mozilla/Telemetry.h" #include "nsIInterfaceRequestor.h" #include "nsIInterfaceRequestorUtils.h" #include "nsILoadContext.h" @@ -1396,63 +1395,6 @@ nsDocument::~nsDocument() NS_ASSERTION(!mIsShowing, "Destroying a currently-showing document"); - if (IsTopLevelContentDocument()) { - //don't report for about: pages - if (!IsAboutPage()) { - // Record the page load - uint32_t pageLoaded = 1; - Accumulate(Telemetry::MIXED_CONTENT_UNBLOCK_COUNTER, pageLoaded); - // Record the mixed content status of the docshell in Telemetry - enum { - NO_MIXED_CONTENT = 0, // There is no Mixed Content on the page - MIXED_DISPLAY_CONTENT = 1, // The page attempted to load Mixed Display Content - MIXED_ACTIVE_CONTENT = 2, // The page attempted to load Mixed Active Content - MIXED_DISPLAY_AND_ACTIVE_CONTENT = 3 // The page attempted to load Mixed Display & Mixed Active Content - }; - - bool mixedActiveLoaded = GetHasMixedActiveContentLoaded(); - bool mixedActiveBlocked = GetHasMixedActiveContentBlocked(); - - bool mixedDisplayLoaded = GetHasMixedDisplayContentLoaded(); - bool mixedDisplayBlocked = GetHasMixedDisplayContentBlocked(); - - bool hasMixedDisplay = (mixedDisplayBlocked || mixedDisplayLoaded); - bool hasMixedActive = (mixedActiveBlocked || mixedActiveLoaded); - - uint32_t mixedContentLevel = NO_MIXED_CONTENT; - if (hasMixedDisplay && hasMixedActive) { - mixedContentLevel = MIXED_DISPLAY_AND_ACTIVE_CONTENT; - } else if (hasMixedActive){ - mixedContentLevel = MIXED_ACTIVE_CONTENT; - } else if (hasMixedDisplay) { - mixedContentLevel = MIXED_DISPLAY_CONTENT; - } - Accumulate(Telemetry::MIXED_CONTENT_PAGE_LOAD, mixedContentLevel); - - // record mixed object subrequest telemetry - if (mHasMixedContentObjectSubrequest) { - /* mixed object subrequest loaded on page*/ - Accumulate(Telemetry::MIXED_CONTENT_OBJECT_SUBREQUEST, 1); - } else { - /* no mixed object subrequests loaded on page*/ - Accumulate(Telemetry::MIXED_CONTENT_OBJECT_SUBREQUEST, 0); - } - - // record CSP telemetry on this document - if (mHasCSP) { - Accumulate(Telemetry::CSP_DOCUMENTS_COUNT, 1); - } - if (mHasUnsafeInlineCSP) { - Accumulate(Telemetry::CSP_UNSAFE_INLINE_DOCUMENTS_COUNT, 1); - } - if (mHasUnsafeEvalCSP) { - Accumulate(Telemetry::CSP_UNSAFE_EVAL_DOCUMENTS_COUNT, 1); - } - } - } - - ReportUseCounters(); - mInDestructor = true; mInUnlinkOrDeletion = true; @@ -1648,10 +1590,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsDocument) NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsDocument, tmp->mRefCnt.get()) } - // Always need to traverse script objects, so do that before we check - // if we're uncollectable. - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS - if (!nsINode::Traverse(tmp, cb)) { return NS_SUCCESS_INTERRUPTED_TRAVERSE; } @@ -1737,8 +1675,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsDocument) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOnDemandBuiltInUASheets) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPreloadingImages) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIntersectionObservers) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSubImportLinks) for (uint32_t i = 0; i < tmp->mFrameRequestCallbacks.Length(); ++i) { @@ -12356,134 +12292,27 @@ nsIDocument::InlineScriptAllowedByCSP() return allowsInlineScript; } -static bool -MightBeAboutOrChromeScheme(nsIURI* aURI) -{ - MOZ_ASSERT(aURI); - bool isAbout = true; - bool isChrome = true; - aURI->SchemeIs("about", &isAbout); - aURI->SchemeIs("chrome", &isChrome); - return isAbout || isChrome; -} - -void -nsDocument::ReportUseCounters() -{ - static const bool sDebugUseCounters = false; - if (mReportedUseCounters) { - return; - } - - mReportedUseCounters = true; - - if (Telemetry::HistogramUseCounterCount > 0 && - (IsContentDocument() || IsResourceDoc())) { - nsCOMPtr<nsIURI> uri; - NodePrincipal()->GetURI(getter_AddRefs(uri)); - if (!uri || MightBeAboutOrChromeScheme(uri)) { - return; - } - - if (sDebugUseCounters) { - nsCString spec = uri->GetSpecOrDefault(); - - // URIs can be rather long for data documents, so truncate them to - // some reasonable length. - spec.Truncate(std::min(128U, spec.Length())); - printf("-- Use counters for %s --\n", spec.get()); - } - - // We keep separate counts for individual documents and top-level - // pages to more accurately track how many web pages might break if - // certain features were removed. Consider the case of a single - // HTML document with several SVG images and/or iframes with - // sub-documents of their own. If we maintained a single set of use - // counters and all the sub-documents use a particular feature, then - // telemetry would indicate that we would be breaking N documents if - // that feature were removed. Whereas with a document/top-level - // page split, we can see that N documents would be affected, but - // only a single web page would be affected. - - // The difference between the values of these two histograms and the - // related use counters below tell us how many pages did *not* use - // the feature in question. For instance, if we see that a given - // session has destroyed 30 content documents, but a particular use - // counter shows only a count of 5, we can infer that the use - // counter was *not* used in 25 of those 30 documents. - // - // We do things this way, rather than accumulating a boolean flag - // for each use counter, to avoid sending histograms for features - // that don't get widely used. Doing things in this fashion means - // smaller telemetry payloads and faster processing on the server - // side. - Telemetry::Accumulate(Telemetry::CONTENT_DOCUMENTS_DESTROYED, 1); - if (IsTopLevelContentDocument()) { - Telemetry::Accumulate(Telemetry::TOP_LEVEL_CONTENT_DOCUMENTS_DESTROYED, 1); - } - - for (int32_t c = 0; - c < eUseCounter_Count; ++c) { - UseCounter uc = static_cast<UseCounter>(c); - - Telemetry::ID id = - static_cast<Telemetry::ID>(Telemetry::HistogramFirstUseCounter + uc * 2); - bool value = GetUseCounter(uc); - - if (value) { - if (sDebugUseCounters) { - const char* name = Telemetry::GetHistogramName(id); - if (name) { - printf(" %s", name); - } else { - printf(" #%d", id); - } - printf(": %d\n", value); - } - - Telemetry::Accumulate(id, 1); - } - - if (IsTopLevelContentDocument()) { - id = static_cast<Telemetry::ID>(Telemetry::HistogramFirstUseCounter + - uc * 2 + 1); - value = GetUseCounter(uc) || GetChildDocumentUseCounter(uc); - - if (value) { - if (sDebugUseCounters) { - const char* name = Telemetry::GetHistogramName(id); - if (name) { - printf(" %s", name); - } else { - printf(" #%d", id); - } - printf(": %d\n", value); - } - - Telemetry::Accumulate(id, 1); - } - } - } - } -} - void nsDocument::AddIntersectionObserver(DOMIntersectionObserver* aObserver) { - NS_ASSERTION(mIntersectionObservers.IndexOf(aObserver) == nsTArray<int>::NoIndex, - "Intersection observer already in the list"); - mIntersectionObservers.AppendElement(aObserver); + MOZ_ASSERT(!mIntersectionObservers.Contains(aObserver), + "Intersection observer already in the list"); + mIntersectionObservers.PutEntry(aObserver); } void nsDocument::RemoveIntersectionObserver(DOMIntersectionObserver* aObserver) { - mIntersectionObservers.RemoveElement(aObserver); + mIntersectionObservers.RemoveEntry(aObserver); } void nsDocument::UpdateIntersectionObservations() { + if (mIntersectionObservers.IsEmpty()) { + return; + } + DOMHighResTimeStamp time = 0; if (nsPIDOMWindowInner* window = GetInnerWindow()) { Performance* perf = window->GetPerformance(); @@ -12491,25 +12320,42 @@ nsDocument::UpdateIntersectionObservations() time = perf->Now(); } } - for (const auto& observer : mIntersectionObservers) { - observer->Update(this, time); + nsTArray<RefPtr<DOMIntersectionObserver>> observers(mIntersectionObservers.Count()); + for (auto iter = mIntersectionObservers.Iter(); !iter.Done(); iter.Next()) { + DOMIntersectionObserver* observer = iter.Get()->GetKey(); + observers.AppendElement(observer); + } + for (const auto& observer : observers) { + if (observer) { + observer->Update(this, time); + } } } void nsDocument::ScheduleIntersectionObserverNotification() { + if (mIntersectionObservers.IsEmpty()) { + return; + } + nsCOMPtr<nsIRunnable> notification = NewRunnableMethod(this, &nsDocument::NotifyIntersectionObservers); - NS_DispatchToCurrentThread(notification); + NS_DispatchToCurrentThread(notification.forget()); } void nsDocument::NotifyIntersectionObservers() { - nsTArray<RefPtr<DOMIntersectionObserver>> observers(mIntersectionObservers); + nsTArray<RefPtr<DOMIntersectionObserver>> observers(mIntersectionObservers.Count()); + for (auto iter = mIntersectionObservers.Iter(); !iter.Done(); iter.Next()) { + DOMIntersectionObserver* observer = iter.Get()->GetKey(); + observers.AppendElement(observer); + } for (const auto& observer : observers) { - observer->Notify(); + if (observer) { + observer->Notify(); + } } } diff --git a/dom/base/nsDocument.h b/dom/base/nsDocument.h index 3725b3c18..95fd57545 100644 --- a/dom/base/nsDocument.h +++ b/dom/base/nsDocument.h @@ -774,8 +774,6 @@ public: virtual nsViewportInfo GetViewportInfo(const mozilla::ScreenIntSize& aDisplaySize) override; - void ReportUseCounters(); - virtual void AddIntersectionObserver( mozilla::dom::DOMIntersectionObserver* aObserver) override; virtual void RemoveIntersectionObserver( @@ -1341,8 +1339,9 @@ protected: // Array of observers nsTObserverArray<nsIDocumentObserver*> mObservers; - // Array of intersection observers - nsTArray<RefPtr<mozilla::dom::DOMIntersectionObserver>> mIntersectionObservers; + // Hashtable of intersection observers + nsTHashtable<nsPtrHashKey<mozilla::dom::DOMIntersectionObserver>> + mIntersectionObservers; // Tracker for animations that are waiting to start. // nullptr until GetOrCreatePendingAnimationTracker is called. @@ -1448,14 +1447,6 @@ public: // 'style-sheet-applicable-state-changed' notification. bool mSSApplicableStateNotificationPending:1; - // Whether we have reported use counters for this document with Telemetry yet. - // Normally this is only done at document destruction time, but for image - // documents (SVG documents) that are not guaranteed to be destroyed, we - // report use counters when the image cache no longer has any imgRequestProxys - // pointing to them. We track whether we ever reported use counters so - // that we only report them once for the document. - bool mReportedUseCounters:1; - // Whether we have filled our pres shell's style set with the document's // additional sheets and sheets from the nsStyleSheetService. bool mStyleSetFilled:1; diff --git a/dom/base/nsFrameLoader.cpp b/dom/base/nsFrameLoader.cpp index 23067becd..2804f2d4c 100644 --- a/dom/base/nsFrameLoader.cpp +++ b/dom/base/nsFrameLoader.cpp @@ -588,6 +588,9 @@ nsFrameLoader::ReallyStartLoadingInternal() flags = nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP | nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL; } + + // Notify that this load resulted from attribute changes. + loadInfo->SetIsFromProcessingFrameAttributes(true); // Kick off the load... bool tmpState = mNeedsAsyncDestroy; diff --git a/dom/base/nsFrameMessageManager.cpp b/dom/base/nsFrameMessageManager.cpp index 6fffd376b..bba4232aa 100644 --- a/dom/base/nsFrameMessageManager.cpp +++ b/dom/base/nsFrameMessageManager.cpp @@ -32,7 +32,6 @@ #include "mozilla/CycleCollectedJSContext.h" #include "mozilla/IntentionalCrash.h" #include "mozilla/Preferences.h" -#include "mozilla/Telemetry.h" #include "mozilla/dom/File.h" #include "mozilla/dom/MessagePort.h" #include "mozilla/dom/nsIContentParent.h" @@ -133,7 +132,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsFrameMessageManager) } NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildManagers) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParentManager) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsFrameMessageManager) @@ -707,18 +705,9 @@ nsFrameMessageManager::SendRpcMessage(const nsAString& aMessageName, static bool AllowMessage(size_t aDataLength, const nsAString& aMessageName) { - static const size_t kMinTelemetryMessageSize = 8192; - - if (aDataLength < kMinTelemetryMessageSize) { - return true; - } - NS_ConvertUTF16toUTF8 messageName(aMessageName); messageName.StripChars("0123456789"); - Telemetry::Accumulate(Telemetry::MESSAGE_MANAGER_MESSAGE_SIZE2, messageName, - aDataLength); - // A message includes more than structured clone data, so subtract // 20KB to make it more likely that a message within this bound won't // result in an overly large IPC message. @@ -727,9 +716,6 @@ AllowMessage(size_t aDataLength, const nsAString& aMessageName) return true; } - Telemetry::Accumulate(Telemetry::REJECTED_MESSAGE_MANAGER_MESSAGE, - messageName); - return false; } @@ -2248,7 +2234,6 @@ nsSameProcessAsyncMessageBase::Init(const nsAString& aMessage, nsIPrincipal* aPrincipal) { if (!mData.Copy(aData)) { - Telemetry::Accumulate(Telemetry::IPC_SAME_PROCESS_MESSAGE_COPY_OOM_KB, aData.DataLength()); return NS_ERROR_OUT_OF_MEMORY; } diff --git a/dom/base/nsGenericDOMDataNode.cpp b/dom/base/nsGenericDOMDataNode.cpp index 9688588e0..0ae15e09e 100644 --- a/dom/base/nsGenericDOMDataNode.cpp +++ b/dom/base/nsGenericDOMDataNode.cpp @@ -98,10 +98,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGenericDOMDataNode) NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsGenericDOMDataNode, tmp->mRefCnt.get()) } - // Always need to traverse script objects, so do that before we check - // if we're uncollectable. - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS - if (!nsINode::Traverse(tmp, cb)) { return NS_SUCCESS_INTERRUPTED_TRAVERSE; } diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 884ad69ca..ac85e34c0 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -202,16 +202,12 @@ #include "mozilla/dom/GamepadManager.h" #endif -#include "mozilla/dom/VRDisplay.h" -#include "mozilla/dom/VREventObserver.h" - #include "nsRefreshDriver.h" #include "Layers.h" #include "mozilla/AddonPathService.h" #include "mozilla/BasePrincipal.h" #include "mozilla/Services.h" -#include "mozilla/Telemetry.h" #include "mozilla/dom/Location.h" #include "nsHTMLDocument.h" #include "nsWrapperCacheInlines.h" @@ -292,7 +288,6 @@ static bool gMouseDown = false; static bool gDragServiceDisabled = false; static FILE *gDumpFile = nullptr; static uint32_t gSerialCounter = 0; -static TimeStamp gLastRecordedRecentTimeouts; #define STATISTICS_INTERVAL (30 * PR_MSEC_PER_SEC) #ifdef DEBUG_jst @@ -1522,7 +1517,6 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow) mIsPopupSpam(false), mBlockScriptedClosingFlag(false), mWasOffline(false), - mHasHadSlowScript(false), mNotifyIdleObserversIdleOnThaw(false), mNotifyIdleObserversActiveOnThaw(false), mCreatingInnerWindow(false), @@ -1533,7 +1527,6 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow) mShowFocusRingForContent(false), mFocusByKeyOccurred(false), mHasGamepad(false), - mHasVREvents(false), #ifdef MOZ_GAMEPAD mHasSeenGamepadInput(false), #endif @@ -1759,9 +1752,6 @@ nsGlobalWindow::~nsGlobalWindow() DropOuterWindowDocs(); } else { - Telemetry::Accumulate(Telemetry::INNERWINDOWS_WITH_MUTATION_LISTENERS, - mMutationBits ? 1 : 0); - if (mListenerManager) { mListenerManager->Disconnect(); mListenerManager = nullptr; @@ -1971,12 +1961,9 @@ nsGlobalWindow::CleanUp() if (IsInnerWindow()) { DisableGamepadUpdates(); mHasGamepad = false; - DisableVRUpdates(); - mHasVREvents = false; DisableIdleCallbackRequests(); } else { MOZ_ASSERT(!mHasGamepad); - MOZ_ASSERT(!mHasVREvents); } if (mCleanMessageManager) { @@ -2027,7 +2014,7 @@ nsGlobalWindow::ClearControllers() } void -nsGlobalWindow::FreeInnerObjects() +nsGlobalWindow::FreeInnerObjects(bool aForDocumentOpen) { NS_ASSERTION(IsInnerWindow(), "Don't free inner objects on an outer window"); @@ -2086,8 +2073,10 @@ nsGlobalWindow::FreeInnerObjects() mDocumentURI = mDoc->GetDocumentURI(); mDocBaseURI = mDoc->GetDocBaseURI(); - while (mDoc->EventHandlingSuppressed()) { - mDoc->UnsuppressEventHandlingAndFireEvents(nsIDocument::eEvents, false); + if (!aForDocumentOpen) { + while (mDoc->EventHandlingSuppressed()) { + mDoc->UnsuppressEventHandlingAndFireEvents(nsIDocument::eEvents, false); + } } // Note: we don't have to worry about eAnimationsOnly suppressions because @@ -2120,9 +2109,6 @@ nsGlobalWindow::FreeInnerObjects() mHasGamepad = false; mGamepads.Clear(); #endif - DisableVRUpdates(); - mHasVREvents = false; - mVRDisplays.Clear(); } //***************************************************************************** @@ -2277,7 +2263,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindow) #endif NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCacheStorage) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVRDisplays) // Traverse stuff from nsPIDOMWindow NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeEventHandler) @@ -2299,7 +2284,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindow) tmp->TraverseHostObjectURIs(cb); - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow) @@ -2354,7 +2338,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow) #endif NS_IMPL_CYCLE_COLLECTION_UNLINK(mCacheStorage) - NS_IMPL_CYCLE_COLLECTION_UNLINK(mVRDisplays) // Unlink stuff from nsPIDOMWindow NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeEventHandler) @@ -2695,7 +2678,6 @@ TreatAsRemoteXUL(nsIPrincipal* aPrincipal) static bool EnablePrivilege(JSContext* cx, unsigned argc, JS::Value* vp) { - Telemetry::Accumulate(Telemetry::ENABLE_PRIVILEGE_EVER_CALLED, true); return xpc::EnableUniversalXPConnect(cx); } @@ -3005,6 +2987,8 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument, nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState); NS_ASSERTION(!aState || wsh, "What kind of weird state are you giving me here?"); + bool handleDocumentOpen = false; + JS::Rooted<JSObject*> newInnerGlobal(cx); if (reUseInnerWindow) { // We're reusing the current inner window. @@ -3096,6 +3080,7 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument, if (currentInner && currentInner->GetWrapperPreserveColor()) { if (oldDoc == aDocument) { + handleDocumentOpen = true; // Move the navigator from the old inner window to the new one since // this is a document.write. This is safe from a same-origin point of // view because document.write can only be used by the same origin. @@ -3120,7 +3105,7 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument, // Don't free objects on our current inner window if it's going to be // held in the bfcache. if (!currentInner->IsFrozen()) { - currentInner->FreeInnerObjects(); + currentInner->FreeInnerObjects(handleDocumentOpen); } } @@ -3389,9 +3374,6 @@ nsGlobalWindow::InnerSetNewDocument(JSContext* aCx, nsIDocument* aDocument) mLastOpenedURI = aDocument->GetDocumentURI(); #endif - Telemetry::Accumulate(Telemetry::INNERWINDOWS_WITH_MUTATION_LISTENERS, - mMutationBits ? 1 : 0); - // Clear our mutation bitfield. mMutationBits = 0; } @@ -6848,8 +6830,6 @@ FullscreenTransitionTask::Run() Preferences::GetUint("full-screen-api.transition.timeout", 1000); mTimer->Init(observer, timeout, nsITimer::TYPE_ONE_SHOT); } else if (stage == eAfterToggle) { - Telemetry::AccumulateTimeDelta(Telemetry::FULLSCREEN_TRANSITION_BLACK_MS, - mFullscreenChangeStartTime); mWidget->PerformFullscreenTransition(nsIWidget::eAfterFullscreenToggle, mDuration.mFadeOut, mTransitionData, this); @@ -10513,24 +10493,6 @@ nsGlobalWindow::DisableGamepadUpdates() } void -nsGlobalWindow::EnableVRUpdates() -{ - MOZ_ASSERT(IsInnerWindow()); - - if (mHasVREvents && !mVREventObserver) { - mVREventObserver = new VREventObserver(this); - } -} - -void -nsGlobalWindow::DisableVRUpdates() -{ - MOZ_ASSERT(IsInnerWindow()); - - mVREventObserver = nullptr; -} - -void nsGlobalWindow::SetChromeEventHandler(EventTarget* aChromeEventHandler) { MOZ_ASSERT(IsOuterWindow()); @@ -11577,13 +11539,6 @@ nsGlobalWindow::ShowSlowScriptDialog() unsigned lineno; bool hasFrame = JS::DescribeScriptedCaller(cx, &filename, &lineno); - // Record the slow script event if we haven't done so already for this inner window - // (which represents a particular page to the user). - if (!mHasHadSlowScript) { - Telemetry::Accumulate(Telemetry::SLOW_SCRIPT_PAGE_COUNT, 1); - } - mHasHadSlowScript = true; - if (XRE_IsContentProcess() && ProcessHangMonitor::Get()) { ProcessHangMonitor::SlowScriptAction action; @@ -11613,10 +11568,6 @@ nsGlobalWindow::ShowSlowScriptDialog() return ContinueSlowScriptAndKeepNotifying; } - // Reached only on non-e10s - once per slow script dialog. - // On e10s - we probe once at ProcessHangsMonitor.jsm - Telemetry::Accumulate(Telemetry::SLOW_SCRIPT_NOTICE_COUNT, 1); - // Get the nsIPrompt interface from the docshell nsCOMPtr<nsIDocShell> ds = GetDocShell(); NS_ENSURE_TRUE(ds, KillSlowScript); @@ -12224,7 +12175,6 @@ nsGlobalWindow::Suspend() ac->RemoveWindowListener(mEnabledSensors[i], this); } DisableGamepadUpdates(); - DisableVRUpdates(); mozilla::dom::workers::SuspendWorkersForWindow(AsInner()); @@ -12288,7 +12238,6 @@ nsGlobalWindow::Resume() ac->AddWindowListener(mEnabledSensors[i], this); } EnableGamepadUpdates(); - EnableVRUpdates(); // Resume all of the AudioContexts for this window for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) { @@ -13445,13 +13394,6 @@ nsGlobalWindow::RunTimeout(Timeout* aTimeout) return; } - // Record telemetry information about timers set recently. - TimeDuration recordingInterval = TimeDuration::FromMilliseconds(STATISTICS_INTERVAL); - if (gLastRecordedRecentTimeouts.IsNull() || - now - gLastRecordedRecentTimeouts > recordingInterval) { - gLastRecordedRecentTimeouts = now; - } - // Insert a dummy timeout into the list of timeouts between the // portion of the list that we are about to process now and those // timeouts that will be processed in a future call to @@ -14044,19 +13986,6 @@ nsGlobalWindow::SetHasGamepadEventListener(bool aHasGamepad/* = true*/) void nsGlobalWindow::EventListenerAdded(nsIAtom* aType) { - if (aType == nsGkAtoms::onvrdisplayconnect || - aType == nsGkAtoms::onvrdisplaydisconnect || - aType == nsGkAtoms::onvrdisplaypresentchange) { - NotifyVREventListenerAdded(); - } -} - -void -nsGlobalWindow::NotifyVREventListenerAdded() -{ - MOZ_ASSERT(IsInnerWindow()); - mHasVREvents = true; - EnableVRUpdates(); } void @@ -14201,27 +14130,6 @@ nsGlobalWindow::SyncGamepadState() } #endif // MOZ_GAMEPAD -bool -nsGlobalWindow::UpdateVRDisplays(nsTArray<RefPtr<mozilla::dom::VRDisplay>>& aDevices) -{ - FORWARD_TO_INNER(UpdateVRDisplays, (aDevices), false); - - VRDisplay::UpdateVRDisplays(mVRDisplays, AsInner()); - aDevices = mVRDisplays; - return true; -} - -void -nsGlobalWindow::NotifyActiveVRDisplaysChanged() -{ - MOZ_ASSERT(IsInnerWindow()); - - if (mNavigator) { - mNavigator->NotifyActiveVRDisplaysChanged(); - } -} - - // nsGlobalChromeWindow implementation NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalChromeWindow) diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h index 467bc6796..1f420895c 100644 --- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -135,8 +135,6 @@ class SpeechSynthesis; class TabGroup; class Timeout; class U2F; -class VRDisplay; -class VREventObserver; class WakeLock; #if defined(MOZ_WIDGET_ANDROID) class WindowOrientationObserver; @@ -745,18 +743,6 @@ public: void EnableGamepadUpdates(); void DisableGamepadUpdates(); - // Inner windows only. - // Enable/disable updates for VR - void EnableVRUpdates(); - void DisableVRUpdates(); - - // Update the VR displays for this window - bool UpdateVRDisplays(nsTArray<RefPtr<mozilla::dom::VRDisplay>>& aDisplays); - - // Inner windows only. - // Called to inform that the set of active VR displays has changed. - void NotifyActiveVRDisplaysChanged(); - #define EVENT(name_, id_, type_, struct_) \ mozilla::dom::EventHandlerNonNull* GetOn##name_() \ { \ @@ -1380,7 +1366,7 @@ protected: } } - void FreeInnerObjects(); + void FreeInnerObjects(bool aForDocumentOpen = false); nsGlobalWindow *CallerInnerWindow(); // Only to be called on an inner window. @@ -1794,11 +1780,6 @@ protected: // Window offline status. Checked to see if we need to fire offline event bool mWasOffline : 1; - // Represents whether the inner window's page has had a slow script notice. - // Only used by inner windows; will always be false for outer windows. - // This is used to implement Telemetry measures such as SLOW_SCRIPT_PAGE_COUNT. - bool mHasHadSlowScript : 1; - // Track what sorts of events we need to fire when thawed bool mNotifyIdleObserversIdleOnThaw : 1; bool mNotifyIdleObserversActiveOnThaw : 1; @@ -1832,9 +1813,6 @@ protected: // Indicates whether this window wants gamepad input events bool mHasGamepad : 1; - // Inner windows only. - // Indicates whether this window wants VR events - bool mHasVREvents : 1; #ifdef MOZ_GAMEPAD nsCheapSet<nsUint32HashKey> mGamepadIndexSet; nsRefPtrHashtable<nsUint32HashKey, mozilla::dom::Gamepad> mGamepads; @@ -1989,11 +1967,6 @@ protected: // This is the CC generation the last time we called CanSkip. uint32_t mCanSkipCCGeneration; - // The VR Displays for this window - nsTArray<RefPtr<mozilla::dom::VRDisplay>> mVRDisplays; - - nsAutoPtr<mozilla::dom::VREventObserver> mVREventObserver; - friend class nsDOMScriptableHelper; friend class nsDOMWindowUtils; friend class mozilla::dom::PostMessageEvent; diff --git a/dom/base/nsIDocument.h b/dom/base/nsIDocument.h index 7a73fae71..e5d12ab8f 100644 --- a/dom/base/nsIDocument.h +++ b/dom/base/nsIDocument.h @@ -3439,13 +3439,29 @@ nsINode::OwnerDocAsNode() const return OwnerDoc(); } +// ShouldUseXBLScope is defined here as a template so that we can get the faster +// version of IsInAnonymousSubtree if we're statically known to be an +// nsIContent. we could try defining ShouldUseXBLScope separately on nsINode +// and nsIContent, but then we couldn't put its nsINode implementation here +// (because this header does not include nsIContent) and we can't put it in +// nsIContent.h, because the definition of nsIContent::IsInAnonymousSubtree is +// in nsIContentInlines.h. And then we get include hell from people trying to +// call nsINode::GetParentObject but not including nsIContentInlines.h and with +// no really good way to include it. +template<typename T> +inline bool ShouldUseXBLScope(const T* aNode) +{ + return aNode->IsInAnonymousSubtree() && + !aNode->IsAnonymousContentInSVGUseSubtree(); +} + inline mozilla::dom::ParentObject nsINode::GetParentObject() const { mozilla::dom::ParentObject p(OwnerDoc()); // Note that mUseXBLScope is a no-op for chrome, and other places where we // don't use XBL scopes. - p.mUseXBLScope = IsInAnonymousSubtree() && !IsAnonymousContentInSVGUseSubtree(); + p.mUseXBLScope = ShouldUseXBLScope(this); return p; } diff --git a/dom/base/nsINode.cpp b/dom/base/nsINode.cpp index 09e848710..ca507a5fc 100644 --- a/dom/base/nsINode.cpp +++ b/dom/base/nsINode.cpp @@ -27,6 +27,7 @@ #include "mozilla/dom/Element.h" #include "mozilla/dom/Event.h" #include "mozilla/dom/ShadowRoot.h" +#include "mozilla/dom/ScriptSettings.h" #include "nsAttrValueOrString.h" #include "nsBindingManager.h" #include "nsCCUncollectableMarker.h" @@ -1569,6 +1570,48 @@ CheckForOutdatedParent(nsINode* aParent, nsINode* aNode) return NS_OK; } +static nsresult +ReparentWrappersInSubtree(nsIContent* aRoot) +{ + MOZ_ASSERT(ShouldUseXBLScope(aRoot)); + // Start off with no global so we don't fire any error events on failure. + AutoJSAPI jsapi; + jsapi.Init(); + + JSContext* cx = jsapi.cx(); + + nsIGlobalObject* docGlobal = aRoot->OwnerDoc()->GetScopeObject(); + if (NS_WARN_IF(!docGlobal)) { + return NS_ERROR_UNEXPECTED; + } + + JS::Rooted<JSObject*> rootedGlobal(cx, docGlobal->GetGlobalJSObject()); + if (NS_WARN_IF(!rootedGlobal)) { + return NS_ERROR_UNEXPECTED; + } + + rootedGlobal = xpc::GetXBLScope(cx, rootedGlobal); + + nsresult rv; + JS::Rooted<JSObject*> reflector(cx); + for (nsIContent* cur = aRoot; cur; cur = cur->GetNextNode(aRoot)) { + if ((reflector = cur->GetWrapper())) { + JSAutoCompartment ac(cx, reflector); + rv = ReparentWrapper(cx, reflector); + if NS_FAILED(rv) { + // We _could_ consider BlastSubtreeToPieces here, but it's not really + // needed. Having some nodes in here accessible to content while others + // are not is probably OK. We just need to fail out of the actual + // insertion, so they're not in the DOM. Returning a failure here will + // do that. + return rv; + } + } + } + + return NS_OK; +} + nsresult nsINode::doInsertChildAt(nsIContent* aKid, uint32_t aIndex, bool aNotify, nsAttrAndChildArray& aChildArray) @@ -1606,9 +1649,15 @@ nsINode::doInsertChildAt(nsIContent* aKid, uint32_t aIndex, nsIContent* parent = IsNodeOfType(eDOCUMENT) ? nullptr : static_cast<nsIContent*>(this); + bool wasInXBLScope = ShouldUseXBLScope(aKid); rv = aKid->BindToTree(doc, parent, parent ? parent->GetBindingParent() : nullptr, true); + if (NS_SUCCEEDED(rv) && !wasInXBLScope && ShouldUseXBLScope(aKid)) { + MOZ_ASSERT(ShouldUseXBLScope(this), + "Why does the kid need to use an XBL scope?"); + rv = ReparentWrappersInSubtree(aKid); + } if (NS_FAILED(rv)) { if (GetFirstChild() == aKid) { mFirstChild = aKid->GetNextSibling(); diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index 3be1a6d2f..dfd380fc2 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -70,7 +70,6 @@ #include "prthread.h" #include "mozilla/Preferences.h" -#include "mozilla/Telemetry.h" #include "mozilla/dom/BindingUtils.h" #include "mozilla/Attributes.h" #include "mozilla/dom/asmjscache/AsmJSCache.h" @@ -626,7 +625,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSContext) NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsJSContext) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobalObjectRef) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsJSContext) @@ -1357,9 +1355,20 @@ nsJSContext::RunCycleCollectorSlice() TimeStamp now = TimeStamp::Now(); // Only run a limited slice if we're within the max running time. - if (TimeBetween(gCCStats.mBeginTime, now) < kMaxICCDuration) { - float sliceMultiplier = std::max(TimeBetween(gCCStats.mEndSliceTime, now) / (float)kICCIntersliceDelay, 1.0f); - budget = js::SliceBudget(js::TimeBudget(kICCSliceBudget * sliceMultiplier)); + uint32_t runningTime = TimeBetween(gCCStats.mBeginTime, now); + if (runningTime < kMaxICCDuration) { + // Try to make up for a delay in running this slice. + float sliceDelayMultiplier = TimeBetween(gCCStats.mEndSliceTime, now) / (float)kICCIntersliceDelay; + float delaySliceBudget = kICCSliceBudget * sliceDelayMultiplier; + + // Increase slice budgets up to |maxLaterSlice| as we approach + // half way through the ICC, to avoid large sync CCs. + float percentToHalfDone = std::min(2.0f * runningTime / kMaxICCDuration, 1.0f); + const float maxLaterSlice = 40.0f; + float laterSliceBudget = maxLaterSlice * percentToHalfDone; + + budget = js::SliceBudget(js::TimeBudget(std::max({delaySliceBudget, + laterSliceBudget, (float)kICCSliceBudget}))); } } } @@ -1477,22 +1486,8 @@ nsJSContext::EndCycleCollectionCallback(CycleCollectorResults &aResults) NS_GC_DELAY - std::min(ccNowDuration, kMaxICCDuration)); } - // Log information about the CC via telemetry, JSON and the console. - Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_FINISH_IGC, gCCStats.mAnyLockedOut); - Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_SYNC_SKIPPABLE, gCCStats.mRanSyncForgetSkippable); - Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_FULL, ccNowDuration); - Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_MAX_PAUSE, gCCStats.mMaxSliceTime); - - if (!sLastCCEndTime.IsNull()) { - // TimeBetween returns milliseconds, but we want to report seconds. - uint32_t timeBetween = TimeBetween(sLastCCEndTime, gCCStats.mBeginTime) / 1000; - Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_TIME_BETWEEN, timeBetween); - } sLastCCEndTime = endCCTimeStamp; - Telemetry::Accumulate(Telemetry::FORGET_SKIPPABLE_MAX, - sMaxForgetSkippableTime / PR_USEC_PER_MSEC); - PRTime delta = GetCollectionTimeDelta(); uint32_t cleanups = sForgetSkippableBeforeCC ? sForgetSkippableBeforeCC : 1; @@ -2633,7 +2628,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSArgArray) tmp->ReleaseJSObjects(); NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsJSArgArray) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSArgArray) diff --git a/dom/base/nsJSTimeoutHandler.cpp b/dom/base/nsJSTimeoutHandler.cpp index 8736cd1dd..ce5d58385 100644 --- a/dom/base/nsJSTimeoutHandler.cpp +++ b/dom/base/nsJSTimeoutHandler.cpp @@ -151,7 +151,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsJSScriptTimeoutHandler) if (tmp->mFunction) { NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFunction) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS } NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END diff --git a/dom/base/nsMappedAttributes.h b/dom/base/nsMappedAttributes.h index 9fa7572dd..f00b888b9 100644 --- a/dom/base/nsMappedAttributes.h +++ b/dom/base/nsMappedAttributes.h @@ -93,20 +93,13 @@ private: nsAttrValue mValue; }; - /** - * Due to a compiler bug in VisualAge C++ for AIX, we need to return the - * address of the first index into mAttrs here, instead of simply - * returning mAttrs itself. - * - * See Bug 231104 for more information. - */ const InternalAttr* Attrs() const { - return reinterpret_cast<const InternalAttr*>(&(mAttrs[0])); + return reinterpret_cast<const InternalAttr*>(mAttrs); } InternalAttr* Attrs() { - return reinterpret_cast<InternalAttr*>(&(mAttrs[0])); + return reinterpret_cast<InternalAttr*>(mAttrs); } uint16_t mAttrCount; diff --git a/dom/base/nsNodeInfoManager.cpp b/dom/base/nsNodeInfoManager.cpp index 66c8c84cf..80f0aa786 100644 --- a/dom/base/nsNodeInfoManager.cpp +++ b/dom/base/nsNodeInfoManager.cpp @@ -392,9 +392,6 @@ nsNodeInfoManager::SetDocumentPrincipal(nsIPrincipal *aPrincipal) NS_ASSERTION(aPrincipal, "Must have principal by this point!"); MOZ_DIAGNOSTIC_ASSERT(!nsContentUtils::IsExpandedPrincipal(aPrincipal), "Documents shouldn't have an expanded principal"); - if (nsContentUtils::IsExpandedPrincipal(aPrincipal)) { - Telemetry::Accumulate(Telemetry::DOCUMENT_WITH_EXPANDED_PRINCIPAL, 1); - } mPrincipal = aPrincipal; } diff --git a/dom/base/nsNodeUtils.cpp b/dom/base/nsNodeUtils.cpp index ecea95dc1..75d408151 100644 --- a/dom/base/nsNodeUtils.cpp +++ b/dom/base/nsNodeUtils.cpp @@ -297,6 +297,16 @@ nsNodeUtils::LastRelease(nsINode* aNode) NodeWillBeDestroyed, (aNode)); } + if (aNode->IsElement()) { + Element* elem = aNode->AsElement(); + FragmentOrElement::nsDOMSlots* domSlots = + static_cast<FragmentOrElement::nsDOMSlots*>(slots); + for (auto iter = domSlots->mRegisteredIntersectionObservers.Iter(); !iter.Done(); iter.Next()) { + DOMIntersectionObserver* observer = iter.Key(); + observer->UnlinkTarget(*elem); + } + } + delete slots; aNode->mSlots = nullptr; } diff --git a/dom/base/nsObjectLoadingContent.cpp b/dom/base/nsObjectLoadingContent.cpp index 9e9dacf01..c1b732258 100644 --- a/dom/base/nsObjectLoadingContent.cpp +++ b/dom/base/nsObjectLoadingContent.cpp @@ -85,7 +85,6 @@ #include "mozilla/AsyncEventDispatcher.h" #include "mozilla/EventDispatcher.h" #include "mozilla/EventStates.h" -#include "mozilla/Telemetry.h" #include "mozilla/dom/HTMLObjectElementBinding.h" #include "mozilla/dom/HTMLSharedObjectElement.h" #include "nsChannelClassifier.h" @@ -1149,7 +1148,6 @@ nsObjectLoadingContent::OnStartRequest(nsIRequest *aRequest, NS_LITERAL_STRING(" since it was found on an internal Firefox blocklist."); console->LogStringMessage(message.get()); } - Telemetry::Accumulate(Telemetry::PLUGIN_BLOCKED_FOR_STABILITY, 1); mContentBlockingEnabled = true; return NS_ERROR_FAILURE; } else if (status == NS_ERROR_TRACKING_URI) { @@ -1565,7 +1563,6 @@ nsObjectLoadingContent::MaybeRewriteYoutubeEmbed(nsIURI* aURI, nsIURI* aBaseURI, } if (uri.Find("enablejsapi=1", true, 0, -1) != kNotFound) { - Telemetry::Accumulate(Telemetry::YOUTUBE_NONREWRITABLE_EMBED_SEEN, 1); return; } @@ -1585,11 +1582,6 @@ nsObjectLoadingContent::MaybeRewriteYoutubeEmbed(nsIURI* aURI, nsIURI* aBaseURI, } } - // If we've made it this far, we've got a rewritable embed. Log it in - // telemetry. - Telemetry::Accumulate(Telemetry::YOUTUBE_REWRITABLE_EMBED_SEEN, 1); - - // If we're pref'd off, return after telemetry has been logged. if (!Preferences::GetBool(kPrefYoutubeRewrite)) { return; } @@ -3800,8 +3792,6 @@ nsObjectLoadingContent::LegacyCall(JSContext* aCx, aRv.Throw(NS_ERROR_FAILURE); return; } - - Telemetry::Accumulate(Telemetry::PLUGIN_CALLED_DIRECTLY, true); } void diff --git a/dom/base/nsRange.cpp b/dom/base/nsRange.cpp index 4b4ce7885..d45a2c975 100644 --- a/dom/base/nsRange.cpp +++ b/dom/base/nsRange.cpp @@ -351,7 +351,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsRange) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEndParent) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRoot) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSelection) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsRange) diff --git a/dom/base/nsScriptLoader.cpp b/dom/base/nsScriptLoader.cpp index a6d20e363..1e23d6c5f 100644 --- a/dom/base/nsScriptLoader.cpp +++ b/dom/base/nsScriptLoader.cpp @@ -81,11 +81,19 @@ ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback, NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsScriptLoadRequest) NS_INTERFACE_MAP_END -NS_IMPL_CYCLE_COLLECTION_0(nsScriptLoadRequest) - NS_IMPL_CYCLE_COLLECTING_ADDREF(nsScriptLoadRequest) NS_IMPL_CYCLE_COLLECTING_RELEASE(nsScriptLoadRequest) +NS_IMPL_CYCLE_COLLECTION_CLASS(nsScriptLoadRequest) + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsScriptLoadRequest) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mElement) +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsScriptLoadRequest) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mElement) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + nsScriptLoadRequest::~nsScriptLoadRequest() { js_free(mScriptTextBuf); @@ -345,7 +353,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsModuleScript) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoader) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsModuleScript) diff --git a/dom/base/nsWrapperCache.cpp b/dom/base/nsWrapperCache.cpp index b91d86598..c5993fe7b 100644 --- a/dom/base/nsWrapperCache.cpp +++ b/dom/base/nsWrapperCache.cpp @@ -133,7 +133,7 @@ nsWrapperCache::CheckCCWrapperTraversal(void* aScriptObjectHolder, // see through the COM layer, so we use a suppression to help it. JS::AutoSuppressGCAnalysis suppress; - aTracer->Traverse(aScriptObjectHolder, callback); + aTracer->TraverseNativeAndJS(aScriptObjectHolder, callback); MOZ_ASSERT(callback.mFound, "Cycle collection participant didn't traverse to preserved " "wrapper! This will probably crash."); diff --git a/dom/base/nsWrapperCache.h b/dom/base/nsWrapperCache.h index 3c69a7ec4..56cae89ed 100644 --- a/dom/base/nsWrapperCache.h +++ b/dom/base/nsWrapperCache.h @@ -331,8 +331,7 @@ private: * causes between the native object and the JS object, so it is important that * any native object that supports preserving of its wrapper * traces/traverses/unlinks the cached JS object (see - * NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER, - * NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS and + * NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER and * NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER). */ enum { WRAPPER_BIT_PRESERVED = 1 << 0 }; @@ -383,7 +382,6 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsWrapperCache, NS_WRAPPERCACHE_IID) NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER \ NS_IMPL_CYCLE_COLLECTION_UNLINK_END \ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS \ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END \ NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class) @@ -395,7 +393,6 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsWrapperCache, NS_WRAPPERCACHE_IID) NS_IMPL_CYCLE_COLLECTION_UNLINK_END \ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class) \ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(__VA_ARGS__) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS \ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END \ NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class) diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp index 323feca52..8d2bdaac6 100644 --- a/dom/bindings/BindingUtils.cpp +++ b/dom/bindings/BindingUtils.cpp @@ -2558,7 +2558,7 @@ NonVoidByteStringToJsval(JSContext *cx, const nsACString &str, template<typename T> static void -NormalizeUSVStringInternal(JSContext* aCx, T& aString) +NormalizeUSVStringInternal(T& aString) { char16_t* start = aString.BeginWriting(); // Must use const here because we can't pass char** to UTF16CharEnumerator as @@ -2575,15 +2575,15 @@ NormalizeUSVStringInternal(JSContext* aCx, T& aString) } void -NormalizeUSVString(JSContext* aCx, nsAString& aString) +NormalizeUSVString(nsAString& aString) { - NormalizeUSVStringInternal(aCx, aString); + NormalizeUSVStringInternal(aString); } void -NormalizeUSVString(JSContext* aCx, binding_detail::FakeString& aString) +NormalizeUSVString(binding_detail::FakeString& aString) { - NormalizeUSVStringInternal(aCx, aString); + NormalizeUSVStringInternal(aString); } bool diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h index 3e58390c9..a3ec70f47 100644 --- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -49,7 +49,7 @@ namespace mozilla { enum UseCounter : int16_t; namespace dom { -template<typename DataType> class MozMap; +template<typename KeyType, typename ValueType> class Record; nsresult UnwrapArgImpl(JS::Handle<JSObject*> src, const nsIID& iid, void** ppArg); @@ -515,7 +515,7 @@ class ProtoAndIfaceCache { public: PageTableCache() { - memset(&mPages, 0, sizeof(mPages)); + memset(mPages.begin(), 0, sizeof(mPages)); } ~PageTableCache() { @@ -2127,11 +2127,30 @@ ConvertJSValueToString(JSContext* cx, JS::Handle<JS::Value> v, return AssignJSString(cx, result, s); } +template<typename T> +static inline bool +ConvertJSValueToString(JSContext* cx, JS::Handle<JS::Value> v, T& result) +{ + return ConvertJSValueToString(cx, v, eStringify, eStringify, result); +} + void -NormalizeUSVString(JSContext* aCx, nsAString& aString); +NormalizeUSVString(nsAString& aString); void -NormalizeUSVString(JSContext* aCx, binding_detail::FakeString& aString); +NormalizeUSVString(binding_detail::FakeString& aString); + +template<typename T> +static inline bool +ConvertJSValueToUSVString(JSContext* cx, JS::Handle<JS::Value> v, T& result) +{ + if (!ConvertJSValueToString(cx, v, eStringify, eStringify, result)) { + return false; + } + + NormalizeUSVString(result); + return true; +} template<typename T> inline bool @@ -2158,6 +2177,13 @@ bool ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v, bool nullable, nsACString& result); +inline bool +ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v, + nsACString& result) +{ + return ConvertJSValueToByteString(cx, v, false, result); +} + template<typename T> void DoTraceSequence(JSTracer* trc, FallibleTArray<T>& seq); template<typename T> @@ -2293,31 +2319,26 @@ public: } }; -template<typename T> -static void -TraceMozMapValue(T* aValue, void* aClosure) -{ - JSTracer* trc = static_cast<JSTracer*>(aClosure); - // Act like it's a one-element sequence to leverage all that infrastructure. - SequenceTracer<T>::TraceSequence(trc, aValue, aValue + 1); -} - -template<typename T> -void TraceMozMap(JSTracer* trc, MozMap<T>& map) +template<typename K, typename V> +void TraceRecord(JSTracer* trc, Record<K, V>& record) { - map.EnumerateValues(TraceMozMapValue<T>, trc); + for (auto& entry : record.Entries()) { + // Act like it's a one-element sequence to leverage all that infrastructure. + SequenceTracer<V>::TraceSequence(trc, &entry.mValue, &entry.mValue + 1); + } } -// sequence<MozMap> -template<typename T> -class SequenceTracer<MozMap<T>, false, false, false> +// sequence<record> +template<typename K, typename V> +class SequenceTracer<Record<K, V>, false, false, false> { explicit SequenceTracer() = delete; // Should never be instantiated public: - static void TraceSequence(JSTracer* trc, MozMap<T>* seqp, MozMap<T>* end) { + static void TraceSequence(JSTracer* trc, Record<K, V>* seqp, + Record<K, V>* end) { for (; seqp != end; ++seqp) { - seqp->EnumerateValues(TraceMozMapValue<T>, trc); + TraceRecord(trc, *seqp); } } }; @@ -2395,51 +2416,51 @@ public: SequenceType mSequenceType; }; -// Rooter class for MozMap; this is what we mostly use in the codegen. -template<typename T> -class MOZ_RAII MozMapRooter final : private JS::CustomAutoRooter +// Rooter class for Record; this is what we mostly use in the codegen. +template<typename K, typename V> +class MOZ_RAII RecordRooter final : private JS::CustomAutoRooter { public: - MozMapRooter(JSContext *aCx, MozMap<T>* aMozMap + RecordRooter(JSContext *aCx, Record<K, V>* aRecord MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT), - mMozMap(aMozMap), - mMozMapType(eMozMap) + mRecord(aRecord), + mRecordType(eRecord) { } - MozMapRooter(JSContext *aCx, Nullable<MozMap<T>>* aMozMap + RecordRooter(JSContext *aCx, Nullable<Record<K, V>>* aRecord MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT), - mNullableMozMap(aMozMap), - mMozMapType(eNullableMozMap) + mNullableRecord(aRecord), + mRecordType(eNullableRecord) { } private: - enum MozMapType { - eMozMap, - eNullableMozMap + enum RecordType { + eRecord, + eNullableRecord }; virtual void trace(JSTracer *trc) override { - if (mMozMapType == eMozMap) { - TraceMozMap(trc, *mMozMap); + if (mRecordType == eRecord) { + TraceRecord(trc, *mRecord); } else { - MOZ_ASSERT(mMozMapType == eNullableMozMap); - if (!mNullableMozMap->IsNull()) { - TraceMozMap(trc, mNullableMozMap->Value()); + MOZ_ASSERT(mRecordType == eNullableRecord); + if (!mNullableRecord->IsNull()) { + TraceRecord(trc, mNullableRecord->Value()); } } } union { - MozMap<T>* mMozMap; - Nullable<MozMap<T>>* mNullableMozMap; + Record<K, V>* mRecord; + Nullable<Record<K, V>>* mNullableRecord; }; - MozMapType mMozMapType; + RecordType mRecordType; }; template<typename T> diff --git a/dom/bindings/CallbackObject.cpp b/dom/bindings/CallbackObject.cpp index 7c7d2c6b4..bb01c804c 100644 --- a/dom/bindings/CallbackObject.cpp +++ b/dom/bindings/CallbackObject.cpp @@ -37,7 +37,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CallbackObject) NS_IMPL_CYCLE_COLLECTION_UNLINK(mIncumbentGlobal) NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CallbackObject) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIncumbentGlobal) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(CallbackObject) diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 7a6668687..74acb5918 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -84,7 +84,7 @@ def idlTypeNeedsCycleCollection(type): return True elif type.isUnion(): return any(idlTypeNeedsCycleCollection(t) for t in type.flatMemberTypes) - elif type.isMozMap(): + elif type.isRecord(): if idlTypeNeedsCycleCollection(type.inner): raise TypeError("Cycle collection for type %s is not supported" % type) return False @@ -996,6 +996,8 @@ class CGElseChain(CGThing): class CGTemplatedType(CGWrapper): def __init__(self, templateName, child, isConst=False, isReference=False): + if isinstance(child, list): + child = CGList(child, ", ") const = "const " if isConst else "" pre = "%s%s<" % (const, templateName) ref = "&" if isReference else "" @@ -1171,12 +1173,12 @@ class CGHeaders(CGWrapper): declareIncludes.add(filename) elif unrolled.isPrimitive(): bindingHeaders.add("mozilla/dom/PrimitiveConversions.h") - elif unrolled.isMozMap(): + elif unrolled.isRecord(): if dictionary or jsImplementedDescriptors: - declareIncludes.add("mozilla/dom/MozMap.h") + declareIncludes.add("mozilla/dom/Record.h") else: - bindingHeaders.add("mozilla/dom/MozMap.h") - # Also add headers for the type the MozMap is + bindingHeaders.add("mozilla/dom/Record.h") + # Also add headers for the type the record is # parametrized over, if needed. addHeadersForType((t.inner, dictionary)) @@ -1388,8 +1390,8 @@ def UnionTypes(unionTypes, config): # the right header to be able to Release() in our inlined # code. headers.add(CGHeaders.getDeclarationFilename(f.callback)) - elif f.isMozMap(): - headers.add("mozilla/dom/MozMap.h") + elif f.isRecord(): + headers.add("mozilla/dom/Record.h") # And add headers for the type we're parametrized over addHeadersForType(f.inner) @@ -1448,9 +1450,9 @@ def UnionConversions(unionTypes, config): headers.add(CGHeaders.getDeclarationFilename(f.inner)) elif f.isPrimitive(): headers.add("mozilla/dom/PrimitiveConversions.h") - elif f.isMozMap(): - headers.add("mozilla/dom/MozMap.h") - # And the internal type of the MozMap + elif f.isRecord(): + headers.add("mozilla/dom/Record.h") + # And the internal type of the record addHeadersForType(f.inner) # We plan to include UnionTypes.h no matter what, so it's @@ -4290,6 +4292,9 @@ class JSToNativeConversionInfo(): for whether we have a JS::Value. Only used when defaultValue is not None or when True is passed for checkForValue to instantiateJSToNativeConversion. + This expression may not be already-parenthesized, so if + you use it with && or || make sure to put parens + around it. ${passedToJSImpl} replaced by an expression that evaluates to a boolean for whether this value is being passed to a JS- implemented interface. @@ -4355,7 +4360,9 @@ def handleDefaultStringValue(defaultValue, method): passing as the second argument of handleDefault; in particular it does not end with a ';' """ - assert defaultValue.type.isDOMString() or defaultValue.type.isByteString() + assert (defaultValue.type.isDOMString() or + defaultValue.type.isUSVString() or + defaultValue.type.isByteString()) return ("static const %(char_t)s data[] = { %(data)s };\n" "%(method)s(data, ArrayLength(data) - 1)") % { 'char_t': "char" if defaultValue.type.isByteString() else "char16_t", @@ -4365,6 +4372,17 @@ def handleDefaultStringValue(defaultValue, method): } +def recordKeyType(recordType): + assert recordType.keyType.isString() + if recordType.keyType.isByteString(): + return "nsCString" + return "nsString" + + +def recordKeyDeclType(recordType): + return CGGeneric(recordKeyType(recordType)) + + # If this function is modified, modify CGNativeMember.getArg and # CGNativeMember.getRetvalInfo accordingly. The latter cares about the decltype # and holdertype we end up using, because it needs to be able to return the code @@ -4559,7 +4577,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, declArgs = "cx" else: assert (isMember in - ("Sequence", "Variadic", "Dictionary", "OwningUnion", "MozMap")) + ("Sequence", "Variadic", "Dictionary", "OwningUnion", "Record")) # We'll get traced by the sequence or dictionary or union tracer declType = CGGeneric("JSObject*") declArgs = None @@ -4725,39 +4743,41 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, dealWithOptional=isOptional, holderArgs=holderArgs) - if type.isMozMap(): + if type.isRecord(): assert not isEnforceRange and not isClamp if failureCode is None: - notMozMap = ('ThrowErrorMessage(cx, MSG_NOT_OBJECT, "%s");\n' + notRecord = ('ThrowErrorMessage(cx, MSG_NOT_OBJECT, "%s");\n' "%s" % (firstCap(sourceDescription), exceptionCode)) else: - notMozMap = failureCode + notRecord = failureCode nullable = type.nullable() # Be very careful not to change "type": we need it later if nullable: - valueType = type.inner.inner + recordType = type.inner else: - valueType = type.inner + recordType = type + valueType = recordType.inner valueInfo = getJSToNativeConversionInfo( - valueType, descriptorProvider, isMember="MozMap", + valueType, descriptorProvider, isMember="Record", exceptionCode=exceptionCode, lenientFloatCode=lenientFloatCode, isCallbackReturnValue=isCallbackReturnValue, sourceDescription="value in %s" % sourceDescription, nestingLevel=incrementNestingLevel()) if valueInfo.dealWithOptional: - raise TypeError("Shouldn't have optional things in MozMap") + raise TypeError("Shouldn't have optional things in record") if valueInfo.holderType is not None: - raise TypeError("Shouldn't need holders for MozMap") + raise TypeError("Shouldn't need holders for record") - typeName = CGTemplatedType("MozMap", valueInfo.declType) - mozMapType = typeName.define() + declType = CGTemplatedType("Record", [recordKeyDeclType(recordType), + valueInfo.declType]) + typeName = declType.define() if nullable: - typeName = CGTemplatedType("Nullable", typeName) - mozMapRef = "${declName}.SetValue()" + declType = CGTemplatedType("Nullable", declType) + recordRef = "${declName}.SetValue()" else: - mozMapRef = "${declName}" + recordRef = "${declName}" valueConversion = string.Template(valueInfo.template).substitute({ "val": "temp", @@ -4770,68 +4790,122 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, "passedToJSImpl": "${passedToJSImpl}" }) + keyType = recordKeyType(recordType) + if recordType.keyType.isByteString(): + keyConversionFunction = "ConvertJSValueToByteString" + hashKeyType = "nsCStringHashKey" + else: + hashKeyType = "nsStringHashKey" + if recordType.keyType.isDOMString(): + keyConversionFunction = "ConvertJSValueToString" + else: + assert recordType.keyType.isUSVString() + keyConversionFunction = "ConvertJSValueToUSVString" + templateBody = fill( """ - ${mozMapType} &mozMap = ${mozMapRef}; + auto& recordEntries = ${recordRef}.Entries(); - JS::Rooted<JSObject*> mozMapObj(cx, &$${val}.toObject()); - JS::Rooted<JS::IdVector> ids(cx, JS::IdVector(cx)); - if (!JS_Enumerate(cx, mozMapObj, &ids)) { + JS::Rooted<JSObject*> recordObj(cx, &$${val}.toObject()); + JS::AutoIdVector ids(cx); + if (!js::GetPropertyKeys(cx, recordObj, + JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, &ids)) { + $*{exceptionCode} + } + if (!recordEntries.SetCapacity(ids.length(), mozilla::fallible)) { + JS_ReportOutOfMemory(cx); $*{exceptionCode} } JS::Rooted<JS::Value> propNameValue(cx); JS::Rooted<JS::Value> temp(cx); JS::Rooted<jsid> curId(cx); + JS::Rooted<JS::Value> idVal(cx); + // Use a hashset to keep track of ids seen, to avoid + // introducing nasty O(N^2) behavior scanning for them all the + // time. Ideally we'd use a data structure with O(1) lookup + // _and_ ordering for the MozMap, but we don't have one lying + // around. + nsTHashtable<${hashKeyType}> idsSeen; for (size_t i = 0; i < ids.length(); ++i) { - // Make sure we get the value before converting the name, since - // getting the value can trigger GC but our name is a dependent - // string. curId = ids[i]; - binding_detail::FakeString propName; - bool isSymbol; - if (!ConvertIdToString(cx, curId, propName, isSymbol) || - (!isSymbol && !JS_GetPropertyById(cx, mozMapObj, curId, &temp))) { + + JS::Rooted<JS::PropertyDescriptor> desc(cx); + if (!JS_GetOwnPropertyDescriptorById(cx, recordObj, curId, + &desc)) { $*{exceptionCode} } - if (isSymbol) { + + if (!desc.object() /* == undefined in spec terms */ || + !desc.enumerable()) { continue; } - ${valueType}* slotPtr = mozMap.AddEntry(propName); - if (!slotPtr) { - JS_ReportOutOfMemory(cx); + idVal = js::IdToValue(curId); + ${keyType} propName; + // This will just throw if idVal is a Symbol, like the spec says + // to do. + if (!${keyConversionFunction}(cx, idVal, propName)) { $*{exceptionCode} } - ${valueType}& slot = *slotPtr; + + if (!JS_GetPropertyById(cx, recordObj, curId, &temp)) { + $*{exceptionCode} + } + + ${typeName}::EntryType* entry; + if (idsSeen.Contains(propName)) { + // Find the existing entry. + auto idx = recordEntries.IndexOf(propName); + MOZ_ASSERT(idx != recordEntries.NoIndex, + "Why is it not found?"); + // Now blow it away to make it look like it was just added + // to the array, because it's not obvious that it's + // safe to write to its already-initialized mValue via our + // normal codegen conversions. For example, the value + // could be a union and this would change its type, but + // codegen assumes we won't do that. + entry = recordEntries.ReconstructElementAt(idx); + } else { + // Safe to do an infallible append here, because we did a + // SetCapacity above to the right capacity. + entry = recordEntries.AppendElement(); + idsSeen.PutEntry(propName); + } + entry->mKey = propName; + ${valueType}& slot = entry->mValue; $*{valueConversion} } """, exceptionCode=exceptionCode, - mozMapType=mozMapType, - mozMapRef=mozMapRef, + recordRef=recordRef, + hashKeyType=hashKeyType, + keyType=keyType, + keyConversionFunction=keyConversionFunction, + typeName=typeName, valueType=valueInfo.declType.define(), valueConversion=valueConversion) templateBody = wrapObjectTemplate(templateBody, type, "${declName}.SetNull();\n", - notMozMap) + notRecord) - declType = typeName declArgs = None holderType = None holderArgs = None - # MozMap arguments that might contain traceable things need + # record arguments that might contain traceable things need # to get traced if not isMember and isCallbackReturnValue: # Go ahead and just convert directly into our actual return value declType = CGWrapper(declType, post="&") declArgs = "aRetVal" elif not isMember and typeNeedsRooting(valueType): - holderType = CGTemplatedType("MozMapRooter", valueInfo.declType) - # If our MozMap is nullable, this will set the Nullable to be + holderType = CGTemplatedType("RecordRooter", + [recordKeyDeclType(recordType), + valueInfo.declType]) + # If our record is nullable, this will set the Nullable to be # not-null, but that's ok because we make an explicit SetNull() call # on it as needed if our JS value is actually null. - holderArgs = "cx, &%s" % mozMapRef + holderArgs = "cx, &%s" % recordRef return JSToNativeConversionInfo(templateBody, declType=declType, declArgs=declArgs, @@ -4914,16 +4988,16 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, else: setDictionary = None - mozMapMemberTypes = filter(lambda t: t.isMozMap(), memberTypes) - if len(mozMapMemberTypes) > 0: - assert len(mozMapMemberTypes) == 1 - name = getUnionMemberName(mozMapMemberTypes[0]) - mozMapObject = CGGeneric( + recordMemberTypes = filter(lambda t: t.isRecord(), memberTypes) + if len(recordMemberTypes) > 0: + assert len(recordMemberTypes) == 1 + name = getUnionMemberName(recordMemberTypes[0]) + recordObject = CGGeneric( "done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n" % (unionArgumentObj, name)) names.append(name) else: - mozMapObject = None + recordObject = None objectMemberTypes = filter(lambda t: t.isObject(), memberTypes) if len(objectMemberTypes) > 0: @@ -4939,10 +5013,10 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, else: object = None - hasObjectTypes = interfaceObject or sequenceObject or dateObject or callbackObject or object or mozMapObject + hasObjectTypes = interfaceObject or sequenceObject or dateObject or callbackObject or object or recordObject if hasObjectTypes: # "object" is not distinguishable from other types - assert not object or not (interfaceObject or sequenceObject or dateObject or callbackObject or mozMapObject) + assert not object or not (interfaceObject or sequenceObject or dateObject or callbackObject or recordObject) if sequenceObject or dateObject or callbackObject: # An object can be both an sequence object and a callback or # dictionary, but we shouldn't have both in the union's members @@ -4962,9 +5036,9 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, if dateObject: templateBody.prepend(CGGeneric("JS::Rooted<JSObject*> argObj(cx, &${val}.toObject());\n")) - if mozMapObject: + if recordObject: templateBody = CGList([templateBody, - CGIfWrapper(mozMapObject, "!done")]) + CGIfWrapper(recordObject, "!done")]) templateBody = CGIfWrapper(templateBody, "${val}.isObject()") else: @@ -5144,7 +5218,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, if isinstance(defaultValue, IDLNullValue): extraConditionForNull = "!(${haveValue}) || " else: - extraConditionForNull = "${haveValue} && " + extraConditionForNull = "(${haveValue}) && " else: extraConditionForNull = "" templateBody = handleNull(templateBody, declLoc, @@ -5525,7 +5599,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, def getConversionCode(varName): normalizeCode = "" if type.isUSVString(): - normalizeCode = "NormalizeUSVString(cx, %s);\n" % varName + normalizeCode = "NormalizeUSVString(%s);\n" % varName conversionCode = fill(""" if (!ConvertJSValueToString(cx, $${val}, ${nullBehavior}, ${undefinedBehavior}, ${varName})) { @@ -5688,7 +5762,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, haveCallable = "${val}.isObject() && " + haveCallable if defaultValue is not None: assert(isinstance(defaultValue, IDLNullValue)) - haveCallable = "${haveValue} && " + haveCallable + haveCallable = "(${haveValue}) && " + haveCallable template = ( ("if (%s) {\n" % haveCallable) + conversion + @@ -5700,7 +5774,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, haveObject = "${val}.isObject()" if defaultValue is not None: assert(isinstance(defaultValue, IDLNullValue)) - haveObject = "${haveValue} && " + haveObject + haveObject = "(${haveValue}) && " + haveObject template = CGIfElseWrapper(haveObject, CGGeneric(conversion), CGGeneric("${declName} = nullptr;\n")).define() @@ -5724,7 +5798,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, assert not isEnforceRange and not isClamp declArgs = None - if isMember in ("Variadic", "Sequence", "Dictionary", "MozMap"): + if isMember in ("Variadic", "Sequence", "Dictionary", "Record"): # Rooting is handled by the sequence and dictionary tracers. declType = "JS::Value" else: @@ -5768,8 +5842,9 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, return handleJSObjectType(type, isMember, failureCode, exceptionCode, sourceDescription) if type.isDictionary(): - # There are no nullable dictionaries - assert not type.nullable() or isCallbackReturnValue + # There are no nullable dictionary arguments or dictionary members + assert(not type.nullable() or isCallbackReturnValue or + (isMember and isMember != "Dictionary")) # All optional dictionaries always have default values, so we # should be able to assume not isOptional here. assert not isOptional @@ -6256,7 +6331,7 @@ def getMaybeWrapValueFuncForType(type): sequenceWrapLevel = 0 -mozMapWrapLevel = 0 +recordWrapLevel = 0 def getWrapTemplateForType(type, descriptorProvider, result, successCode, @@ -6361,7 +6436,7 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode, if type is None or type.isVoid(): return (setUndefined(), True) - if (type.isSequence() or type.isMozMap()) and type.nullable(): + if (type.isSequence() or type.isRecord()) and type.nullable(): # These are both wrapped in Nullable<> recTemplate, recInfall = getWrapTemplateForType(type.inner, descriptorProvider, "%s.Value()" % result, successCode, @@ -6434,14 +6509,14 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode, return (code, False) - if type.isMozMap(): - # Now do non-nullable MozMap. Our success code is just to break to + if type.isRecord(): + # Now do non-nullable record. Our success code is just to break to # where we define the property on the object. Note that we bump the - # mozMapWrapLevel around this call so that nested MozMap conversions + # recordWrapLevel around this call so that nested record conversions # will use different temp value names. - global mozMapWrapLevel - valueName = "mozMapValue%d" % mozMapWrapLevel - mozMapWrapLevel += 1 + global recordWrapLevel + valueName = "recordValue%d" % recordWrapLevel + recordWrapLevel += 1 innerTemplate = wrapForType( type.inner, descriptorProvider, { @@ -6454,12 +6529,22 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode, 'obj': "returnObj", 'typedArraysAreStructs': typedArraysAreStructs }) - mozMapWrapLevel -= 1 + recordWrapLevel -= 1 + if type.keyType.isByteString(): + # There is no length-taking JS_DefineProperty. So to keep + # things sane with embedded nulls, we want to byte-inflate + # to an nsAString. The only byte-inflation function we + # have around is AppendASCIItoUTF16, which luckily doesn't + # assert anything about the input being ASCII. + expandedKeyDecl = "NS_ConvertASCIItoUTF16 expandedKey(entry.mKey);\n" + keyName = "expandedKey" + else: + expandedKeyDecl = "" + keyName = "entry.mKey" + code = fill( """ - nsTArray<nsString> keys; - ${result}.GetKeys(keys); JS::Rooted<JSObject*> returnObj(cx, JS_NewPlainObject(cx)); if (!returnObj) { $*{exceptionCode} @@ -6467,15 +6552,17 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode, // Scope for 'tmp' { JS::Rooted<JS::Value> tmp(cx); - for (size_t idx = 0; idx < keys.Length(); ++idx) { - auto& ${valueName} = ${result}.Get(keys[idx]); + for (auto& entry : ${result}.Entries()) { + auto& ${valueName} = entry.mValue; // Control block to let us common up the JS_DefineUCProperty calls when there // are different ways to succeed at wrapping the value. do { $*{innerTemplate} } while (0); - if (!JS_DefineUCProperty(cx, returnObj, keys[idx].get(), - keys[idx].Length(), tmp, + $*{expandedKeyDecl} + if (!JS_DefineUCProperty(cx, returnObj, + ${keyName}.BeginReading(), + ${keyName}.Length(), tmp, JSPROP_ENUMERATE)) { $*{exceptionCode} } @@ -6487,6 +6574,8 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode, exceptionCode=exceptionCode, valueName=valueName, innerTemplate=innerTemplate, + expandedKeyDecl=expandedKeyDecl, + keyName=keyName, set=setObject("*returnObj")) return (code, False) @@ -6770,7 +6859,7 @@ def typeMatchesLambda(type, func): return False if type.nullable(): return typeMatchesLambda(type.inner, func) - if type.isSequence() or type.isMozMap(): + if type.isSequence() or type.isRecord(): return typeMatchesLambda(type.inner, func) if type.isUnion(): return any(typeMatchesLambda(t, func) for t in @@ -6866,20 +6955,21 @@ def getRetvalDeclarationForType(returnType, descriptorProvider, if nullable: result = CGTemplatedType("Nullable", result) return result, "ref", rooter, None, None - if returnType.isMozMap(): + if returnType.isRecord(): nullable = returnType.nullable() if nullable: returnType = returnType.inner result, _, _, _, _ = getRetvalDeclarationForType(returnType.inner, descriptorProvider, - isMember="MozMap") + isMember="Record") # While we have our inner type, set up our rooter, if needed if not isMember and typeNeedsRooting(returnType): - rooter = CGGeneric("MozMapRooter<%s> resultRooter(cx, &result);\n" % - result.define()) + rooter = CGGeneric("RecordRooter<%s> resultRooter(cx, &result);\n" % + ("nsString, " + result.define())) else: rooter = None - result = CGTemplatedType("MozMap", result) + result = CGTemplatedType("Record", [recordKeyDeclType(returnType), + result]) if nullable: result = CGTemplatedType("Nullable", result) return result, "ref", rooter, None, None @@ -6976,7 +7066,7 @@ class CGCallGenerator(CGThing): return True if a.type.isSequence(): return True - if a.type.isMozMap(): + if a.type.isRecord(): return True # isObject() types are always a JS::Rooted, whether # nullable or not, and it turns out a const JS::Rooted @@ -7138,7 +7228,7 @@ class MethodNotNewObjectError(Exception): # nested sequences we don't use the same variable name to iterate over # different sequences. sequenceWrapLevel = 0 -mapWrapLevel = 0 +recordWrapLevel = 0 def wrapTypeIntoCurrentCompartment(type, value, isMember=True): @@ -7199,29 +7289,27 @@ def wrapTypeIntoCurrentCompartment(type, value, isMember=True): wrapCode = CGIfWrapper(wrapCode, "!%s.IsNull()" % origValue) return wrapCode - if type.isMozMap(): - origValue = value + if type.isRecord(): origType = type if type.nullable(): type = type.inner - value = "%s.Value()" % value - global mapWrapLevel - key = "mapName%d" % mapWrapLevel - mapWrapLevel += 1 + recordRef = "%s.Value()" % value + else: + recordRef = value + global recordWrapLevel + entryRef = "mapEntry%d" % recordWrapLevel + recordWrapLevel += 1 wrapElement = wrapTypeIntoCurrentCompartment(type.inner, - "%s.Get(%sKeys[%sIndex])" % (value, key, key)) - mapWrapLevel -= 1 + "%s.mValue" % entryRef) + recordWrapLevel -= 1 if not wrapElement: return None wrapCode = CGWrapper(CGIndenter(wrapElement), - pre=(""" - nsTArray<nsString> %sKeys; - %s.GetKeys(%sKeys); - for (uint32_t %sIndex = 0; %sIndex < %sKeys.Length(); ++%sIndex) { - """ % (key, value, key, key, key, key, key)), + pre=("for (auto& %s : %s.Entries()) {\n" % + (entryRef, recordRef)), post="}\n") if origType.nullable(): - wrapCode = CGIfWrapper(wrapCode, "!%s.IsNull()" % origValue) + wrapCode = CGIfWrapper(wrapCode, "!%s.IsNull()" % value) return wrapCode if type.isDictionary(): @@ -8110,11 +8198,11 @@ class CGMethodCall(CGThing): if distinguishingType(s).isSequence()) # Now append all the overloads that take a dictionary or callback - # interface or MozMap. There should be only one of these! + # interface or record. There should be only one of these! genericObjectSigs = [ s for s in possibleSignatures if (distinguishingType(s).isDictionary() or - distinguishingType(s).isMozMap() or + distinguishingType(s).isRecord() or distinguishingType(s).isCallbackInterface())] assert len(genericObjectSigs) <= 1 objectSigs.extend(genericObjectSigs) @@ -9408,7 +9496,7 @@ class CGMemberJITInfo(CGThing): return "JSVAL_TYPE_UNDEFINED" if t.isSequence(): return "JSVAL_TYPE_OBJECT" - if t.isMozMap(): + if t.isRecord(): return "JSVAL_TYPE_OBJECT" if t.isGeckoInterface(): return "JSVAL_TYPE_OBJECT" @@ -9669,17 +9757,22 @@ def getUnionAccessorSignatureType(type, descriptorProvider): # Flat member types have already unwrapped nullables. assert not type.nullable() - if type.isSequence() or type.isMozMap(): + if type.isSequence() or type.isRecord(): if type.isSequence(): wrapperType = "Sequence" else: - wrapperType = "MozMap" + wrapperType = "Record" # We don't use the returned template here, so it's OK to just pass no # sourceDescription. elementInfo = getJSToNativeConversionInfo(type.inner, descriptorProvider, isMember=wrapperType) - return CGTemplatedType(wrapperType, elementInfo.declType, + if wrapperType == "Sequence": + innerType = elementInfo.declType + else: + innerType = [recordKeyDeclType(type), elementInfo.declType] + + return CGTemplatedType(wrapperType, innerType, isConst=True, isReference=True) # Nested unions are unwrapped automatically into our flatMemberTypes. @@ -10040,10 +10133,10 @@ class CGUnionStruct(CGThing): CGCase("e" + vars["name"], CGGeneric("DoTraceSequence(trc, mValue.m%s.Value());\n" % vars["name"]))) - elif t.isMozMap(): + elif t.isRecord(): traceCases.append( CGCase("e" + vars["name"], - CGGeneric("TraceMozMap(trc, mValue.m%s.Value());\n" % + CGGeneric("TraceRecord(trc, mValue.m%s.Value());\n" % vars["name"]))) else: assert t.isSpiderMonkeyInterface() @@ -13172,8 +13265,8 @@ class CGDictionary(CGThing): trace = CGGeneric('%s.TraceSelf(trc);\n' % memberData) if type.nullable(): trace = CGIfWrapper(trace, "!%s.IsNull()" % memberNullable) - elif type.isMozMap(): - # If you implement this, add a MozMap<object> to + elif type.isRecord(): + # If you implement this, add a record<DOMString, object> to # TestInterfaceJSDictionary and test it in test_bug1036214.html # to make sure we end up with the correct security properties. assert False @@ -13583,7 +13676,7 @@ class ForwardDeclarationBuilder: # since we don't know which one we might want self.addInMozillaDom(CGUnionStruct.unionTypeName(t, False)) self.addInMozillaDom(CGUnionStruct.unionTypeName(t, True)) - elif t.isMozMap(): + elif t.isRecord(): self.forwardDeclareForType(t.inner, config) # Don't need to do anything for void, primitive, string, any or object. # There may be some other cases we are missing. @@ -14089,9 +14182,9 @@ class CGNativeMember(ClassMethod): else: returnCode = "aRetVal.SwapElements(${declName});\n" return "void", "", returnCode - if type.isMozMap(): - # If we want to handle MozMap-of-MozMap return values, we're - # going to need to fix example codegen to not produce MozMap<void> + if type.isRecord(): + # If we want to handle record-of-record return values, we're + # going to need to fix example codegen to not produce record<void> # for the relevant argument... assert not isMember # In this case we convert directly into our outparam to start with @@ -14139,13 +14232,14 @@ class CGNativeMember(ClassMethod): if nullable: type = CGTemplatedType("Nullable", type) args.append(Argument("%s&" % type.define(), "aRetVal")) - elif returnType.isMozMap(): + elif returnType.isRecord(): nullable = returnType.nullable() if nullable: returnType = returnType.inner # And now the actual underlying type elementDecl = self.getReturnType(returnType.inner, True) - type = CGTemplatedType("MozMap", CGGeneric(elementDecl)) + type = CGTemplatedType("Record", [recordKeyDeclType(returnType), + CGGeneric(elementDecl)]) if nullable: type = CGTemplatedType("Nullable", type) args.append(Argument("%s&" % type.define(), "aRetVal")) @@ -14206,7 +14300,7 @@ class CGNativeMember(ClassMethod): Nullable as needed. isMember can be false or one of the strings "Sequence", "Variadic", - "MozMap" + "Record" """ if type.isSequence(): nullable = type.nullable() @@ -14217,13 +14311,13 @@ class CGNativeMember(ClassMethod): decl = CGTemplatedType("Sequence", argType) return decl.define(), True, True - if type.isMozMap(): + if type.isRecord(): nullable = type.nullable() if nullable: type = type.inner elementType = type.inner - argType = self.getArgType(elementType, False, "MozMap")[0] - decl = CGTemplatedType("MozMap", argType) + argType = self.getArgType(elementType, False, "Record")[0] + decl = CGTemplatedType("Record", [recordKeyDeclType(type), argType]) return decl.define(), True, True if type.isUnion(): @@ -14994,7 +15088,6 @@ class CGJSImplClass(CGBindingImplClass): NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(${ifaceName}) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImpl) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(${ifaceName}) NS_IMPL_CYCLE_COLLECTING_ADDREF(${ifaceName}) diff --git a/dom/bindings/Configuration.py b/dom/bindings/Configuration.py index 5c96580a1..f80c19c33 100644 --- a/dom/bindings/Configuration.py +++ b/dom/bindings/Configuration.py @@ -115,7 +115,7 @@ class Configuration(DescriptorProvider): for (t, _) in getAllTypes(self.descriptors, self.dictionaries, self.callbacks): while True: - if t.isMozMap(): + if t.isRecord(): t = t.inner elif t.unroll() != t: t = t.unroll() diff --git a/dom/bindings/Exceptions.cpp b/dom/bindings/Exceptions.cpp index a3f807688..8ace37051 100644 --- a/dom/bindings/Exceptions.cpp +++ b/dom/bindings/Exceptions.cpp @@ -305,7 +305,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(JSStackFrame) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCaller) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAsyncCaller) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(JSStackFrame) NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mStack) diff --git a/dom/bindings/MozMap.h b/dom/bindings/MozMap.h deleted file mode 100644 index 1e920c098..000000000 --- a/dom/bindings/MozMap.h +++ /dev/null @@ -1,121 +0,0 @@ -/* -*- 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/. */ - -/** - * Class for representing MozMap arguments. This is an nsTHashtable - * under the hood, but we don't want to leak that implementation - * detail. - */ - -#ifndef mozilla_dom_MozMap_h -#define mozilla_dom_MozMap_h - -#include "nsTHashtable.h" -#include "nsHashKeys.h" -#include "nsStringGlue.h" -#include "nsTArray.h" -#include "mozilla/Attributes.h" -#include "mozilla/Move.h" - -namespace mozilla { -namespace dom { - -namespace binding_detail { -template<typename DataType> -class MozMapEntry : public nsStringHashKey -{ -public: - explicit MozMapEntry(const nsAString* aKeyTypePointer) - : nsStringHashKey(aKeyTypePointer) - { - } - - // Move constructor so we can do MozMaps of MozMaps. - MozMapEntry(MozMapEntry<DataType>&& aOther) - : nsStringHashKey(aOther), - mData(Move(aOther.mData)) - { - } - - DataType mData; -}; - -} // namespace binding_detail - -template<typename DataType> -class MozMap : protected nsTHashtable<binding_detail::MozMapEntry<DataType>> -{ -public: - typedef typename binding_detail::MozMapEntry<DataType> EntryType; - typedef nsTHashtable<EntryType> Base; - typedef MozMap<DataType> SelfType; - - MozMap() - { - } - - // Move constructor so we can do MozMap of MozMap. - MozMap(SelfType&& aOther) : - Base(Move(aOther)) - { - } - - // The return value is only safe to use until an AddEntry call. - const DataType& Get(const nsAString& aKey) const - { - const EntryType* ent = this->GetEntry(aKey); - MOZ_ASSERT(ent, "Why are you using a key we didn't claim to have?"); - return ent->mData; - } - - DataType& Get(const nsAString& aKey) - { - EntryType* ent = this->GetEntry(aKey); - MOZ_ASSERT(ent, "Why are you using a key we didn't claim to have?"); - return ent->mData; - } - - // The return value is only safe to use until an AddEntry call. - const DataType* GetIfExists(const nsAString& aKey) const - { - const EntryType* ent = this->GetEntry(aKey); - if (!ent) { - return nullptr; - } - return &ent->mData; - } - - void GetKeys(nsTArray<nsString>& aKeys) const { - for (auto iter = this->ConstIter(); !iter.Done(); iter.Next()) { - aKeys.AppendElement(iter.Get()->GetKey()); - } - } - - // XXXbz we expose this generic enumerator for tracing. Otherwise we'd end up - // with a dependency on BindingUtils.h here for the SequenceTracer bits. - typedef void (* Enumerator)(DataType* aValue, void* aClosure); - void EnumerateValues(Enumerator aEnumerator, void *aClosure) - { - for (auto iter = this->Iter(); !iter.Done(); iter.Next()) { - aEnumerator(&iter.Get()->mData, aClosure); - } - } - - MOZ_MUST_USE - DataType* AddEntry(const nsAString& aKey) - { - EntryType* ent = this->PutEntry(aKey, fallible); - if (!ent) { - return nullptr; - } - return &ent->mData; - } -}; - -} // namespace dom -} // namespace mozilla - -#endif // mozilla_dom_MozMap_h diff --git a/dom/bindings/Record.h b/dom/bindings/Record.h new file mode 100644 index 000000000..d6ab31699 --- /dev/null +++ b/dom/bindings/Record.h @@ -0,0 +1,91 @@ +/* -*- 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/. */ + +/** + * Class for representing record arguments. Basically an array under the hood. + */ + +#ifndef mozilla_dom_Record_h +#define mozilla_dom_Record_h + +#include "nsTHashtable.h" +#include "nsHashKeys.h" +#include "nsStringGlue.h" +#include "nsTArray.h" +#include "mozilla/Attributes.h" +#include "mozilla/Move.h" + +namespace mozilla { +namespace dom { + +namespace binding_detail { +template<typename KeyType, typename ValueType> +class RecordEntry +{ +public: + RecordEntry() + { + } + + // Move constructor so we can do Records of Records. + RecordEntry(RecordEntry<KeyType, ValueType>&& aOther) + : mKey(Move(aOther.mKey)), + mValue(Move(aOther.mValue)) + { + } + + KeyType mKey; + ValueType mValue; +}; + +} // namespace binding_detail + +template<typename KeyType, typename ValueType> +class Record +{ +public: + typedef typename binding_detail::RecordEntry<KeyType, ValueType> EntryType; + typedef Record<KeyType, ValueType> SelfType; + + Record() + { + } + + // Move constructor so we can do Record of Record. + Record(SelfType&& aOther) : + mEntries(Move(aOther.mEntries)) + { + } + + const nsTArray<EntryType>& Entries() const + { + return mEntries; + } + + nsTArray<EntryType>& Entries() + { + return mEntries; + } + +private: + nsTArray<EntryType> mEntries; +}; + +} // namespace dom +} // namespace mozilla + +template<typename K, typename V> +class nsDefaultComparator<mozilla::dom::binding_detail::RecordEntry<K, V>, K> +{ +public: + bool Equals(const mozilla::dom::binding_detail::RecordEntry<K, V>& aEntry, + const K& aKey) const + { + return aEntry.mKey == aKey; + } +}; + +#endif // mozilla_dom_Record_h diff --git a/dom/bindings/SimpleGlobalObject.cpp b/dom/bindings/SimpleGlobalObject.cpp index 6ac397019..88710f7d9 100644 --- a/dom/bindings/SimpleGlobalObject.cpp +++ b/dom/bindings/SimpleGlobalObject.cpp @@ -29,8 +29,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(SimpleGlobalObject) NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(SimpleGlobalObject) - - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS tmp->TraverseHostObjectURIs(cb); NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END diff --git a/dom/bindings/moz.build b/dom/bindings/moz.build index f1ce9e276..7e1358e9c 100644 --- a/dom/bindings/moz.build +++ b/dom/bindings/moz.build @@ -32,10 +32,10 @@ EXPORTS.mozilla.dom += [ 'FakeString.h', 'IterableIterator.h', 'JSSlots.h', - 'MozMap.h', 'NonRefcountedDOMObject.h', 'Nullable.h', 'PrimitiveConversions.h', + 'Record.h', 'RootedDictionary.h', 'SimpleGlobalObject.h', 'StructuredClone.h', diff --git a/dom/bindings/parser/WebIDL.py b/dom/bindings/parser/WebIDL.py index f668d7d62..8c32a8738 100644 --- a/dom/bindings/parser/WebIDL.py +++ b/dom/bindings/parser/WebIDL.py @@ -1867,7 +1867,7 @@ class IDLDictionary(IDLObjectWithScope): if (memberType.nullable() or memberType.isSequence() or - memberType.isMozMap()): + memberType.isRecord()): return typeContainsDictionary(memberType.inner, dictionary) if memberType.isDictionary(): @@ -1988,7 +1988,7 @@ class IDLType(IDLObject): 'callback', 'union', 'sequence', - 'mozmap' + 'record' ) def __init__(self, location, name): @@ -2038,7 +2038,7 @@ class IDLType(IDLObject): def isSequence(self): return False - def isMozMap(self): + def isRecord(self): return False def isArrayBuffer(self): @@ -2263,8 +2263,8 @@ class IDLNullableType(IDLParameterizedType): def isSequence(self): return self.inner.isSequence() - def isMozMap(self): - return self.inner.isMozMap() + def isRecord(self): + return self.inner.isRecord() def isArrayBuffer(self): return self.inner.isArrayBuffer() @@ -2321,8 +2321,10 @@ class IDLNullableType(IDLParameterizedType): return self def isDistinguishableFrom(self, other): - if (other.nullable() or (other.isUnion() and other.hasNullableType) or - other.isDictionary()): + if (other.nullable() or + other.isDictionary() or + (other.isUnion() and + (other.hasNullableType or other.hasDictionaryType()))): # Can't tell which type null should become return False return self.inner.isDistinguishableFrom(other) @@ -2397,34 +2399,38 @@ class IDLSequenceType(IDLParameterizedType): return (other.isPrimitive() or other.isString() or other.isEnum() or other.isDate() or other.isInterface() or other.isDictionary() or - other.isCallback() or other.isMozMap()) + other.isCallback() or other.isRecord()) -class IDLMozMapType(IDLParameterizedType): - def __init__(self, location, parameterType): - assert not parameterType.isVoid() +class IDLRecordType(IDLParameterizedType): + def __init__(self, location, keyType, valueType): + assert keyType.isString() + assert keyType.isComplete() + assert not valueType.isVoid() + + IDLParameterizedType.__init__(self, location, valueType.name, valueType) + self.keyType = keyType - IDLParameterizedType.__init__(self, location, parameterType.name, parameterType) # Need to set self.name up front if our inner type is already complete, # since in that case our .complete() won't be called. if self.inner.isComplete(): - self.name = self.inner.name + "MozMap" + self.name = self.keyType.name + self.inner.name + "Record" def __eq__(self, other): - return isinstance(other, IDLMozMapType) and self.inner == other.inner + return isinstance(other, IDLRecordType) and self.inner == other.inner def __str__(self): - return self.inner.__str__() + "MozMap" + return self.keyType.__str__() + self.inner.__str__() + "Record" - def isMozMap(self): + def isRecord(self): return True def tag(self): - return IDLType.Tags.mozmap + return IDLType.Tags.record def complete(self, scope): self.inner = self.inner.complete(scope) - self.name = self.inner.name + "MozMap" + self.name = self.keyType.name + self.inner.name + "Record" return self def unroll(self): @@ -2614,8 +2620,8 @@ class IDLTypedefType(IDLType): def isSequence(self): return self.inner.isSequence() - def isMozMap(self): - return self.inner.isMozMap() + def isRecord(self): + return self.inner.isRecord() def isDictionary(self): return self.inner.isDictionary() @@ -2798,7 +2804,7 @@ class IDLWrapperType(IDLType): if self.isEnum(): return (other.isPrimitive() or other.isInterface() or other.isObject() or other.isCallback() or other.isDictionary() or - other.isSequence() or other.isMozMap() or other.isDate()) + other.isSequence() or other.isRecord() or other.isDate()) if self.isDictionary() and other.nullable(): return False if (other.isPrimitive() or other.isString() or other.isEnum() or @@ -2820,7 +2826,7 @@ class IDLWrapperType(IDLType): (self.isNonCallbackInterface() or other.isNonCallbackInterface())) if (other.isDictionary() or other.isCallback() or - other.isMozMap()): + other.isRecord()): return self.isNonCallbackInterface() # Not much else |other| can be @@ -3030,17 +3036,17 @@ class IDLBuiltinType(IDLType): return (other.isNumeric() or other.isString() or other.isEnum() or other.isInterface() or other.isObject() or other.isCallback() or other.isDictionary() or - other.isSequence() or other.isMozMap() or other.isDate()) + other.isSequence() or other.isRecord() or other.isDate()) if self.isNumeric(): return (other.isBoolean() or other.isString() or other.isEnum() or other.isInterface() or other.isObject() or other.isCallback() or other.isDictionary() or - other.isSequence() or other.isMozMap() or other.isDate()) + other.isSequence() or other.isRecord() or other.isDate()) if self.isString(): return (other.isPrimitive() or other.isInterface() or other.isObject() or other.isCallback() or other.isDictionary() or - other.isSequence() or other.isMozMap() or other.isDate()) + other.isSequence() or other.isRecord() or other.isDate()) if self.isAny(): # Can't tell "any" apart from anything return False @@ -3050,7 +3056,7 @@ class IDLBuiltinType(IDLType): return (other.isPrimitive() or other.isString() or other.isEnum() or other.isInterface() or other.isCallback() or other.isDictionary() or other.isSequence() or - other.isMozMap()) + other.isRecord()) if self.isVoid(): return not other.isVoid() # Not much else we could be! @@ -3058,7 +3064,7 @@ class IDLBuiltinType(IDLType): # Like interfaces, but we know we're not a callback return (other.isPrimitive() or other.isString() or other.isEnum() or other.isCallback() or other.isDictionary() or - other.isSequence() or other.isMozMap() or other.isDate() or + other.isSequence() or other.isRecord() or other.isDate() or (other.isInterface() and ( # ArrayBuffer is distinguishable from everything # that's not an ArrayBuffer or a callback interface @@ -3843,6 +3849,9 @@ class IDLConst(IDLInterfaceMember): if type.isDictionary(): raise WebIDLError("A constant cannot be of a dictionary type", [self.location]) + if type.isRecord(): + raise WebIDLError("A constant cannot be of a record type", + [self.location]) self.type = type self.value = value @@ -3954,8 +3963,8 @@ class IDLAttribute(IDLInterfaceMember): if self.type.isSequence() and not self.getExtendedAttribute("Cached"): raise WebIDLError("A non-cached attribute cannot be of a sequence " "type", [self.location]) - if self.type.isMozMap() and not self.getExtendedAttribute("Cached"): - raise WebIDLError("A non-cached attribute cannot be of a MozMap " + if self.type.isRecord() and not self.getExtendedAttribute("Cached"): + raise WebIDLError("A non-cached attribute cannot be of a record " "type", [self.location]) if self.type.isUnion(): for f in self.type.unroll().flatMemberTypes: @@ -3971,11 +3980,11 @@ class IDLAttribute(IDLInterfaceMember): "one of its member types's member " "types, and so on) is a sequence " "type", [self.location, f.location]) - if f.isMozMap(): + if f.isRecord(): raise WebIDLError("An attribute cannot be of a union " "type if one of its member types (or " "one of its member types's member " - "types, and so on) is a MozMap " + "types, and so on) is a record " "type", [self.location, f.location]) if not self.type.isInterface() and self.getExtendedAttribute("PutForwards"): raise WebIDLError("An attribute with [PutForwards] must have an " @@ -3989,7 +3998,7 @@ class IDLAttribute(IDLInterfaceMember): def typeContainsChromeOnlyDictionaryMember(type): if (type.nullable() or type.isSequence() or - type.isMozMap()): + type.isRecord()): return typeContainsChromeOnlyDictionaryMember(type.inner) if type.isUnion(): @@ -4035,10 +4044,10 @@ class IDLAttribute(IDLInterfaceMember): [self.location, location]) if self.getExtendedAttribute("Frozen"): if (not self.type.isSequence() and not self.type.isDictionary() and - not self.type.isMozMap()): + not self.type.isRecord()): raise WebIDLError("[Frozen] is only allowed on " "sequence-valued, dictionary-valued, and " - "MozMap-valued attributes", + "record-valued attributes", [self.location]) if not self.type.unroll().isExposedInAllOf(self.exposureSet): raise WebIDLError("Attribute returns a type that is not exposed " @@ -5147,7 +5156,7 @@ class Tokenizer(object): "Promise": "PROMISE", "required": "REQUIRED", "sequence": "SEQUENCE", - "MozMap": "MOZMAP", + "record": "RECORD", "short": "SHORT", "unsigned": "UNSIGNED", "void": "VOID", @@ -6276,7 +6285,7 @@ class Parser(Tokenizer): | OCTET | OPTIONAL | SEQUENCE - | MOZMAP + | RECORD | SETTER | SHORT | STATIC @@ -6355,7 +6364,7 @@ class Parser(Tokenizer): def p_NonAnyType(self, p): """ - NonAnyType : PrimitiveOrStringType Null + NonAnyType : PrimitiveType Null | ARRAYBUFFER Null | SHAREDARRAYBUFFER Null | OBJECT Null @@ -6371,6 +6380,12 @@ class Parser(Tokenizer): p[0] = self.handleNullable(type, p[2]) + def p_NonAnyTypeStringType(self, p): + """ + NonAnyType : StringType Null + """ + p[0] = self.handleNullable(p[1], p[2]) + def p_NonAnyTypeSequenceType(self, p): """ NonAnyType : SEQUENCE LT Type GT Null @@ -6391,13 +6406,14 @@ class Parser(Tokenizer): type = IDLUnresolvedType(self.getLocation(p, 1), promiseIdent, p[3]) p[0] = self.handleNullable(type, p[5]) - def p_NonAnyTypeMozMapType(self, p): + def p_NonAnyTypeRecordType(self, p): """ - NonAnyType : MOZMAP LT Type GT Null + NonAnyType : RECORD LT StringType COMMA Type GT Null """ - innerType = p[3] - type = IDLMozMapType(self.getLocation(p, 1), innerType) - p[0] = self.handleNullable(type, p[5]) + keyType = p[3] + valueType = p[5] + type = IDLRecordType(self.getLocation(p, 1), keyType, valueType) + p[0] = self.handleNullable(type, p[7]) def p_NonAnyTypeScopedName(self, p): """ @@ -6440,7 +6456,7 @@ class Parser(Tokenizer): def p_ConstType(self, p): """ - ConstType : PrimitiveOrStringType Null + ConstType : PrimitiveType Null """ type = BuiltinTypes[p[1]] p[0] = self.handleNullable(type, p[2]) @@ -6454,69 +6470,75 @@ class Parser(Tokenizer): type = IDLUnresolvedType(self.getLocation(p, 1), identifier) p[0] = self.handleNullable(type, p[2]) - def p_PrimitiveOrStringTypeUint(self, p): + def p_PrimitiveTypeUint(self, p): """ - PrimitiveOrStringType : UnsignedIntegerType + PrimitiveType : UnsignedIntegerType """ p[0] = p[1] - def p_PrimitiveOrStringTypeBoolean(self, p): + def p_PrimitiveTypeBoolean(self, p): """ - PrimitiveOrStringType : BOOLEAN + PrimitiveType : BOOLEAN """ p[0] = IDLBuiltinType.Types.boolean - def p_PrimitiveOrStringTypeByte(self, p): + def p_PrimitiveTypeByte(self, p): """ - PrimitiveOrStringType : BYTE + PrimitiveType : BYTE """ p[0] = IDLBuiltinType.Types.byte - def p_PrimitiveOrStringTypeOctet(self, p): + def p_PrimitiveTypeOctet(self, p): """ - PrimitiveOrStringType : OCTET + PrimitiveType : OCTET """ p[0] = IDLBuiltinType.Types.octet - def p_PrimitiveOrStringTypeFloat(self, p): + def p_PrimitiveTypeFloat(self, p): """ - PrimitiveOrStringType : FLOAT + PrimitiveType : FLOAT """ p[0] = IDLBuiltinType.Types.float - def p_PrimitiveOrStringTypeUnrestictedFloat(self, p): + def p_PrimitiveTypeUnrestictedFloat(self, p): """ - PrimitiveOrStringType : UNRESTRICTED FLOAT + PrimitiveType : UNRESTRICTED FLOAT """ p[0] = IDLBuiltinType.Types.unrestricted_float - def p_PrimitiveOrStringTypeDouble(self, p): + def p_PrimitiveTypeDouble(self, p): """ - PrimitiveOrStringType : DOUBLE + PrimitiveType : DOUBLE """ p[0] = IDLBuiltinType.Types.double - def p_PrimitiveOrStringTypeUnrestictedDouble(self, p): + def p_PrimitiveTypeUnrestictedDouble(self, p): """ - PrimitiveOrStringType : UNRESTRICTED DOUBLE + PrimitiveType : UNRESTRICTED DOUBLE """ p[0] = IDLBuiltinType.Types.unrestricted_double - def p_PrimitiveOrStringTypeDOMString(self, p): + def p_StringType(self, p): + """ + StringType : BuiltinStringType + """ + p[0] = BuiltinTypes[p[1]] + + def p_BuiltinStringTypeDOMString(self, p): """ - PrimitiveOrStringType : DOMSTRING + BuiltinStringType : DOMSTRING """ p[0] = IDLBuiltinType.Types.domstring - def p_PrimitiveOrStringTypeBytestring(self, p): + def p_BuiltinStringTypeBytestring(self, p): """ - PrimitiveOrStringType : BYTESTRING + BuiltinStringType : BYTESTRING """ p[0] = IDLBuiltinType.Types.bytestring - def p_PrimitiveOrStringTypeUSVString(self, p): + def p_BuiltinStringTypeUSVString(self, p): """ - PrimitiveOrStringType : USVSTRING + BuiltinStringType : USVSTRING """ p[0] = IDLBuiltinType.Types.usvstring diff --git a/dom/browser-element/BrowserElementParent.js b/dom/browser-element/BrowserElementParent.js index 67d05f0ab..8e4475bfa 100644 --- a/dom/browser-element/BrowserElementParent.js +++ b/dom/browser-element/BrowserElementParent.js @@ -23,15 +23,6 @@ function debug(msg) { //dump("BrowserElementParent - " + msg + "\n"); } -function getIntPref(prefName, def) { - try { - return Services.prefs.getIntPref(prefName); - } - catch(err) { - return def; - } -} - function handleWindowEvent(e) { if (this._browserElementParents) { let beps = ThreadSafeChromeUtils.nondeterministicGetWeakMapKeys(this._browserElementParents); @@ -856,8 +847,8 @@ BrowserElementParent.prototype = { */ zoom: defineNoReturnMethod(function(zoom) { zoom *= 100; - zoom = Math.min(getIntPref("zoom.maxPercent", 300), zoom); - zoom = Math.max(getIntPref("zoom.minPercent", 50), zoom); + zoom = Math.min(Services.prefs.getIntPref("zoom.maxPercent", 300), zoom); + zoom = Math.max(Services.prefs.getIntPref("zoom.minPercent", 50), zoom); this._sendAsyncMsg('zoom', {zoom: zoom / 100.0}); }), diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index 18af28e9f..4849fda57 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -783,6 +783,15 @@ public: : mCanvas(aCanvas) {} + void OnShutdown() { + if(!mCanvas) { + return; + } + + mCanvas = nullptr; + nsContentUtils::UnregisterShutdownObserver(this); + } + NS_DECL_ISUPPORTS NS_DECL_NSIOBSERVER private: @@ -800,7 +809,7 @@ CanvasShutdownObserver::Observe(nsISupports* aSubject, { if (mCanvas && strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) { mCanvas->OnShutdown(); - nsContentUtils::UnregisterShutdownObserver(this); + OnShutdown(); } return NS_OK; @@ -1038,7 +1047,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CanvasRenderingContext2D) ImplCycleCollectionTraverse(cb, info.mElement, "Hit region fallback element"); } } - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(CanvasRenderingContext2D) @@ -1097,6 +1105,7 @@ CanvasRenderingContext2D::CanvasRenderingContext2D(layers::LayersBackend aCompos , mIsCapturedFrameInvalid(false) , mPathTransformWillUpdate(false) , mInvalidateCount(0) + , mWriteOnly(false) // == !origin-clean { sNumLivingContexts++; @@ -1218,7 +1227,7 @@ void CanvasRenderingContext2D::RemoveShutdownObserver() { if (mShutdownObserver) { - nsContentUtils::UnregisterShutdownObserver(mShutdownObserver); + mShutdownObserver->OnShutdown(); mShutdownObserver = nullptr; } } @@ -2554,7 +2563,8 @@ CanvasRenderingContext2D::CreatePattern(const CanvasImageSource& aSource, // nullptr and set CORSUsed to true for passing the security check in // CanvasUtils::DoDrawImageSecurityCheck(). RefPtr<CanvasPattern> pat = - new CanvasPattern(this, srcSurf, repeatMode, nullptr, false, true); + new CanvasPattern(this, srcSurf, repeatMode, nullptr, + imgBitmap.IsWriteOnly(), true); return pat.forget(); } @@ -4944,6 +4954,10 @@ CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage, aError.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return; } + + if (canvas->IsWriteOnly()) { + SetWriteOnly(); + } } else if (aImage.IsImageBitmap()) { ImageBitmap& imageBitmap = aImage.GetAsImageBitmap(); srcSurf = imageBitmap.PrepareForDrawTarget(mTarget); @@ -4952,6 +4966,10 @@ CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage, return; } + if (imageBitmap.IsWriteOnly()) { + SetWriteOnly(); + } + imgSize = gfx::IntSize(imageBitmap.Width(), imageBitmap.Height()); } else { @@ -5666,9 +5684,8 @@ CanvasRenderingContext2D::GetImageData(JSContext* aCx, double aSx, // Check only if we have a canvas element; if we were created with a docshell, // then it's special internal use. - if (mCanvasElement && mCanvasElement->IsWriteOnly() && - !nsContentUtils::IsCallerChrome()) - { + if (IsWriteOnly() || + (mCanvasElement && mCanvasElement->IsWriteOnly() && !nsContentUtils::IsCallerChrome())) { // XXX ERRMSG we need to report an error to developers here! (bug 329026) aError.Throw(NS_ERROR_DOM_SECURITY_ERR); return nullptr; @@ -6312,6 +6329,13 @@ CanvasRenderingContext2D::ShouldForceInactiveLayer(LayerManager* aManager) return !aManager->CanUseCanvasLayerForSize(GetSize()); } +void CanvasRenderingContext2D::SetWriteOnly() { + mWriteOnly = true; + if (mCanvasElement) { + mCanvasElement->SetWriteOnly(); + } +} + NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(CanvasPath, AddRef) NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(CanvasPath, Release) diff --git a/dom/canvas/CanvasRenderingContext2D.h b/dom/canvas/CanvasRenderingContext2D.h index 848b3ee08..d4f295a03 100644 --- a/dom/canvas/CanvasRenderingContext2D.h +++ b/dom/canvas/CanvasRenderingContext2D.h @@ -40,6 +40,7 @@ class SourceSurface; namespace dom { class HTMLImageElementOrSVGImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmap; typedef HTMLImageElementOrSVGImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmap CanvasImageSource; +class ImageBitmap; class ImageData; class StringOrCanvasGradientOrCanvasPattern; class OwningStringOrCanvasGradientOrCanvasPattern; @@ -1151,6 +1152,17 @@ protected: friend struct CanvasBidiProcessor; friend class CanvasDrawObserver; + friend class ImageBitmap; + + // For the origin-clean algorithm (mWriteOnly == !origin-clean) + // See https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html + void SetWriteOnly(); + + bool IsWriteOnly() const { + return mWriteOnly; + } + + bool mWriteOnly; }; } // namespace dom diff --git a/dom/canvas/CanvasRenderingContextHelper.cpp b/dom/canvas/CanvasRenderingContextHelper.cpp index 3000e59bd..61317fb51 100644 --- a/dom/canvas/CanvasRenderingContextHelper.cpp +++ b/dom/canvas/CanvasRenderingContextHelper.cpp @@ -7,7 +7,6 @@ #include "ImageBitmapRenderingContext.h" #include "ImageEncoder.h" #include "mozilla/dom/CanvasRenderingContext2D.h" -#include "mozilla/Telemetry.h" #include "mozilla/UniquePtr.h" #include "nsContentUtils.h" #include "nsDOMJSUtils.h" @@ -138,13 +137,10 @@ CanvasRenderingContextHelper::CreateContextHelper(CanvasContextType aContextType break; case CanvasContextType::Canvas2D: - Telemetry::Accumulate(Telemetry::CANVAS_2D_USED, 1); ret = new CanvasRenderingContext2D(aCompositorBackend); break; case CanvasContextType::WebGL1: - Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1); - ret = WebGL1Context::Create(); if (!ret) return nullptr; @@ -152,8 +148,6 @@ CanvasRenderingContextHelper::CreateContextHelper(CanvasContextType aContextType break; case CanvasContextType::WebGL2: - Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1); - ret = WebGL2Context::Create(); if (!ret) return nullptr; @@ -205,16 +199,8 @@ CanvasRenderingContextHelper::GetContext(JSContext* aCx, // See bug 645792 and bug 1215072. // We want to throw only if dictionary initialization fails, // so only in case aRv has been set to some error value. - if (contextType == CanvasContextType::WebGL1) - Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_SUCCESS, 0); - else if (contextType == CanvasContextType::WebGL2) - Telemetry::Accumulate(Telemetry::CANVAS_WEBGL2_SUCCESS, 0); return nullptr; } - if (contextType == CanvasContextType::WebGL1) - Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_SUCCESS, 1); - else if (contextType == CanvasContextType::WebGL2) - Telemetry::Accumulate(Telemetry::CANVAS_WEBGL2_SUCCESS, 1); } else { // We already have a context of some type. if (contextType != mCurrentContextType) diff --git a/dom/canvas/ImageBitmap.cpp b/dom/canvas/ImageBitmap.cpp index e45cdfc6f..6efe1b318 100644 --- a/dom/canvas/ImageBitmap.cpp +++ b/dom/canvas/ImageBitmap.cpp @@ -351,29 +351,27 @@ CheckSecurityForHTMLElements(const nsLayoutUtils::SurfaceFromElementResult& aRes */ template<class HTMLElementType> static already_AddRefed<SourceSurface> -GetSurfaceFromElement(nsIGlobalObject* aGlobal, HTMLElementType& aElement, ErrorResult& aRv) +GetSurfaceFromElement(nsIGlobalObject* aGlobal, HTMLElementType& aElement, + bool* aWriteOnly, ErrorResult& aRv) { nsLayoutUtils::SurfaceFromElementResult res = nsLayoutUtils::SurfaceFromElement(&aElement, nsLayoutUtils::SFE_WANT_FIRST_FRAME); - // check origin-clean - if (!CheckSecurityForHTMLElements(res)) { - aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); - return nullptr; - } - RefPtr<SourceSurface> surface = res.GetSourceSurface(); if (NS_WARN_IF(!surface)) { - aRv.Throw(NS_ERROR_NOT_AVAILABLE); + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return nullptr; } + + // Check origin-clean and pass back + *aWriteOnly = !CheckSecurityForHTMLElements(res); return surface.forget(); } /* - * The specification doesn't allow to create an ImegeBitmap from a vector image. + * The specification doesn't allow to create an ImageBitmap from a vector image. * This function is used to check if the given HTMLImageElement contains a * raster image. */ @@ -398,7 +396,7 @@ HasRasterImage(HTMLImageElement& aImageEl) } ImageBitmap::ImageBitmap(nsIGlobalObject* aGlobal, layers::Image* aData, - bool aIsPremultipliedAlpha /* = true */) + bool aWriteOnly, bool aIsPremultipliedAlpha /* = true */) : mParent(aGlobal) , mData(aData) , mSurface(nullptr) @@ -406,6 +404,7 @@ ImageBitmap::ImageBitmap(nsIGlobalObject* aGlobal, layers::Image* aData, , mPictureRect(0, 0, aData->GetSize().width, aData->GetSize().height) , mIsPremultipliedAlpha(aIsPremultipliedAlpha) , mIsCroppingAreaOutSideOfSourceImage(false) + , mWriteOnly(aWriteOnly) { MOZ_ASSERT(aData, "aData is null in ImageBitmap constructor."); } @@ -698,6 +697,7 @@ ImageBitmap::ToCloneData() const RefPtr<SourceSurface> surface = mData->GetAsSourceSurface(); result->mSurface = surface->GetDataSurface(); MOZ_ASSERT(result->mSurface); + result->mWriteOnly = mWriteOnly; return Move(result); } @@ -708,7 +708,7 @@ ImageBitmap::CreateFromCloneData(nsIGlobalObject* aGlobal, { RefPtr<layers::Image> data = CreateImageFromSurface(aData->mSurface); - RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, + RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, aData->mWriteOnly, aData->mIsPremultipliedAlpha); ret->mIsCroppingAreaOutSideOfSourceImage = @@ -724,11 +724,8 @@ ImageBitmap::CreateFromOffscreenCanvas(nsIGlobalObject* aGlobal, OffscreenCanvas& aOffscreenCanvas, ErrorResult& aRv) { - // Check origin-clean. - if (aOffscreenCanvas.IsWriteOnly()) { - aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); - return nullptr; - } + // Check origin-clean + bool writeOnly = aOffscreenCanvas.IsWriteOnly(); nsLayoutUtils::SurfaceFromElementResult res = nsLayoutUtils::SurfaceFromOffscreenCanvas(&aOffscreenCanvas, @@ -744,7 +741,7 @@ ImageBitmap::CreateFromOffscreenCanvas(nsIGlobalObject* aGlobal, RefPtr<layers::Image> data = CreateImageFromSurface(surface); - RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data); + RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, writeOnly); return ret.forget(); } @@ -757,16 +754,19 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLImageElement& aImageEl aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return nullptr; } - + // Check if the image element is a bitmap (e.g. it's a vector graphic) or not. if (!HasRasterImage(aImageEl)) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return nullptr; } + bool writeOnly = true; + // Get the SourceSurface out from the image element and then do security // checking. - RefPtr<SourceSurface> surface = GetSurfaceFromElement(aGlobal, aImageEl, aRv); + RefPtr<SourceSurface> surface = GetSurfaceFromElement(aGlobal, aImageEl, + &writeOnly, aRv); if (NS_WARN_IF(aRv.Failed())) { return nullptr; @@ -780,7 +780,7 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLImageElement& aImageEl return nullptr; } - RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data); + RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, writeOnly); // Set the picture rectangle. if (ret && aCropRect.isSome()) { @@ -812,13 +812,13 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLVideoElement& aVideoEl return nullptr; } + bool writeOnly = true; + // Check security. nsCOMPtr<nsIPrincipal> principal = aVideoEl.GetCurrentVideoPrincipal(); bool CORSUsed = aVideoEl.GetCORSMode() != CORS_NONE; - if (!CheckSecurityForHTMLElements(false, CORSUsed, principal)) { - aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); - return nullptr; - } + + writeOnly = !CheckSecurityForHTMLElements(false, CORSUsed, principal); // Create ImageBitmap. ImageContainer *container = aVideoEl.GetImageContainer(); @@ -834,7 +834,7 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLVideoElement& aVideoEl aRv.Throw(NS_ERROR_NOT_AVAILABLE); return nullptr; } - RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data); + RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, writeOnly); // Set the picture rectangle. if (ret && aCropRect.isSome()) { @@ -856,12 +856,18 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLCanvasElement& aCanvas return nullptr; } - RefPtr<SourceSurface> surface = GetSurfaceFromElement(aGlobal, aCanvasEl, aRv); + bool writeOnly = true; + + RefPtr<SourceSurface> surface = GetSurfaceFromElement(aGlobal, aCanvasEl, &writeOnly, aRv); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } + if (!writeOnly) { + writeOnly = aCanvasEl.IsWriteOnly(); + } + // Crop the source surface if needed. RefPtr<SourceSurface> croppedSurface; IntRect cropRect = aCropRect.valueOr(IntRect()); @@ -874,8 +880,7 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLCanvasElement& aCanvas aCropRect.isSome()) { // The _surface_ must be a DataSourceSurface. MOZ_ASSERT(surface->GetType() == SurfaceType::DATA, - "The snapshot SourceSurface from WebGL rendering contest is not \ - DataSourceSurface."); + "The snapshot SourceSurface from WebGL rendering contest is not DataSourceSurface."); RefPtr<DataSourceSurface> dataSurface = surface->GetDataSurface(); croppedSurface = CropAndCopyDataSourceSurface(dataSurface, cropRect); cropRect.MoveTo(0, 0); @@ -897,7 +902,7 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLCanvasElement& aCanvas return nullptr; } - RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data); + RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, writeOnly); // Set the picture rectangle. if (ret && aCropRect.isSome()) { @@ -958,9 +963,12 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, ImageData& aImageData, return nullptr; } - // Create an ImageBimtap. + // Create an ImageBitmap. // ImageData's underlying data is not alpha-premultiplied. - RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, false); + RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, + data, + false /* write-only */, + false /* alpha-premult */); // The cropping information has been handled in the CreateImageFromRawData() // function. @@ -975,11 +983,8 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, ImageData& aImageData, ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, CanvasRenderingContext2D& aCanvasCtx, const Maybe<IntRect>& aCropRect, ErrorResult& aRv) { - // Check origin-clean. - if (aCanvasCtx.GetCanvas()->IsWriteOnly()) { - aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); - return nullptr; - } + // Check origin-clean + bool writeOnly = aCanvasCtx.GetCanvas()->IsWriteOnly() || aCanvasCtx.IsWriteOnly(); RefPtr<SourceSurface> surface = aCanvasCtx.GetSurfaceSnapshot(); @@ -1001,7 +1006,7 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, CanvasRenderingContext2D& return nullptr; } - RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data); + RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, writeOnly); // Set the picture rectangle. if (ret && aCropRect.isSome()) { @@ -1024,7 +1029,10 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, ImageBitmap& aImageBitmap, } RefPtr<layers::Image> data = aImageBitmap.mData; - RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, aImageBitmap.mIsPremultipliedAlpha); + RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, + data, + aImageBitmap.mWriteOnly, + aImageBitmap.mIsPremultipliedAlpha); // Set the picture rectangle. if (ret && aCropRect.isSome()) { @@ -1295,7 +1303,7 @@ private: } // Create ImageBitmap object. - RefPtr<ImageBitmap> imageBitmap = new ImageBitmap(mGlobalObject, data); + RefPtr<ImageBitmap> imageBitmap = new ImageBitmap(mGlobalObject, data, false /* write-only */); // Set mIsCroppingAreaOutSideOfSourceImage. imageBitmap->SetIsCroppingAreaOutSideOfSourceImage(sourceSize, originalCropRect); @@ -1391,7 +1399,7 @@ private: } // Create ImageBitmap object. - RefPtr<ImageBitmap> imageBitmap = new ImageBitmap(mGlobalObject, data); + RefPtr<ImageBitmap> imageBitmap = new ImageBitmap(mGlobalObject, data, false /* write-only */); // Set mIsCroppingAreaOutSideOfSourceImage. imageBitmap->SetIsCroppingAreaOutSideOfSourceImage(sourceSize, originalCropRect); @@ -1486,14 +1494,19 @@ ImageBitmap::ReadStructuredClone(JSContext* aCx, uint32_t picRectHeight_; uint32_t isPremultipliedAlpha_; uint32_t isCroppingAreaOutSideOfSourceImage_; + uint32_t writeOnly; + uint32_t dummy; if (!JS_ReadUint32Pair(aReader, &picRectX_, &picRectY_) || !JS_ReadUint32Pair(aReader, &picRectWidth_, &picRectHeight_) || !JS_ReadUint32Pair(aReader, &isPremultipliedAlpha_, - &isCroppingAreaOutSideOfSourceImage_)) { + &isCroppingAreaOutSideOfSourceImage_) || + !JS_ReadUint32Pair(aReader, &writeOnly, &dummy)) { return nullptr; } + MOZ_ASSERT(dummy == 0); + int32_t picRectX = BitwiseCast<int32_t>(picRectX_); int32_t picRectY = BitwiseCast<int32_t>(picRectY_); int32_t picRectWidth = BitwiseCast<int32_t>(picRectWidth_); @@ -1512,7 +1525,7 @@ ImageBitmap::ReadStructuredClone(JSContext* aCx, { RefPtr<layers::Image> img = CreateImageFromSurface(aClonedSurfaces[aIndex]); RefPtr<ImageBitmap> imageBitmap = - new ImageBitmap(aParent, img, isPremultipliedAlpha_); + new ImageBitmap(aParent, img, !!writeOnly, isPremultipliedAlpha_); imageBitmap->mIsCroppingAreaOutSideOfSourceImage = isCroppingAreaOutSideOfSourceImage_; @@ -1547,6 +1560,7 @@ ImageBitmap::WriteStructuredClone(JSStructuredCloneWriter* aWriter, const uint32_t picRectHeight = BitwiseCast<uint32_t>(aImageBitmap->mPictureRect.height); const uint32_t isPremultipliedAlpha = aImageBitmap->mIsPremultipliedAlpha ? 1 : 0; const uint32_t isCroppingAreaOutSideOfSourceImage = aImageBitmap->mIsCroppingAreaOutSideOfSourceImage ? 1 : 0; + const uint32_t isWriteOnly = aImageBitmap->mWriteOnly ? 1 : 0; // Indexing the cloned surfaces and send the index to the receiver. uint32_t index = aClonedSurfaces.Length(); @@ -1555,7 +1569,8 @@ ImageBitmap::WriteStructuredClone(JSStructuredCloneWriter* aWriter, NS_WARN_IF(!JS_WriteUint32Pair(aWriter, picRectX, picRectY)) || NS_WARN_IF(!JS_WriteUint32Pair(aWriter, picRectWidth, picRectHeight)) || NS_WARN_IF(!JS_WriteUint32Pair(aWriter, isPremultipliedAlpha, - isCroppingAreaOutSideOfSourceImage))) { + isCroppingAreaOutSideOfSourceImage)) || + NS_WARN_IF(!JS_WriteUint32Pair(aWriter, isWriteOnly, 0))) { return false; } diff --git a/dom/canvas/ImageBitmap.h b/dom/canvas/ImageBitmap.h index 2119c6bda..25084b6ac 100644 --- a/dom/canvas/ImageBitmap.h +++ b/dom/canvas/ImageBitmap.h @@ -65,6 +65,7 @@ struct ImageBitmapCloneData final gfx::IntRect mPictureRect; bool mIsPremultipliedAlpha; bool mIsCroppingAreaOutSideOfSourceImage; + bool mWriteOnly; }; /* @@ -161,6 +162,10 @@ public: template<typename T> friend class MapDataIntoBufferSource; + bool IsWriteOnly() const { + return mWriteOnly; + } + // Mozilla Extensions ImageBitmapFormat FindOptimalFormat(const Optional<Sequence<ImageBitmapFormat>>& aPossibleFormats, @@ -197,6 +202,7 @@ protected: * CreateInternal(from ImageData) method. */ ImageBitmap(nsIGlobalObject* aGlobal, layers::Image* aData, + bool aWriteOnly, bool aIsPremultipliedAlpha = true); virtual ~ImageBitmap(); @@ -280,6 +286,12 @@ protected: */ bool mIsCroppingAreaOutSideOfSourceImage; + /* + * Write-Only flag is set to true if this image has been generated from a + * cross-origin source. This is the opposite of what is called 'origin-clean' + * in the spec. + */ + bool mWriteOnly; }; } // namespace dom diff --git a/dom/canvas/ImageBitmapRenderingContext.cpp b/dom/canvas/ImageBitmapRenderingContext.cpp index 8f5074554..ad313906a 100644 --- a/dom/canvas/ImageBitmapRenderingContext.cpp +++ b/dom/canvas/ImageBitmapRenderingContext.cpp @@ -63,6 +63,11 @@ ImageBitmapRenderingContext::TransferFromImageBitmap(ImageBitmap& aImageBitmap) if (!mImage) { return; } + + // Check if ImageBitmap is tainted, and if so flag the canvas tainted too. + if (aImageBitmap.IsWriteOnly() && mCanvasElement) { + mCanvasElement->SetWriteOnly(); + } Redraw(gfxRect(0, 0, mWidth, mHeight)); } diff --git a/dom/canvas/ImageData.cpp b/dom/canvas/ImageData.cpp index b201fa279..d24fbca95 100644 --- a/dom/canvas/ImageData.cpp +++ b/dom/canvas/ImageData.cpp @@ -29,7 +29,6 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ImageData) NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ImageData) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ImageData) diff --git a/dom/canvas/WebGL1Context.cpp b/dom/canvas/WebGL1Context.cpp index c1818a3f9..e82cafbe5 100644 --- a/dom/canvas/WebGL1Context.cpp +++ b/dom/canvas/WebGL1Context.cpp @@ -6,7 +6,6 @@ #include "WebGL1Context.h" #include "mozilla/dom/WebGLRenderingContextBinding.h" -#include "mozilla/Telemetry.h" #include "WebGLFormats.h" namespace mozilla { @@ -43,8 +42,6 @@ WebGL1Context::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) nsresult NS_NewCanvasRenderingContextWebGL(nsIDOMWebGLRenderingContext** out_result) { - mozilla::Telemetry::Accumulate(mozilla::Telemetry::CANVAS_WEBGL_USED, 1); - nsIDOMWebGLRenderingContext* ctx = mozilla::WebGL1Context::Create(); NS_ADDREF(*out_result = ctx); diff --git a/dom/canvas/WebGLContext.cpp b/dom/canvas/WebGLContext.cpp index 32eed6354..e2e05e5fd 100644 --- a/dom/canvas/WebGLContext.cpp +++ b/dom/canvas/WebGLContext.cpp @@ -47,7 +47,6 @@ #include "nsSVGEffects.h" #include "prenv.h" #include "ScopedGLHelpers.h" -#include "VRManagerChild.h" #include "mozilla/layers/TextureClientSharedSurface.h" // Local @@ -825,10 +824,6 @@ NS_IMETHODIMP WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight) { if (signedWidth < 0 || signedHeight < 0) { - if (!gl) { - Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID, - NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_SIZE")); - } GenerateWarning("Canvas size is too large (seems like a negative value wrapped)"); return NS_ERROR_OUT_OF_MEMORY; } @@ -884,12 +879,6 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight) return NS_OK; } - nsCString failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_UNKOWN"); - auto autoTelemetry = mozilla::MakeScopeExit([&] { - Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID, - failureId); - }); - // End of early return cases. // At this point we know that we're not just resizing an existing context, // we are initializing a new context. @@ -911,7 +900,6 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight) // resource handles created from older context generations. if (!(mGeneration + 1).isValid()) { // exit without changing the value of mGeneration - failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_TOO_MANY"); const nsLiteralCString text("Too many WebGL contexts created this run."); ThrowEvent_WebGLContextCreationError(text); return NS_ERROR_FAILURE; @@ -928,11 +916,6 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight) disabled |= gfxPlatform::InSafeMode(); if (disabled) { - if (gfxPlatform::InSafeMode()) { - failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_SAFEMODE"); - } else { - failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_DISABLED"); - } const nsLiteralCString text("WebGL is currently disabled."); ThrowEvent_WebGLContextCreationError(text); return NS_ERROR_FAILURE; @@ -945,7 +928,6 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight) if (mOptions.failIfMajorPerformanceCaveat) { nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo(); if (!HasAcceleratedLayers(gfxInfo)) { - failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_PERF_CAVEAT"); const nsLiteralCString text("failIfMajorPerformanceCaveat: Compositor is not" " hardware-accelerated."); ThrowEvent_WebGLContextCreationError(text); @@ -961,12 +943,9 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight) if (!CreateAndInitGL(forceEnabled, &failReasons)) { nsCString text("WebGL creation failed: "); for (const auto& cur : failReasons) { - Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID, cur.key); - text.AppendASCII("\n* "); text.Append(cur.info); } - failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_REASON"); ThrowEvent_WebGLContextCreationError(text); return NS_ERROR_FAILURE; } @@ -978,7 +957,6 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight) DestroyResourcesAndContext(); MOZ_ASSERT(!gl); - failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_PERF_WARP"); const nsLiteralCString text("failIfMajorPerformanceCaveat: Driver is not" " hardware-accelerated."); ThrowEvent_WebGLContextCreationError(text); @@ -992,7 +970,6 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight) DestroyResourcesAndContext(); MOZ_ASSERT(!gl); - failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_DXGL_INTEROP2"); const nsLiteralCString text("Caveat: WGL without DXGLInterop2."); ThrowEvent_WebGLContextCreationError(text); return NS_ERROR_FAILURE; @@ -1001,7 +978,6 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight) } if (!ResizeBackbuffer(width, height)) { - failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_BACKBUFFER"); const nsLiteralCString text("Initializing WebGL backbuffer failed."); ThrowEvent_WebGLContextCreationError(text); return NS_ERROR_FAILURE; @@ -1085,7 +1061,6 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight) ////// - failureId = NS_LITERAL_CSTRING("SUCCESS"); return NS_OK; } @@ -2263,84 +2238,6 @@ WebGLContext::GetUnpackSize(bool isFunc3D, uint32_t width, uint32_t height, return totalBytes; } -already_AddRefed<layers::SharedSurfaceTextureClient> -WebGLContext::GetVRFrame() -{ - if (!mLayerIsMirror) { - /** - * Do not allow VR frame submission until a mirroring canvas layer has - * been returned by GetCanvasLayer - */ - return nullptr; - } - - VRManagerChild* vrmc = VRManagerChild::Get(); - if (!vrmc) { - return nullptr; - } - - /** - * Swap buffers as though composition has occurred. - * We will then share the resulting front buffer to be submitted to the VR - * compositor. - */ - BeginComposition(); - EndComposition(); - - gl::GLScreenBuffer* screen = gl->Screen(); - if (!screen) { - return nullptr; - } - - RefPtr<SharedSurfaceTextureClient> sharedSurface = screen->Front(); - if (!sharedSurface) { - return nullptr; - } - - if (sharedSurface && sharedSurface->GetAllocator() != vrmc) { - RefPtr<SharedSurfaceTextureClient> dest = - screen->Factory()->NewTexClient(sharedSurface->GetSize()); - if (!dest) { - return nullptr; - } - gl::SharedSurface* destSurf = dest->Surf(); - destSurf->ProducerAcquire(); - SharedSurface::ProdCopy(sharedSurface->Surf(), dest->Surf(), - screen->Factory()); - destSurf->ProducerRelease(); - - return dest.forget(); - } - - return sharedSurface.forget(); -} - -bool -WebGLContext::StartVRPresentation() -{ - VRManagerChild* vrmc = VRManagerChild::Get(); - if (!vrmc) { - return false; - } - gl::GLScreenBuffer* screen = gl->Screen(); - if (!screen) { - return false; - } - gl::SurfaceCaps caps = screen->mCaps; - - UniquePtr<gl::SurfaceFactory> factory = - gl::GLScreenBuffer::CreateFactory(gl, - caps, - vrmc, - vrmc->GetBackendType(), - TextureFlags::ORIGIN_BOTTOM_LEFT); - - if (factory) { - screen->Morph(Move(factory)); - } - return true; -} - //////////////////////////////////////////////////////////////////////////////// static inline size_t diff --git a/dom/canvas/WebGLContext.h b/dom/canvas/WebGLContext.h index b4d416a33..8a20237ff 100644 --- a/dom/canvas/WebGLContext.h +++ b/dom/canvas/WebGLContext.h @@ -275,8 +275,9 @@ struct TexImageSourceAdapter final : public TexImageSource mPboOffset = pboOffset; } - TexImageSourceAdapter(const dom::ImageBitmap* imageBitmap, ErrorResult*) { + TexImageSourceAdapter(const dom::ImageBitmap* imageBitmap, ErrorResult* out_error) { mImageBitmap = imageBitmap; + mOut_error = out_error; } TexImageSourceAdapter(const dom::ImageData* imageData, ErrorResult*) { @@ -656,9 +657,6 @@ public: void PixelStorei(GLenum pname, GLint param); void PolygonOffset(GLfloat factor, GLfloat units); - already_AddRefed<layers::SharedSurfaceTextureClient> GetVRFrame(); - bool StartVRPresentation(); - //// webgl::PackingInfo diff --git a/dom/canvas/WebGLTextureUpload.cpp b/dom/canvas/WebGLTextureUpload.cpp index 612d5889d..3839b5d5e 100644 --- a/dom/canvas/WebGLTextureUpload.cpp +++ b/dom/canvas/WebGLTextureUpload.cpp @@ -12,6 +12,7 @@ #include "GLBlitHelper.h" #include "GLContext.h" #include "mozilla/gfx/2D.h" +#include "mozilla/dom/HTMLCanvasElement.h" #include "mozilla/dom/HTMLVideoElement.h" #include "mozilla/dom/ImageBitmap.h" #include "mozilla/dom/ImageData.h" @@ -214,9 +215,18 @@ FromPboOffset(WebGLContext* webgl, const char* funcName, TexImageTarget target, static UniquePtr<webgl::TexUnpackBlob> FromImageBitmap(WebGLContext* webgl, const char* funcName, TexImageTarget target, uint32_t width, uint32_t height, uint32_t depth, - const dom::ImageBitmap& imageBitmap) + const dom::ImageBitmap& imageBitmap, ErrorResult* aRv) { + if (imageBitmap.IsWriteOnly()) { + aRv->Throw(NS_ERROR_DOM_SECURITY_ERR); + return nullptr; + } + UniquePtr<dom::ImageBitmapCloneData> cloneData = Move(imageBitmap.ToCloneData()); + if (!cloneData) { + return nullptr; + } + const RefPtr<gfx::DataSourceSurface> surf = cloneData->mSurface; //// @@ -293,6 +303,14 @@ WebGLContext::FromDomElem(const char* funcName, TexImageTarget target, uint32_t uint32_t height, uint32_t depth, const dom::Element& elem, ErrorResult* const out_error) { + if (elem.IsHTMLElement(nsGkAtoms::canvas)) {
+ const dom::HTMLCanvasElement* canvas = static_cast<const dom::HTMLCanvasElement*>(&elem);
+ if (canvas->IsWriteOnly()) {
+ out_error->Throw(NS_ERROR_DOM_SECURITY_ERR);
+ return nullptr;
+ }
+ }
+ uint32_t flags = nsLayoutUtils::SFE_WANT_IMAGE_SURFACE | nsLayoutUtils::SFE_USE_ELEMENT_SIZE_IF_VECTOR; @@ -412,7 +430,7 @@ WebGLContext::From(const char* funcName, TexImageTarget target, GLsizei rawWidth if (src.mImageBitmap) { return FromImageBitmap(this, funcName, target, width, height, depth, - *(src.mImageBitmap)); + *(src.mImageBitmap), src.mOut_error); } if (src.mImageData) { diff --git a/dom/canvas/test/test_imagebitmap.html b/dom/canvas/test/test_imagebitmap.html index b3d3c08ad..3b74970ac 100644 --- a/dom/canvas/test/test_imagebitmap.html +++ b/dom/canvas/test/test_imagebitmap.html @@ -270,13 +270,22 @@ function testSecurityErrors() { } function checkPromiseFailedWithSecurityError(p) { - return p.then( function(reason) { ok(false, "Did not get SecurityError with unclean source. ImageBitmap was created successfully."); }, - function(reason) { if (reason == "SecurityError: The operation is insecure.") { - ok(true, reason); - } - else { - ok(false, "Did not get SecurityError with unclean source. Error Message: " + reason); - }}); + return p.then(imageBitmap => { + ok(!!imageBitmap, "ImageBitmaps are always created"); + const context = document.createElement("canvas").getContext("2d"); + context.drawImage(imageBitmap, 0, 0); + try { + context.getImageData(0, 0, 1, 1); + ok(false, "Did not get SecurityError with unclean source. ImageBitmap was created successfully."); + } catch (ex) { + if (ex == "SecurityError: The operation is insecure.") { + ok(true, ex); + } + else { + ok(false, "Did not get SecurityError with unclean source. Error Message: " + ex); + } + } + }); } return Promise.all([ diff --git a/dom/console/Console.cpp b/dom/console/Console.cpp index ff5a92167..b174172e0 100755 --- a/dom/console/Console.cpp +++ b/dom/console/Console.cpp @@ -797,7 +797,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Console) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsoleEventNotifier) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Console) diff --git a/dom/crypto/WebCryptoTask.cpp b/dom/crypto/WebCryptoTask.cpp index f5fc7b5bc..e5f5882e9 100644 --- a/dom/crypto/WebCryptoTask.cpp +++ b/dom/crypto/WebCryptoTask.cpp @@ -452,7 +452,6 @@ void WebCryptoTask::FailWithError(nsresult aRv) { MOZ_ASSERT(IsOnOriginalThread()); - Telemetry::Accumulate(Telemetry::WEBCRYPTO_RESOLVED, false); // Blindly convert nsresult to DOMException // Individual tasks must ensure they pass the right values @@ -491,7 +490,6 @@ WebCryptoTask::CallCallback(nsresult rv) } Resolve(); - Telemetry::Accumulate(Telemetry::WEBCRYPTO_RESOLVED, true); // Manually release mResultPromise while we're on the main thread mResultPromise = nullptr; @@ -586,7 +584,7 @@ public: mMechanism = CKM_AES_CBC_PAD; telemetryAlg = TA_AES_CBC; - AesCbcParams params; + RootedDictionary<AesCbcParams> params(aCx); nsresult rv = Coerce(aCx, params, aAlgorithm); if (NS_FAILED(rv)) { mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR; @@ -603,7 +601,7 @@ public: mMechanism = CKM_AES_CTR; telemetryAlg = TA_AES_CTR; - AesCtrParams params; + RootedDictionary<AesCtrParams> params(aCx); nsresult rv = Coerce(aCx, params, aAlgorithm); if (NS_FAILED(rv)) { mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; @@ -622,7 +620,7 @@ public: mMechanism = CKM_AES_GCM; telemetryAlg = TA_AES_GCM; - AesGcmParams params; + RootedDictionary<AesGcmParams> params(aCx); nsresult rv = Coerce(aCx, params, aAlgorithm); if (NS_FAILED(rv)) { mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; @@ -650,7 +648,6 @@ public: mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR; return; } - Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, telemetryAlg); } private: @@ -794,7 +791,6 @@ public: return; } - Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_AES_KW); } private: @@ -908,8 +904,6 @@ public: void Init(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey, bool aEncrypt) { - Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_RSA_OAEP); - CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_RSA_OAEP); if (mEncrypt) { @@ -1049,7 +1043,6 @@ public: case CKM_SHA512_HMAC: telemetryAlg = TA_HMAC_SHA_512; break; default: telemetryAlg = TA_UNKNOWN; } - Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, telemetryAlg); } private: @@ -1158,12 +1151,10 @@ public: if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) { mAlgorithm = Algorithm::RSA_PKCS1; - Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_RSASSA_PKCS1); CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_RSASSA_PKCS1); hashAlgName = aKey.Algorithm().mRsa.mHash.mName; } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS)) { mAlgorithm = Algorithm::RSA_PSS; - Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_RSA_PSS); CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_RSA_PSS); KeyAlgorithm& hashAlg = aKey.Algorithm().mRsa.mHash; @@ -1188,7 +1179,6 @@ public: mSaltLength = params.mSaltLength; } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) { mAlgorithm = Algorithm::ECDSA; - Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_ECDSA); CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_ECDSA); // For ECDSA, the hash name comes from the algorithm parameter @@ -1356,7 +1346,6 @@ public: mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; return; } - Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, telemetryAlg); mOidTag = MapHashAlgorithmNameToOID(algName); } @@ -2656,7 +2645,6 @@ public: void Init(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey, uint32_t aLength) { - Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_HKDF); CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_HKDF); // Check that we have a key. @@ -2806,7 +2794,6 @@ public: void Init(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey, uint32_t aLength) { - Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_PBKDF2); CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_PBKDF2); // Check that we got a symmetric key @@ -2981,7 +2968,6 @@ public: void Init(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey) { - Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_ECDH); CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_ECDH); // Check that we have a private key. @@ -3277,10 +3263,6 @@ WebCryptoTask::CreateEncryptDecryptTask(JSContext* aCx, const CryptoOperationData& aData, bool aEncrypt) { - TelemetryMethod method = (aEncrypt)? TM_ENCRYPT : TM_DECRYPT; - Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, method); - Telemetry::Accumulate(Telemetry::WEBCRYPTO_EXTRACTABLE_ENC, aKey.Extractable()); - // Ensure key is usable for this operation if ((aEncrypt && !aKey.HasUsage(CryptoKey::ENCRYPT)) || (!aEncrypt && !aKey.HasUsage(CryptoKey::DECRYPT))) { @@ -3312,10 +3294,6 @@ WebCryptoTask::CreateSignVerifyTask(JSContext* aCx, const CryptoOperationData& aData, bool aSign) { - TelemetryMethod method = (aSign)? TM_SIGN : TM_VERIFY; - Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, method); - Telemetry::Accumulate(Telemetry::WEBCRYPTO_EXTRACTABLE_SIG, aKey.Extractable()); - // Ensure key is usable for this operation if ((aSign && !aKey.HasUsage(CryptoKey::SIGN)) || (!aSign && !aKey.HasUsage(CryptoKey::VERIFY))) { @@ -3345,8 +3323,6 @@ WebCryptoTask::CreateDigestTask(JSContext* aCx, const ObjectOrString& aAlgorithm, const CryptoOperationData& aData) { - Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_DIGEST); - nsString algName; nsresult rv = GetAlgorithmName(aCx, aAlgorithm, algName); if (NS_FAILED(rv)) { @@ -3372,9 +3348,6 @@ WebCryptoTask::CreateImportKeyTask(nsIGlobalObject* aGlobal, bool aExtractable, const Sequence<nsString>& aKeyUsages) { - Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_IMPORTKEY); - Telemetry::Accumulate(Telemetry::WEBCRYPTO_EXTRACTABLE_IMPORT, aExtractable); - // Verify that the format is recognized if (!aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW) && !aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI) && @@ -3426,8 +3399,6 @@ WebCryptoTask* WebCryptoTask::CreateExportKeyTask(const nsAString& aFormat, CryptoKey& aKey) { - Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_EXPORTKEY); - // Verify that the format is recognized if (!aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW) && !aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI) && @@ -3470,9 +3441,6 @@ WebCryptoTask::CreateGenerateKeyTask(nsIGlobalObject* aGlobal, bool aExtractable, const Sequence<nsString>& aKeyUsages) { - Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_GENERATEKEY); - Telemetry::Accumulate(Telemetry::WEBCRYPTO_EXTRACTABLE_GENERATE, aExtractable); - // Verify that aKeyUsages does not contain an unrecognized value // SPEC-BUG: Spec says that this should be InvalidAccessError, but that // is inconsistent with other analogous points in the spec @@ -3515,8 +3483,6 @@ WebCryptoTask::CreateDeriveKeyTask(nsIGlobalObject* aGlobal, bool aExtractable, const Sequence<nsString>& aKeyUsages) { - Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_DERIVEKEY); - // Ensure baseKey is usable for this operation if (!aBaseKey.HasUsage(CryptoKey::DERIVEKEY)) { return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR); @@ -3560,8 +3526,6 @@ WebCryptoTask::CreateDeriveBitsTask(JSContext* aCx, CryptoKey& aKey, uint32_t aLength) { - Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_DERIVEBITS); - // Ensure baseKey is usable for this operation if (!aKey.HasUsage(CryptoKey::DERIVEBITS)) { return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR); @@ -3599,8 +3563,6 @@ WebCryptoTask::CreateWrapKeyTask(JSContext* aCx, CryptoKey& aWrappingKey, const ObjectOrString& aWrapAlgorithm) { - Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_WRAPKEY); - // Verify that the format is recognized if (!aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW) && !aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI) && @@ -3652,8 +3614,6 @@ WebCryptoTask::CreateUnwrapKeyTask(nsIGlobalObject* aGlobal, bool aExtractable, const Sequence<nsString>& aKeyUsages) { - Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_UNWRAPKEY); - // Ensure key is usable for this operation if (!aUnwrappingKey.HasUsage(CryptoKey::UNWRAPKEY)) { return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR); diff --git a/dom/events/DOMEventTargetHelper.cpp b/dom/events/DOMEventTargetHelper.cpp index f8a5227d6..dd9a01d8d 100644 --- a/dom/events/DOMEventTargetHelper.cpp +++ b/dom/events/DOMEventTargetHelper.cpp @@ -43,7 +43,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(DOMEventTargetHelper) NS_IMPL_CYCLE_COLLECTION_DESCRIBE(DOMEventTargetHelper, tmp->mRefCnt.get()) } - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListenerManager) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END diff --git a/dom/events/DataTransfer.cpp b/dom/events/DataTransfer.cpp index 45c72e662..40a0f42e6 100644 --- a/dom/events/DataTransfer.cpp +++ b/dom/events/DataTransfer.cpp @@ -57,7 +57,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DataTransfer) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mItems) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDragTarget) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDragImage) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(DataTransfer) diff --git a/dom/events/Event.cpp b/dom/events/Event.cpp index f33bfa5a8..280e40ad5 100755 --- a/dom/events/Event.cpp +++ b/dom/events/Event.cpp @@ -231,7 +231,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Event) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPresContext) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExplicitOriginalTarget) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END diff --git a/dom/events/EventDispatcher.cpp b/dom/events/EventDispatcher.cpp index 65f01844b..1d4dfd7d9 100644 --- a/dom/events/EventDispatcher.cpp +++ b/dom/events/EventDispatcher.cpp @@ -858,63 +858,46 @@ EventDispatcher::CreateEvent(EventTarget* aOwner, // And if we didn't get an event, check the type argument. -#define LOG_EVENT_CREATION(name) mozilla::Telemetry::Accumulate( \ - mozilla::Telemetry::CREATE_EVENT_##name, true); - if (aEventType.LowerCaseEqualsLiteral("mouseevent")) { - LOG_EVENT_CREATION(MOUSEEVENT); return NS_NewDOMMouseEvent(aOwner, aPresContext, nullptr); } if (aEventType.LowerCaseEqualsLiteral("mouseevents")) { - LOG_EVENT_CREATION(MOUSEEVENTS); return NS_NewDOMMouseEvent(aOwner, aPresContext, nullptr); } if (aEventType.LowerCaseEqualsLiteral("popupevents")) { - LOG_EVENT_CREATION(POPUPEVENTS); return NS_NewDOMMouseEvent(aOwner, aPresContext, nullptr); } if (aEventType.LowerCaseEqualsLiteral("mousescrollevents")) { - LOG_EVENT_CREATION(MOUSESCROLLEVENTS); return NS_NewDOMMouseScrollEvent(aOwner, aPresContext, nullptr); } if (aEventType.LowerCaseEqualsLiteral("dragevent")) { - LOG_EVENT_CREATION(DRAGEVENT); return NS_NewDOMDragEvent(aOwner, aPresContext, nullptr); } if (aEventType.LowerCaseEqualsLiteral("dragevents")) { - LOG_EVENT_CREATION(DRAGEVENTS); return NS_NewDOMDragEvent(aOwner, aPresContext, nullptr); } if (aEventType.LowerCaseEqualsLiteral("keyboardevent")) { - LOG_EVENT_CREATION(KEYBOARDEVENT); return NS_NewDOMKeyboardEvent(aOwner, aPresContext, nullptr); } if (aEventType.LowerCaseEqualsLiteral("keyevents")) { - LOG_EVENT_CREATION(KEYEVENTS); return NS_NewDOMKeyboardEvent(aOwner, aPresContext, nullptr); } if (aEventType.LowerCaseEqualsLiteral("compositionevent")) { - LOG_EVENT_CREATION(COMPOSITIONEVENT); return NS_NewDOMCompositionEvent(aOwner, aPresContext, nullptr); } if (aEventType.LowerCaseEqualsLiteral("textevent")) { - LOG_EVENT_CREATION(TEXTEVENT); return NS_NewDOMCompositionEvent(aOwner, aPresContext, nullptr); } if (aEventType.LowerCaseEqualsLiteral("textevents")) { - LOG_EVENT_CREATION(TEXTEVENTS); return NS_NewDOMCompositionEvent(aOwner, aPresContext, nullptr); } if (aEventType.LowerCaseEqualsLiteral("mutationevent")) { - LOG_EVENT_CREATION(MUTATIONEVENT); return NS_NewDOMMutationEvent(aOwner, aPresContext, nullptr); } if (aEventType.LowerCaseEqualsLiteral("mutationevents")) { - LOG_EVENT_CREATION(MUTATIONEVENTS); return NS_NewDOMMutationEvent(aOwner, aPresContext, nullptr); } if (aEventType.LowerCaseEqualsLiteral("deviceorientationevent")) { - LOG_EVENT_CREATION(DEVICEORIENTATIONEVENT); DeviceOrientationEventInit init; RefPtr<Event> event = DeviceOrientationEvent::Constructor(aOwner, EmptyString(), init); @@ -922,97 +905,74 @@ EventDispatcher::CreateEvent(EventTarget* aOwner, return event.forget(); } if (aEventType.LowerCaseEqualsLiteral("devicemotionevent")) { - LOG_EVENT_CREATION(DEVICEMOTIONEVENT); return NS_NewDOMDeviceMotionEvent(aOwner, aPresContext, nullptr); } if (aEventType.LowerCaseEqualsLiteral("uievent")) { - LOG_EVENT_CREATION(UIEVENT); return NS_NewDOMUIEvent(aOwner, aPresContext, nullptr); } if (aEventType.LowerCaseEqualsLiteral("uievents")) { - LOG_EVENT_CREATION(UIEVENTS); return NS_NewDOMUIEvent(aOwner, aPresContext, nullptr); } if (aEventType.LowerCaseEqualsLiteral("event")) { - LOG_EVENT_CREATION(EVENT); return NS_NewDOMEvent(aOwner, aPresContext, nullptr); } if (aEventType.LowerCaseEqualsLiteral("events")) { - LOG_EVENT_CREATION(EVENTS); return NS_NewDOMEvent(aOwner, aPresContext, nullptr); } if (aEventType.LowerCaseEqualsLiteral("htmlevents")) { - LOG_EVENT_CREATION(HTMLEVENTS); return NS_NewDOMEvent(aOwner, aPresContext, nullptr); } if (aEventType.LowerCaseEqualsLiteral("svgevent")) { - LOG_EVENT_CREATION(SVGEVENT); return NS_NewDOMEvent(aOwner, aPresContext, nullptr); } if (aEventType.LowerCaseEqualsLiteral("svgevents")) { - LOG_EVENT_CREATION(SVGEVENTS); return NS_NewDOMEvent(aOwner, aPresContext, nullptr); } if (aEventType.LowerCaseEqualsLiteral("svgzoomevent")) { - LOG_EVENT_CREATION(SVGZOOMEVENT); return NS_NewDOMSVGZoomEvent(aOwner, aPresContext, nullptr); } if (aEventType.LowerCaseEqualsLiteral("svgzoomevents")) { - LOG_EVENT_CREATION(SVGZOOMEVENTS); return NS_NewDOMSVGZoomEvent(aOwner, aPresContext, nullptr); } if (aEventType.LowerCaseEqualsLiteral("timeevent")) { - LOG_EVENT_CREATION(TIMEEVENT); return NS_NewDOMTimeEvent(aOwner, aPresContext, nullptr); } if (aEventType.LowerCaseEqualsLiteral("timeevents")) { - LOG_EVENT_CREATION(TIMEEVENTS); return NS_NewDOMTimeEvent(aOwner, aPresContext, nullptr); } if (aEventType.LowerCaseEqualsLiteral("xulcommandevent")) { - LOG_EVENT_CREATION(XULCOMMANDEVENT); return NS_NewDOMXULCommandEvent(aOwner, aPresContext, nullptr); } if (aEventType.LowerCaseEqualsLiteral("xulcommandevents")) { - LOG_EVENT_CREATION(XULCOMMANDEVENTS); return NS_NewDOMXULCommandEvent(aOwner, aPresContext, nullptr); } if (aEventType.LowerCaseEqualsLiteral("commandevent")) { - LOG_EVENT_CREATION(COMMANDEVENT); return NS_NewDOMCommandEvent(aOwner, aPresContext, nullptr); } if (aEventType.LowerCaseEqualsLiteral("commandevents")) { - LOG_EVENT_CREATION(COMMANDEVENTS); return NS_NewDOMCommandEvent(aOwner, aPresContext, nullptr); } if (aEventType.LowerCaseEqualsLiteral("datacontainerevent")) { - LOG_EVENT_CREATION(DATACONTAINEREVENT); return NS_NewDOMDataContainerEvent(aOwner, aPresContext, nullptr); } if (aEventType.LowerCaseEqualsLiteral("datacontainerevents")) { - LOG_EVENT_CREATION(DATACONTAINEREVENTS); return NS_NewDOMDataContainerEvent(aOwner, aPresContext, nullptr); } if (aEventType.LowerCaseEqualsLiteral("messageevent")) { - LOG_EVENT_CREATION(MESSAGEEVENT); RefPtr<Event> event = new MessageEvent(aOwner, aPresContext, nullptr); return event.forget(); } if (aEventType.LowerCaseEqualsLiteral("notifypaintevent")) { - LOG_EVENT_CREATION(NOTIFYPAINTEVENT); return NS_NewDOMNotifyPaintEvent(aOwner, aPresContext, nullptr); } if (aEventType.LowerCaseEqualsLiteral("simplegestureevent")) { - LOG_EVENT_CREATION(SIMPLEGESTUREEVENT); return NS_NewDOMSimpleGestureEvent(aOwner, aPresContext, nullptr); } if (aEventType.LowerCaseEqualsLiteral("beforeunloadevent")) { - LOG_EVENT_CREATION(BEFOREUNLOADEVENT); return NS_NewDOMBeforeUnloadEvent(aOwner, aPresContext, nullptr); } // XXXkhuey this is broken if (aEventType.LowerCaseEqualsLiteral("pagetransition")) { - LOG_EVENT_CREATION(PAGETRANSITION); PageTransitionEventInit init; RefPtr<Event> event = PageTransitionEvent::Constructor(aOwner, EmptyString(), init); @@ -1020,14 +980,12 @@ EventDispatcher::CreateEvent(EventTarget* aOwner, return event.forget(); } if (aEventType.LowerCaseEqualsLiteral("scrollareaevent")) { - LOG_EVENT_CREATION(SCROLLAREAEVENT); return NS_NewDOMScrollAreaEvent(aOwner, aPresContext, nullptr); } // XXXkhuey Chrome supports popstateevent here, even though it provides no // initPopStateEvent method. This is nuts ... but copying it is unlikely to // break the web. if (aEventType.LowerCaseEqualsLiteral("popstateevent")) { - LOG_EVENT_CREATION(POPSTATEEVENT); AutoJSContext cx; RootedDictionary<PopStateEventInit> init(cx); RefPtr<Event> event = @@ -1037,11 +995,9 @@ EventDispatcher::CreateEvent(EventTarget* aOwner, } if (aEventType.LowerCaseEqualsLiteral("touchevent") && TouchEvent::PrefEnabled(nsContentUtils::GetDocShellForEventTarget(aOwner))) { - LOG_EVENT_CREATION(TOUCHEVENT); return NS_NewDOMTouchEvent(aOwner, aPresContext, nullptr); } if (aEventType.LowerCaseEqualsLiteral("hashchangeevent")) { - LOG_EVENT_CREATION(HASHCHANGEEVENT); HashChangeEventInit init; RefPtr<Event> event = HashChangeEvent::Constructor(aOwner, EmptyString(), init); @@ -1049,11 +1005,9 @@ EventDispatcher::CreateEvent(EventTarget* aOwner, return event.forget(); } if (aEventType.LowerCaseEqualsLiteral("customevent")) { - LOG_EVENT_CREATION(CUSTOMEVENT); return NS_NewDOMCustomEvent(aOwner, aPresContext, nullptr); } if (aEventType.LowerCaseEqualsLiteral("storageevent")) { - LOG_EVENT_CREATION(STORAGEEVENT); return NS_NewDOMStorageEvent(aOwner); } if (aEventType.LowerCaseEqualsLiteral("focusevent")) { @@ -1062,8 +1016,6 @@ EventDispatcher::CreateEvent(EventTarget* aOwner, return event.forget(); } -#undef LOG_EVENT_CREATION - // NEW EVENT TYPES SHOULD NOT BE ADDED HERE; THEY SHOULD USE ONLY EVENT // CONSTRUCTORS diff --git a/dom/events/EventStateManager.cpp b/dom/events/EventStateManager.cpp index 7bbfe21b7..e16d68c81 100644 --- a/dom/events/EventStateManager.cpp +++ b/dom/events/EventStateManager.cpp @@ -3240,6 +3240,12 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext, action = WheelPrefs::GetInstance()->ComputeActionFor(wheelEvent); } switch (action) { + case WheelPrefs::ACTION_HSCROLL: { + // Swap axes and fall through + double deltaX = wheelEvent->mDeltaX; + wheelEvent->mDeltaX = wheelEvent->mDeltaY; + wheelEvent->mDeltaY = deltaX; + } case WheelPrefs::ACTION_SCROLL: { // For scrolling of default action, we should honor the mouse wheel // transaction. diff --git a/dom/events/EventStateManager.h b/dom/events/EventStateManager.h index d0461e7fa..95ce9a907 100644 --- a/dom/events/EventStateManager.h +++ b/dom/events/EventStateManager.h @@ -513,7 +513,8 @@ protected: ACTION_SCROLL, ACTION_HISTORY, ACTION_ZOOM, - ACTION_LAST = ACTION_ZOOM, + ACTION_HSCROLL, + ACTION_LAST = ACTION_HSCROLL, // Following actions are used only by internal processing. So, cannot // specified by prefs. ACTION_SEND_TO_PLUGIN diff --git a/dom/events/JSEventHandler.cpp b/dom/events/JSEventHandler.cpp index 4b1b33313..b9e7c4d84 100644 --- a/dom/events/JSEventHandler.cpp +++ b/dom/events/JSEventHandler.cpp @@ -63,7 +63,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(JSEventHandler) NS_IMPL_CYCLE_COLLECTION_DESCRIBE(JSEventHandler, tmp->mRefCnt.get()) } NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mTypedHandler.Ptr()) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(JSEventHandler) diff --git a/dom/fetch/Fetch.cpp b/dom/fetch/Fetch.cpp index 5c05f3602..f944352e3 100644 --- a/dom/fetch/Fetch.cpp +++ b/dom/fetch/Fetch.cpp @@ -38,7 +38,6 @@ #include "mozilla/dom/ScriptSettings.h" #include "mozilla/dom/URLSearchParams.h" #include "mozilla/dom/workers/ServiceWorkerManager.h" -#include "mozilla/Telemetry.h" #include "InternalRequest.h" #include "InternalResponse.h" @@ -237,8 +236,6 @@ FetchRequest(nsIGlobalObject* aGlobal, const RequestOrUSVString& aInput, } } - Telemetry::Accumulate(Telemetry::FETCH_IS_MAINTHREAD, 1); - RefPtr<MainThreadFetchResolver> resolver = new MainThreadFetchResolver(p); RefPtr<FetchDriver> fetch = new FetchDriver(r, principal, loadGroup); fetch->SetDocument(doc); @@ -251,8 +248,6 @@ FetchRequest(nsIGlobalObject* aGlobal, const RequestOrUSVString& aInput, WorkerPrivate* worker = GetCurrentThreadWorkerPrivate(); MOZ_ASSERT(worker); - Telemetry::Accumulate(Telemetry::FETCH_IS_MAINTHREAD, 0); - if (worker->IsServiceWorker()) { r->SetSkipServiceWorker(); } @@ -265,7 +260,7 @@ FetchRequest(nsIGlobalObject* aGlobal, const RequestOrUSVString& aInput, } RefPtr<MainThreadFetchRunnable> run = new MainThreadFetchRunnable(resolver, r); - worker->DispatchToMainThread(run.forget()); + MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(run)); } return p.forget(); diff --git a/dom/fetch/FetchConsumer.cpp b/dom/fetch/FetchConsumer.cpp index 42dfcbaba..e82e5ec51 100644 --- a/dom/fetch/FetchConsumer.cpp +++ b/dom/fetch/FetchConsumer.cpp @@ -339,11 +339,7 @@ FetchBodyConsumer<Derived>::Create(nsIGlobalObject* aGlobal, nsCOMPtr<nsIRunnable> r = new BeginConsumeBodyRunnable<Derived>(consumer); - if (workerPrivate) { - aRv = workerPrivate->DispatchToMainThread(r.forget()); - } else { - aRv = NS_DispatchToMainThread(r.forget()); - } + aRv = NS_DispatchToMainThread(r.forget()); if (NS_WARN_IF(aRv.Failed())) { return nullptr; @@ -655,9 +651,7 @@ FetchBodyConsumer<Derived>::ShutDownMainThreadConsuming() nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction( [self] () { self->ShutDownMainThreadConsuming(); }); - WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); - MOZ_ASSERT(workerPrivate); - workerPrivate->DispatchToMainThread(r.forget()); + MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r.forget())); return; } diff --git a/dom/fetch/FetchDriver.cpp b/dom/fetch/FetchDriver.cpp index aac79b829..6294b0dc5 100644 --- a/dom/fetch/FetchDriver.cpp +++ b/dom/fetch/FetchDriver.cpp @@ -77,9 +77,6 @@ FetchDriver::Fetch(FetchDriverObserver* aObserver) mObserver = aObserver; - Telemetry::Accumulate(Telemetry::SERVICE_WORKER_REQUEST_PASSTHROUGH, - mRequest->WasCreatedByFetchEvent()); - // FIXME(nsm): Deal with HSTS. MOZ_RELEASE_ASSERT(!mRequest->IsSynchronous(), @@ -906,11 +903,7 @@ FetchDriver::SetRequestHeaders(nsIHttpChannel* aChannel) const AutoTArray<InternalHeaders::Entry, 5> headers; mRequest->Headers()->GetEntries(headers); - bool hasAccept = false; for (uint32_t i = 0; i < headers.Length(); ++i) { - if (!hasAccept && headers[i].mName.EqualsLiteral("accept")) { - hasAccept = true; - } if (headers[i].mValue.IsEmpty()) { aChannel->SetEmptyRequestHeader(headers[i].mName); } else { @@ -918,12 +911,6 @@ FetchDriver::SetRequestHeaders(nsIHttpChannel* aChannel) const } } - if (!hasAccept) { - aChannel->SetRequestHeader(NS_LITERAL_CSTRING("accept"), - NS_LITERAL_CSTRING("*/*"), - false /* merge */); - } - if (mRequest->ForceOriginHeader()) { nsAutoString origin; if (NS_SUCCEEDED(nsContentUtils::GetUTFOrigin(mPrincipal, origin))) { diff --git a/dom/fetch/Headers.cpp b/dom/fetch/Headers.cpp index 1e1a46c62..ca5aa57a6 100644 --- a/dom/fetch/Headers.cpp +++ b/dom/fetch/Headers.cpp @@ -25,7 +25,7 @@ NS_INTERFACE_MAP_END // static already_AddRefed<Headers> Headers::Constructor(const GlobalObject& aGlobal, - const Optional<HeadersOrByteStringSequenceSequenceOrByteStringMozMap>& aInit, + const Optional<HeadersOrByteStringSequenceSequenceOrByteStringByteStringRecord>& aInit, ErrorResult& aRv) { RefPtr<InternalHeaders> ih = new InternalHeaders(); @@ -39,8 +39,8 @@ Headers::Constructor(const GlobalObject& aGlobal, ih->Fill(*aInit.Value().GetAsHeaders().mInternalHeaders, aRv); } else if (aInit.Value().IsByteStringSequenceSequence()) { ih->Fill(aInit.Value().GetAsByteStringSequenceSequence(), aRv); - } else if (aInit.Value().IsByteStringMozMap()) { - ih->Fill(aInit.Value().GetAsByteStringMozMap(), aRv); + } else if (aInit.Value().IsByteStringByteStringRecord()) { + ih->Fill(aInit.Value().GetAsByteStringByteStringRecord(), aRv); } if (aRv.Failed()) { @@ -53,7 +53,7 @@ Headers::Constructor(const GlobalObject& aGlobal, // static already_AddRefed<Headers> Headers::Constructor(const GlobalObject& aGlobal, - const OwningHeadersOrByteStringSequenceSequenceOrByteStringMozMap& aInit, + const OwningHeadersOrByteStringSequenceSequenceOrByteStringByteStringRecord& aInit, ErrorResult& aRv) { nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports()); @@ -62,7 +62,7 @@ Headers::Constructor(const GlobalObject& aGlobal, /* static */ already_AddRefed<Headers> Headers::Create(nsIGlobalObject* aGlobal, - const OwningHeadersOrByteStringSequenceSequenceOrByteStringMozMap& aInit, + const OwningHeadersOrByteStringSequenceSequenceOrByteStringByteStringRecord& aInit, ErrorResult& aRv) { RefPtr<InternalHeaders> ih = new InternalHeaders(); @@ -72,8 +72,8 @@ Headers::Create(nsIGlobalObject* aGlobal, ih->Fill(*(aInit.GetAsHeaders().get()->mInternalHeaders), aRv); } else if (aInit.IsByteStringSequenceSequence()) { ih->Fill(aInit.GetAsByteStringSequenceSequence(), aRv); - } else if (aInit.IsByteStringMozMap()) { - ih->Fill(aInit.GetAsByteStringMozMap(), aRv); + } else if (aInit.IsByteStringByteStringRecord()) { + ih->Fill(aInit.GetAsByteStringByteStringRecord(), aRv); } if (NS_WARN_IF(aRv.Failed())) { diff --git a/dom/fetch/Headers.h b/dom/fetch/Headers.h index b603dc836..1dd92f779 100644 --- a/dom/fetch/Headers.h +++ b/dom/fetch/Headers.h @@ -20,9 +20,9 @@ class ErrorResult; namespace dom { -template<typename T> class MozMap; -class HeadersOrByteStringSequenceSequenceOrByteStringMozMap; -class OwningHeadersOrByteStringSequenceSequenceOrByteStringMozMap; +template<typename K, typename V> class Record; +class HeadersOrByteStringSequenceSequenceOrByteStringByteStringRecord; +class OwningHeadersOrByteStringSequenceSequenceOrByteStringByteStringRecord; /** * This Headers class is only used to represent the content facing Headers @@ -57,17 +57,17 @@ public: static already_AddRefed<Headers> Constructor(const GlobalObject& aGlobal, - const Optional<HeadersOrByteStringSequenceSequenceOrByteStringMozMap>& aInit, + const Optional<HeadersOrByteStringSequenceSequenceOrByteStringByteStringRecord>& aInit, ErrorResult& aRv); static already_AddRefed<Headers> Constructor(const GlobalObject& aGlobal, - const OwningHeadersOrByteStringSequenceSequenceOrByteStringMozMap& aInit, + const OwningHeadersOrByteStringSequenceSequenceOrByteStringByteStringRecord& aInit, ErrorResult& aRv); static already_AddRefed<Headers> Create(nsIGlobalObject* aGlobalObject, - const OwningHeadersOrByteStringSequenceSequenceOrByteStringMozMap& aInit, + const OwningHeadersOrByteStringSequenceSequenceOrByteStringByteStringRecord& aInit, ErrorResult& aRv); void Append(const nsACString& aName, const nsACString& aValue, diff --git a/dom/fetch/InternalHeaders.cpp b/dom/fetch/InternalHeaders.cpp index 11585615e..f66221d42 100644 --- a/dom/fetch/InternalHeaders.cpp +++ b/dom/fetch/InternalHeaders.cpp @@ -314,12 +314,13 @@ InternalHeaders::Fill(const Sequence<Sequence<nsCString>>& aInit, ErrorResult& a } void -InternalHeaders::Fill(const MozMap<nsCString>& aInit, ErrorResult& aRv) +InternalHeaders::Fill(const Record<nsCString, nsCString>& aInit, ErrorResult& aRv) { - nsTArray<nsString> keys; - aInit.GetKeys(keys); - for (uint32_t i = 0; i < keys.Length() && !aRv.Failed(); ++i) { - Append(NS_ConvertUTF16toUTF8(keys[i]), aInit.Get(keys[i]), aRv); + for (auto& entry : aInit.Entries()) { + Append(entry.mKey, entry.mValue, aRv); + if (aRv.Failed()) { + return; + } } } diff --git a/dom/fetch/InternalHeaders.h b/dom/fetch/InternalHeaders.h index 9a6d6dae7..98046f0ef 100644 --- a/dom/fetch/InternalHeaders.h +++ b/dom/fetch/InternalHeaders.h @@ -20,7 +20,7 @@ class ErrorResult; namespace dom { -template<typename T> class MozMap; +template<typename K, typename V> class Record; class HeadersEntry; class InternalHeaders final @@ -113,7 +113,7 @@ public: void Fill(const InternalHeaders& aInit, ErrorResult& aRv); void Fill(const Sequence<Sequence<nsCString>>& aInit, ErrorResult& aRv); - void Fill(const MozMap<nsCString>& aInit, ErrorResult& aRv); + void Fill(const Record<nsCString, nsCString>& aInit, ErrorResult& aRv); bool HasOnlySimpleHeaders() const; diff --git a/dom/filesystem/Directory.cpp b/dom/filesystem/Directory.cpp index 59c78fb2c..5e8a4a745 100644 --- a/dom/filesystem/Directory.cpp +++ b/dom/filesystem/Directory.cpp @@ -36,7 +36,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Directory) tmp->mFileSystem->Traverse(cb); } NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(Directory) diff --git a/dom/gamepad/GamepadManager.cpp b/dom/gamepad/GamepadManager.cpp index dde71dd0a..e17829652 100644 --- a/dom/gamepad/GamepadManager.cpp +++ b/dom/gamepad/GamepadManager.cpp @@ -28,7 +28,6 @@ #include "nsIObserverService.h" #include "nsIServiceManager.h" #include "nsThreadUtils.h" -#include "VRManagerChild.h" #include "mozilla/Services.h" #include "mozilla/Unused.h" @@ -110,11 +109,6 @@ GamepadManager::StopMonitoring() } mChannelChildren.Clear(); mGamepads.Clear(); - -#if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_LINUX) - mVRChannelChild = gfx::VRManagerChild::Get(); - mVRChannelChild->SendControllerListenerRemoved(); -#endif } void @@ -211,11 +205,6 @@ uint32_t GamepadManager::GetGamepadIndexWithServiceType(uint32_t aIndex, newIndex = aIndex; break; } - case GamepadServiceType::VR: - { - newIndex = aIndex + VR_GAMEPAD_IDX_OFFSET; - break; - } default: MOZ_ASSERT(false); break; @@ -679,13 +668,6 @@ GamepadManager::ActorCreated(PBackgroundChild *aActor) MOZ_ASSERT(initedChild == child); child->SendGamepadListenerAdded(); mChannelChildren.AppendElement(child); - -#if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_LINUX) - // Construct VRManagerChannel and ask adding the connected - // VR controllers to GamepadManager - mVRChannelChild = gfx::VRManagerChild::Get(); - mVRChannelChild->SendControllerListenerAdded(); -#endif } //Override nsIIPCBackgroundChildCreateCallback diff --git a/dom/gamepad/GamepadManager.h b/dom/gamepad/GamepadManager.h index 1bb437d8f..a772221ca 100644 --- a/dom/gamepad/GamepadManager.h +++ b/dom/gamepad/GamepadManager.h @@ -16,9 +16,6 @@ class nsGlobalWindow; namespace mozilla { -namespace gfx { -class VRManagerChild; -} // namespace gfx namespace dom { class EventTarget; @@ -123,7 +120,6 @@ class GamepadManager final : public nsIObserver, // will be destroyed during the IPDL shutdown chain, so we // don't need to refcount it here. nsTArray<GamepadEventChannelChild *> mChannelChildren; - gfx::VRManagerChild* mVRChannelChild; private: @@ -138,8 +134,6 @@ class GamepadManager final : public nsIObserver, // Indicate that a window has received data from a gamepad. void SetWindowHasSeenGamepad(nsGlobalWindow* aWindow, uint32_t aIndex, bool aHasSeen = true); - // Our gamepad index has VR_GAMEPAD_IDX_OFFSET while GamepadChannelType - // is from VRManager. uint32_t GetGamepadIndexWithServiceType(uint32_t aIndex, GamepadServiceType aServiceType); // Gamepads connected to the system. Copies of these are handed out diff --git a/dom/gamepad/GamepadServiceTest.cpp b/dom/gamepad/GamepadServiceTest.cpp index a6fde58f0..89429b52a 100644 --- a/dom/gamepad/GamepadServiceTest.cpp +++ b/dom/gamepad/GamepadServiceTest.cpp @@ -35,7 +35,6 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(GamepadServiceTest) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(GamepadServiceTest, DOMEventTargetHelper) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END diff --git a/dom/gamepad/ipc/GamepadServiceType.h b/dom/gamepad/ipc/GamepadServiceType.h index acc0967d1..6200cdfa9 100644 --- a/dom/gamepad/ipc/GamepadServiceType.h +++ b/dom/gamepad/ipc/GamepadServiceType.h @@ -6,11 +6,9 @@ namespace mozilla{ namespace dom{ // Standard channel is used for managing gamepads that -// are from GamepadPlatformService. VR channel -// is for gamepads that are from VRManagerChild. +// are from GamepadPlatformService. enum class GamepadServiceType : uint16_t { Standard, - VR, NumGamepadServiceType }; diff --git a/dom/geolocation/nsGeolocation.cpp b/dom/geolocation/nsGeolocation.cpp index 2d84a3e11..846e7fff4 100644 --- a/dom/geolocation/nsGeolocation.cpp +++ b/dom/geolocation/nsGeolocation.cpp @@ -7,7 +7,6 @@ #include "nsXULAppAPI.h" #include "mozilla/dom/ContentChild.h" -#include "mozilla/Telemetry.h" #include "mozilla/UniquePtr.h" #include "nsGeolocation.h" @@ -70,7 +69,6 @@ class nsGeolocationRequest final GeoPositionCallback aCallback, GeoPositionErrorCallback aErrorCallback, UniquePtr<PositionOptions>&& aOptions, - uint8_t aProtocolType, bool aWatchPositionRequest = false, int32_t aWatchId = 0); @@ -119,7 +117,6 @@ class nsGeolocationRequest final int32_t mWatchId; bool mShutdown; nsCOMPtr<nsIContentPermissionRequester> mRequester; - uint8_t mProtocolType; }; static UniquePtr<PositionOptions> @@ -287,7 +284,6 @@ nsGeolocationRequest::nsGeolocationRequest(Geolocation* aLocator, GeoPositionCallback aCallback, GeoPositionErrorCallback aErrorCallback, UniquePtr<PositionOptions>&& aOptions, - uint8_t aProtocolType, bool aWatchPositionRequest, int32_t aWatchId) : mIsWatchPositionRequest(aWatchPositionRequest), @@ -296,8 +292,7 @@ nsGeolocationRequest::nsGeolocationRequest(Geolocation* aLocator, mOptions(Move(aOptions)), mLocator(aLocator), mWatchId(aWatchId), - mShutdown(false), - mProtocolType(aProtocolType) + mShutdown(false) { if (nsCOMPtr<nsPIDOMWindowInner> win = do_QueryReferent(mLocator->GetOwner())) { @@ -382,13 +377,6 @@ nsGeolocationRequest::GetElement(nsIDOMElement * *aRequestingElement) NS_IMETHODIMP nsGeolocationRequest::Cancel() { - if (mRequester) { - // Record the number of denied requests for regular web content. - // This method is only called when the user explicitly denies the request, - // and is not called when the page is simply unloaded, or similar. - Telemetry::Accumulate(Telemetry::GEOLOCATION_REQUEST_GRANTED, mProtocolType); - } - if (mLocator->ClearPendingRequest(this)) { return NS_OK; } @@ -402,27 +390,6 @@ nsGeolocationRequest::Allow(JS::HandleValue aChoices) { MOZ_ASSERT(aChoices.isUndefined()); - if (mRequester) { - // Record the number of granted requests for regular web content. - Telemetry::Accumulate(Telemetry::GEOLOCATION_REQUEST_GRANTED, mProtocolType + 10); - - // Record whether a location callback is fulfilled while the owner window - // is not visible. - bool isVisible = false; - nsCOMPtr<nsPIDOMWindowInner> window = mLocator->GetParentObject(); - - if (window) { - nsCOMPtr<nsIDocument> doc = window->GetDoc(); - isVisible = doc && !doc->Hidden(); - } - - if (IsWatch()) { - mozilla::Telemetry::Accumulate(mozilla::Telemetry::GEOLOCATION_WATCHPOSITION_VISIBLE, isVisible); - } else { - mozilla::Telemetry::Accumulate(mozilla::Telemetry::GEOLOCATION_GETCURRENTPOSITION_VISIBLE, isVisible); - } - } - if (mLocator->ClearPendingRequest(this)) { return NS_OK; } @@ -977,8 +944,7 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Geolocation, mPendingRequests) Geolocation::Geolocation() -: mProtocolType(ProtocolType::OTHER) -, mLastWatchId(0) +: mLastWatchId(0) { } @@ -1010,23 +976,6 @@ Geolocation::Init(nsPIDOMWindowInner* aContentDom) nsCOMPtr<nsIURI> uri; nsresult rv = mPrincipal->GetURI(getter_AddRefs(uri)); NS_ENSURE_SUCCESS(rv, rv); - - if (uri) { - bool isHttp; - rv = uri->SchemeIs("http", &isHttp); - NS_ENSURE_SUCCESS(rv, rv); - - bool isHttps; - rv = uri->SchemeIs("https", &isHttps); - NS_ENSURE_SUCCESS(rv, rv); - - // Store the protocol to send via telemetry later. - if (isHttp) { - mProtocolType = ProtocolType::HTTP; - } else if (isHttps) { - mProtocolType = ProtocolType::HTTPS; - } - } } // If no aContentDom was passed into us, we are being used @@ -1110,7 +1059,6 @@ Geolocation::Update(nsIDOMGeoPosition *aSomewhere) if (coords) { double accuracy = -1; coords->GetAccuracy(&accuracy); - mozilla::Telemetry::Accumulate(mozilla::Telemetry::GEOLOCATION_ACCURACY_EXPONENTIAL, accuracy); } } @@ -1135,8 +1083,6 @@ Geolocation::NotifyError(uint16_t aErrorCode) return NS_OK; } - mozilla::Telemetry::Accumulate(mozilla::Telemetry::GEOLOCATION_ERROR, true); - for (uint32_t i = mPendingCallbacks.Length(); i > 0; i--) { mPendingCallbacks[i-1]->NotifyErrorAndShutdown(aErrorCode); //NotifyErrorAndShutdown() removes the request from the array @@ -1214,13 +1160,9 @@ Geolocation::GetCurrentPosition(GeoPositionCallback callback, // After this we hand over ownership of options to our nsGeolocationRequest. - // Count the number of requests per protocol/scheme. - Telemetry::Accumulate(Telemetry::GEOLOCATION_GETCURRENTPOSITION_SECURE_ORIGIN, - static_cast<uint8_t>(mProtocolType)); - RefPtr<nsGeolocationRequest> request = new nsGeolocationRequest(this, Move(callback), Move(errorCallback), - Move(options), static_cast<uint8_t>(mProtocolType), + Move(options), false); if (!sGeoEnabled) { @@ -1292,17 +1234,13 @@ Geolocation::WatchPosition(GeoPositionCallback aCallback, return NS_ERROR_NOT_AVAILABLE; } - // Count the number of requests per protocol/scheme. - Telemetry::Accumulate(Telemetry::GEOLOCATION_WATCHPOSITION_SECURE_ORIGIN, - static_cast<uint8_t>(mProtocolType)); - // The watch ID: *aRv = mLastWatchId++; RefPtr<nsGeolocationRequest> request = new nsGeolocationRequest(this, Move(aCallback), Move(aErrorCallback), Move(aOptions), - static_cast<uint8_t>(mProtocolType), true, *aRv); + true, *aRv); if (!sGeoEnabled) { nsCOMPtr<nsIRunnable> ev = new RequestAllowEvent(false, request); diff --git a/dom/geolocation/nsGeolocation.h b/dom/geolocation/nsGeolocation.h index 0bc527e34..0bcc587e4 100644 --- a/dom/geolocation/nsGeolocation.h +++ b/dom/geolocation/nsGeolocation.h @@ -202,12 +202,6 @@ private: // where the content was loaded from nsCOMPtr<nsIPrincipal> mPrincipal; - // the protocols we want to measure - enum class ProtocolType: uint8_t { OTHER, HTTP, HTTPS }; - - // the protocol used to load the content - ProtocolType mProtocolType; - // owning back pointer. RefPtr<nsGeolocationService> mService; diff --git a/dom/html/HTMLCanvasElement.cpp b/dom/html/HTMLCanvasElement.cpp index 88b41bce0..a01795d9e 100644 --- a/dom/html/HTMLCanvasElement.cpp +++ b/dom/html/HTMLCanvasElement.cpp @@ -42,7 +42,6 @@ #include "nsRefreshDriver.h" #include "nsStreamUtils.h" #include "ActiveLayerTracker.h" -#include "VRManagerChild.h" #include "WebGL1Context.h" #include "WebGL2Context.h" @@ -358,7 +357,6 @@ NS_IMPL_ISUPPORTS(HTMLCanvasElementObserver, nsIObserver) HTMLCanvasElement::HTMLCanvasElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo) : nsGenericHTMLElement(aNodeInfo), mResetLayer(true) , - mVRPresentationActive(false), mWriteOnly(false) {} @@ -1002,7 +1000,7 @@ HTMLCanvasElement::GetSize() } bool -HTMLCanvasElement::IsWriteOnly() +HTMLCanvasElement::IsWriteOnly() const { return mWriteOnly; } @@ -1111,7 +1109,7 @@ HTMLCanvasElement::GetCanvasLayer(nsDisplayListBuilder* aBuilder, static uint8_t sOffscreenCanvasLayerUserDataDummy = 0; if (mCurrentContext) { - return mCurrentContext->GetCanvasLayer(aBuilder, aOldLayer, aManager, mVRPresentationActive); + return mCurrentContext->GetCanvasLayer(aBuilder, aOldLayer, aManager); } if (mOffscreenCanvas) { @@ -1441,42 +1439,5 @@ HTMLCanvasElement::InvalidateFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRende element->InvalidateCanvasContent(nullptr); } -void -HTMLCanvasElement::StartVRPresentation() -{ - WebGLContext* webgl = static_cast<WebGLContext*>(GetContextAtIndex(0)); - if (!webgl) { - return; - } - - if (!webgl->StartVRPresentation()) { - return; - } - - mVRPresentationActive = true; -} - -void -HTMLCanvasElement::StopVRPresentation() -{ - mVRPresentationActive = false; -} - -already_AddRefed<layers::SharedSurfaceTextureClient> -HTMLCanvasElement::GetVRFrame() -{ - if (GetCurrentContextType() != CanvasContextType::WebGL1 && - GetCurrentContextType() != CanvasContextType::WebGL2) { - return nullptr; - } - - WebGLContext* webgl = static_cast<WebGLContext*>(GetContextAtIndex(0)); - if (!webgl) { - return nullptr; - } - - return webgl->GetVRFrame(); -} - } // namespace dom } // namespace mozilla diff --git a/dom/html/HTMLCanvasElement.h b/dom/html/HTMLCanvasElement.h index 81c141d3c..e77db6ff1 100644 --- a/dom/html/HTMLCanvasElement.h +++ b/dom/html/HTMLCanvasElement.h @@ -224,9 +224,9 @@ public: nsIntSize GetSize(); /** - * Determine whether the canvas is write-only. + * Determine whether the canvas is write-only (tainted). */ - bool IsWriteOnly(); + bool IsWriteOnly() const; /** * Force the canvas to be write-only. @@ -350,10 +350,6 @@ public: static void SetAttrFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRenderer); static void InvalidateFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRenderer); - void StartVRPresentation(); - void StopVRPresentation(); - already_AddRefed<layers::SharedSurfaceTextureClient> GetVRFrame(); - protected: virtual ~HTMLCanvasElement(); diff --git a/dom/html/HTMLFormControlsCollection.cpp b/dom/html/HTMLFormControlsCollection.cpp index d91a6b5de..77fafae99 100644 --- a/dom/html/HTMLFormControlsCollection.cpp +++ b/dom/html/HTMLFormControlsCollection.cpp @@ -134,7 +134,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(HTMLFormControlsCollection) NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(HTMLFormControlsCollection) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNameLookupTable) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(HTMLFormControlsCollection) NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER diff --git a/dom/html/HTMLFormElement.cpp b/dom/html/HTMLFormElement.cpp index 5164391f8..6bea19a2b 100644 --- a/dom/html/HTMLFormElement.cpp +++ b/dom/html/HTMLFormElement.cpp @@ -38,7 +38,6 @@ // form submission #include "HTMLFormSubmissionConstants.h" #include "mozilla/dom/FormData.h" -#include "mozilla/Telemetry.h" #include "nsIFormSubmitObserver.h" #include "nsIObserverService.h" #include "nsICategoryManager.h" @@ -52,7 +51,6 @@ #include "nsIWebProgress.h" #include "nsIDocShell.h" #include "nsIPrompt.h" -#include "nsISecurityUITelemetry.h" #include "nsIStringBundle.h" // radio buttons @@ -955,15 +953,6 @@ HTMLFormElement::DoSecureToInsecureSubmitCheck(nsIURI* aActionURL, return rv; } *aCancelSubmit = (buttonPressed == 1); - uint32_t telemetryBucket = - nsISecurityUITelemetry::WARNING_CONFIRM_POST_TO_INSECURE_FROM_SECURE; - mozilla::Telemetry::Accumulate(mozilla::Telemetry::SECURITY_UI, - telemetryBucket); - if (!*aCancelSubmit) { - // The user opted to continue, so note that in the next telemetry bucket. - mozilla::Telemetry::Accumulate(mozilla::Telemetry::SECURITY_UI, - telemetryBucket + 1); - } return NS_OK; } diff --git a/dom/html/HTMLImageElement.cpp b/dom/html/HTMLImageElement.cpp index 4b2e7a07b..fab1cdef4 100644 --- a/dom/html/HTMLImageElement.cpp +++ b/dom/html/HTMLImageElement.cpp @@ -1345,8 +1345,6 @@ HTMLImageElement::FlushUseCounters() nsCOMPtr<imgIContainer> container; request->GetImage(getter_AddRefs(container)); - - static_cast<image::Image*>(container.get())->ReportUseCounters(); } } // namespace dom diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp index e9086933b..0b879bb9b 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -24,7 +24,6 @@ #include "nsIPhonetic.h" #include "HTMLFormSubmissionConstants.h" -#include "mozilla/Telemetry.h" #include "nsIControllers.h" #include "nsIStringBundle.h" #include "nsFocusManager.h" @@ -1275,10 +1274,6 @@ HTMLInputElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName, container->RadioRequiredWillChange(name, !!aValue); } } - - if (aName == nsGkAtoms::webkitdirectory) { - Telemetry::Accumulate(Telemetry::WEBKIT_DIRECTORY_USED, true); - } } return nsGenericHTMLFormElementWithState::BeforeSetAttr(aNameSpaceID, aName, @@ -4989,10 +4984,6 @@ HTMLInputElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, true); dispatcher->PostDOMEvent(); } - -#ifdef EARLY_BETA_OR_EARLIER - Telemetry::Accumulate(Telemetry::PWMGR_PASSWORD_INPUT_IN_FORM, !!mForm); -#endif } return rv; @@ -8863,7 +8854,6 @@ HTMLInputElement::UpdateEntries(const nsTArray<OwningFileOrDirectory>& aFilesOrD void HTMLInputElement::GetWebkitEntries(nsTArray<RefPtr<FileSystemEntry>>& aSequence) { - Telemetry::Accumulate(Telemetry::BLINK_FILESYSTEM_USED, true); aSequence.AppendElements(mEntries); } diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp index 3954e6208..050d1ac69 100644 --- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -92,7 +92,6 @@ #include "mozilla/dom/VideoTrackList.h" #include "mozilla/dom/TextTrack.h" #include "nsIContentPolicy.h" -#include "mozilla/Telemetry.h" #include "DecoderDoctorDiagnostics.h" #include "DecoderTraits.h" #include "MediaContentType.h" @@ -1038,14 +1037,6 @@ void HTMLMediaElement::ShutdownDecoder() void HTMLMediaElement::AbortExistingLoads() { -#ifdef MOZ_EME - // If there is no existing decoder then we don't have anything to - // report. This prevents reporting the initial load from an - // empty video element as a failed EME load. - if (mDecoder) { - ReportEMETelemetry(); - } -#endif // Abort any already-running instance of the resource selection algorithm. mLoadWaitStatus = NOT_WAITING; @@ -1901,8 +1892,6 @@ NS_IMETHODIMP HTMLMediaElement::GetCurrentTime(double* aCurrentTime) void HTMLMediaElement::FastSeek(double aTime, ErrorResult& aRv) { - LOG(LogLevel::Debug, ("Reporting telemetry VIDEO_FASTSEEK_USED")); - Telemetry::Accumulate(Telemetry::VIDEO_FASTSEEK_USED, 1); RefPtr<Promise> tobeDropped = Seek(aTime, SeekTarget::PrevSyncPoint, aRv); } @@ -3156,10 +3145,6 @@ HTMLMediaElement::~HTMLMediaElement() if (mProgressTimer) { StopProgress(); } - if (mVideoDecodeSuspendTimer) { - mVideoDecodeSuspendTimer->Cancel(); - mVideoDecodeSuspendTimer = nullptr; - } if (mSrcStream) { EndSrcMediaStreamPlayback(); } @@ -3650,228 +3635,6 @@ nsresult HTMLMediaElement::BindToTree(nsIDocument* aDocument, nsIContent* aParen return rv; } -/* static */ -void HTMLMediaElement::VideoDecodeSuspendTimerCallback(nsITimer* aTimer, void* aClosure) -{ - MOZ_ASSERT(NS_IsMainThread()); - auto element = static_cast<HTMLMediaElement*>(aClosure); - element->mVideoDecodeSuspendTime.Start(); - element->mVideoDecodeSuspendTimer = nullptr; -} - -void HTMLMediaElement::HiddenVideoStart() -{ - MOZ_ASSERT(NS_IsMainThread()); - mHiddenPlayTime.Start(); - if (mVideoDecodeSuspendTimer) { - // Already started, just keep it running. - return; - } - mVideoDecodeSuspendTimer = do_CreateInstance("@mozilla.org/timer;1"); - mVideoDecodeSuspendTimer->InitWithNamedFuncCallback( - VideoDecodeSuspendTimerCallback, this, - MediaPrefs::MDSMSuspendBackgroundVideoDelay(), nsITimer::TYPE_ONE_SHOT, - "HTMLMediaElement::VideoDecodeSuspendTimerCallback"); -} - -void HTMLMediaElement::HiddenVideoStop() -{ - MOZ_ASSERT(NS_IsMainThread()); - mHiddenPlayTime.Pause(); - mVideoDecodeSuspendTime.Pause(); - if (!mVideoDecodeSuspendTimer) { - return; - } - mVideoDecodeSuspendTimer->Cancel(); - mVideoDecodeSuspendTimer = nullptr; -} - -#ifdef MOZ_EME -void -HTMLMediaElement::ReportEMETelemetry() -{ - // Report telemetry for EME videos when a page is unloaded. - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - if (mIsEncrypted && Preferences::GetBool("media.eme.enabled")) { - Telemetry::Accumulate(Telemetry::VIDEO_EME_PLAY_SUCCESS, mLoadedDataFired); - LOG(LogLevel::Debug, ("%p VIDEO_EME_PLAY_SUCCESS = %s", - this, mLoadedDataFired ? "true" : "false")); - } -} -#endif - -void -HTMLMediaElement::ReportTelemetry() -{ - // Report telemetry for videos when a page is unloaded. We - // want to know data on what state the video is at when - // the user has exited. - enum UnloadedState { - ENDED = 0, - PAUSED = 1, - STALLED = 2, - SEEKING = 3, - OTHER = 4 - }; - - UnloadedState state = OTHER; - if (Seeking()) { - state = SEEKING; - } - else if (Ended()) { - state = ENDED; - } - else if (Paused()) { - state = PAUSED; - } - else { - // For buffering we check if the current playback position is at the end - // of a buffered range, within a margin of error. We also consider to be - // buffering if the last frame status was buffering and the ready state is - // HAVE_CURRENT_DATA to account for times where we are in a buffering state - // regardless of what actual data we have buffered. - bool stalled = false; - RefPtr<TimeRanges> ranges = Buffered(); - const double errorMargin = 0.05; - double t = CurrentTime(); - TimeRanges::index_type index = ranges->Find(t, errorMargin); - ErrorResult ignore; - stalled = index != TimeRanges::NoIndex && - (ranges->End(index, ignore) - t) < errorMargin; - stalled |= mDecoder && NextFrameStatus() == MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_BUFFERING && - mReadyState == HTMLMediaElement::HAVE_CURRENT_DATA; - if (stalled) { - state = STALLED; - } - } - - Telemetry::Accumulate(Telemetry::VIDEO_UNLOAD_STATE, state); - LOG(LogLevel::Debug, ("%p VIDEO_UNLOAD_STATE = %d", this, state)); - - FrameStatisticsData data; - - if (HTMLVideoElement* vid = HTMLVideoElement::FromContentOrNull(this)) { - FrameStatistics* stats = vid->GetFrameStatistics(); - if (stats) { - data = stats->GetFrameStatisticsData(); - if (data.mParsedFrames) { - MOZ_ASSERT(data.mDroppedFrames <= data.mParsedFrames); - // Dropped frames <= total frames, so 'percentage' cannot be higher than - // 100 and therefore can fit in a uint32_t (that Telemetry takes). - uint32_t percentage = 100 * data.mDroppedFrames / data.mParsedFrames; - LOG(LogLevel::Debug, - ("Reporting telemetry DROPPED_FRAMES_IN_VIDEO_PLAYBACK")); - Telemetry::Accumulate(Telemetry::VIDEO_DROPPED_FRAMES_PROPORTION, - percentage); - } - } - } - - if (mMediaInfo.HasVideo() && - mMediaInfo.mVideo.mImage.height > 0) { - // We have a valid video. - double playTime = mPlayTime.Total(); - double hiddenPlayTime = mHiddenPlayTime.Total(); - double videoDecodeSuspendTime = mVideoDecodeSuspendTime.Total(); - - Telemetry::Accumulate(Telemetry::VIDEO_PLAY_TIME_MS, SECONDS_TO_MS(playTime)); - LOG(LogLevel::Debug, ("%p VIDEO_PLAY_TIME_MS = %f", this, playTime)); - - Telemetry::Accumulate(Telemetry::VIDEO_HIDDEN_PLAY_TIME_MS, SECONDS_TO_MS(hiddenPlayTime)); - LOG(LogLevel::Debug, ("%p VIDEO_HIDDEN_PLAY_TIME_MS = %f", this, hiddenPlayTime)); - - if (playTime > 0.0) { - // We have actually played something -> Report some valid-video telemetry. - - // Keyed by audio+video or video alone, and by a resolution range. - nsCString key(mMediaInfo.HasAudio() ? "AV," : "V,"); - static const struct { int32_t mH; const char* mRes; } sResolutions[] = { - { 240, "0<h<=240" }, - { 480, "240<h<=480" }, - { 576, "480<h<=576" }, - { 720, "576<h<=720" }, - { 1080, "720<h<=1080" }, - { 2160, "1080<h<=2160" } - }; - const char* resolution = "h>2160"; - int32_t height = mMediaInfo.mVideo.mImage.height; - for (const auto& res : sResolutions) { - if (height <= res.mH) { - resolution = res.mRes; - break; - } - } - key.AppendASCII(resolution); - - uint32_t hiddenPercentage = uint32_t(hiddenPlayTime / playTime * 100.0 + 0.5); - Telemetry::Accumulate(Telemetry::VIDEO_HIDDEN_PLAY_TIME_PERCENTAGE, - key, - hiddenPercentage); - // Also accumulate all percentages in an "All" key. - Telemetry::Accumulate(Telemetry::VIDEO_HIDDEN_PLAY_TIME_PERCENTAGE, - NS_LITERAL_CSTRING("All"), - hiddenPercentage); - LOG(LogLevel::Debug, ("%p VIDEO_HIDDEN_PLAY_TIME_PERCENTAGE = %u, keys: '%s' and 'All'", - this, hiddenPercentage, key.get())); - - uint32_t videoDecodeSuspendPercentage = - uint32_t(videoDecodeSuspendTime / playTime * 100.0 + 0.5); - Telemetry::Accumulate(Telemetry::VIDEO_INFERRED_DECODE_SUSPEND_PERCENTAGE, - key, - videoDecodeSuspendPercentage); - Telemetry::Accumulate(Telemetry::VIDEO_INFERRED_DECODE_SUSPEND_PERCENTAGE, - NS_LITERAL_CSTRING("All"), - videoDecodeSuspendPercentage); - LOG(LogLevel::Debug, ("%p VIDEO_INFERRED_DECODE_SUSPEND_PERCENTAGE = %u, keys: '%s' and 'All'", - this, videoDecodeSuspendPercentage, key.get())); - - if (data.mInterKeyframeCount != 0) { - uint32_t average_ms = - uint32_t(std::min<uint64_t>(double(data.mInterKeyframeSum_us) - / double(data.mInterKeyframeCount) - / 1000.0 - + 0.5, - UINT32_MAX)); - Telemetry::Accumulate(Telemetry::VIDEO_INTER_KEYFRAME_AVERAGE_MS, - key, - average_ms); - Telemetry::Accumulate(Telemetry::VIDEO_INTER_KEYFRAME_AVERAGE_MS, - NS_LITERAL_CSTRING("All"), - average_ms); - LOG(LogLevel::Debug, ("%p VIDEO_INTER_KEYFRAME_AVERAGE_MS = %u, keys: '%s' and 'All'", - this, average_ms, key.get())); - - uint32_t max_ms = - uint32_t(std::min<uint64_t>((data.mInterKeyFrameMax_us + 500) / 1000, - UINT32_MAX)); - Telemetry::Accumulate(Telemetry::VIDEO_INTER_KEYFRAME_MAX_MS, - key, - max_ms); - Telemetry::Accumulate(Telemetry::VIDEO_INTER_KEYFRAME_MAX_MS, - NS_LITERAL_CSTRING("All"), - max_ms); - LOG(LogLevel::Debug, ("%p VIDEO_INTER_KEYFRAME_MAX_MS = %u, keys: '%s' and 'All'", - this, max_ms, key.get())); - } else { - // Here, we have played *some* of the video, but didn't get more than 1 - // keyframe. Report '0' if we have played for longer than the video- - // decode-suspend delay (showing recovery would be difficult). - uint32_t suspendDelay_ms = MediaPrefs::MDSMSuspendBackgroundVideoDelay(); - if (uint32_t(playTime * 1000.0) > suspendDelay_ms) { - Telemetry::Accumulate(Telemetry::VIDEO_INTER_KEYFRAME_MAX_MS, - key, - 0); - Telemetry::Accumulate(Telemetry::VIDEO_INTER_KEYFRAME_MAX_MS, - NS_LITERAL_CSTRING("All"), - 0); - LOG(LogLevel::Debug, ("%p VIDEO_INTER_KEYFRAME_MAX_MS = 0 (only 1 keyframe), keys: '%s' and 'All'", - this, key.get())); - } - } - } - } -} - void HTMLMediaElement::UnbindFromTree(bool aDeep, bool aNullParent) { @@ -5351,19 +5114,6 @@ nsresult HTMLMediaElement::DispatchAsyncEvent(const nsAString& aName) nsCOMPtr<nsIRunnable> event = new nsAsyncEventRunner(aName, this); NS_DispatchToMainThread(event); - if ((aName.EqualsLiteral("play") || aName.EqualsLiteral("playing"))) { - mPlayTime.Start(); - if (IsHidden()) { - HiddenVideoStart(); - } - } else if (aName.EqualsLiteral("waiting")) { - mPlayTime.Pause(); - HiddenVideoStop(); - } else if (aName.EqualsLiteral("pause")) { - mPlayTime.Pause(); - HiddenVideoStop(); - } - return NS_OK; } @@ -5489,11 +5239,6 @@ void HTMLMediaElement::SuspendOrResumeElement(bool aPauseElement, bool aSuspendE UpdateSrcMediaStreamPlaying(); UpdateAudioChannelPlayingState(); if (aPauseElement) { - ReportTelemetry(); -#ifdef MOZ_EME - ReportEMETelemetry(); -#endif - #ifdef MOZ_EME // For EME content, we may force destruction of the CDM client (and CDM // instance if this is the last client for that CDM instance) and @@ -5545,13 +5290,6 @@ bool HTMLMediaElement::IsBeingDestroyed() void HTMLMediaElement::NotifyOwnerDocumentActivityChanged() { bool visible = !IsHidden(); - if (visible) { - // Visible -> Just pause hidden play time (no-op if already paused). - HiddenVideoStop(); - } else if (mPlayTime.IsStarted()) { - // Not visible, play time is running -> Start hidden play time if needed. - HiddenVideoStart(); - } if (mDecoder && !IsBeingDestroyed()) { mDecoder->NotifyOwnerActivityChanged(visible); @@ -6327,18 +6065,10 @@ HTMLMediaElement::OnVisibilityChange(Visibility aNewVisibility) break; } case Visibility::APPROXIMATELY_NONVISIBLE: { - if (mPlayTime.IsStarted()) { - // Not visible, play time is running -> Start hidden play time if needed. - HiddenVideoStart(); - } - mDecoder->NotifyOwnerActivityChanged(false); break; } case Visibility::APPROXIMATELY_VISIBLE: { - // Visible -> Just pause hidden play time (no-op if already paused). - HiddenVideoStop(); - mDecoder->NotifyOwnerActivityChanged(true); break; } @@ -6860,97 +6590,6 @@ HTMLMediaElement::MarkAsContentSource(CallerAPI aAPI) { const bool isVisible = mVisibilityState != Visibility::APPROXIMATELY_NONVISIBLE; - if (isVisible) { - // 0 = ALL_VISIBLE - Telemetry::Accumulate(Telemetry::VIDEO_AS_CONTENT_SOURCE, 0); - } else { - // 1 = ALL_INVISIBLE - Telemetry::Accumulate(Telemetry::VIDEO_AS_CONTENT_SOURCE, 1); - - if (IsInUncomposedDoc()) { - // 0 = ALL_IN_TREE - Telemetry::Accumulate(Telemetry::VIDEO_AS_CONTENT_SOURCE_IN_TREE_OR_NOT, 0); - } else { - // 1 = ALL_NOT_IN_TREE - Telemetry::Accumulate(Telemetry::VIDEO_AS_CONTENT_SOURCE_IN_TREE_OR_NOT, 1); - } - } - - switch (aAPI) { - case CallerAPI::DRAW_IMAGE: { - if (isVisible) { - // 2 = drawImage_VISIBLE - Telemetry::Accumulate(Telemetry::VIDEO_AS_CONTENT_SOURCE, 2); - } else { - // 3 = drawImage_INVISIBLE - Telemetry::Accumulate(Telemetry::VIDEO_AS_CONTENT_SOURCE, 3); - - if (IsInUncomposedDoc()) { - // 2 = drawImage_IN_TREE - Telemetry::Accumulate(Telemetry::VIDEO_AS_CONTENT_SOURCE_IN_TREE_OR_NOT, 2); - } else { - // 3 = drawImage_NOT_IN_TREE - Telemetry::Accumulate(Telemetry::VIDEO_AS_CONTENT_SOURCE_IN_TREE_OR_NOT, 3); - } - } - break; - } - case CallerAPI::CREATE_PATTERN: { - if (isVisible) { - // 4 = createPattern_VISIBLE - Telemetry::Accumulate(Telemetry::VIDEO_AS_CONTENT_SOURCE, 4); - } else { - // 5 = createPattern_INVISIBLE - Telemetry::Accumulate(Telemetry::VIDEO_AS_CONTENT_SOURCE, 5); - - if (IsInUncomposedDoc()) { - // 4 = createPattern_IN_TREE - Telemetry::Accumulate(Telemetry::VIDEO_AS_CONTENT_SOURCE_IN_TREE_OR_NOT, 4); - } else { - // 5 = createPattern_NOT_IN_TREE - Telemetry::Accumulate(Telemetry::VIDEO_AS_CONTENT_SOURCE_IN_TREE_OR_NOT, 5); - } - } - break; - } - case CallerAPI::CREATE_IMAGEBITMAP: { - if (isVisible) { - // 6 = createImageBitmap_VISIBLE - Telemetry::Accumulate(Telemetry::VIDEO_AS_CONTENT_SOURCE, 6); - } else { - // 7 = createImageBitmap_INVISIBLE - Telemetry::Accumulate(Telemetry::VIDEO_AS_CONTENT_SOURCE, 7); - - if (IsInUncomposedDoc()) { - // 6 = createImageBitmap_IN_TREE - Telemetry::Accumulate(Telemetry::VIDEO_AS_CONTENT_SOURCE_IN_TREE_OR_NOT, 6); - } else { - // 7 = createImageBitmap_NOT_IN_TREE - Telemetry::Accumulate(Telemetry::VIDEO_AS_CONTENT_SOURCE_IN_TREE_OR_NOT, 7); - } - } - break; - } - case CallerAPI::CAPTURE_STREAM: { - if (isVisible) { - // 8 = captureStream_VISIBLE - Telemetry::Accumulate(Telemetry::VIDEO_AS_CONTENT_SOURCE, 8); - } else { - // 9 = captureStream_INVISIBLE - Telemetry::Accumulate(Telemetry::VIDEO_AS_CONTENT_SOURCE, 9); - - if (IsInUncomposedDoc()) { - // 8 = captureStream_IN_TREE - Telemetry::Accumulate(Telemetry::VIDEO_AS_CONTENT_SOURCE_IN_TREE_OR_NOT, 8); - } else { - // 9 = captureStream_NOT_IN_TREE - Telemetry::Accumulate(Telemetry::VIDEO_AS_CONTENT_SOURCE_IN_TREE_OR_NOT, 9); - } - } - break; - } - } - LOG(LogLevel::Debug, ("%p Log VIDEO_AS_CONTENT_SOURCE: visibility = %u, API: '%d' and 'All'", this, isVisible, aAPI)); diff --git a/dom/html/HTMLMediaElement.h b/dom/html/HTMLMediaElement.h index af944a318..899e8449a 100644 --- a/dom/html/HTMLMediaElement.h +++ b/dom/html/HTMLMediaElement.h @@ -1195,29 +1195,6 @@ protected: return isPaused; } - /** - * Video has been playing while hidden and, if feature was enabled, would - * trigger suspending decoder. - * Used to track hidden-video-decode-suspend telemetry. - */ - static void VideoDecodeSuspendTimerCallback(nsITimer* aTimer, void* aClosure); - /** - * Video is now both: playing and hidden. - * Used to track hidden-video telemetry. - */ - void HiddenVideoStart(); - /** - * Video is not playing anymore and/or has become visible. - * Used to track hidden-video telemetry. - */ - void HiddenVideoStop(); - -#ifdef MOZ_EME - void ReportEMETelemetry(); -#endif - - void ReportTelemetry(); - // Check the permissions for audiochannel. bool CheckAudioChannelPermissions(const nsAString& aType); @@ -1484,9 +1461,6 @@ protected: // Timer used for updating progress events. nsCOMPtr<nsITimer> mProgressTimer; - // Timer used to simulate video-suspend. - nsCOMPtr<nsITimer> mVideoDecodeSuspendTimer; - #ifdef MOZ_EME // Encrypted Media Extension media keys. RefPtr<MediaKeys> mMediaKeys; @@ -1688,65 +1662,7 @@ protected: // before attaching to the DOM tree. bool mUnboundFromTree = false; -public: - // Helper class to measure times for MSE telemetry stats - class TimeDurationAccumulator - { - public: - TimeDurationAccumulator() - : mCount(0) - {} - void Start() - { - if (IsStarted()) { - return; - } - mStartTime = TimeStamp::Now(); - } - void Pause() - { - if (!IsStarted()) { - return; - } - mSum += (TimeStamp::Now() - mStartTime); - mCount++; - mStartTime = TimeStamp(); - } - bool IsStarted() const - { - return !mStartTime.IsNull(); - } - double Total() const - { - if (!IsStarted()) { - return mSum.ToSeconds(); - } - // Add current running time until now, but keep it running. - return (mSum + (TimeStamp::Now() - mStartTime)).ToSeconds(); - } - uint32_t Count() const - { - if (!IsStarted()) { - return mCount; - } - // Count current run in this report, without increasing the stored count. - return mCount + 1; - } - private: - TimeStamp mStartTime; - TimeDuration mSum; - uint32_t mCount; - }; private: - // Total time a video has spent playing. - TimeDurationAccumulator mPlayTime; - - // Total time a video has spent playing while hidden. - TimeDurationAccumulator mHiddenPlayTime; - - // Total time a video has (or would have) spent in video-decode-suspend mode. - TimeDurationAccumulator mVideoDecodeSuspendTime; - // Indicates if user has interacted with the element. // Used to block autoplay when disabled. bool mHasUserInteraction; diff --git a/dom/html/HTMLOptionsCollection.cpp b/dom/html/HTMLOptionsCollection.cpp index 294493c0c..67de97fc4 100644 --- a/dom/html/HTMLOptionsCollection.cpp +++ b/dom/html/HTMLOptionsCollection.cpp @@ -35,23 +35,8 @@ namespace mozilla { namespace dom { HTMLOptionsCollection::HTMLOptionsCollection(HTMLSelectElement* aSelect) -{ - // Do not maintain a reference counted reference. When - // the select goes away, it will let us know. - mSelect = aSelect; -} - -HTMLOptionsCollection::~HTMLOptionsCollection() -{ - DropReference(); -} - -void -HTMLOptionsCollection::DropReference() -{ - // Drop our (non ref-counted) reference - mSelect = nullptr; -} + : mSelect(aSelect) +{} nsresult HTMLOptionsCollection::GetOptionIndex(Element* aOption, @@ -88,7 +73,9 @@ HTMLOptionsCollection::GetOptionIndex(Element* aOption, } -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(HTMLOptionsCollection, mElements) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(HTMLOptionsCollection, + mElements, + mSelect) // nsISupports @@ -124,10 +111,6 @@ HTMLOptionsCollection::GetLength(uint32_t* aLength) NS_IMETHODIMP HTMLOptionsCollection::SetLength(uint32_t aLength) { - if (!mSelect) { - return NS_ERROR_UNEXPECTED; - } - return mSelect->SetLength(aLength); } @@ -135,10 +118,6 @@ NS_IMETHODIMP HTMLOptionsCollection::SetOption(uint32_t aIndex, nsIDOMHTMLOptionElement* aOption) { - if (!mSelect) { - return NS_OK; - } - // if the new option is null, just remove this option. Note that it's safe // to pass a too-large aIndex in here. if (!aOption) { @@ -187,11 +166,6 @@ HTMLOptionsCollection::SetOption(uint32_t aIndex, int32_t HTMLOptionsCollection::GetSelectedIndex(ErrorResult& aError) { - if (!mSelect) { - aError.Throw(NS_ERROR_UNEXPECTED); - return 0; - } - int32_t selectedIndex; aError = mSelect->GetSelectedIndex(&selectedIndex); return selectedIndex; @@ -209,11 +183,6 @@ void HTMLOptionsCollection::SetSelectedIndex(int32_t aSelectedIndex, ErrorResult& aError) { - if (!mSelect) { - aError.Throw(NS_ERROR_UNEXPECTED); - return; - } - aError = mSelect->SetSelectedIndex(aSelectedIndex); } @@ -339,22 +308,12 @@ HTMLOptionsCollection::Add(const HTMLOptionOrOptGroupElement& aElement, const Nullable<HTMLElementOrLong>& aBefore, ErrorResult& aError) { - if (!mSelect) { - aError.Throw(NS_ERROR_NOT_INITIALIZED); - return; - } - mSelect->Add(aElement, aBefore, aError); } void HTMLOptionsCollection::Remove(int32_t aIndex, ErrorResult& aError) { - if (!mSelect) { - aError.Throw(NS_ERROR_UNEXPECTED); - return; - } - uint32_t len = 0; mSelect->GetLength(&len); if (aIndex < 0 || (uint32_t)aIndex >= len) diff --git a/dom/html/HTMLOptionsCollection.h b/dom/html/HTMLOptionsCollection.h index 21123b3d2..496919555 100644 --- a/dom/html/HTMLOptionsCollection.h +++ b/dom/html/HTMLOptionsCollection.h @@ -46,7 +46,7 @@ public: using nsWrapperCache::GetWrapper; virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; protected: - virtual ~HTMLOptionsCollection(); + virtual ~HTMLOptionsCollection() = default; virtual JSObject* GetWrapperPreserveColorInternal() override { @@ -113,11 +113,6 @@ public: } /** - * Drop the reference to the select. Called during select destruction. - */ - void DropReference(); - - /** * Finds the index of a given option element. * If the option isn't part of the collection, return NS_ERROR_FAILURE * without setting aIndex. @@ -161,7 +156,7 @@ private: * various members such as InsertOptionAt are also infallible. */ nsTArray<RefPtr<mozilla::dom::HTMLOptionElement> > mElements; /** The select element that contains this array */ - HTMLSelectElement* mSelect; + RefPtr<HTMLSelectElement> mSelect; }; } // namespace dom diff --git a/dom/html/HTMLSelectElement.cpp b/dom/html/HTMLSelectElement.cpp index 53f42317a..9ba0a1efe 100644 --- a/dom/html/HTMLSelectElement.cpp +++ b/dom/html/HTMLSelectElement.cpp @@ -130,11 +130,6 @@ HTMLSelectElement::HTMLSelectElement(already_AddRefed<mozilla::dom::NodeInfo>& a NS_EVENT_STATE_VALID); } -HTMLSelectElement::~HTMLSelectElement() -{ - mOptions->DropReference(); -} - // ISupports NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLSelectElement) diff --git a/dom/html/HTMLSelectElement.h b/dom/html/HTMLSelectElement.h index 8a25385de..dc1075cd7 100644 --- a/dom/html/HTMLSelectElement.h +++ b/dom/html/HTMLSelectElement.h @@ -436,7 +436,7 @@ public: void SetOpenInParentProcess(bool aVal); protected: - virtual ~HTMLSelectElement(); + virtual ~HTMLSelectElement() = default; friend class SafeOptionListMutation; diff --git a/dom/html/HTMLTableElement.cpp b/dom/html/HTMLTableElement.cpp index ec1b7cecb..c5b7696cf 100644 --- a/dom/html/HTMLTableElement.cpp +++ b/dom/html/HTMLTableElement.cpp @@ -421,11 +421,10 @@ HTMLTableElement::CreateTHead() void HTMLTableElement::DeleteTHead() { - HTMLTableSectionElement* tHead = GetTHead(); + RefPtr<HTMLTableSectionElement> tHead = GetTHead(); if (tHead) { - mozilla::ErrorResult rv; + mozilla::IgnoredErrorResult rv; nsINode::RemoveChild(*tHead, rv); - MOZ_ASSERT(!rv.Failed()); } } @@ -452,11 +451,10 @@ HTMLTableElement::CreateTFoot() void HTMLTableElement::DeleteTFoot() { - HTMLTableSectionElement* tFoot = GetTFoot(); + RefPtr<HTMLTableSectionElement> tFoot = GetTFoot(); if (tFoot) { - mozilla::ErrorResult rv; + mozilla::IgnoredErrorResult rv; nsINode::RemoveChild(*tFoot, rv); - MOZ_ASSERT(!rv.Failed()); } } @@ -483,11 +481,10 @@ HTMLTableElement::CreateCaption() void HTMLTableElement::DeleteCaption() { - HTMLTableCaptionElement* caption = GetCaption(); + RefPtr<HTMLTableCaptionElement> caption = GetCaption(); if (caption) { - mozilla::ErrorResult rv; + mozilla::IgnoredErrorResult rv; nsINode::RemoveChild(*caption, rv); - MOZ_ASSERT(!rv.Failed()); } } diff --git a/dom/html/HTMLTableSectionElement.cpp b/dom/html/HTMLTableSectionElement.cpp index c7b0665dd..e99597636 100644 --- a/dom/html/HTMLTableSectionElement.cpp +++ b/dom/html/HTMLTableSectionElement.cpp @@ -122,7 +122,7 @@ HTMLTableSectionElement::DeleteRow(int32_t aValue, ErrorResult& aError) refIndex = (uint32_t)aValue; } - nsINode* row = rows->Item(refIndex); + nsCOMPtr<nsINode> row = rows->Item(refIndex); if (!row) { aError.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); return; diff --git a/dom/html/ImageDocument.cpp b/dom/html/ImageDocument.cpp index 200bb5d46..f83a804be 100644 --- a/dom/html/ImageDocument.cpp +++ b/dom/html/ImageDocument.cpp @@ -40,12 +40,14 @@ #include "nsThreadUtils.h" #include "nsIScrollableFrame.h" #include "nsContentUtils.h" +#include "nsCSSParser.h" // for CSS colors on the background #include "mozilla/dom/Element.h" #include "mozilla/Preferences.h" #include <algorithm> #define AUTOMATIC_IMAGE_RESIZING_PREF "browser.enable_automatic_image_resizing" #define CLICK_IMAGE_RESIZING_PREF "browser.enable_click_image_resizing" +#define STANDALONE_IMAGE_BACKGROUND_COLOR_PREF "browser.display.standalone_images.background_color" //XXX A hack needed for Firefox's site specific zoom. #define SITE_SPECIFIC_ZOOM "browser.zoom.siteSpecific" @@ -170,6 +172,8 @@ ImageDocument::Init() mClickResizingEnabled = Preferences::GetBool(CLICK_IMAGE_RESIZING_PREF); mShouldResize = mResizeImageByDefault; mFirstResize = true; + + mBackgroundColor = Preferences::GetString(STANDALONE_IMAGE_BACKGROUND_COLOR_PREF); return NS_OK; } @@ -682,9 +686,22 @@ ImageDocument::CreateSyntheticDocument() mImageContent->SetAttr(kNameSpaceID_None, nsGkAtoms::src, srcString, false); mImageContent->SetAttr(kNameSpaceID_None, nsGkAtoms::alt, srcString, false); + // Implement mechanism for custom background color from pref. + if (!mBackgroundColor.IsEmpty()) { + nsCSSValue color; + nsCSSParser parser; + if (parser.ParseColorString(mBackgroundColor, nullptr, 0, color)) { + nsAutoString styleAttr(NS_LITERAL_STRING("background-color: ")); + styleAttr.Append(mBackgroundColor); + body->SetAttr(kNameSpaceID_None, nsGkAtoms::style, styleAttr, false); + } + } + body->AppendChildTo(mImageContent, false); imageLoader->SetLoadingEnabled(true); + UpdateTitleAndCharset(); + return NS_OK; } diff --git a/dom/html/ImageDocument.h b/dom/html/ImageDocument.h index fdf2a00a8..945317314 100644 --- a/dom/html/ImageDocument.h +++ b/dom/html/ImageDocument.h @@ -112,6 +112,9 @@ protected: float mVisibleHeight; int32_t mImageWidth; int32_t mImageHeight; + + // Holds the custom background color for stand-alone images + nsAutoString mBackgroundColor; bool mResizeImageByDefault; bool mClickResizingEnabled; diff --git a/dom/html/TextTrackManager.cpp b/dom/html/TextTrackManager.cpp index 8110dab29..7f9d32794 100644 --- a/dom/html/TextTrackManager.cpp +++ b/dom/html/TextTrackManager.cpp @@ -12,7 +12,6 @@ #include "mozilla/dom/TextTrackCue.h" #include "mozilla/dom/Event.h" #include "mozilla/ClearOnShutdown.h" -#include "mozilla/Telemetry.h" #include "nsComponentManagerUtils.h" #include "nsVariant.h" #include "nsVideoFrame.h" @@ -30,6 +29,13 @@ namespace dom { NS_IMPL_ISUPPORTS(TextTrackManager::ShutdownObserverProxy, nsIObserver); +void +TextTrackManager::ShutdownObserverProxy::Unregister() +{ + nsContentUtils::UnregisterShutdownObserver(this); + mManager = nullptr; +} + CompareTextTracks::CompareTextTracks(HTMLMediaElement* aMediaElement) { mMediaElement = aMediaElement; @@ -112,7 +118,6 @@ TextTrackManager::TextTrackManager(HTMLMediaElement *aMediaElement) , mTimeMarchesOnDispatched(false) , mUpdateCueDisplayDispatched(false) , performedTrackSelection(false) - , mCueTelemetryReported(false) , mShutdown(false) { nsISupports* parentObject = @@ -138,7 +143,7 @@ TextTrackManager::TextTrackManager(HTMLMediaElement *aMediaElement) TextTrackManager::~TextTrackManager() { WEBVTT_LOG("%p ~TextTrackManager",this); - nsContentUtils::UnregisterShutdownObserver(mShutdownProxy); + mShutdownProxy->Unregister(); } TextTrackList* @@ -164,7 +169,6 @@ TextTrackManager::AddTextTrack(TextTrackKind aKind, const nsAString& aLabel, mTextTracks->AddTextTrack(aKind, aLabel, aLanguage, aMode, aReadyState, aTextTrackSource, CompareTextTracks(mMediaElement)); AddCues(track); - ReportTelemetryForTrack(track); if (aTextTrackSource == TextTrackSource::Track) { RefPtr<nsIRunnable> task = @@ -184,7 +188,6 @@ TextTrackManager::AddTextTrack(TextTrack* aTextTrack) WEBVTT_LOG("%p AddTextTrack TextTrack %p",this, aTextTrack); mTextTracks->AddTextTrack(aTextTrack, CompareTextTracks(mMediaElement)); AddCues(aTextTrack); - ReportTelemetryForTrack(aTextTrack); if (aTextTrack->GetTextTrackSource() == TextTrackSource::Track) { RefPtr<nsIRunnable> task = @@ -303,7 +306,6 @@ TextTrackManager::NotifyCueAdded(TextTrackCue& aCue) mNewCues->AddCue(aCue); } DispatchTimeMarchesOn(); - ReportTelemetryForCue(); } void @@ -821,28 +823,5 @@ TextTrackManager::NotifyReset() mLastTimeMarchesOnCalled = 0.0; } -void -TextTrackManager::ReportTelemetryForTrack(TextTrack* aTextTrack) const -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(aTextTrack); - MOZ_ASSERT(mTextTracks->Length() > 0); - - TextTrackKind kind = aTextTrack->Kind(); - Telemetry::Accumulate(Telemetry::WEBVTT_TRACK_KINDS, uint32_t(kind)); -} - -void -TextTrackManager::ReportTelemetryForCue() -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(!mNewCues->IsEmpty() || !mLastActiveCues->IsEmpty()); - - if (!mCueTelemetryReported) { - Telemetry::Accumulate(Telemetry::WEBVTT_USED_VTT_CUES, 1); - mCueTelemetryReported = true; - } -} - } // namespace dom } // namespace mozilla diff --git a/dom/html/TextTrackManager.h b/dom/html/TextTrackManager.h index d20707346..2375aa4bb 100644 --- a/dom/html/TextTrackManager.h +++ b/dom/html/TextTrackManager.h @@ -148,13 +148,6 @@ private: nsTArray<TextTrack*>& aTextTracks); bool TrackIsDefault(TextTrack* aTextTrack); - void ReportTelemetryForTrack(TextTrack* aTextTrack) const; - void ReportTelemetryForCue(); - - // If there is at least one cue has been added to the cue list once, we would - // report the usage of cue to Telemetry. - bool mCueTelemetryReported; - class ShutdownObserverProxy final : public nsIObserver { NS_DECL_ISUPPORTS @@ -170,11 +163,15 @@ private: { MOZ_ASSERT(NS_IsMainThread()); if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) { - nsContentUtils::UnregisterShutdownObserver(this); - mManager->NotifyShutdown(); + if (mManager) { + mManager->NotifyShutdown(); + } + Unregister(); } return NS_OK; } + + void Unregister(); private: ~ShutdownObserverProxy() {}; diff --git a/dom/html/nsDOMStringMap.cpp b/dom/html/nsDOMStringMap.cpp index 42725bc6f..6d2bc424d 100644 --- a/dom/html/nsDOMStringMap.cpp +++ b/dom/html/nsDOMStringMap.cpp @@ -19,7 +19,6 @@ using namespace mozilla::dom; NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMStringMap) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMStringMap) -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mElement) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END diff --git a/dom/html/nsGenericHTMLElement.h b/dom/html/nsGenericHTMLElement.h index 0635c27e1..24a7a3652 100644 --- a/dom/html/nsGenericHTMLElement.h +++ b/dom/html/nsGenericHTMLElement.h @@ -396,13 +396,6 @@ public: } NS_IMETHOD InsertAdjacentHTML(const nsAString& position, const nsAString& text) final override; - NS_IMETHOD ScrollIntoView(bool top, uint8_t _argc) final override { - if (!_argc) { - top = true; - } - mozilla::dom::Element::ScrollIntoView(top); - return NS_OK; - } NS_IMETHOD GetOffsetParent(nsIDOMElement** aOffsetParent) final override { mozilla::dom::Element* offsetParent = GetOffsetParent(); diff --git a/dom/html/nsTextEditorState.cpp b/dom/html/nsTextEditorState.cpp index 187afb66d..25be6016c 100644 --- a/dom/html/nsTextEditorState.cpp +++ b/dom/html/nsTextEditorState.cpp @@ -47,7 +47,6 @@ #include "mozilla/dom/HTMLInputElement.h" #include "nsNumberControlFrame.h" #include "nsFrameSelection.h" -#include "mozilla/Telemetry.h" #include "mozilla/layers/ScrollInputMethods.h" using namespace mozilla; @@ -585,9 +584,6 @@ nsTextInputSelectionImpl::CompleteScroll(bool aForward) if (!mScrollFrame) return NS_ERROR_NOT_INITIALIZED; - mozilla::Telemetry::Accumulate(mozilla::Telemetry::SCROLL_INPUT_METHODS, - (uint32_t) ScrollInputMethod::MainThreadCompleteScroll); - mScrollFrame->ScrollBy(nsIntPoint(0, aForward ? 1 : -1), nsIScrollableFrame::WHOLE, nsIScrollableFrame::INSTANT); @@ -640,9 +636,6 @@ nsTextInputSelectionImpl::ScrollPage(bool aForward) if (!mScrollFrame) return NS_ERROR_NOT_INITIALIZED; - mozilla::Telemetry::Accumulate(mozilla::Telemetry::SCROLL_INPUT_METHODS, - (uint32_t) ScrollInputMethod::MainThreadScrollPage); - mScrollFrame->ScrollBy(nsIntPoint(0, aForward ? 1 : -1), nsIScrollableFrame::PAGES, nsIScrollableFrame::SMOOTH); @@ -655,9 +648,6 @@ nsTextInputSelectionImpl::ScrollLine(bool aForward) if (!mScrollFrame) return NS_ERROR_NOT_INITIALIZED; - mozilla::Telemetry::Accumulate(mozilla::Telemetry::SCROLL_INPUT_METHODS, - (uint32_t) ScrollInputMethod::MainThreadScrollLine); - mScrollFrame->ScrollBy(nsIntPoint(0, aForward ? 1 : -1), nsIScrollableFrame::LINES, nsIScrollableFrame::SMOOTH); @@ -670,9 +660,6 @@ nsTextInputSelectionImpl::ScrollCharacter(bool aRight) if (!mScrollFrame) return NS_ERROR_NOT_INITIALIZED; - mozilla::Telemetry::Accumulate(mozilla::Telemetry::SCROLL_INPUT_METHODS, - (uint32_t) ScrollInputMethod::MainThreadScrollCharacter); - mScrollFrame->ScrollBy(nsIntPoint(aRight ? 1 : -1, 0), nsIScrollableFrame::LINES, nsIScrollableFrame::SMOOTH); @@ -2268,7 +2255,11 @@ nsTextEditorState::UpdatePlaceholderText(bool aNotify) nsCOMPtr<nsIContent> content = do_QueryInterface(mTextCtrlElement); content->GetAttr(kNameSpaceID_None, nsGkAtoms::placeholder, placeholderValue); - nsContentUtils::RemoveNewlines(placeholderValue); + if (mTextCtrlElement->IsTextArea()) { // <textarea>s preserve newlines... + nsContentUtils::PlatformToDOMLineBreaks(placeholderValue); + } else { // ...<input>s don't + nsContentUtils::RemoveNewlines(placeholderValue); + } NS_ASSERTION(mPlaceholderDiv->GetFirstChild(), "placeholder div has no child"); mPlaceholderDiv->GetFirstChild()->SetText(placeholderValue, aNotify); } diff --git a/dom/indexedDB/ActorsChild.cpp b/dom/indexedDB/ActorsChild.cpp index 3e8f97348..c4fcceb90 100644 --- a/dom/indexedDB/ActorsChild.cpp +++ b/dom/indexedDB/ActorsChild.cpp @@ -3456,6 +3456,8 @@ BackgroundCursorChild::RecvResponse(const CursorResponse& aResponse) RefPtr<IDBCursor> cursor; mStrongCursor.swap(cursor); + + RefPtr<IDBTransaction> transaction = mTransaction; switch (aResponse.type()) { case CursorResponse::Tnsresult: @@ -3486,7 +3488,7 @@ BackgroundCursorChild::RecvResponse(const CursorResponse& aResponse) MOZ_CRASH("Should never get here!"); } - mTransaction->OnRequestFinished(/* aActorDestroyedNormally */ true); + transaction->OnRequestFinished(/* aActorDestroyedNormally */ true); return true; } diff --git a/dom/indexedDB/ActorsParent.cpp b/dom/indexedDB/ActorsParent.cpp index e6fe9e2a8..38621cee3 100644 --- a/dom/indexedDB/ActorsParent.cpp +++ b/dom/indexedDB/ActorsParent.cpp @@ -23,6 +23,7 @@ #include "mozilla/AppProcessChecker.h" #include "mozilla/AutoRestore.h" #include "mozilla/Casting.h" +#include "mozilla/CheckedInt.h" #include "mozilla/EndianUtils.h" #include "mozilla/ErrorNames.h" #include "mozilla/LazyIdleThread.h" @@ -249,8 +250,6 @@ const char kSQLiteJournalSuffix[] = ".sqlite-journal"; const char kSQLiteSHMSuffix[] = ".sqlite-shm"; const char kSQLiteWALSuffix[] = ".sqlite-wal"; -const char kPrefIndexedDBEnabled[] = "dom.indexedDB.enabled"; - const char kPrefFileHandleEnabled[] = "dom.fileHandle.enabled"; #define IDB_PREFIX "indexedDB" @@ -784,29 +783,25 @@ MakeCompressedIndexDataValues( MOZ_ASSERT(!keyBuffer.IsEmpty()); - // Don't let |infoLength| overflow. - if (NS_WARN_IF(UINT32_MAX - keyBuffer.Length() < - CompressedByteCountForIndexId(info.mIndexId) + - CompressedByteCountForNumber(keyBufferLength) + - CompressedByteCountForNumber(sortKeyBufferLength))) { - IDB_REPORT_INTERNAL_ERR(); - return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; - } - - const uint32_t infoLength = - CompressedByteCountForIndexId(info.mIndexId) + + const CheckedUint32 infoLength = + CheckedUint32(CompressedByteCountForIndexId(info.mIndexId)) + CompressedByteCountForNumber(keyBufferLength) + CompressedByteCountForNumber(sortKeyBufferLength) + keyBufferLength + sortKeyBufferLength; + // Don't let |infoLength| overflow. + if (NS_WARN_IF(!infoLength.isValid())) { + IDB_REPORT_INTERNAL_ERR(); + return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; + } // Don't let |blobDataLength| overflow. - if (NS_WARN_IF(UINT32_MAX - infoLength < blobDataLength)) { + if (NS_WARN_IF(UINT32_MAX - infoLength.value() < blobDataLength)) { IDB_REPORT_INTERNAL_ERR(); return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } - blobDataLength += infoLength; + blobDataLength += infoLength.value(); } UniqueFreePtr<uint8_t> blobData( @@ -4134,7 +4129,6 @@ GetDatabaseFileURL(nsIFile* aDatabaseFile, PersistenceType aPersistenceType, const nsACString& aGroup, const nsACString& aOrigin, - uint32_t aTelemetryId, nsIFileURL** aResult) { MOZ_ASSERT(aDatabaseFile); @@ -4166,18 +4160,10 @@ GetDatabaseFileURL(nsIFile* aDatabaseFile, nsAutoCString type; PersistenceTypeToText(aPersistenceType, type); - nsAutoCString telemetryFilenameClause; - if (aTelemetryId) { - telemetryFilenameClause.AssignLiteral("&telemetryFilename=indexedDB-"); - telemetryFilenameClause.AppendInt(aTelemetryId); - telemetryFilenameClause.AppendLiteral(".sqlite"); - } - rv = fileUrl->SetQuery(NS_LITERAL_CSTRING("persistenceType=") + type + NS_LITERAL_CSTRING("&group=") + aGroup + NS_LITERAL_CSTRING("&origin=") + aOrigin + - NS_LITERAL_CSTRING("&cache=private") + - telemetryFilenameClause); + NS_LITERAL_CSTRING("&cache=private")); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } @@ -4427,7 +4413,6 @@ CreateStorageConnection(nsIFile* aDBFile, PersistenceType aPersistenceType, const nsACString& aGroup, const nsACString& aOrigin, - uint32_t aTelemetryId, mozIStorageConnection** aConnection) { AssertIsOnIOThread(); @@ -4459,7 +4444,6 @@ CreateStorageConnection(nsIFile* aDBFile, aPersistenceType, aGroup, aOrigin, - aTelemetryId, getter_AddRefs(dbFileUrl)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; @@ -4895,7 +4879,6 @@ GetStorageConnection(nsIFile* aDatabaseFile, PersistenceType aPersistenceType, const nsACString& aGroup, const nsACString& aOrigin, - uint32_t aTelemetryId, mozIStorageConnection** aConnection) { MOZ_ASSERT(!NS_IsMainThread()); @@ -4923,7 +4906,6 @@ GetStorageConnection(nsIFile* aDatabaseFile, aPersistenceType, aGroup, aOrigin, - aTelemetryId, getter_AddRefs(dbFileUrl)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; @@ -4960,7 +4942,6 @@ GetStorageConnection(const nsAString& aDatabaseFilePath, PersistenceType aPersistenceType, const nsACString& aGroup, const nsACString& aOrigin, - uint32_t aTelemetryId, mozIStorageConnection** aConnection) { MOZ_ASSERT(!NS_IsMainThread()); @@ -4979,7 +4960,6 @@ GetStorageConnection(const nsAString& aDatabaseFilePath, aPersistenceType, aGroup, aOrigin, - aTelemetryId, aConnection); } @@ -6301,7 +6281,6 @@ private: const nsCString mId; const nsString mFilePath; uint32_t mActiveMutableFileCount; - const uint32_t mTelemetryId; const PersistenceType mPersistenceType; const bool mFileHandleDisabled; const bool mChromeWriteAccessAllowed; @@ -6318,7 +6297,6 @@ public: const Maybe<ContentParentId>& aOptionalContentParentId, const nsACString& aGroup, const nsACString& aOrigin, - uint32_t aTelemetryId, FullDatabaseMetadata* aMetadata, FileManager* aFileManager, already_AddRefed<DirectoryLock> aDirectoryLock, @@ -6377,12 +6355,6 @@ public: return mId; } - uint32_t - TelemetryId() const - { - return mTelemetryId; - } - PersistenceType Type() const { @@ -7678,8 +7650,6 @@ class OpenDatabaseOp final // cycles. VersionChangeOp* mVersionChangeOp; - uint32_t mTelemetryId; - public: OpenDatabaseOp(Factory* aFactory, already_AddRefed<ContentParent> aContentParent, @@ -10307,13 +10277,6 @@ typedef nsDataHashtable<nsIDHashKey, DatabaseLoggingInfo*> StaticAutoPtr<DatabaseLoggingInfoHashtable> gLoggingInfoHashtable; -typedef nsDataHashtable<nsUint32HashKey, uint32_t> TelemetryIdHashtable; - -StaticAutoPtr<TelemetryIdHashtable> gTelemetryIdHashtable; - -// Protects all reads and writes to gTelemetryIdHashtable. -StaticAutoPtr<Mutex> gTelemetryIdMutex; - #ifdef DEBUG StaticRefPtr<DEBUGThreadSlower> gDEBUGThreadSlower; @@ -10409,88 +10372,6 @@ DecreaseBusyCount() } } -uint32_t -TelemetryIdForFile(nsIFile* aFile) -{ - // May be called on any thread! - - MOZ_ASSERT(aFile); - MOZ_ASSERT(gTelemetryIdMutex); - - // The storage directory is structured like this: - // - // <profile>/storage/<persistence>/<origin>/idb/<filename>.sqlite - // - // For the purposes of this function we're only concerned with the - // <persistence>, <origin>, and <filename> pieces. - - nsString filename; - MOZ_ALWAYS_SUCCEEDS(aFile->GetLeafName(filename)); - - // Make sure we were given a database file. - NS_NAMED_LITERAL_STRING(sqliteExtension, ".sqlite"); - - MOZ_ASSERT(StringEndsWith(filename, sqliteExtension)); - - filename.Truncate(filename.Length() - sqliteExtension.Length()); - - // Get the "idb" directory. - nsCOMPtr<nsIFile> idbDirectory; - MOZ_ALWAYS_SUCCEEDS(aFile->GetParent(getter_AddRefs(idbDirectory))); - - DebugOnly<nsString> idbLeafName; - MOZ_ASSERT(NS_SUCCEEDED(idbDirectory->GetLeafName(idbLeafName))); - MOZ_ASSERT(static_cast<nsString&>(idbLeafName).EqualsLiteral("idb")); - - // Get the <origin> directory. - nsCOMPtr<nsIFile> originDirectory; - MOZ_ALWAYS_SUCCEEDS( - idbDirectory->GetParent(getter_AddRefs(originDirectory))); - - nsString origin; - MOZ_ALWAYS_SUCCEEDS(originDirectory->GetLeafName(origin)); - - // Any databases in these directories are owned by the application and should - // not have their filenames masked. Hopefully they also appear in the - // Telemetry.cpp whitelist. - if (origin.EqualsLiteral("chrome") || - origin.EqualsLiteral("moz-safe-about+home")) { - return 0; - } - - // Get the <persistence> directory. - nsCOMPtr<nsIFile> persistenceDirectory; - MOZ_ALWAYS_SUCCEEDS( - originDirectory->GetParent(getter_AddRefs(persistenceDirectory))); - - nsString persistence; - MOZ_ALWAYS_SUCCEEDS(persistenceDirectory->GetLeafName(persistence)); - - NS_NAMED_LITERAL_STRING(separator, "*"); - - uint32_t hashValue = HashString(persistence + separator + - origin + separator + - filename); - - MutexAutoLock lock(*gTelemetryIdMutex); - - if (!gTelemetryIdHashtable) { - gTelemetryIdHashtable = new TelemetryIdHashtable(); - } - - uint32_t id; - if (!gTelemetryIdHashtable->Get(hashValue, &id)) { - static uint32_t sNextId = 1; - - // We're locked, no need for atomics. - id = sNextId++; - - gTelemetryIdHashtable->Put(hashValue, id); - } - - return id; -} - } // namespace /******************************************************************************* @@ -12270,7 +12151,6 @@ ConnectionPool::GetOrCreateConnection(const Database* aDatabase, aDatabase->Type(), aDatabase->Group(), aDatabase->Origin(), - aDatabase->TelemetryId(), getter_AddRefs(storageConnection)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; @@ -14139,7 +14019,6 @@ Database::Database(Factory* aFactory, const Maybe<ContentParentId>& aOptionalContentParentId, const nsACString& aGroup, const nsACString& aOrigin, - uint32_t aTelemetryId, FullDatabaseMetadata* aMetadata, FileManager* aFileManager, already_AddRefed<DirectoryLock> aDirectoryLock, @@ -14156,7 +14035,6 @@ Database::Database(Factory* aFactory, , mId(aMetadata->mDatabaseId) , mFilePath(aMetadata->mFilePath) , mActiveMutableFileCount(0) - , mTelemetryId(aTelemetryId) , mPersistenceType(aMetadata->mCommonMetadata.persistenceType()) , mFileHandleDisabled(aFileHandleDisabled) , mChromeWriteAccessAllowed(aChromeWriteAccessAllowed) @@ -17396,8 +17274,7 @@ FileManager::InitDirectory(nsIFile* aDirectory, nsIFile* aDatabaseFile, PersistenceType aPersistenceType, const nsACString& aGroup, - const nsACString& aOrigin, - uint32_t aTelemetryId) + const nsACString& aOrigin) { AssertIsOnIOThread(); MOZ_ASSERT(aDirectory); @@ -17469,7 +17346,6 @@ FileManager::InitDirectory(nsIFile* aDirectory, aPersistenceType, aGroup, aOrigin, - aTelemetryId, getter_AddRefs(connection)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; @@ -17653,11 +17529,6 @@ QuotaClient::QuotaClient() { AssertIsOnBackgroundThread(); MOZ_ASSERT(!sInstance, "We expect this to be a singleton!"); - MOZ_ASSERT(!gTelemetryIdMutex); - - // Always create this so that later access to gTelemetryIdHashtable can be - // properly synchronized. - gTelemetryIdMutex = new Mutex("IndexedDB gTelemetryIdMutex"); sInstance = this; } @@ -17666,14 +17537,8 @@ QuotaClient::~QuotaClient() { AssertIsOnBackgroundThread(); MOZ_ASSERT(sInstance == this, "We expect this to be a singleton!"); - MOZ_ASSERT(gTelemetryIdMutex); MOZ_ASSERT(!mMaintenanceThreadPool); - // No one else should be able to touch gTelemetryIdHashtable now that the - // QuotaClient has gone away. - gTelemetryIdHashtable = nullptr; - gTelemetryIdMutex = nullptr; - sInstance = nullptr; } @@ -17947,8 +17812,7 @@ QuotaClient::InitOrigin(PersistenceType aPersistenceType, initInfo.mDatabaseFile, aPersistenceType, aGroup, - aOrigin, - TelemetryIdForFile(initInfo.mDatabaseFile)); + aOrigin); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } @@ -19041,7 +18905,6 @@ DatabaseMaintenance::PerformMaintenanceOnDatabase() mPersistenceType, mGroup, mOrigin, - TelemetryIdForFile(databaseFile), getter_AddRefs(connection)); if (NS_WARN_IF(NS_FAILED(rv))) { return; @@ -21172,16 +21035,6 @@ FactoryOp::CheckPermission(ContentParent* aContentParent, return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR; } - if (NS_WARN_IF(!Preferences::GetBool(kPrefIndexedDBEnabled, false))) { - if (aContentParent) { - // The DOM in the other process should have kept us from receiving any - // indexedDB messages so assume that the child is misbehaving. - aContentParent->KillHard("IndexedDB CheckPermission 1"); - } - - return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR; - } - const ContentPrincipalInfo& contentPrincipalInfo = principalInfo.get_ContentPrincipalInfo(); if (contentPrincipalInfo.attrs().mPrivateBrowsingId != 0) { @@ -21668,7 +21521,6 @@ OpenDatabaseOp::OpenDatabaseOp(Factory* aFactory, , mMetadata(new FullDatabaseMetadata(aParams.metadata())) , mRequestedVersion(aParams.metadata().version()) , mVersionChangeOp(nullptr) - , mTelemetryId(0) { if (mContentParent) { // This is a little scary but it looks safe to call this off the main thread @@ -21777,8 +21629,6 @@ OpenDatabaseOp::DoDatabaseWork() return rv; } - mTelemetryId = TelemetryIdForFile(dbFile); - #ifdef DEBUG nsString databaseFilePath; rv = dbFile->GetPath(databaseFilePath); @@ -21809,7 +21659,6 @@ OpenDatabaseOp::DoDatabaseWork() persistenceType, mGroup, mOrigin, - mTelemetryId, getter_AddRefs(connection)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; @@ -22692,7 +22541,6 @@ OpenDatabaseOp::EnsureDatabaseActor() mOptionalContentParentId, mGroup, mOrigin, - mTelemetryId, mMetadata, mFileManager, mDirectoryLock.forget(), diff --git a/dom/indexedDB/FileManager.h b/dom/indexedDB/FileManager.h index da917f431..0fba46ec0 100644 --- a/dom/indexedDB/FileManager.h +++ b/dom/indexedDB/FileManager.h @@ -58,8 +58,7 @@ public: nsIFile* aDatabaseFile, PersistenceType aPersistenceType, const nsACString& aGroup, - const nsACString& aOrigin, - uint32_t aTelemetryId); + const nsACString& aOrigin); static nsresult GetUsage(nsIFile* aDirectory, uint64_t* aUsage); diff --git a/dom/indexedDB/IDBCursor.cpp b/dom/indexedDB/IDBCursor.cpp index 7ae35e981..af88742f0 100644 --- a/dom/indexedDB/IDBCursor.cpp +++ b/dom/indexedDB/IDBCursor.cpp @@ -948,7 +948,6 @@ NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTION_CLASS(IDBCursor) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBCursor) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRequest) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceObjectStore) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceIndex) diff --git a/dom/indexedDB/IDBFactory.cpp b/dom/indexedDB/IDBFactory.cpp index 663828978..c1ef6353d 100644 --- a/dom/indexedDB/IDBFactory.cpp +++ b/dom/indexedDB/IDBFactory.cpp @@ -47,12 +47,6 @@ namespace dom { using namespace mozilla::dom::quota; using namespace mozilla::ipc; -namespace { - -const char kPrefIndexedDBEnabled[] = "dom.indexedDB.enabled"; - -} // namespace - class IDBFactory::BackgroundCreateCallback final : public nsIIPCBackgroundChildCreateCallback { @@ -130,12 +124,6 @@ IDBFactory::CreateForWindow(nsPIDOMWindowInner* aWindow, nsCOMPtr<nsIPrincipal> principal; nsresult rv = AllowedForWindowInternal(aWindow, getter_AddRefs(principal)); - if (!(NS_SUCCEEDED(rv) && nsContentUtils::IsSystemPrincipal(principal)) && - NS_WARN_IF(!Preferences::GetBool(kPrefIndexedDBEnabled, false))) { - *aFactory = nullptr; - return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR; - } - if (rv == NS_ERROR_DOM_NOT_SUPPORTED_ERR) { NS_WARNING("IndexedDB is not permitted in a third-party window."); *aFactory = nullptr; @@ -246,12 +234,6 @@ IDBFactory::CreateForMainThreadJSInternal( MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aPrincipalInfo); - if (aPrincipalInfo->type() != PrincipalInfo::TSystemPrincipalInfo && - NS_WARN_IF(!Preferences::GetBool(kPrefIndexedDBEnabled, false))) { - *aFactory = nullptr; - return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR; - } - IndexedDatabaseManager* mgr = IndexedDatabaseManager::GetOrCreate(); if (NS_WARN_IF(!mgr)) { IDB_REPORT_INTERNAL_ERR(); @@ -883,7 +865,6 @@ NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTION_CLASS(IDBFactory) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBFactory) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END diff --git a/dom/indexedDB/IDBIndex.cpp b/dom/indexedDB/IDBIndex.cpp index 657e744c9..af50926e6 100644 --- a/dom/indexedDB/IDBIndex.cpp +++ b/dom/indexedDB/IDBIndex.cpp @@ -652,7 +652,6 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBIndex) NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBIndex) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObjectStore) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END diff --git a/dom/indexedDB/IDBKeyRange.cpp b/dom/indexedDB/IDBKeyRange.cpp index 2de48a70c..e61c80617 100644 --- a/dom/indexedDB/IDBKeyRange.cpp +++ b/dom/indexedDB/IDBKeyRange.cpp @@ -239,7 +239,6 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(IDBKeyRange) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBKeyRange) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBKeyRange) diff --git a/dom/indexedDB/IDBObjectStore.cpp b/dom/indexedDB/IDBObjectStore.cpp index 8a0b292ad..756792741 100644 --- a/dom/indexedDB/IDBObjectStore.cpp +++ b/dom/indexedDB/IDBObjectStore.cpp @@ -1758,7 +1758,6 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBObjectStore) NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBObjectStore) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTransaction) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexes) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDeletedIndexes) diff --git a/dom/indexedDB/IDBRequest.cpp b/dom/indexedDB/IDBRequest.cpp index 919d3adc7..e0e318059 100644 --- a/dom/indexedDB/IDBRequest.cpp +++ b/dom/indexedDB/IDBRequest.cpp @@ -417,8 +417,6 @@ IDBRequest::GetError(ErrorResult& aRv) NS_IMPL_CYCLE_COLLECTION_CLASS(IDBRequest) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBRequest, IDBWrapperCache) - // Don't need NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS because - // DOMEventTargetHelper does it for us. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceAsObjectStore) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceAsIndex) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceAsCursor) diff --git a/dom/indexedDB/IDBWrapperCache.cpp b/dom/indexedDB/IDBWrapperCache.cpp index df62514c8..ccc2bb43e 100644 --- a/dom/indexedDB/IDBWrapperCache.cpp +++ b/dom/indexedDB/IDBWrapperCache.cpp @@ -18,8 +18,6 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(IDBWrapperCache) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBWrapperCache, DOMEventTargetHelper) - // Don't need NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS because - // DOMEventTargetHelper does it for us. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBWrapperCache, diff --git a/dom/indexedDB/KeyPath.cpp b/dom/indexedDB/KeyPath.cpp index dc8d10668..30edd8cd7 100644 --- a/dom/indexedDB/KeyPath.cpp +++ b/dom/indexedDB/KeyPath.cpp @@ -14,6 +14,7 @@ #include "xpcpublic.h" #include "mozilla/dom/BindingDeclarations.h" +#include "mozilla/dom/BlobBinding.h" #include "mozilla/dom/IDBObjectStoreBinding.h" namespace mozilla { @@ -100,7 +101,6 @@ GetJSValFromKeyPathString(JSContext* aCx, const char16_t* keyPathChars = token.BeginReading(); const size_t keyPathLen = token.Length(); - bool hasProp; if (!targetObject) { // We're still walking the chain of existing objects // http://w3c.github.io/IndexedDB/#dfn-evaluate-a-key-path-on-a-value @@ -116,16 +116,77 @@ GetJSValFromKeyPathString(JSContext* aCx, } obj = ¤tVal.toObject(); - bool ok = JS_HasUCProperty(aCx, obj, keyPathChars, keyPathLen, - &hasProp); + // We call JS_GetOwnUCPropertyDescriptor on purpose (as opposed to + // JS_GetUCPropertyDescriptor) to avoid searching the prototype chain. + JS::Rooted<JS::PropertyDescriptor> desc(aCx); + bool ok = JS_GetOwnUCPropertyDescriptor(aCx, obj, keyPathChars, + keyPathLen, &desc); IDB_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - if (hasProp) { - // Get if the property exists... - JS::Rooted<JS::Value> intermediate(aCx); - bool ok = JS_GetUCProperty(aCx, obj, keyPathChars, keyPathLen, &intermediate); - IDB_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + JS::Rooted<JS::Value> intermediate(aCx); + bool hasProp = false; + + if (desc.object()) { + intermediate = desc.value(); + hasProp = true; + } else { + // If we get here it means the object doesn't have the property or the + // property is available throuch a getter. We don't want to call any + // getters to avoid potential re-entrancy. + // The blob object is special since its properties are available + // only through getters but we still want to support them for key + // extraction. So they need to be handled manually. + Blob* blob; + if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, &obj, blob))) { + if (token.EqualsLiteral("size")) { + ErrorResult rv; + uint64_t size = blob->GetSize(rv); + MOZ_ALWAYS_TRUE(!rv.Failed()); + + intermediate = JS_NumberValue(size); + hasProp = true; + } else if (token.EqualsLiteral("type")) { + nsString type; + blob->GetType(type); + + JSString* string = + JS_NewUCStringCopyN(aCx, type.get(), type.Length()); + + intermediate = JS::StringValue(string); + hasProp = true; + } else { + RefPtr<File> file = blob->ToFile(); + if (file) { + if (token.EqualsLiteral("name")) { + nsString name; + file->GetName(name); + + JSString* string = + JS_NewUCStringCopyN(aCx, name.get(), name.Length()); + + intermediate = JS::StringValue(string); + hasProp = true; + } else if (token.EqualsLiteral("lastModified")) { + ErrorResult rv; + int64_t lastModifiedDate = file->GetLastModified(rv); + MOZ_ALWAYS_TRUE(!rv.Failed()); + + intermediate = JS_NumberValue(lastModifiedDate); + hasProp = true; + } else if (token.EqualsLiteral("lastModifiedDate")) { + ErrorResult rv; + Date lastModifiedDate = file->GetLastModifiedDate(rv); + MOZ_ALWAYS_TRUE(!rv.Failed()); + + lastModifiedDate.ToDateObject(aCx, &intermediate); + hasProp = true; + } + } + } + } + } + if (hasProp) { // Treat explicitly undefined as an error. if (intermediate.isUndefined()) { return NS_ERROR_DOM_INDEXEDDB_DATA_ERR; diff --git a/dom/interfaces/html/nsIDOMHTMLElement.idl b/dom/interfaces/html/nsIDOMHTMLElement.idl index 63a1f9572..686475f04 100644 --- a/dom/interfaces/html/nsIDOMHTMLElement.idl +++ b/dom/interfaces/html/nsIDOMHTMLElement.idl @@ -58,7 +58,6 @@ interface nsIDOMHTMLElement : nsIDOMElement // CSSOM View - [optional_argc] void scrollIntoView([optional] in boolean top); readonly attribute nsIDOMElement offsetParent; readonly attribute long offsetTop; readonly attribute long offsetLeft; diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index fc288e2c5..fdf0fcf3e 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -171,7 +171,6 @@ #include "GMPServiceChild.h" #include "gfxPlatform.h" #include "nscore.h" // for NS_FREE_PERMANENT_DATA -#include "VRManagerChild.h" using namespace mozilla; using namespace mozilla::docshell; @@ -1148,7 +1147,6 @@ ContentChild::RecvGMPsChanged(nsTArray<GMPCapabilityData>&& capabilities) bool ContentChild::RecvInitRendering(Endpoint<PCompositorBridgeChild>&& aCompositor, Endpoint<PImageBridgeChild>&& aImageBridge, - Endpoint<PVRManagerChild>&& aVRBridge, Endpoint<PVideoDecoderManagerChild>&& aVideoManager) { if (!CompositorBridgeChild::InitForContent(Move(aCompositor))) { @@ -1157,9 +1155,6 @@ ContentChild::RecvInitRendering(Endpoint<PCompositorBridgeChild>&& aCompositor, if (!ImageBridgeChild::InitForContent(Move(aImageBridge))) { return false; } - if (!gfx::VRManagerChild::InitForContent(Move(aVRBridge))) { - return false; - } VideoDecoderManagerChild::InitForContent(Move(aVideoManager)); return true; } @@ -1167,7 +1162,6 @@ ContentChild::RecvInitRendering(Endpoint<PCompositorBridgeChild>&& aCompositor, bool ContentChild::RecvReinitRendering(Endpoint<PCompositorBridgeChild>&& aCompositor, Endpoint<PImageBridgeChild>&& aImageBridge, - Endpoint<PVRManagerChild>&& aVRBridge, Endpoint<PVideoDecoderManagerChild>&& aVideoManager) { nsTArray<RefPtr<TabChild>> tabs = TabChild::GetAll(); @@ -1186,9 +1180,6 @@ ContentChild::RecvReinitRendering(Endpoint<PCompositorBridgeChild>&& aCompositor if (!ImageBridgeChild::ReinitForContent(Move(aImageBridge))) { return false; } - if (!gfx::VRManagerChild::ReinitForContent(Move(aVRBridge))) { - return false; - } // Establish new PLayerTransactions. for (const auto& tabChild : tabs) { diff --git a/dom/ipc/ContentChild.h b/dom/ipc/ContentChild.h index ba590b58e..4c8f15cc0 100644 --- a/dom/ipc/ContentChild.h +++ b/dom/ipc/ContentChild.h @@ -152,14 +152,12 @@ public: RecvInitRendering( Endpoint<PCompositorBridgeChild>&& aCompositor, Endpoint<PImageBridgeChild>&& aImageBridge, - Endpoint<PVRManagerChild>&& aVRBridge, Endpoint<PVideoDecoderManagerChild>&& aVideoManager) override; bool RecvReinitRendering( Endpoint<PCompositorBridgeChild>&& aCompositor, Endpoint<PImageBridgeChild>&& aImageBridge, - Endpoint<PVRManagerChild>&& aVRBridge, Endpoint<PVideoDecoderManagerChild>&& aVideoManager) override; PProcessHangMonitorChild* diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 0a07147bf..79446151c 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -84,7 +84,6 @@ #include "mozilla/ScopeExit.h" #include "mozilla/Services.h" #include "mozilla/StaticPtr.h" -#include "mozilla/Telemetry.h" #include "mozilla/WebBrowserPersistDocumentParent.h" #include "mozilla/Unused.h" #include "nsAnonymousTemporaryFile.h" @@ -1718,9 +1717,6 @@ ContentParent::ActorDestroy(ActorDestroyReason why) props->SetPropertyAsUint64(NS_LITERAL_STRING("childID"), mChildID); if (AbnormalShutdown == why) { - Telemetry::Accumulate(Telemetry::SUBPROCESS_ABNORMAL_ABORT, - NS_LITERAL_CSTRING("content"), 1); - props->SetPropertyAsBool(NS_LITERAL_STRING("abnormal"), true); } nsAutoString cpId; @@ -2076,21 +2072,18 @@ ContentParent::InitInternal(ProcessPriority aInitialPriority, Endpoint<PCompositorBridgeChild> compositor; Endpoint<PImageBridgeChild> imageBridge; - Endpoint<PVRManagerChild> vrBridge; Endpoint<PVideoDecoderManagerChild> videoManager; DebugOnly<bool> opened = gpm->CreateContentBridges( OtherPid(), &compositor, &imageBridge, - &vrBridge, &videoManager); MOZ_ASSERT(opened); Unused << SendInitRendering( Move(compositor), Move(imageBridge), - Move(vrBridge), Move(videoManager)); gpm->AddListener(this); @@ -2204,21 +2197,18 @@ ContentParent::OnCompositorUnexpectedShutdown() Endpoint<PCompositorBridgeChild> compositor; Endpoint<PImageBridgeChild> imageBridge; - Endpoint<PVRManagerChild> vrBridge; Endpoint<PVideoDecoderManagerChild> videoManager; DebugOnly<bool> opened = gpm->CreateContentBridges( OtherPid(), &compositor, &imageBridge, - &vrBridge, &videoManager); MOZ_ASSERT(opened); Unused << SendReinitRendering( Move(compositor), Move(imageBridge), - Move(vrBridge), Move(videoManager)); } @@ -3373,17 +3363,6 @@ ContentParent::RecvIsSecureURI(const uint32_t& type, } bool -ContentParent::RecvAccumulateMixedContentHSTS(const URIParams& aURI, const bool& aActive) -{ - nsCOMPtr<nsIURI> ourURI = DeserializeURI(aURI); - if (!ourURI) { - return false; - } - nsMixedContentBlocker::AccumulateMixedContentHSTS(ourURI, aActive); - return true; -} - -bool ContentParent::RecvLoadURIExternal(const URIParams& uri, PBrowserParent* windowContext) { @@ -4773,19 +4752,3 @@ ContentParent::ForceTabPaint(TabParent* aTabParent, uint64_t aLayerObserverEpoch } ProcessHangMonitor::ForcePaint(mHangMonitorActor, aTabParent, aLayerObserverEpoch); } - -bool -ContentParent::RecvAccumulateChildHistogram( - InfallibleTArray<Accumulation>&& aAccumulations) -{ - Telemetry::AccumulateChild(GeckoProcessType_Content, aAccumulations); - return true; -} - -bool -ContentParent::RecvAccumulateChildKeyedHistogram( - InfallibleTArray<KeyedAccumulation>&& aAccumulations) -{ - Telemetry::AccumulateChildKeyed(GeckoProcessType_Content, aAccumulations); - return true; -} diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index abcea0b65..26b5c44ac 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -741,9 +741,6 @@ private: virtual bool RecvIsSecureURI(const uint32_t& aType, const URIParams& aURI, const uint32_t& aFlags, bool* aIsSecureURI) override; - virtual bool RecvAccumulateMixedContentHSTS(const URIParams& aURI, - const bool& aActive) override; - virtual bool DeallocPHalParent(PHalParent*) override; virtual bool @@ -1044,10 +1041,6 @@ private: virtual bool RecvDeleteGetFilesRequest(const nsID& aID) override; - virtual bool RecvAccumulateChildHistogram( - InfallibleTArray<Accumulation>&& aAccumulations) override; - virtual bool RecvAccumulateChildKeyedHistogram( - InfallibleTArray<KeyedAccumulation>&& aAccumulations) override; public: void SendGetFilesResponseAndForget(const nsID& aID, const GetFilesResponseResult& aResult); diff --git a/dom/ipc/PContent.ipdl b/dom/ipc/PContent.ipdl index c01ad59c1..e8fb25aec 100644 --- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -44,7 +44,6 @@ include protocol PRemoteSpellcheckEngine; include protocol PWebBrowserPersistDocument; include protocol PWebrtcGlobal; include protocol PPresentation; -include protocol PVRManager; include protocol PVideoDecoderManager; include protocol PFlyWebPublishedServer; include DOMTypes; @@ -90,8 +89,6 @@ using mozilla::DataStorageType from "ipc/DataStorageIPCUtils.h"; using mozilla::DocShellOriginAttributes from "mozilla/ipc/BackgroundUtils.h"; using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/CompositorTypes.h"; using struct mozilla::dom::FlyWebPublishOptions from "mozilla/dom/FlyWebPublishOptionsIPCSerializer.h"; -using mozilla::Telemetry::Accumulation from "mozilla/TelemetryComms.h"; -using mozilla::Telemetry::KeyedAccumulation from "mozilla/TelemetryComms.h"; union ChromeRegistryItem { @@ -311,7 +308,6 @@ child: async InitRendering( Endpoint<PCompositorBridgeChild> compositor, Endpoint<PImageBridgeChild> imageBridge, - Endpoint<PVRManagerChild> vr, Endpoint<PVideoDecoderManagerChild> video); // Re-create the rendering stack using the given endpoints. This is sent @@ -320,7 +316,6 @@ child: async ReinitRendering( Endpoint<PCompositorBridgeChild> compositor, Endpoint<PImageBridgeChild> bridge, - Endpoint<PVRManagerChild> vr, Endpoint<PVideoDecoderManagerChild> video); /** @@ -661,8 +656,6 @@ parent: sync IsSecureURI(uint32_t type, URIParams uri, uint32_t flags) returns (bool isSecureURI); - async AccumulateMixedContentHSTS(URIParams uri, bool active); - sync GetLookAndFeelCache() returns (LookAndFeelInt[] lookAndFeelIntCache); @@ -1025,12 +1018,6 @@ parent: async UnstoreAndBroadcastBlobURLUnregistration(nsCString url); - /** - * Messages for communicating child Telemetry to the parent process - */ - async AccumulateChildHistogram(Accumulation[] accumulations); - async AccumulateChildKeyedHistogram(KeyedAccumulation[] accumulations); - sync GetA11yContentId() returns (uint32_t aContentId); both: diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp index 705799c54..e1355adee 100644 --- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -107,7 +107,6 @@ #include "nsDeviceContext.h" #include "nsSandboxFlags.h" #include "FrameLayerBuilder.h" -#include "VRManagerChild.h" #include "nsICommandParams.h" #include "nsISHistory.h" #include "nsQueryObject.h" @@ -177,7 +176,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(TabChildBase) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTabChildGlobal) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWebBrowserChrome) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END @@ -2395,7 +2393,6 @@ TabChild::RecvSetDocShellIsActive(const bool& aIsActive, root->SchedulePaint(); } - Telemetry::AutoTimer<Telemetry::TABCHILD_PAINT_TIME> timer; // If we need to repaint, let's do that right away. No sense waiting until // we get back to the event loop again. We suppress the display port so that // we only paint what's visible. This ensures that the tab we're switching @@ -2566,7 +2563,6 @@ TabChild::InitRenderingState(const TextureFactoryIdentifier& aTextureFactoryIden lf->SetShadowManager(shadowManager); lf->IdentifyTextureHost(mTextureFactoryIdentifier); ImageBridgeChild::IdentifyCompositorTextureHost(mTextureFactoryIdentifier); - gfx::VRManagerChild::IdentifyTextureHost(mTextureFactoryIdentifier); } mRemoteFrame = remoteFrame; diff --git a/dom/locales/en-US/chrome/security/security.properties b/dom/locales/en-US/chrome/security/security.properties index 8efdb0a6d..2be56fb9d 100644 --- a/dom/locales/en-US/chrome/security/security.properties +++ b/dom/locales/en-US/chrome/security/security.properties @@ -85,3 +85,5 @@ BlockScriptWithWrongMimeType=Script from “%1$S” was blocked because of a dis # LOCALIZATION NOTE: Do not translate "data: URI". BlockTopLevelDataURINavigation=Navigation to toplevel data: URI not allowed (Blocked loading of: “%1$S”) + +BlockSubresourceFTP=Loading FTP subresource within http(s) page not allowed (Blocked loading of: “%1$S”) diff --git a/dom/media/AudioStream.cpp b/dom/media/AudioStream.cpp index 54cf7b965..4b1d82c37 100644 --- a/dom/media/AudioStream.cpp +++ b/dom/media/AudioStream.cpp @@ -14,7 +14,6 @@ #include "mozilla/Mutex.h" #include "mozilla/Sprintf.h" #include <algorithm> -#include "mozilla/Telemetry.h" #include "CubebUtils.h" #include "nsPrintfCString.h" #include "gfxPrefs.h" @@ -346,7 +345,6 @@ AudioStream::Init(uint32_t aNumChannels, uint32_t aRate, cubeb* cubebContext = CubebUtils::GetCubebContext(); if (!cubebContext) { NS_WARNING("Can't get cubeb context!"); - CubebUtils::ReportCubebStreamInitFailure(true); return NS_ERROR_DOM_MEDIA_CUBEB_INITIALIZATION_ERR; } @@ -368,18 +366,14 @@ AudioStream::OpenCubeb(cubeb* aContext, cubeb_stream_params& aParams, latency_frames, DataCallback_S, StateCallback_S, this) == CUBEB_OK) { mCubebStream.reset(stream); - CubebUtils::ReportCubebBackendUsed(); } else { NS_WARNING(nsPrintfCString("AudioStream::OpenCubeb() %p failed to init cubeb", this).get()); - CubebUtils::ReportCubebStreamInitFailure(aIsFirst); return NS_ERROR_FAILURE; } TimeDuration timeDelta = TimeStamp::Now() - aStartTime; LOG("creation time %sfirst: %u ms", aIsFirst ? "" : "not ", (uint32_t) timeDelta.ToMilliseconds()); - Telemetry::Accumulate(aIsFirst ? Telemetry::AUDIOSTREAM_FIRST_OPEN_MS : - Telemetry::AUDIOSTREAM_LATER_OPEN_MS, timeDelta.ToMilliseconds()); return NS_OK; } diff --git a/dom/media/Benchmark.cpp b/dom/media/Benchmark.cpp index fdbedeca5..7394f8036 100644 --- a/dom/media/Benchmark.cpp +++ b/dom/media/Benchmark.cpp @@ -11,7 +11,6 @@ #include "PDMFactory.h" #include "WebMDemuxer.h" #include "mozilla/Preferences.h" -#include "mozilla/Telemetry.h" #include "mozilla/dom/ContentChild.h" #ifndef MOZ_WIDGET_ANDROID @@ -68,7 +67,6 @@ VP9Benchmark::IsVP9DecodeFast() Preferences::SetUint(sBenchmarkFpsPref, aDecodeFps); Preferences::SetUint(sBenchmarkFpsVersionCheck, sBenchmarkVersionID); } - Telemetry::Accumulate(Telemetry::ID::VIDEO_VP9_BENCHMARK_FPS, aDecodeFps); }, []() { }); } diff --git a/dom/media/CubebUtils.cpp b/dom/media/CubebUtils.cpp index fe94264ee..0f0167d9c 100644 --- a/dom/media/CubebUtils.cpp +++ b/dom/media/CubebUtils.cpp @@ -239,39 +239,6 @@ cubeb* GetCubebContextUnlocked() return sCubebContext; } -void ReportCubebBackendUsed() -{ - StaticMutexAutoLock lock(sMutex); - - sAudioStreamInitEverSucceeded = true; - - bool foundBackend = false; - for (uint32_t i = 0; i < ArrayLength(AUDIOSTREAM_BACKEND_ID_STR); i++) { - if (!strcmp(cubeb_get_backend_id(sCubebContext), AUDIOSTREAM_BACKEND_ID_STR[i])) { - Telemetry::Accumulate(Telemetry::AUDIOSTREAM_BACKEND_USED, i); - foundBackend = true; - } - } - if (!foundBackend) { - Telemetry::Accumulate(Telemetry::AUDIOSTREAM_BACKEND_USED, - CUBEB_BACKEND_UNKNOWN); - } -} - -void ReportCubebStreamInitFailure(bool aIsFirst) -{ - StaticMutexAutoLock lock(sMutex); - if (!aIsFirst && !sAudioStreamInitEverSucceeded) { - // This machine has no audio hardware, or it's in really bad shape, don't - // send this info, since we want CUBEB_BACKEND_INIT_FAILURE_OTHER to detect - // failures to open multiple streams in a process over time. - return; - } - Telemetry::Accumulate(Telemetry::AUDIOSTREAM_BACKEND_USED, - aIsFirst ? CUBEB_BACKEND_INIT_FAILURE_FIRST - : CUBEB_BACKEND_INIT_FAILURE_OTHER); -} - uint32_t GetCubebPlaybackLatencyInMilliseconds() { StaticMutexAutoLock lock(sMutex); diff --git a/dom/media/CubebUtils.h b/dom/media/CubebUtils.h index fa5fc2294..f43492374 100644 --- a/dom/media/CubebUtils.h +++ b/dom/media/CubebUtils.h @@ -35,8 +35,6 @@ double GetVolumeScale(); bool GetFirstStream(); cubeb* GetCubebContext(); cubeb* GetCubebContextUnlocked(); -void ReportCubebStreamInitFailure(bool aIsFirstStream); -void ReportCubebBackendUsed(); uint32_t GetCubebPlaybackLatencyInMilliseconds(); Maybe<uint32_t> GetCubebMSGLatencyInFrames(); bool CubebLatencyPrefSet(); diff --git a/dom/media/DecoderTraits.cpp b/dom/media/DecoderTraits.cpp index ddd35fe0d..6aa44f3e5 100644 --- a/dom/media/DecoderTraits.cpp +++ b/dom/media/DecoderTraits.cpp @@ -10,7 +10,6 @@ #include "nsCharSeparatedTokenizer.h" #include "nsMimeTypes.h" #include "mozilla/Preferences.h" -#include "mozilla/Telemetry.h" #include "OggDecoder.h" #include "OggDemuxer.h" @@ -18,15 +17,6 @@ #include "WebMDecoder.h" #include "WebMDemuxer.h" -#ifdef MOZ_ANDROID_OMX -#include "AndroidMediaDecoder.h" -#include "AndroidMediaReader.h" -#include "AndroidMediaPluginHost.h" -#endif -#ifdef MOZ_DIRECTSHOW -#include "DirectShowDecoder.h" -#include "DirectShowReader.h" -#endif #ifdef MOZ_FMP4 #include "MP4Decoder.h" #include "MP4Demuxer.h" @@ -94,45 +84,6 @@ DecoderTraits::IsWebMAudioType(const nsACString& aType) return aType.EqualsASCII("audio/webm"); } -static char const *const gHttpLiveStreamingTypes[] = { - // For m3u8. - // https://tools.ietf.org/html/draft-pantos-http-live-streaming-19#section-10 - "application/vnd.apple.mpegurl", - // Some sites serve these as the informal m3u type. - "application/x-mpegurl", - "audio/x-mpegurl", - nullptr -}; - -static bool -IsHttpLiveStreamingType(const nsACString& aType) -{ - return CodecListContains(gHttpLiveStreamingTypes, aType); -} - -#ifdef MOZ_ANDROID_OMX -static bool -IsAndroidMediaType(const nsACString& aType) -{ - if (!MediaDecoder::IsAndroidMediaPluginEnabled()) { - return false; - } - - static const char* supportedTypes[] = { - "audio/mpeg", "audio/mp4", "video/mp4", "video/x-m4v", nullptr - }; - return CodecListContains(supportedTypes, aType); -} -#endif - -#ifdef MOZ_DIRECTSHOW -static bool -IsDirectShowSupportedType(const nsACString& aType) -{ - return DirectShowDecoder::GetSupportedCodecs(aType, nullptr); -} -#endif - #ifdef MOZ_FMP4 static bool IsMP4SupportedType(const MediaContentType& aParsedType, @@ -247,14 +198,6 @@ CanHandleCodecsType(const MediaContentType& aType, if (IsFlacSupportedType(aType.GetMIMEType(), aType.GetCodecs())) { return CANPLAY_YES; } -#ifdef MOZ_DIRECTSHOW - DirectShowDecoder::GetSupportedCodecs(aType.GetMIMEType(), &codecList); -#endif -#ifdef MOZ_ANDROID_OMX - if (MediaDecoder::IsAndroidMediaPluginEnabled()) { - EnsureAndroidMediaPluginHost()->FindDecoder(aType.GetMIMEType(), &codecList); - } -#endif if (!codecList) { return CANPLAY_MAYBE; } @@ -287,10 +230,6 @@ CanHandleMediaType(const MediaContentType& aType, { MOZ_ASSERT(NS_IsMainThread()); - if (IsHttpLiveStreamingType(aType.GetMIMEType())) { - Telemetry::Accumulate(Telemetry::MEDIA_HLS_CANPLAY_REQUESTED, true); - } - if (aType.HaveCodecs()) { CanPlayStatus result = CanHandleCodecsType(aType, aDiagnostics); if (result == CANPLAY_NO || result == CANPLAY_YES) { @@ -320,17 +259,6 @@ CanHandleMediaType(const MediaContentType& aType, if (IsFlacSupportedType(aType.GetMIMEType())) { return CANPLAY_MAYBE; } -#ifdef MOZ_DIRECTSHOW - if (DirectShowDecoder::GetSupportedCodecs(aType.GetMIMEType(), nullptr)) { - return CANPLAY_MAYBE; - } -#endif -#ifdef MOZ_ANDROID_OMX - if (MediaDecoder::IsAndroidMediaPluginEnabled() && - EnsureAndroidMediaPluginHost()->FindDecoder(aType.GetMIMEType(), nullptr)) { - return CANPLAY_MAYBE; - } -#endif return CANPLAY_NO; } @@ -411,33 +339,12 @@ InstantiateDecoder(const nsACString& aType, decoder = new FlacDecoder(aOwner); return decoder.forget(); } -#ifdef MOZ_ANDROID_OMX - if (MediaDecoder::IsAndroidMediaPluginEnabled() && - EnsureAndroidMediaPluginHost()->FindDecoder(aType, nullptr)) { - decoder = new AndroidMediaDecoder(aOwner, aType); - return decoder.forget(); - } -#endif if (IsWebMSupportedType(aType)) { decoder = new WebMDecoder(aOwner); return decoder.forget(); } -#ifdef MOZ_DIRECTSHOW - // Note: DirectShow should come before WMF, so that we prefer DirectShow's - // MP3 support over WMF's. - if (IsDirectShowSupportedType(aType)) { - decoder = new DirectShowDecoder(aOwner); - return decoder.forget(); - } -#endif - - if (IsHttpLiveStreamingType(aType)) { - // We don't have an HLS decoder. - Telemetry::Accumulate(Telemetry::MEDIA_HLS_DECODER_SUCCESS, false); - } - return nullptr; } @@ -466,7 +373,7 @@ MediaDecoderReader* DecoderTraits::CreateReader(const nsACString& aType, Abstrac } else #endif if (IsMP3SupportedType(aType)) { - decoderReader = new MediaFormatReader(aDecoder, new mp3::MP3Demuxer(aDecoder->GetResource())); + decoderReader = new MediaFormatReader(aDecoder, new MP3Demuxer(aDecoder->GetResource())); } else if (IsAACSupportedType(aType)) { decoderReader = new MediaFormatReader(aDecoder, new ADTSDemuxer(aDecoder->GetResource())); @@ -480,22 +387,10 @@ MediaDecoderReader* DecoderTraits::CreateReader(const nsACString& aType, Abstrac if (IsOggSupportedType(aType)) { decoderReader = new MediaFormatReader(aDecoder, new OggDemuxer(aDecoder->GetResource())); } else -#ifdef MOZ_ANDROID_OMX - if (MediaDecoder::IsAndroidMediaPluginEnabled() && - EnsureAndroidMediaPluginHost()->FindDecoder(aType, nullptr)) { - decoderReader = new AndroidMediaReader(aDecoder, aType); - } else -#endif if (IsWebMSupportedType(aType)) { decoderReader = new MediaFormatReader(aDecoder, new WebMDemuxer(aDecoder->GetResource())); - } else -#ifdef MOZ_DIRECTSHOW - if (IsDirectShowSupportedType(aType)) { - decoderReader = new DirectShowReader(aDecoder); - } else -#endif - if (false) {} // dummy if to take care of the dangling else + } return decoderReader; } @@ -514,18 +409,12 @@ bool DecoderTraits::IsSupportedInVideoDocument(const nsACString& aType) return IsOggSupportedType(aType) || IsWebMSupportedType(aType) || -#ifdef MOZ_ANDROID_OMX - (MediaDecoder::IsAndroidMediaPluginEnabled() && IsAndroidMediaType(aType)) || -#endif #ifdef MOZ_FMP4 IsMP4SupportedType(aType, /* DecoderDoctorDiagnostics* */ nullptr) || #endif IsMP3SupportedType(aType) || IsAACSupportedType(aType) || IsFlacSupportedType(aType) || -#ifdef MOZ_DIRECTSHOW - IsDirectShowSupportedType(aType) || -#endif false; } diff --git a/dom/media/GraphDriver.cpp b/dom/media/GraphDriver.cpp index cae15eb8c..37c692a4b 100644 --- a/dom/media/GraphDriver.cpp +++ b/dom/media/GraphDriver.cpp @@ -200,7 +200,7 @@ public: STREAM_LOG(LogLevel::Debug, ("Starting system thread")); profiler_register_thread("MediaStreamGraph", &aLocal); LIFECYCLE_LOG("Starting a new system driver for graph %p\n", - mDriver->mGraphImpl); + mDriver->mGraphImpl.get()); RefPtr<GraphDriver> previousDriver; { @@ -236,7 +236,7 @@ private: void ThreadedDriver::Start() { - LIFECYCLE_LOG("Starting thread for a SystemClockDriver %p\n", mGraphImpl); + LIFECYCLE_LOG("Starting thread for a SystemClockDriver %p\n", mGraphImpl.get()); Unused << NS_WARN_IF(mThread); if (!mThread) { // Ensure we haven't already started it nsCOMPtr<nsIRunnable> event = new MediaStreamGraphInitThreadRunnable(this); @@ -623,16 +623,12 @@ AudioCallbackDriver::Init() cubeb* cubebContext = CubebUtils::GetCubebContext(); if (!cubebContext) { NS_WARNING("Could not get cubeb context."); - if (!mFromFallback) { - CubebUtils::ReportCubebStreamInitFailure(true); - } return; } cubeb_stream_params output; cubeb_stream_params input; uint32_t latency_frames; - bool firstStream = CubebUtils::GetFirstStream(); MOZ_ASSERT(!NS_IsMainThread(), "This is blocking and should never run on the main thread."); @@ -710,18 +706,11 @@ AudioCallbackDriver::Init() NS_WARNING_ASSERTION( rv == CUBEB_OK, "Could not set the audio stream volume in GraphDriver.cpp"); - CubebUtils::ReportCubebBackendUsed(); } else { #ifdef MOZ_WEBRTC StaticMutexAutoUnlock unlock(AudioInputCubeb::Mutex()); #endif NS_WARNING("Could not create a cubeb stream for MediaStreamGraph, falling back to a SystemClockDriver"); - // Only report failures when we're not coming from a driver that was - // created itself as a fallback driver because of a previous audio driver - // failure. - if (!mFromFallback) { - CubebUtils::ReportCubebStreamInitFailure(firstStream); - } // Fall back to a driver using a normal thread. If needed, // the graph will try to re-open an audio stream later. MonitorAutoLock lock(GraphImpl()->GetMonitor()); @@ -761,7 +750,7 @@ AudioCallbackDriver::Destroy() void AudioCallbackDriver::Resume() { - STREAM_LOG(LogLevel::Debug, ("Resuming audio threads for MediaStreamGraph %p", mGraphImpl)); + STREAM_LOG(LogLevel::Debug, ("Resuming audio threads for MediaStreamGraph %p", mGraphImpl.get())); if (cubeb_stream_start(mAudioStream) != CUBEB_OK) { NS_WARNING("Could not start cubeb stream for MSG."); } @@ -830,7 +819,9 @@ AudioCallbackDriver::Revive() mGraphImpl->SetCurrentDriver(NextDriver()); NextDriver()->Start(); } else { - STREAM_LOG(LogLevel::Debug, ("Starting audio threads for MediaStreamGraph %p from a new thread.", mGraphImpl)); + STREAM_LOG(LogLevel::Debug, + ("Starting audio threads for MediaStreamGraph %p from a new thread.", + mGraphImpl.get())); RefPtr<AsyncCubebTask> initEvent = new AsyncCubebTask(this, AsyncCubebOperation::INIT); initEvent->Dispatch(); diff --git a/dom/media/GraphDriver.h b/dom/media/GraphDriver.h index 411e175d3..bb4f2689b 100644 --- a/dom/media/GraphDriver.h +++ b/dom/media/GraphDriver.h @@ -210,10 +210,8 @@ protected: // Time of the end of this graph iteration. This must be accessed while having // the monitor. GraphTime mIterationEnd; - // The MediaStreamGraphImpl that owns this driver. This has a lifetime longer - // than the driver, and will never be null. Hence, it can be accesed without - // monitor. - MediaStreamGraphImpl* mGraphImpl; + // The MediaStreamGraphImpl associated with this driver. + const RefPtr<MediaStreamGraphImpl> mGraphImpl; // This enum specifies the wait state of the driver. enum WaitState { diff --git a/dom/media/MP3FrameParser.cpp b/dom/media/MP3FrameParser.cpp deleted file mode 100644 index 242e3df00..000000000 --- a/dom/media/MP3FrameParser.cpp +++ /dev/null @@ -1,591 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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 <algorithm> - -#include "nsMemory.h" -#include "MP3FrameParser.h" -#include "VideoUtils.h" - - -#define FROM_BIG_ENDIAN(X) ((uint32_t)((uint8_t)(X)[0] << 24 | (uint8_t)(X)[1] << 16 | \ - (uint8_t)(X)[2] << 8 | (uint8_t)(X)[3])) - - -namespace mozilla { - -/* - * Following code taken from http://www.hydrogenaudio.org/forums/index.php?showtopic=85125 - * with permission from the author, Nick Wallette <sirnickity@gmail.com>. - */ - -/* BEGIN shameless copy and paste */ - -// Bitrates - use [version][layer][bitrate] -const uint16_t mpeg_bitrates[4][4][16] = { - { // Version 2.5 - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Reserved - { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 }, // Layer 3 - { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 }, // Layer 2 - { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0 } // Layer 1 - }, - { // Reserved - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Invalid - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Invalid - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Invalid - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } // Invalid - }, - { // Version 2 - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Reserved - { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 }, // Layer 3 - { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 }, // Layer 2 - { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0 } // Layer 1 - }, - { // Version 1 - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Reserved - { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0 }, // Layer 3 - { 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0 }, // Layer 2 - { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0 }, // Layer 1 - } -}; - -// Sample rates - use [version][srate] -const uint16_t mpeg_srates[4][4] = { - { 11025, 12000, 8000, 0 }, // MPEG 2.5 - { 0, 0, 0, 0 }, // Reserved - { 22050, 24000, 16000, 0 }, // MPEG 2 - { 44100, 48000, 32000, 0 } // MPEG 1 -}; - -// Samples per frame - use [version][layer] -const uint16_t mpeg_frame_samples[4][4] = { -// Rsvd 3 2 1 < Layer v Version - { 0, 576, 1152, 384 }, // 2.5 - { 0, 0, 0, 0 }, // Reserved - { 0, 576, 1152, 384 }, // 2 - { 0, 1152, 1152, 384 } // 1 -}; - -// Slot size (MPEG unit of measurement) - use [layer] -const uint8_t mpeg_slot_size[4] = { 0, 1, 1, 4 }; // Rsvd, 3, 2, 1 - -uint16_t -MP3Frame::CalculateLength() -{ - // Lookup real values of these fields - uint32_t bitrate = mpeg_bitrates[mVersion][mLayer][mBitrate] * 1000; - uint32_t samprate = mpeg_srates[mVersion][mSampleRate]; - uint16_t samples = mpeg_frame_samples[mVersion][mLayer]; - uint8_t slot_size = mpeg_slot_size[mLayer]; - - // In-between calculations - float bps = (float)samples / 8.0; - float fsize = ( (bps * (float)bitrate) / (float)samprate ) - + ( (mPad) ? slot_size : 0 ); - - // Frame sizes are truncated integers - return (uint16_t)fsize; -} - -/* END shameless copy and paste */ - - -/** MP3Parser methods **/ - -MP3Parser::MP3Parser() - : mCurrentChar(0) -{ } - -void -MP3Parser::Reset() -{ - mCurrentChar = 0; -} - -uint16_t -MP3Parser::ParseFrameLength(uint8_t ch) -{ - mData.mRaw[mCurrentChar] = ch; - - MP3Frame &frame = mData.mFrame; - - // Validate MP3 header as we read. We can't mistake the start of an MP3 frame - // for the middle of another frame due to the sync byte at the beginning - // of the frame. - - // The only valid position for an all-high byte is the sync byte at the - // beginning of the frame. - if (ch == 0xff) { - mCurrentChar = 0; - } - - // Make sure the current byte is valid in context. If not, reset the parser. - if (mCurrentChar == 2) { - if (frame.mBitrate == 0x0f) { - goto fail; - } - } else if (mCurrentChar == 1) { - if (frame.mSync2 != 0x07 - || frame.mVersion == 0x01 - || frame.mLayer == 0x00) { - goto fail; - } - } - - // The only valid character at the beginning of the header is 0xff. Fail if - // it's different. - if (mCurrentChar == 0 && frame.mSync1 != 0xff) { - // Couldn't find the sync byte. Fail. - return 0; - } - - mCurrentChar++; - MOZ_ASSERT(mCurrentChar <= sizeof(MP3Frame)); - - // Don't have a full header yet. - if (mCurrentChar < sizeof(MP3Frame)) { - return 0; - } - - // Woo, valid header. Return the length. - mCurrentChar = 0; - return frame.CalculateLength(); - -fail: - Reset(); - return 0; -} - -uint32_t -MP3Parser::GetSampleRate() -{ - MP3Frame &frame = mData.mFrame; - return mpeg_srates[frame.mVersion][frame.mSampleRate]; -} - -uint32_t -MP3Parser::GetSamplesPerFrame() -{ - MP3Frame &frame = mData.mFrame; - return mpeg_frame_samples[frame.mVersion][frame.mLayer]; -} - - -/** ID3Parser methods **/ - -const char sID3Head[3] = { 'I', 'D', '3' }; -const uint32_t ID3_HEADER_LENGTH = 10; -const uint32_t ID3_FOOTER_LENGTH = 10; -const uint8_t ID3_FOOTER_PRESENT = 0x10; - -ID3Parser::ID3Parser() - : mCurrentChar(0) - , mVersion(0) - , mFlags(0) - , mHeaderLength(0) -{ } - -void -ID3Parser::Reset() -{ - mCurrentChar = mVersion = mFlags = mHeaderLength = 0; -} - -bool -ID3Parser::ParseChar(char ch) -{ - switch (mCurrentChar) { - // The first three bytes of an ID3v2 header must match the string "ID3". - case 0: case 1: case 2: - if (ch != sID3Head[mCurrentChar]) { - goto fail; - } - break; - // The fourth and fifth bytes give the version, between 2 and 4. - case 3: - if (ch < '\2' || ch > '\4') { - goto fail; - } - mVersion = uint8_t(ch); - break; - case 4: - if (ch != '\0') { - goto fail; - } - break; - // The sixth byte gives the flags; valid flags depend on the version. - case 5: - if ((ch & (0xff >> mVersion)) != '\0') { - goto fail; - } - mFlags = uint8_t(ch); - break; - // Bytes seven through ten give the sum of the byte length of the extended - // header, the padding and the frames after unsynchronisation. - // These bytes form a 28-bit integer, with the high bit of each byte unset. - case 6: case 7: case 8: case 9: - if (ch & 0x80) { - goto fail; - } - mHeaderLength <<= 7; - mHeaderLength |= ch; - if (mCurrentChar == 9) { - mHeaderLength += ID3_HEADER_LENGTH; - mHeaderLength += (mFlags & ID3_FOOTER_PRESENT) ? ID3_FOOTER_LENGTH : 0; - } - break; - default: - MOZ_CRASH("Header already fully parsed!"); - } - - mCurrentChar++; - - return IsParsed(); - -fail: - if (mCurrentChar) { - Reset(); - return ParseChar(ch); - } - Reset(); - return false; -} - -bool -ID3Parser::IsParsed() const -{ - return mCurrentChar >= ID3_HEADER_LENGTH; -} - -uint32_t -ID3Parser::GetHeaderLength() const -{ - MOZ_ASSERT(IsParsed(), - "Queried length of ID3 header before parsing finished."); - return mHeaderLength; -} - - -/** VBR header helper stuff **/ - -// Helper function to find a VBR header in an MP3 frame. -// Based on information from -// http://www.codeproject.com/Articles/8295/MPEG-Audio-Frame-Header - -const uint32_t VBRI_TAG = FROM_BIG_ENDIAN("VBRI"); -const uint32_t VBRI_OFFSET = 32 - sizeof(MP3Frame); -const uint32_t VBRI_FRAME_COUNT_OFFSET = VBRI_OFFSET + 14; -const uint32_t VBRI_MIN_FRAME_SIZE = VBRI_OFFSET + 26; - -const uint32_t XING_TAG = FROM_BIG_ENDIAN("Xing"); -enum XingFlags { - XING_HAS_NUM_FRAMES = 0x01, - XING_HAS_NUM_BYTES = 0x02, - XING_HAS_TOC = 0x04, - XING_HAS_VBR_SCALE = 0x08 -}; - -static int64_t -ParseXing(const char *aBuffer) -{ - uint32_t flags = FROM_BIG_ENDIAN(aBuffer + 4); - - if (!(flags & XING_HAS_NUM_FRAMES)) { - NS_WARNING("VBR file without frame count. Duration estimation likely to " - "be totally wrong."); - return -1; - } - - int64_t numFrames = -1; - if (flags & XING_HAS_NUM_FRAMES) { - numFrames = FROM_BIG_ENDIAN(aBuffer + 8); - } - - return numFrames; -} - -static int64_t -FindNumVBRFrames(const nsCString& aFrame) -{ - const char *buffer = aFrame.get(); - const char *bufferEnd = aFrame.get() + aFrame.Length(); - - // VBRI header is nice and well-defined; let's try to find that first. - if (aFrame.Length() > VBRI_MIN_FRAME_SIZE && - FROM_BIG_ENDIAN(buffer + VBRI_OFFSET) == VBRI_TAG) { - return FROM_BIG_ENDIAN(buffer + VBRI_FRAME_COUNT_OFFSET); - } - - // We have to search for the Xing header as its position can change. - for (; buffer + sizeof(XING_TAG) < bufferEnd; buffer++) { - if (FROM_BIG_ENDIAN(buffer) == XING_TAG) { - return ParseXing(buffer); - } - } - - return -1; -} - - -/** MP3FrameParser methods **/ - -// Some MP3's have large ID3v2 tags, up to 150KB, so we allow lots of -// skipped bytes to be read, just in case, before we give up and assume -// we're not parsing an MP3 stream. -static const uint32_t MAX_SKIPPED_BYTES = 4096; - -enum { - MP3_HEADER_LENGTH = 4, -}; - -MP3FrameParser::MP3FrameParser(int64_t aLength) -: mLock("MP3FrameParser.mLock"), - mTotalID3Size(0), - mTotalFrameSize(0), - mFrameCount(0), - mOffset(0), - mLength(aLength), - mMP3Offset(-1), - mSamplesPerSecond(0), - mFirstFrameEnd(-1), - mIsMP3(MAYBE_MP3) -{ } - -nsresult MP3FrameParser::ParseBuffer(const uint8_t* aBuffer, - uint32_t aLength, - int64_t aStreamOffset, - uint32_t* aOutBytesRead) -{ - // Iterate forwards over the buffer, looking for ID3 tag, or MP3 - // Frame headers. - const uint8_t *buffer = aBuffer; - const uint8_t *bufferEnd = aBuffer + aLength; - - // If we haven't found any MP3 frame data yet, there might be ID3 headers - // we can skip over. - if (mMP3Offset < 0) { - for (const uint8_t *ch = buffer; ch < bufferEnd; ch++) { - if (mID3Parser.ParseChar(*ch)) { - // Found an ID3 header. We don't care about the body of the header, so - // just skip past. - buffer = ch + mID3Parser.GetHeaderLength() - (ID3_HEADER_LENGTH - 1); - - if (buffer <= ch) { - return NS_ERROR_FAILURE; - } - - ch = buffer; - - mTotalID3Size += mID3Parser.GetHeaderLength(); - - // Yes, this is an MP3! - mIsMP3 = DEFINITELY_MP3; - - mID3Parser.Reset(); - } - } - } - - // The first MP3 frame in a variable bitrate stream can contain metadata - // for duration estimation and seeking, so we buffer that first frame here. - if (aStreamOffset < mFirstFrameEnd) { - uint64_t copyLen = std::min((int64_t)aLength, mFirstFrameEnd - aStreamOffset); - mFirstFrame.Append((const char *)buffer, copyLen); - buffer += copyLen; - } - - while (buffer < bufferEnd) { - uint16_t frameLen = mMP3Parser.ParseFrameLength(*buffer); - - if (frameLen) { - // We've found an MP3 frame! - // This is the first frame (and the only one we'll bother parsing), so: - // * Mark this stream as MP3; - // * Store the offset at which the MP3 data started; and - // * Start buffering the frame, as it might contain handy metadata. - - // We're now sure this is an MP3 stream. - mIsMP3 = DEFINITELY_MP3; - - // We need to know these to convert the number of frames in the stream - // to the length of the stream in seconds. - mSamplesPerSecond = mMP3Parser.GetSampleRate(); - mSamplesPerFrame = mMP3Parser.GetSamplesPerFrame(); - - // If the stream has a constant bitrate, we should only need the length - // of the first frame and the length (in bytes) of the stream to - // estimate the length (in seconds). - mTotalFrameSize += frameLen; - mFrameCount++; - - // If |mMP3Offset| isn't set then this is the first MP3 frame we have - // seen in the stream, which is useful for duration estimation. - if (mMP3Offset > -1) { - uint16_t skip = frameLen - sizeof(MP3Frame); - buffer += skip ? skip : 1; - continue; - } - - // Remember the offset of the MP3 stream. - // We're at the last byte of an MP3Frame, so MP3 data started - // sizeof(MP3Frame) - 1 bytes ago. - mMP3Offset = aStreamOffset - + (buffer - aBuffer) - - (sizeof(MP3Frame) - 1); - - buffer++; - - // If the stream has a variable bitrate, the first frame has metadata - // we need for duration estimation and seeking. Start buffering it so we - // can parse it later. - mFirstFrameEnd = mMP3Offset + frameLen; - uint64_t currOffset = buffer - aBuffer + aStreamOffset; - uint64_t copyLen = std::min(mFirstFrameEnd - currOffset, - (uint64_t)(bufferEnd - buffer)); - mFirstFrame.Append((const char *)buffer, copyLen); - - buffer += copyLen; - - } else { - // Nothing to see here. Move along. - buffer++; - } - } - - *aOutBytesRead = buffer - aBuffer; - - if (mFirstFrameEnd > -1 && mFirstFrameEnd <= aStreamOffset + buffer - aBuffer) { - // We have our whole first frame. Try to find a VBR header. - mNumFrames = FindNumVBRFrames(mFirstFrame); - mFirstFrameEnd = -1; - } - - return NS_OK; -} - -void MP3FrameParser::Parse(const uint8_t* aBuffer, uint32_t aLength, uint64_t aOffset) -{ - MutexAutoLock mon(mLock); - - if (HasExactDuration()) { - // We know the duration; nothing to do here. - return; - } - - const uint8_t* buffer = aBuffer; - int32_t length = aLength; - uint64_t offset = aOffset; - - // Got some data we have seen already. Skip forward to what we need. - if (aOffset < mOffset) { - buffer += mOffset - aOffset; - length -= mOffset - aOffset; - offset = mOffset; - - if (length <= 0) { - return; - } - } - - // If there is a discontinuity in the input stream, reset the state of the - // parsers so we don't get any partial headers. - if (mOffset < aOffset) { - if (!mID3Parser.IsParsed()) { - // Only reset this if it hasn't finished yet. - mID3Parser.Reset(); - } - - if (mFirstFrameEnd > -1) { - NS_WARNING("Discontinuity in input while buffering first frame."); - mFirstFrameEnd = -1; - } - - mMP3Parser.Reset(); - } - - uint32_t bytesRead = 0; - if (NS_FAILED(ParseBuffer(buffer, - length, - offset, - &bytesRead))) { - return; - } - - MOZ_ASSERT(length <= (int)bytesRead, "All bytes should have been consumed"); - - // Update next data offset - mOffset = offset + bytesRead; - - // If we've parsed lots of data and we still have nothing, just give up. - // We don't count ID3 headers towards the skipped bytes count, as MP3 files - // can have massive ID3 sections. - if (!mID3Parser.IsParsed() && mMP3Offset < 0 && - mOffset - mTotalID3Size > MAX_SKIPPED_BYTES) { - mIsMP3 = NOT_MP3; - } -} - -int64_t MP3FrameParser::GetDuration() -{ - MutexAutoLock mon(mLock); - - if (!ParsedHeaders() || !mSamplesPerSecond) { - // Not a single frame decoded yet. - return -1; - } - - MOZ_ASSERT(mFrameCount > 0 && mTotalFrameSize > 0, - "Frame parser should have seen at least one MP3 frame of positive length."); - - if (!mFrameCount || !mTotalFrameSize) { - // This should never happen. - return -1; - } - - double frames; - if (mNumFrames < 0) { - // Estimate the number of frames in the stream based on the average frame - // size and the length of the MP3 file. - double frameSize = (double)mTotalFrameSize / mFrameCount; - frames = (double)(mLength - mMP3Offset) / frameSize; - } else { - // We know the exact number of frames from the VBR header. - frames = mNumFrames; - } - - // The duration of each frame is constant over a given stream. - double usPerFrame = USECS_PER_S * mSamplesPerFrame / mSamplesPerSecond; - - return frames * usPerFrame; -} - -int64_t MP3FrameParser::GetMP3Offset() -{ - MutexAutoLock mon(mLock); - return mMP3Offset; -} - -bool MP3FrameParser::ParsedHeaders() -{ - // We have seen both the beginning and the end of the first MP3 frame in the - // stream. - return mMP3Offset > -1 && mFirstFrameEnd < 0; -} - -bool MP3FrameParser::HasExactDuration() -{ - return ParsedHeaders() && mNumFrames > -1; -} - -bool MP3FrameParser::NeedsData() -{ - // If we don't know the duration exactly then either: - // - we're still waiting for a VBR header; or - // - we look at all frames to constantly update our duration estimate. - return IsMP3() && !HasExactDuration(); -} - -} // namespace mozilla diff --git a/dom/media/MP3FrameParser.h b/dom/media/MP3FrameParser.h deleted file mode 100644 index d2ba791fd..000000000 --- a/dom/media/MP3FrameParser.h +++ /dev/null @@ -1,219 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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/. */ - -#ifndef MP3FrameParser_h -#define MP3FrameParser_h - -#include <stdint.h> - -#include "mozilla/Mutex.h" -#include "nsString.h" -#include "Intervals.h" - -namespace mozilla { - -// Simple parser to tell whether we've found an ID3 header and how long it is, -// so that we can skip it. -// XXX maybe actually parse this stuff? -class ID3Parser -{ -public: - ID3Parser(); - - void Reset(); - bool ParseChar(char ch); - bool IsParsed() const; - uint32_t GetHeaderLength() const; - -private: - uint32_t mCurrentChar; - uint8_t mVersion; - uint8_t mFlags; - uint32_t mHeaderLength; -}; - -struct MP3Frame { - uint16_t mSync1 : 8; // Always all set - uint16_t mProtected : 1; // Ignored - uint16_t mLayer : 2; - uint16_t mVersion : 2; - uint16_t mSync2 : 3; // Always all set - uint16_t mPrivate : 1; // Ignored - uint16_t mPad : 1; - uint16_t mSampleRate : 2; // Index into mpeg_srates above - uint16_t mBitrate : 4; // Index into mpeg_bitrates above - - uint16_t CalculateLength(); -}; - -// Buffering parser for MP3 frames. -class MP3Parser -{ -public: - MP3Parser(); - - // Forget all data the parser has seen so far. - void Reset(); - - // Parse the given byte. If we have found a frame header, return the length of - // the frame. - uint16_t ParseFrameLength(uint8_t ch); - - // Get the sample rate from the current header. - uint32_t GetSampleRate(); - - // Get the number of samples per frame. - uint32_t GetSamplesPerFrame(); - -private: - uint32_t mCurrentChar; - union { - uint8_t mRaw[3]; - MP3Frame mFrame; - } mData; -}; - - -// A description of the MP3 format and its extensions is available at -// -// http://www.codeproject.com/Articles/8295/MPEG-Audio-Frame-Header -// -// The data in MP3 streams is split into small frames, with each frame -// containing a fixed number of samples. The duration of a frame depends -// on the frame's bit rate and sample rate. Both values can vary among -// frames, so it is necessary to examine each individual frame of an MP3 -// stream to calculate the stream's overall duration. -// -// The MP3 frame parser extracts information from an MP3 data stream. It -// accepts a range of frames of an MP3 stream as input, and parses all -// frames for their duration. Callers can query the stream's overall -// duration from the parser. -// -// Call the methods NotifyDataArrived or Parse to add new data. If you added -// information for a certain stream position, you cannot go back to previous -// positions. The parser will simply ignore the input. If you skip stream -// positions, the duration of the related MP3 frames will be estimated from -// the stream's average. -// -// The method GetDuration returns calculated duration of the stream, including -// estimates for skipped ranges. -// -// All public methods are thread-safe. - -class MP3FrameParser -{ -public: - explicit MP3FrameParser(int64_t aLength=-1); - - bool IsMP3() { - MutexAutoLock mon(mLock); - return mIsMP3 != NOT_MP3; - } - - void Parse(const uint8_t* aBuffer, uint32_t aLength, uint64_t aStreamOffset); - - // Returns the duration, in microseconds. If the entire stream has not - // been parsed yet, this is an estimate based on the bitrate of the - // frames parsed so far. - int64_t GetDuration(); - - // Returns the offset of the first MP3 frame in the stream, or -1 of - // no MP3 frame has been detected yet. - int64_t GetMP3Offset(); - - // Returns true if we've seen the whole first frame of the MP3 stream, and - // therefore can make an estimate on the stream duration. - // Otherwise, returns false. - bool ParsedHeaders(); - - // Returns true if we know the exact duration of the MP3 stream; - // false otherwise. - bool HasExactDuration(); - - // Returns true if the parser needs more data for duration estimation. - bool NeedsData(); - // Assign the total lenght of this mp3 stream - void SetLength(int64_t aLength) { - MutexAutoLock mon(mLock); - mLength = aLength; - } -private: - - // Parses aBuffer, starting at offset 0. Returns the number of bytes - // parsed, relative to the start of the buffer. Note this may be - // greater than aLength if the headers in the buffer indicate that - // the frame or ID3 tag extends outside of aBuffer. Returns failure - // if too many non-MP3 bytes are parsed. - nsresult ParseBuffer(const uint8_t* aBuffer, - uint32_t aLength, - int64_t aStreamOffset, - uint32_t* aOutBytesRead); - - // A low-contention lock for protecting the parser results - Mutex mLock; - - // ID3 header parser. Keeps state between reads in case the header falls - // in between. - ID3Parser mID3Parser; - - // MP3 frame header parser. - MP3Parser mMP3Parser; - - // If we read |MAX_SKIPPED_BYTES| from the stream without finding any MP3 - // frames, we give up and report |NOT_MP3|. Here we track the cumulative size - // of any ID3 headers we've seen so big ID3 sections aren't counted towards - // skipped bytes. - uint32_t mTotalID3Size; - - // All fields below are protected by mLock - - // We keep stats on the size of all the frames we've seen, as well as how many - // so that we can estimate the duration of the rest of the stream. - uint64_t mTotalFrameSize; - uint64_t mFrameCount; - - // Offset of the last data parsed. This is the end offset of the last data - // block parsed, so it's the start offset we expect to get on the next - // call to Parse(). - uint64_t mOffset; - - // Total length of the stream in bytes. - int64_t mLength; - - // Offset of first MP3 frame in the bitstream. Has value -1 until the - // first MP3 frame is found. - int64_t mMP3Offset; - - // The exact number of frames in this stream, if we know it. -1 otherwise. - int64_t mNumFrames; - - // Number of audio samples per second and per frame. Fixed through the whole - // file. If we know these variables as well as the number of frames in the - // file, we can get an exact duration for the stream. - uint16_t mSamplesPerSecond; - uint16_t mSamplesPerFrame; - - // If the MP3 has a variable bitrate, then there *should* be metadata about - // the encoding in the first frame. We buffer the first frame here. - nsCString mFirstFrame; - - // While we are reading the first frame, this is the stream offset of the - // last byte of that frame. -1 at all other times. - int64_t mFirstFrameEnd; - - enum eIsMP3 { - MAYBE_MP3, // We're giving the stream the benefit of the doubt... - DEFINITELY_MP3, // We've hit at least one ID3 tag or MP3 frame. - NOT_MP3 // Not found any evidence of the stream being MP3. - }; - - eIsMP3 mIsMP3; - -}; - -} // namespace mozilla - -#endif diff --git a/dom/media/MediaData.h b/dom/media/MediaData.h index a79aac6ed..905b4c1d9 100644 --- a/dom/media/MediaData.h +++ b/dom/media/MediaData.h @@ -14,6 +14,7 @@ #include "nsIMemoryReporter.h" #include "SharedBuffer.h" #include "mozilla/RefPtr.h" +#include "mozilla/Span.h" #include "mozilla/UniquePtr.h" #include "mozilla/UniquePtrExtensions.h" #include "nsTArray.h" @@ -631,6 +632,8 @@ public: { return sizeof(*this) + mBuffer.ComputedSizeOfExcludingThis(); } + // Access the buffer as a Span. + operator Span<const uint8_t>() { return MakeSpan(Data(), Size()); } const CryptoSample& mCrypto; RefPtr<MediaByteBuffer> mExtraData; diff --git a/dom/media/MediaDecoder.cpp b/dom/media/MediaDecoder.cpp index 9334d1bcb..223c59c3b 100644 --- a/dom/media/MediaDecoder.cpp +++ b/dom/media/MediaDecoder.cpp @@ -30,15 +30,10 @@ #include "mozilla/dom/VideoTrack.h" #include "mozilla/dom/VideoTrackList.h" #include "nsPrintfCString.h" -#include "mozilla/Telemetry.h" #include "GMPService.h" #include "Layers.h" #include "mozilla/layers/ShadowLayers.h" -#ifdef MOZ_ANDROID_OMX -#include "AndroidBridge.h" -#endif - using namespace mozilla::dom; using namespace mozilla::layers; using namespace mozilla::media; @@ -425,7 +420,6 @@ MediaDecoder::MediaDecoder(MediaDecoderOwner* aOwner) , INIT_CANONICAL(mPlaybackRateReliable, true) , INIT_CANONICAL(mDecoderPosition, 0) , INIT_CANONICAL(mIsVisible, !aOwner->IsHidden()) - , mTelemetryReported(false) { MOZ_COUNT_CTOR(MediaDecoder); MOZ_ASSERT(NS_IsMainThread()); @@ -845,42 +839,6 @@ MediaDecoder::MetadataLoaded(nsAutoPtr<MediaInfo> aInfo, // So we call Invalidate() after calling mOwner->MetadataLoaded to ensure // the media element has the latest dimensions. Invalidate(); - - EnsureTelemetryReported(); -} - -void -MediaDecoder::EnsureTelemetryReported() -{ - MOZ_ASSERT(NS_IsMainThread()); - - if (mTelemetryReported || !mInfo) { - // Note: sometimes we get multiple MetadataLoaded calls (for example - // for chained ogg). So we ensure we don't report duplicate results for - // these resources. - return; - } - - nsTArray<nsCString> codecs; - if (mInfo->HasAudio() && !mInfo->mAudio.GetAsAudioInfo()->mMimeType.IsEmpty()) { - codecs.AppendElement(mInfo->mAudio.GetAsAudioInfo()->mMimeType); - } - if (mInfo->HasVideo() && !mInfo->mVideo.GetAsVideoInfo()->mMimeType.IsEmpty()) { - codecs.AppendElement(mInfo->mVideo.GetAsVideoInfo()->mMimeType); - } - if (codecs.IsEmpty()) { - if (mResource->GetContentType().IsEmpty()) { - NS_WARNING("Somehow the resource's content type is empty"); - return; - } - codecs.AppendElement(nsPrintfCString("resource; %s", mResource->GetContentType().get())); - } - for (const nsCString& codec : codecs) { - DECODER_LOG("Telemetry MEDIA_CODEC_USED= '%s'", codec.get()); - Telemetry::Accumulate(Telemetry::ID::MEDIA_CODEC_USED, codec); - } - - mTelemetryReported = true; } const char* @@ -1618,16 +1576,6 @@ MediaDecoder::IsWebMEnabled() return Preferences::GetBool("media.webm.enabled"); } -#ifdef MOZ_ANDROID_OMX -bool -MediaDecoder::IsAndroidMediaPluginEnabled() -{ - return AndroidBridge::Bridge() && - AndroidBridge::Bridge()->GetAPIVersion() < 16 && - Preferences::GetBool("media.plugins.enabled"); -} -#endif - NS_IMETHODIMP MediaMemoryTracker::CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData, bool aAnonymize) diff --git a/dom/media/MediaDecoder.h b/dom/media/MediaDecoder.h index a4edcbe72..05e88db8b 100644 --- a/dom/media/MediaDecoder.h +++ b/dom/media/MediaDecoder.h @@ -440,17 +440,11 @@ private: void SetCDMProxy(CDMProxy* aProxy); - void EnsureTelemetryReported(); - static bool IsOggEnabled(); static bool IsOpusEnabled(); static bool IsWaveEnabled(); static bool IsWebMEnabled(); -#ifdef MOZ_ANDROID_OMX - static bool IsAndroidMediaPluginEnabled(); -#endif - #ifdef MOZ_WMF static bool IsWMFEnabled(); #endif @@ -856,8 +850,6 @@ private: // download has ended. Called on the main thread only. aStatus is // the result from OnStopRequest. void NotifyDownloadEnded(nsresult aStatus); - - bool mTelemetryReported; }; } // namespace mozilla diff --git a/dom/media/MediaDecoderStateMachine.cpp b/dom/media/MediaDecoderStateMachine.cpp index c586139ad..2ed1956c9 100644 --- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -1173,60 +1173,12 @@ StateObject::HandleShutdown() return SetState<ShutdownState>(); } -static void -ReportRecoveryTelemetry(const TimeStamp& aRecoveryStart, - const MediaInfo& aMediaInfo, - bool aIsHardwareAccelerated) -{ - MOZ_ASSERT(NS_IsMainThread()); - if (!aMediaInfo.HasVideo()) { - return; - } - - // Keyed by audio+video or video alone, hardware acceleration, - // and by a resolution range. - nsCString key(aMediaInfo.HasAudio() ? "AV" : "V"); - key.AppendASCII(aIsHardwareAccelerated ? "(hw)," : ","); - static const struct { int32_t mH; const char* mRes; } sResolutions[] = { - { 240, "0-240" }, - { 480, "241-480" }, - { 720, "481-720" }, - { 1080, "721-1080" }, - { 2160, "1081-2160" } - }; - const char* resolution = "2161+"; - int32_t height = aMediaInfo.mVideo.mImage.height; - for (const auto& res : sResolutions) { - if (height <= res.mH) { - resolution = res.mRes; - break; - } - } - key.AppendASCII(resolution); - - TimeDuration duration = TimeStamp::Now() - aRecoveryStart; - double duration_ms = duration.ToMilliseconds(); - Telemetry::Accumulate(Telemetry::VIDEO_SUSPEND_RECOVERY_TIME_MS, - key, - uint32_t(duration_ms + 0.5)); - Telemetry::Accumulate(Telemetry::VIDEO_SUSPEND_RECOVERY_TIME_MS, - NS_LITERAL_CSTRING("All"), - uint32_t(duration_ms + 0.5)); -} - void MediaDecoderStateMachine:: StateObject::HandleResumeVideoDecoding() { MOZ_ASSERT(mMaster->mVideoDecodeSuspended); - // Start counting recovery time from right now. - TimeStamp start = TimeStamp::Now(); - - // Local reference to mInfo, so that it will be copied in the lambda below. - auto& info = Info(); - bool hw = Reader()->VideoIsHardwareAccelerated(); - // Start video-only seek to the current time. SeekJob seekJob; @@ -1238,10 +1190,7 @@ StateObject::HandleResumeVideoDecoding() type, true /* aVideoOnly */); - SetState<SeekingState>(Move(seekJob), EventVisibility::Suppressed)->Then( - AbstractThread::MainThread(), __func__, - [start, info, hw](){ ReportRecoveryTelemetry(start, info, hw); }, - [](){}); + SetState<SeekingState>(Move(seekJob), EventVisibility::Suppressed); } void diff --git a/dom/media/MediaFormatReader.cpp b/dom/media/MediaFormatReader.cpp index 06e8b963b..773434710 100644 --- a/dom/media/MediaFormatReader.cpp +++ b/dom/media/MediaFormatReader.cpp @@ -32,6 +32,10 @@ using mozilla::layers::Image; using mozilla::layers::LayerManager; using mozilla::layers::LayersBackend; +// avoid redefined macro warning in unified builds +#undef LOG +#undef LOGV + static mozilla::LazyLogModule sFormatDecoderLog("MediaFormatReader"); mozilla::LazyLogModule gMediaDemuxerLog("MediaDemuxer"); diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index ba6b4cd47..979cb64c7 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -32,7 +32,6 @@ #include "nsAppDirectoryServiceDefs.h" #include "nsIInputStream.h" #include "nsILineInputStream.h" -#include "mozilla/Telemetry.h" #include "mozilla/Types.h" #include "mozilla/PeerIdentity.h" #include "mozilla/dom/ContentChild.h" @@ -2034,7 +2033,6 @@ MediaManager::GetUserMedia(nsPIDOMWindowInner* aWindow, } // Determine permissions early (while we still have a stack). - nsIURI* docURI = aWindow->GetDocumentURI(); if (!docURI) { return NS_ERROR_UNEXPECTED; @@ -2044,48 +2042,23 @@ MediaManager::GetUserMedia(nsPIDOMWindowInner* aWindow, Preferences::GetBool("media.navigator.permission.disabled", false); bool isHTTPS = false; docURI->SchemeIs("https", &isHTTPS); - nsCString host; - nsresult rv = docURI->GetHost(host); - // Test for some other schemes that ServiceWorker recognizes - bool isFile; - docURI->SchemeIs("file", &isFile); - bool isApp; - docURI->SchemeIs("app", &isApp); - // Same localhost check as ServiceWorkers uses - // (see IsOriginPotentiallyTrustworthy()) - bool isLocalhost = NS_SUCCEEDED(rv) && - (host.LowerCaseEqualsLiteral("localhost") || - host.LowerCaseEqualsLiteral("127.0.0.1") || - host.LowerCaseEqualsLiteral("::1")); - - // Record telemetry about whether the source of the call was secure, i.e., - // privileged or HTTPS. We may handle other cases -if (privileged) { - Telemetry::Accumulate(Telemetry::WEBRTC_GET_USER_MEDIA_SECURE_ORIGIN, - (uint32_t) GetUserMediaSecurityState::Privileged); - } else if (isHTTPS) { - Telemetry::Accumulate(Telemetry::WEBRTC_GET_USER_MEDIA_SECURE_ORIGIN, - (uint32_t) GetUserMediaSecurityState::HTTPS); - } else if (isFile) { - Telemetry::Accumulate(Telemetry::WEBRTC_GET_USER_MEDIA_SECURE_ORIGIN, - (uint32_t) GetUserMediaSecurityState::File); - } else if (isApp) { - Telemetry::Accumulate(Telemetry::WEBRTC_GET_USER_MEDIA_SECURE_ORIGIN, - (uint32_t) GetUserMediaSecurityState::App); - } else if (isLocalhost) { - Telemetry::Accumulate(Telemetry::WEBRTC_GET_USER_MEDIA_SECURE_ORIGIN, - (uint32_t) GetUserMediaSecurityState::Localhost); - } else { - Telemetry::Accumulate(Telemetry::WEBRTC_GET_USER_MEDIA_SECURE_ORIGIN, - (uint32_t) GetUserMediaSecurityState::Other); - } nsCString origin; - rv = nsPrincipal::GetOriginForURI(docURI, origin); + nsresult rv = nsPrincipal::GetOriginForURI(docURI, origin); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } + // Disallow access to null principal pages + nsCOMPtr<nsIPrincipal> principal = aWindow->GetExtantDoc()->NodePrincipal(); + if (principal->GetIsNullPrincipal()) { + RefPtr<MediaStreamError> error = + new MediaStreamError(aWindow, + NS_LITERAL_STRING("NotAllowedError")); + onFailure->OnError(error); + return NS_OK; + } + if (!Preferences::GetBool("media.navigator.video.enabled", true)) { c.mVideo.SetAsBoolean() = false; } @@ -2098,8 +2071,6 @@ if (privileged) { videoType = StringToEnum(dom::MediaSourceEnumValues::strings, vc.mMediaSource, MediaSourceEnum::Other); - Telemetry::Accumulate(Telemetry::WEBRTC_GET_USER_MEDIA_TYPE, - (uint32_t) videoType); switch (videoType) { case MediaSourceEnum::Camera: break; @@ -2182,8 +2153,6 @@ if (privileged) { ac.mMediaSource.AssignASCII(EnumToASCII(dom::MediaSourceEnumValues::strings, audioType)); } - Telemetry::Accumulate(Telemetry::WEBRTC_GET_USER_MEDIA_TYPE, - (uint32_t) audioType); switch (audioType) { case MediaSourceEnum::Microphone: @@ -2229,7 +2198,6 @@ if (privileged) { StreamListeners* listeners = AddWindowID(windowID); // Create a disabled listener to act as a placeholder - nsIPrincipal* principal = aWindow->GetExtantDoc()->NodePrincipal(); RefPtr<GetUserMediaCallbackMediaStreamListener> listener = new GetUserMediaCallbackMediaStreamListener(mMediaThread, windowID, MakePrincipalHandle(principal)); diff --git a/dom/media/MediaPrefs.h b/dom/media/MediaPrefs.h index b237ecd3d..c67a89989 100644 --- a/dom/media/MediaPrefs.h +++ b/dom/media/MediaPrefs.h @@ -105,9 +105,6 @@ private: DECL_MEDIA_PREF("media.eme.enabled", EMEEnabled, bool, false); DECL_MEDIA_PREF("media.use-blank-decoder", PDMUseBlankDecoder, bool, false); DECL_MEDIA_PREF("media.gpu-process-decoder", PDMUseGPUDecoder, bool, false); -#ifdef MOZ_GONK_MEDIACODEC - DECL_MEDIA_PREF("media.gonk.enabled", PDMGonkDecoderEnabled, bool, true); -#endif #ifdef MOZ_WIDGET_ANDROID DECL_MEDIA_PREF("media.android-media-codec.enabled", PDMAndroidMediaCodecEnabled, bool, false); DECL_MEDIA_PREF("media.android-media-codec.preferred", PDMAndroidMediaCodecPreferred, bool, false); @@ -120,6 +117,9 @@ private: #ifdef MOZ_FFVPX DECL_MEDIA_PREF("media.ffvpx.enabled", PDMFFVPXEnabled, bool, true); #endif +#ifdef MOZ_AV1 + DECL_MEDIA_PREF("media.av1.enabled", AV1Enabled, bool, false); +#endif #ifdef XP_WIN DECL_MEDIA_PREF("media.wmf.enabled", PDMWMFEnabled, bool, true); DECL_MEDIA_PREF("media.wmf.skip-blacklist", PDMWMFSkipBlacklist, bool, false); diff --git a/dom/media/MediaStreamGraph.cpp b/dom/media/MediaStreamGraph.cpp index e2934cbb2..1b9e4f674 100644 --- a/dom/media/MediaStreamGraph.cpp +++ b/dom/media/MediaStreamGraph.cpp @@ -3371,7 +3371,8 @@ MediaStreamGraphImpl::Destroy() // First unregister from memory reporting. UnregisterWeakMemoryReporter(this); - // Clear the self reference which will destroy this instance. + // Clear the self reference which will destroy this instance if all + // associated GraphDrivers are destroyed. mSelfRef = nullptr; } diff --git a/dom/media/ThreadPoolCOMListener.h b/dom/media/ThreadPoolCOMListener.h index 881013a78..424ca65d2 100644 --- a/dom/media/ThreadPoolCOMListener.h +++ b/dom/media/ThreadPoolCOMListener.h @@ -13,8 +13,8 @@ namespace mozilla { // Thread pool listener which ensures that MSCOM is initialized and -// deinitialized on the thread pool thread. We may call into WMF or -// DirectShow on this thread, so we need MSCOM working. +// deinitialized on the thread pool thread. We may call into WMF on +// this thread, so we need MSCOM working. class MSCOMInitThreadPoolListener final : public nsIThreadPoolListener { ~MSCOMInitThreadPoolListener() {} public: diff --git a/dom/media/VideoFrameContainer.cpp b/dom/media/VideoFrameContainer.cpp index 2b1965766..56aea9d27 100644 --- a/dom/media/VideoFrameContainer.cpp +++ b/dom/media/VideoFrameContainer.cpp @@ -61,7 +61,7 @@ void VideoFrameContainer::UpdatePrincipalHandleForFrameIDLocked(const PrincipalH mFrameIDForPendingPrincipalHandle = aFrameID; } -static void +static bool SetImageToBlackPixel(PlanarYCbCrImage* aImage) { uint8_t blackPixel[] = { 0x10, 0x80, 0x80 }; @@ -72,7 +72,7 @@ SetImageToBlackPixel(PlanarYCbCrImage* aImage) data.mCrChannel = blackPixel + 2; data.mYStride = data.mCbCrStride = 1; data.mPicSize = data.mYSize = data.mCbCrSize = gfx::IntSize(1, 1); - aImage->CopyData(data); + return aImage->CopyData(data); } class VideoFrameContainerInvalidateRunnable : public Runnable { @@ -122,11 +122,13 @@ void VideoFrameContainer::SetCurrentFrames(const VideoSegment& aSegment) if (frame->GetForceBlack()) { if (!mBlackImage) { - mBlackImage = GetImageContainer()->CreatePlanarYCbCrImage(); - if (mBlackImage) { + RefPtr<Image> blackImage = GetImageContainer()->CreatePlanarYCbCrImage(); + if (blackImage) { // Sets the image to a single black pixel, which will be scaled to // fill the rendered size. - SetImageToBlackPixel(mBlackImage->AsPlanarYCbCrImage()); + if (SetImageToBlackPixel(blackImage->AsPlanarYCbCrImage())) { + mBlackImage = blackImage; + } } } if (mBlackImage) { diff --git a/dom/media/VideoUtils.cpp b/dom/media/VideoUtils.cpp index 5c00e54bc..c06ba9070 100644 --- a/dom/media/VideoUtils.cpp +++ b/dom/media/VideoUtils.cpp @@ -6,7 +6,6 @@ #include "mozilla/Base64.h" #include "mozilla/TaskQueue.h" -#include "mozilla/Telemetry.h" #include "mozilla/Function.h" #include "MediaContentType.h" @@ -208,8 +207,20 @@ already_AddRefed<SharedThreadPool> GetMediaThreadPool(MediaThreadType aType) name = "MediaPlayback"; break; } - return SharedThreadPool:: + RefPtr<SharedThreadPool> pool = SharedThreadPool:: Get(nsDependentCString(name), MediaPrefs::MediaThreadPoolDefaultCount()); + + // Ensure a larger stack for platform decoder threads + if (aType == MediaThreadType::PLATFORM_DECODER) { + const uint32_t minStackSize = 512*1024; + uint32_t stackSize; + MOZ_ALWAYS_SUCCEEDS(pool->GetThreadStackSize(&stackSize)); + if (stackSize < minStackSize) { + MOZ_ALWAYS_SUCCEEDS(pool->SetThreadStackSize(minStackSize)); + } + } + + return pool.forget(); } bool @@ -248,24 +259,6 @@ ExtractH264CodecDetails(const nsAString& aCodec, aLevel *= 10; } - // Capture the constraint_set flag value for the purpose of Telemetry. - // We don't NS_ENSURE_SUCCESS here because ExtractH264CodecDetails doesn't - // care about this, but we make sure constraints is above 4 (constraint_set5_flag) - // otherwise collect 0 for unknown. - uint8_t constraints = PromiseFlatString(Substring(aCodec, 7, 2)).ToInteger(&rv, 16); - Telemetry::Accumulate(Telemetry::VIDEO_CANPLAYTYPE_H264_CONSTRAINT_SET_FLAG, - constraints >= 4 ? constraints : 0); - - // 244 is the highest meaningful profile value (High 4:4:4 Intra Profile) - // that can be represented as single hex byte, otherwise collect 0 for unknown. - Telemetry::Accumulate(Telemetry::VIDEO_CANPLAYTYPE_H264_PROFILE, - aProfile <= 244 ? aProfile : 0); - - // Make sure aLevel represents a value between levels 1 and 5.2, - // otherwise collect 0 for unknown. - Telemetry::Accumulate(Telemetry::VIDEO_CANPLAYTYPE_H264_LEVEL, - (aLevel >= 10 && aLevel <= 52) ? aLevel : 0); - return true; } @@ -445,6 +438,16 @@ ParseMIMETypeString(const nsAString& aMIMEType, return ParseCodecsString(codecsStr, aOutCodecs); } +template <int N> +static bool +StartsWith(const nsACString& string, const char (&prefix)[N]) +{ + if (N - 1 > string.Length()) { + return false; + } + return memcmp(string.Data(), prefix, N - 1) == 0; +} + bool IsH264CodecString(const nsAString& aCodec) { @@ -477,15 +480,14 @@ IsVP9CodecString(const nsAString& aCodec) aCodec.EqualsLiteral("vp9.0"); } -template <int N> -static bool -StartsWith(const nsACString& string, const char (&prefix)[N]) +#ifdef MOZ_AV1 +bool +IsAV1CodecString(const nsAString& aCodec) { - if (N - 1 > string.Length()) { - return false; - } - return memcmp(string.Data(), prefix, N - 1) == 0; + return aCodec.EqualsLiteral("av1") || + StartsWith(NS_ConvertUTF16toUTF8(aCodec), "av01"); } +#endif UniquePtr<TrackInfo> CreateTrackInfoWithMIMEType(const nsACString& aCodecMIMEType) diff --git a/dom/media/VideoUtils.h b/dom/media/VideoUtils.h index 441b63792..aaf0e9903 100644 --- a/dom/media/VideoUtils.h +++ b/dom/media/VideoUtils.h @@ -345,6 +345,11 @@ IsVP8CodecString(const nsAString& aCodec); bool IsVP9CodecString(const nsAString& aCodec); +#ifdef MOZ_AV1 +bool +IsAV1CodecString(const nsAString& aCodec); +#endif + // Try and create a TrackInfo with a given codec MIME type. UniquePtr<TrackInfo> CreateTrackInfoWithMIMEType(const nsACString& aCodecMIMEType); diff --git a/dom/media/WebVTTListener.h b/dom/media/WebVTTListener.h index 67271664a..461d7f00d 100644 --- a/dom/media/WebVTTListener.h +++ b/dom/media/WebVTTListener.h @@ -10,6 +10,7 @@ #include "nsIStreamListener.h" #include "nsIChannelEventSink.h" #include "nsIInterfaceRequestor.h" +#include "nsCOMPtr.h" #include "nsCycleCollectionParticipant.h" class nsIWebVTTParserWrapper; diff --git a/dom/media/android/AndroidMediaDecoder.cpp b/dom/media/android/AndroidMediaDecoder.cpp deleted file mode 100644 index 41ef3fcb0..000000000 --- a/dom/media/android/AndroidMediaDecoder.cpp +++ /dev/null @@ -1,25 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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 "MediaDecoderStateMachine.h" -#include "AndroidMediaDecoder.h" -#include "AndroidMediaReader.h" - -namespace mozilla { - -AndroidMediaDecoder::AndroidMediaDecoder(MediaDecoderOwner* aOwner, - const nsACString& aType) - : MediaDecoder(aOwner), mType(aType) -{ -} - -MediaDecoderStateMachine* AndroidMediaDecoder::CreateStateMachine() -{ - return new MediaDecoderStateMachine(this, new AndroidMediaReader(this, mType)); -} - -} // namespace mozilla - diff --git a/dom/media/android/AndroidMediaDecoder.h b/dom/media/android/AndroidMediaDecoder.h deleted file mode 100644 index 88b5a243f..000000000 --- a/dom/media/android/AndroidMediaDecoder.h +++ /dev/null @@ -1,28 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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/. */ -#if !defined(AndroidMediaDecoder_h_) -#define AndroidMediaDecoder_h_ - -#include "MediaDecoder.h" -#include "AndroidMediaDecoder.h" - -namespace mozilla { - -class AndroidMediaDecoder : public MediaDecoder -{ - nsCString mType; -public: - AndroidMediaDecoder(MediaDecoderOwner* aOwner, const nsACString& aType); - - MediaDecoder* Clone(MediaDecoderOwner* aOwner) override { - return new AndroidMediaDecoder(aOwner, mType); - } - MediaDecoderStateMachine* CreateStateMachine() override; -}; - -} // namespace mozilla - -#endif diff --git a/dom/media/android/AndroidMediaPluginHost.cpp b/dom/media/android/AndroidMediaPluginHost.cpp deleted file mode 100644 index d4c4fc59e..000000000 --- a/dom/media/android/AndroidMediaPluginHost.cpp +++ /dev/null @@ -1,305 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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/Preferences.h" -#include "MediaResource.h" -#include "mozilla/dom/HTMLMediaElement.h" -#include "mozilla/Services.h" -#include "AndroidMediaPluginHost.h" -#include "nsAutoPtr.h" -#include "nsXPCOMStrings.h" -#include "nsISeekableStream.h" -#include "nsIGfxInfo.h" -#include "prmem.h" -#include "prlink.h" -#include "AndroidMediaResourceServer.h" -#include "nsServiceManagerUtils.h" - -#include "MPAPI.h" - -#include "nsIPropertyBag2.h" - -#if defined(ANDROID) -#include "android/log.h" -#define ALOG(args...) __android_log_print(ANDROID_LOG_INFO, "AndroidMediaPluginHost" , ## args) -#else -#define ALOG(args...) /* do nothing */ -#endif - -using namespace MPAPI; - -Decoder::Decoder() : - mResource(nullptr), mPrivate(nullptr) -{ -} - -namespace mozilla { - -static char* GetResource(Decoder *aDecoder) -{ - return static_cast<char*>(aDecoder->mResource); -} - -class GetIntPrefEvent : public Runnable { -public: - GetIntPrefEvent(const char* aPref, int32_t* aResult) - : mPref(aPref), mResult(aResult) {} - NS_IMETHOD Run() override { - return Preferences::GetInt(mPref, mResult); - } -private: - const char* mPref; - int32_t* mResult; -}; - -static bool GetIntPref(const char* aPref, int32_t* aResult) -{ - // GetIntPref() is called on the decoder thread, but the Preferences API - // can only be called on the main thread. Post a runnable and wait. - NS_ENSURE_TRUE(aPref, false); - NS_ENSURE_TRUE(aResult, false); - nsCOMPtr<nsIRunnable> event = new GetIntPrefEvent(aPref, aResult); - return NS_SUCCEEDED(NS_DispatchToMainThread(event, NS_DISPATCH_SYNC)); -} - -static bool -GetSystemInfoString(const char *aKey, char *aResult, size_t aResultLength) -{ - NS_ENSURE_TRUE(aKey, false); - NS_ENSURE_TRUE(aResult, false); - - nsCOMPtr<nsIPropertyBag2> infoService = do_GetService("@mozilla.org/system-info;1"); - NS_ASSERTION(infoService, "Could not find a system info service"); - - nsAutoCString key(aKey); - nsAutoCString info; - nsresult rv = infoService->GetPropertyAsACString(NS_ConvertUTF8toUTF16(key), - info); - - NS_ENSURE_SUCCESS(rv, false); - - strncpy(aResult, info.get(), aResultLength); - - return true; -} - -static PluginHost sPluginHost = { - nullptr, - nullptr, - nullptr, - nullptr, - GetIntPref, - GetSystemInfoString -}; - -// Return true if Omx decoding is supported on the device. This checks the -// built in whitelist/blacklist and preferences to see if that is overridden. -static bool IsOmxSupported() -{ - bool forceEnabled = - Preferences::GetBool("stagefright.force-enabled", false); - bool disabled = - Preferences::GetBool("stagefright.disabled", false); - - if (disabled) { - NS_WARNING("XXX stagefright disabled\n"); - return false; - } - - if (!forceEnabled) { - nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo(); - if (gfxInfo) { - int32_t status; - nsCString discardFailure; - if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_STAGEFRIGHT, discardFailure, &status))) { - if (status != nsIGfxInfo::FEATURE_STATUS_OK) { - NS_WARNING("XXX stagefright blacklisted\n"); - return false; - } - } - } - } - - return true; -} - -// Return the name of the shared library that implements Omx based decoding. This varies -// depending on libstagefright version installed on the device and whether it is B2G vs Android. -// nullptr is returned if Omx decoding is not supported on the device, -static const char* GetOmxLibraryName() -{ -#if defined(ANDROID) - nsCOMPtr<nsIPropertyBag2> infoService = do_GetService("@mozilla.org/system-info;1"); - NS_ASSERTION(infoService, "Could not find a system info service"); - - int32_t version; - nsresult rv = infoService->GetPropertyAsInt32(NS_LITERAL_STRING("version"), &version); - if (NS_SUCCEEDED(rv)) { - ALOG("Android Version is: %d", version); - } - - nsAutoString release_version; - rv = infoService->GetPropertyAsAString(NS_LITERAL_STRING("release_version"), release_version); - if (NS_SUCCEEDED(rv)) { - ALOG("Android Release Version is: %s", NS_LossyConvertUTF16toASCII(release_version).get()); - } - - nsAutoString device; - rv = infoService->GetPropertyAsAString(NS_LITERAL_STRING("device"), device); - if (NS_SUCCEEDED(rv)) { - ALOG("Android Device is: %s", NS_LossyConvertUTF16toASCII(device).get()); - } - - nsAutoString manufacturer; - rv = infoService->GetPropertyAsAString(NS_LITERAL_STRING("manufacturer"), manufacturer); - if (NS_SUCCEEDED(rv)) { - ALOG("Android Manufacturer is: %s", NS_LossyConvertUTF16toASCII(manufacturer).get()); - } - - nsAutoString hardware; - rv = infoService->GetPropertyAsAString(NS_LITERAL_STRING("hardware"), hardware); - if (NS_SUCCEEDED(rv)) { - ALOG("Android Hardware is: %s", NS_LossyConvertUTF16toASCII(hardware).get()); - } -#endif - - if (!IsOmxSupported()) - return nullptr; - -#if defined(ANDROID) - if (version >= 17) { - return "libomxpluginkk.so"; - } - - // Ice Cream Sandwich and Jellybean - return "libomxplugin.so"; - -#else - return nullptr; -#endif -} - -AndroidMediaPluginHost::AndroidMediaPluginHost() { - MOZ_COUNT_CTOR(AndroidMediaPluginHost); - MOZ_ASSERT(NS_IsMainThread()); - - mResourceServer = AndroidMediaResourceServer::Start(); - - const char* name = GetOmxLibraryName(); - ALOG("Loading OMX Plugin: %s", name ? name : "nullptr"); - if (name) { - char *path = PR_GetLibraryFilePathname("libxul.so", (PRFuncPtr) GetOmxLibraryName); - PRLibrary *lib = nullptr; - if (path) { - nsAutoCString libpath(path); - PR_Free(path); - int32_t slash = libpath.RFindChar('/'); - if (slash != kNotFound) { - libpath.Truncate(slash + 1); - libpath.Append(name); - lib = PR_LoadLibrary(libpath.get()); - } - } - if (!lib) - lib = PR_LoadLibrary(name); - - if (lib) { - Manifest *manifest = static_cast<Manifest *>(PR_FindSymbol(lib, "MPAPI_MANIFEST")); - if (manifest) { - mPlugins.AppendElement(manifest); - ALOG("OMX plugin successfully loaded"); - } - } - } -} - -AndroidMediaPluginHost::~AndroidMediaPluginHost() { - mResourceServer->Stop(); - MOZ_COUNT_DTOR(AndroidMediaPluginHost); -} - -bool AndroidMediaPluginHost::FindDecoder(const nsACString& aMimeType, const char* const** aCodecs) -{ - const char *chars; - size_t len = NS_CStringGetData(aMimeType, &chars, nullptr); - for (size_t n = 0; n < mPlugins.Length(); ++n) { - Manifest *plugin = mPlugins[n]; - const char* const *codecs; - if (plugin->CanDecode(chars, len, &codecs)) { - if (aCodecs) - *aCodecs = codecs; - return true; - } - } - return false; -} - -MPAPI::Decoder *AndroidMediaPluginHost::CreateDecoder(MediaResource *aResource, const nsACString& aMimeType) -{ - NS_ENSURE_TRUE(aResource, nullptr); - - nsAutoPtr<Decoder> decoder(new Decoder()); - if (!decoder) { - return nullptr; - } - - const char *chars; - size_t len = NS_CStringGetData(aMimeType, &chars, nullptr); - for (size_t n = 0; n < mPlugins.Length(); ++n) { - Manifest *plugin = mPlugins[n]; - const char* const *codecs; - if (!plugin->CanDecode(chars, len, &codecs)) { - continue; - } - - nsCString url; - nsresult rv = mResourceServer->AddResource(aResource, url); - if (NS_FAILED (rv)) continue; - - decoder->mResource = strdup(url.get()); - if (plugin->CreateDecoder(&sPluginHost, decoder, chars, len)) { - return decoder.forget(); - } - } - - return nullptr; -} - -void AndroidMediaPluginHost::DestroyDecoder(Decoder *aDecoder) -{ - aDecoder->DestroyDecoder(aDecoder); - char* resource = GetResource(aDecoder); - if (resource) { - // resource *shouldn't* be null, but check anyway just in case the plugin - // decoder does something stupid. - mResourceServer->RemoveResource(nsCString(resource)); - free(resource); - } - delete aDecoder; -} - -AndroidMediaPluginHost *sAndroidMediaPluginHost = nullptr; -AndroidMediaPluginHost *EnsureAndroidMediaPluginHost() -{ - MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread()); - if (!sAndroidMediaPluginHost) { - sAndroidMediaPluginHost = new AndroidMediaPluginHost(); - } - return sAndroidMediaPluginHost; -} - -AndroidMediaPluginHost *GetAndroidMediaPluginHost() -{ - MOZ_ASSERT(sAndroidMediaPluginHost); - return sAndroidMediaPluginHost; -} - -void AndroidMediaPluginHost::Shutdown() -{ - delete sAndroidMediaPluginHost; - sAndroidMediaPluginHost = nullptr; -} - -} // namespace mozilla diff --git a/dom/media/android/AndroidMediaPluginHost.h b/dom/media/android/AndroidMediaPluginHost.h deleted file mode 100644 index 854b7f21e..000000000 --- a/dom/media/android/AndroidMediaPluginHost.h +++ /dev/null @@ -1,41 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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/. */ -#if !defined(AndroidMediaPluginHost_h_) -#define AndroidMediaPluginHost_h_ - -#include "nsTArray.h" -#include "MediaResource.h" -#include "MPAPI.h" -#include "AndroidMediaResourceServer.h" - -namespace mozilla { - -class AndroidMediaPluginHost { - RefPtr<AndroidMediaResourceServer> mResourceServer; - nsTArray<MPAPI::Manifest *> mPlugins; - - MPAPI::Manifest *FindPlugin(const nsACString& aMimeType); -public: - AndroidMediaPluginHost(); - ~AndroidMediaPluginHost(); - - static void Shutdown(); - - bool FindDecoder(const nsACString& aMimeType, const char* const** aCodecs); - MPAPI::Decoder *CreateDecoder(mozilla::MediaResource *aResource, const nsACString& aMimeType); - void DestroyDecoder(MPAPI::Decoder *aDecoder); -}; - -// Must be called on the main thread. Creates the plugin host if it doesn't -// already exist. -AndroidMediaPluginHost *EnsureAndroidMediaPluginHost(); - -// May be called on any thread after EnsureAndroidMediaPluginHost has been called. -AndroidMediaPluginHost *GetAndroidMediaPluginHost(); - -} // namespace mozilla - -#endif diff --git a/dom/media/android/AndroidMediaReader.cpp b/dom/media/android/AndroidMediaReader.cpp deleted file mode 100644 index 12afacbc9..000000000 --- a/dom/media/android/AndroidMediaReader.cpp +++ /dev/null @@ -1,449 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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 "AndroidMediaReader.h" -#include "mozilla/TimeStamp.h" -#include "mozilla/gfx/Point.h" -#include "MediaResource.h" -#include "VideoUtils.h" -#include "AndroidMediaDecoder.h" -#include "AndroidMediaPluginHost.h" -#include "MediaDecoderStateMachine.h" -#include "ImageContainer.h" -#include "AbstractMediaDecoder.h" -#include "gfx2DGlue.h" -#include "VideoFrameContainer.h" -#include "mozilla/CheckedInt.h" - -namespace mozilla { - -using namespace mozilla::gfx; -using namespace mozilla::media; - -typedef mozilla::layers::Image Image; -typedef mozilla::layers::PlanarYCbCrImage PlanarYCbCrImage; - -AndroidMediaReader::AndroidMediaReader(AbstractMediaDecoder *aDecoder, - const nsACString& aContentType) : - MediaDecoderReader(aDecoder), - mType(aContentType), - mPlugin(nullptr), - mHasAudio(false), - mHasVideo(false), - mVideoSeekTimeUs(-1), - mAudioSeekTimeUs(-1) -{ -} - -nsresult AndroidMediaReader::ReadMetadata(MediaInfo* aInfo, - MetadataTags** aTags) -{ - MOZ_ASSERT(OnTaskQueue()); - - if (!mPlugin) { - mPlugin = GetAndroidMediaPluginHost()->CreateDecoder(mDecoder->GetResource(), mType); - if (!mPlugin) { - return NS_ERROR_FAILURE; - } - } - - // Set the total duration (the max of the audio and video track). - int64_t durationUs; - mPlugin->GetDuration(mPlugin, &durationUs); - if (durationUs) { - mInfo.mMetadataDuration.emplace(TimeUnit::FromMicroseconds(durationUs)); - } - - if (mPlugin->HasVideo(mPlugin)) { - int32_t width, height; - mPlugin->GetVideoParameters(mPlugin, &width, &height); - nsIntRect pictureRect(0, 0, width, height); - - // Validate the container-reported frame and pictureRect sizes. This ensures - // that our video frame creation code doesn't overflow. - nsIntSize displaySize(width, height); - nsIntSize frameSize(width, height); - if (!IsValidVideoRegion(frameSize, pictureRect, displaySize)) { - return NS_ERROR_FAILURE; - } - - // Video track's frame sizes will not overflow. Activate the video track. - mHasVideo = true; - mInfo.mVideo.mDisplay = displaySize; - mPicture = pictureRect; - mInitialFrame = frameSize; - VideoFrameContainer* container = mDecoder->GetVideoFrameContainer(); - if (container) { - container->ClearCurrentFrame(IntSize(displaySize.width, displaySize.height)); - } - } - - if (mPlugin->HasAudio(mPlugin)) { - int32_t numChannels, sampleRate; - mPlugin->GetAudioParameters(mPlugin, &numChannels, &sampleRate); - mHasAudio = true; - mInfo.mAudio.mChannels = numChannels; - mInfo.mAudio.mRate = sampleRate; - } - - *aInfo = mInfo; - *aTags = nullptr; - return NS_OK; -} - -RefPtr<ShutdownPromise> -AndroidMediaReader::Shutdown() -{ - ResetDecode(); - if (mPlugin) { - GetAndroidMediaPluginHost()->DestroyDecoder(mPlugin); - mPlugin = nullptr; - } - - return MediaDecoderReader::Shutdown(); -} - -// Resets all state related to decoding, emptying all buffers etc. -nsresult AndroidMediaReader::ResetDecode(TrackSet aTracks) -{ - if (mLastVideoFrame) { - mLastVideoFrame = nullptr; - } - mSeekRequest.DisconnectIfExists(); - mSeekPromise.RejectIfExists(NS_OK, __func__); - return MediaDecoderReader::ResetDecode(aTracks); -} - -bool AndroidMediaReader::DecodeVideoFrame(bool &aKeyframeSkip, - int64_t aTimeThreshold) -{ - // Record number of frames decoded and parsed. Automatically update the - // stats counters using the AutoNotifyDecoded stack-based class. - AbstractMediaDecoder::AutoNotifyDecoded a(mDecoder); - - // Throw away the currently buffered frame if we are seeking. - if (mLastVideoFrame && mVideoSeekTimeUs != -1) { - mLastVideoFrame = nullptr; - } - - ImageBufferCallback bufferCallback(mDecoder->GetImageContainer()); - RefPtr<Image> currentImage; - - // Read next frame - while (true) { - MPAPI::VideoFrame frame; - if (!mPlugin->ReadVideo(mPlugin, &frame, mVideoSeekTimeUs, &bufferCallback)) { - // We reached the end of the video stream. If we have a buffered - // video frame, push it the video queue using the total duration - // of the video as the end time. - if (mLastVideoFrame) { - int64_t durationUs; - mPlugin->GetDuration(mPlugin, &durationUs); - durationUs = std::max<int64_t>(durationUs - mLastVideoFrame->mTime, 0); - RefPtr<VideoData> data = VideoData::ShallowCopyUpdateDuration(mLastVideoFrame, - durationUs); - mVideoQueue.Push(data); - mLastVideoFrame = nullptr; - } - return false; - } - mVideoSeekTimeUs = -1; - - if (aKeyframeSkip) { - // Disable keyframe skipping for now as - // stagefright doesn't seem to be telling us - // when a frame is a keyframe. -#if 0 - if (!frame.mKeyFrame) { - ++a.mStats.mParsedFrames; - ++a.mStats.mDroppedFrames; - continue; - } -#endif - aKeyframeSkip = false; - } - - if (frame.mSize == 0) - return true; - - currentImage = bufferCallback.GetImage(); - int64_t pos = mDecoder->GetResource()->Tell(); - IntRect picture = mPicture; - - RefPtr<VideoData> v; - if (currentImage) { - gfx::IntSize frameSize = currentImage->GetSize(); - if (frameSize.width != mInitialFrame.width || - frameSize.height != mInitialFrame.height) { - // Frame size is different from what the container reports. This is legal, - // and we will preserve the ratio of the crop rectangle as it - // was reported relative to the picture size reported by the container. - picture.x = (mPicture.x * frameSize.width) / mInitialFrame.width; - picture.y = (mPicture.y * frameSize.height) / mInitialFrame.height; - picture.width = (frameSize.width * mPicture.width) / mInitialFrame.width; - picture.height = (frameSize.height * mPicture.height) / mInitialFrame.height; - } - - v = VideoData::CreateFromImage(mInfo.mVideo, - pos, - frame.mTimeUs, - 1, // We don't know the duration yet. - currentImage, - frame.mKeyFrame, - -1, - picture); - } else { - // Assume YUV - VideoData::YCbCrBuffer b; - b.mPlanes[0].mData = static_cast<uint8_t *>(frame.Y.mData); - b.mPlanes[0].mStride = frame.Y.mStride; - b.mPlanes[0].mHeight = frame.Y.mHeight; - b.mPlanes[0].mWidth = frame.Y.mWidth; - b.mPlanes[0].mOffset = frame.Y.mOffset; - b.mPlanes[0].mSkip = frame.Y.mSkip; - - b.mPlanes[1].mData = static_cast<uint8_t *>(frame.Cb.mData); - b.mPlanes[1].mStride = frame.Cb.mStride; - b.mPlanes[1].mHeight = frame.Cb.mHeight; - b.mPlanes[1].mWidth = frame.Cb.mWidth; - b.mPlanes[1].mOffset = frame.Cb.mOffset; - b.mPlanes[1].mSkip = frame.Cb.mSkip; - - b.mPlanes[2].mData = static_cast<uint8_t *>(frame.Cr.mData); - b.mPlanes[2].mStride = frame.Cr.mStride; - b.mPlanes[2].mHeight = frame.Cr.mHeight; - b.mPlanes[2].mWidth = frame.Cr.mWidth; - b.mPlanes[2].mOffset = frame.Cr.mOffset; - b.mPlanes[2].mSkip = frame.Cr.mSkip; - - if (frame.Y.mWidth != mInitialFrame.width || - frame.Y.mHeight != mInitialFrame.height) { - - // Frame size is different from what the container reports. This is legal, - // and we will preserve the ratio of the crop rectangle as it - // was reported relative to the picture size reported by the container. - picture.x = (mPicture.x * frame.Y.mWidth) / mInitialFrame.width; - picture.y = (mPicture.y * frame.Y.mHeight) / mInitialFrame.height; - picture.width = (frame.Y.mWidth * mPicture.width) / mInitialFrame.width; - picture.height = (frame.Y.mHeight * mPicture.height) / mInitialFrame.height; - } - - // This is the approximate byte position in the stream. - v = VideoData::CreateAndCopyData(mInfo.mVideo, - mDecoder->GetImageContainer(), - pos, - frame.mTimeUs, - 1, // We don't know the duration yet. - b, - frame.mKeyFrame, - -1, - picture); - } - - if (!v) { - return false; - } - a.mStats.mParsedFrames++; - a.mStats.mDecodedFrames++; - NS_ASSERTION(a.mStats.mDecodedFrames <= a.mStats.mParsedFrames, "Expect to decode fewer frames than parsed in AndroidMedia..."); - - // Since MPAPI doesn't give us the end time of frames, we keep one frame - // buffered in AndroidMediaReader and push it into the queue as soon - // we read the following frame so we can use that frame's start time as - // the end time of the buffered frame. - if (!mLastVideoFrame) { - mLastVideoFrame = v; - continue; - } - - // Calculate the duration as the timestamp of the current frame minus the - // timestamp of the previous frame. We can then return the previously - // decoded frame, and it will have a valid timestamp. - int64_t duration = v->mTime - mLastVideoFrame->mTime; - mLastVideoFrame = VideoData::ShallowCopyUpdateDuration(mLastVideoFrame, duration); - - // We have the start time of the next frame, so we can push the previous - // frame into the queue, except if the end time is below the threshold, - // in which case it wouldn't be displayed anyway. - if (mLastVideoFrame->GetEndTime() < aTimeThreshold) { - mLastVideoFrame = nullptr; - continue; - } - - // Buffer the current frame we just decoded. - mVideoQueue.Push(mLastVideoFrame); - mLastVideoFrame = v; - - break; - } - - return true; -} - -bool AndroidMediaReader::DecodeAudioData() -{ - MOZ_ASSERT(OnTaskQueue()); - - // This is the approximate byte position in the stream. - int64_t pos = mDecoder->GetResource()->Tell(); - - // Read next frame - MPAPI::AudioFrame source; - if (!mPlugin->ReadAudio(mPlugin, &source, mAudioSeekTimeUs)) { - return false; - } - mAudioSeekTimeUs = -1; - - // Ignore empty buffers which stagefright media read will sporadically return - if (source.mSize == 0) - return true; - - uint32_t frames = source.mSize / (source.mAudioChannels * - sizeof(AudioDataValue)); - - typedef AudioCompactor::NativeCopy MPCopy; - return mAudioCompactor.Push(pos, - source.mTimeUs, - source.mAudioSampleRate, - frames, - source.mAudioChannels, - MPCopy(static_cast<uint8_t *>(source.mData), - source.mSize, - source.mAudioChannels)); -} - -RefPtr<MediaDecoderReader::SeekPromise> -AndroidMediaReader::Seek(SeekTarget aTarget, int64_t aEndTime) -{ - MOZ_ASSERT(OnTaskQueue()); - - RefPtr<SeekPromise> p = mSeekPromise.Ensure(__func__); - if (mHasAudio && mHasVideo) { - // The decoder seeks/demuxes audio and video streams separately. So if - // we seek both audio and video to aTarget, the audio stream can typically - // seek closer to the seek target, since typically every audio block is - // a sync point, whereas for video there are only keyframes once every few - // seconds. So if we have both audio and video, we must seek the video - // stream to the preceeding keyframe first, get the stream time, and then - // seek the audio stream to match the video stream's time. Otherwise, the - // audio and video streams won't be in sync after the seek. - mVideoSeekTimeUs = aTarget.GetTime().ToMicroseconds(); - - RefPtr<AndroidMediaReader> self = this; - mSeekRequest.Begin(DecodeToFirstVideoData()->Then(OwnerThread(), __func__, [self] (MediaData* v) { - self->mSeekRequest.Complete(); - self->mAudioSeekTimeUs = v->mTime; - self->mSeekPromise.Resolve(media::TimeUnit::FromMicroseconds(self->mAudioSeekTimeUs), __func__); - }, [self, aTarget] () { - self->mSeekRequest.Complete(); - self->mAudioSeekTimeUs = aTarget.GetTime().ToMicroseconds(); - self->mSeekPromise.Resolve(aTarget.GetTime(), __func__); - })); - } else { - mAudioSeekTimeUs = mVideoSeekTimeUs = aTarget.GetTime().ToMicroseconds(); - mSeekPromise.Resolve(aTarget.GetTime(), __func__); - } - - return p; -} - -AndroidMediaReader::ImageBufferCallback::ImageBufferCallback(mozilla::layers::ImageContainer *aImageContainer) : - mImageContainer(aImageContainer) -{ -} - -void * -AndroidMediaReader::ImageBufferCallback::operator()(size_t aWidth, size_t aHeight, - MPAPI::ColorFormat aColorFormat) -{ - if (!mImageContainer) { - NS_WARNING("No image container to construct an image"); - return nullptr; - } - - RefPtr<Image> image; - switch(aColorFormat) { - case MPAPI::RGB565: - image = mozilla::layers::CreateSharedRGBImage(mImageContainer, - nsIntSize(aWidth, aHeight), - SurfaceFormat::R5G6B5_UINT16); - if (!image) { - NS_WARNING("Could not create rgb image"); - return nullptr; - } - - mImage = image; - return image->GetBuffer(); - case MPAPI::I420: - return CreateI420Image(aWidth, aHeight); - default: - NS_NOTREACHED("Color format not supported"); - return nullptr; - } -} - -uint8_t * -AndroidMediaReader::ImageBufferCallback::CreateI420Image(size_t aWidth, - size_t aHeight) -{ - RefPtr<PlanarYCbCrImage> yuvImage = mImageContainer->CreatePlanarYCbCrImage(); - mImage = yuvImage; - - if (!yuvImage) { - NS_WARNING("Could not create I420 image"); - return nullptr; - } - - // Use uint32_t throughout to match AllocateAndGetNewBuffer's param - const auto checkedFrameSize = - CheckedInt<uint32_t>(aWidth) * aHeight; - - // Allocate enough for one full resolution Y plane - // and two quarter resolution Cb/Cr planes. - const auto checkedBufferSize = - checkedFrameSize + checkedFrameSize / 2; - - if (!checkedBufferSize.isValid()) { // checks checkedFrameSize too - NS_WARNING("Could not create I420 image"); - return nullptr; - } - - const auto frameSize = checkedFrameSize.value(); - - uint8_t *buffer = - yuvImage->AllocateAndGetNewBuffer(checkedBufferSize.value()); - - mozilla::layers::PlanarYCbCrData frameDesc; - - frameDesc.mYChannel = buffer; - frameDesc.mCbChannel = buffer + frameSize; - frameDesc.mCrChannel = frameDesc.mCbChannel + frameSize / 4; - - frameDesc.mYSize = IntSize(aWidth, aHeight); - frameDesc.mCbCrSize = IntSize(aWidth / 2, aHeight / 2); - - frameDesc.mYStride = aWidth; - frameDesc.mCbCrStride = aWidth / 2; - - frameDesc.mYSkip = 0; - frameDesc.mCbSkip = 0; - frameDesc.mCrSkip = 0; - - frameDesc.mPicX = 0; - frameDesc.mPicY = 0; - frameDesc.mPicSize = IntSize(aWidth, aHeight); - - yuvImage->AdoptData(frameDesc); - - return buffer; -} - -already_AddRefed<Image> -AndroidMediaReader::ImageBufferCallback::GetImage() -{ - return mImage.forget(); -} - -} // namespace mozilla diff --git a/dom/media/android/AndroidMediaReader.h b/dom/media/android/AndroidMediaReader.h deleted file mode 100644 index def85a343..000000000 --- a/dom/media/android/AndroidMediaReader.h +++ /dev/null @@ -1,75 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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/. */ -#if !defined(AndroidMediaReader_h_) -#define AndroidMediaReader_h_ - -#include "mozilla/Attributes.h" -#include "MediaResource.h" -#include "MediaDecoderReader.h" -#include "ImageContainer.h" -#include "mozilla/layers/SharedRGBImage.h" - -#include "MPAPI.h" - -class nsACString; - -namespace mozilla { - -class AbstractMediaDecoder; - -namespace layers { -class ImageContainer; -} - -class AndroidMediaReader : public MediaDecoderReader -{ - nsCString mType; - MPAPI::Decoder *mPlugin; - bool mHasAudio; - bool mHasVideo; - nsIntRect mPicture; - nsIntSize mInitialFrame; - int64_t mVideoSeekTimeUs; - int64_t mAudioSeekTimeUs; - RefPtr<VideoData> mLastVideoFrame; - MozPromiseHolder<MediaDecoderReader::SeekPromise> mSeekPromise; - MozPromiseRequestHolder<MediaDecoderReader::MediaDataPromise> mSeekRequest; -public: - AndroidMediaReader(AbstractMediaDecoder* aDecoder, - const nsACString& aContentType); - - nsresult ResetDecode(TrackSet aTracks = TrackSet(TrackInfo::kAudioTrack, - TrackInfo::kVideoTrack)) override; - - bool DecodeAudioData() override; - bool DecodeVideoFrame(bool &aKeyframeSkip, int64_t aTimeThreshold) override; - - nsresult ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags) override; - RefPtr<SeekPromise> Seek(SeekTarget aTarget, int64_t aEndTime) override; - - RefPtr<ShutdownPromise> Shutdown() override; - - class ImageBufferCallback : public MPAPI::BufferCallback { - typedef mozilla::layers::Image Image; - - public: - ImageBufferCallback(mozilla::layers::ImageContainer *aImageContainer); - void *operator()(size_t aWidth, size_t aHeight, - MPAPI::ColorFormat aColorFormat) override; - already_AddRefed<Image> GetImage(); - - private: - uint8_t *CreateI420Image(size_t aWidth, size_t aHeight); - - mozilla::layers::ImageContainer *mImageContainer; - RefPtr<Image> mImage; - }; - -}; - -} // namespace mozilla - -#endif diff --git a/dom/media/android/AndroidMediaResourceServer.cpp b/dom/media/android/AndroidMediaResourceServer.cpp deleted file mode 100644 index bd76a8c68..000000000 --- a/dom/media/android/AndroidMediaResourceServer.cpp +++ /dev/null @@ -1,503 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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/Assertions.h" -#include "mozilla/Base64.h" -#include "mozilla/IntegerPrintfMacros.h" -#include "mozilla/UniquePtr.h" -#include "nsThreadUtils.h" -#include "nsIServiceManager.h" -#include "nsISocketTransport.h" -#include "nsIOutputStream.h" -#include "nsIInputStream.h" -#include "nsIRandomGenerator.h" -#include "nsReadLine.h" -#include "nsNetCID.h" -#include "VideoUtils.h" -#include "MediaResource.h" -#include "AndroidMediaResourceServer.h" - -#if defined(_MSC_VER) -#define strtoll _strtoi64 -#endif - -using namespace mozilla; - -/* - ReadCRLF is a variant of NS_ReadLine from nsReadLine.h that deals - with the carriage return/line feed requirements of HTTP requests. -*/ -template<typename CharT, class StreamType, class StringType> -nsresult -ReadCRLF (StreamType* aStream, nsLineBuffer<CharT> * aBuffer, - StringType & aLine, bool *aMore) -{ - // eollast is true if the last character in the buffer is a '\r', - // signaling a potential '\r\n' sequence split between reads. - bool eollast = false; - - aLine.Truncate(); - - while (1) { // will be returning out of this loop on eol or eof - if (aBuffer->start == aBuffer->end) { // buffer is empty. Read into it. - uint32_t bytesRead; - nsresult rv = aStream->Read(aBuffer->buf, kLineBufferSize, &bytesRead); - if (NS_FAILED(rv) || bytesRead == 0) { - *aMore = false; - return rv; - } - aBuffer->start = aBuffer->buf; - aBuffer->end = aBuffer->buf + bytesRead; - *(aBuffer->end) = '\0'; - } - - /* - * Walk the buffer looking for an end-of-line. - * There are 4 cases to consider: - * 1. the CR char is the last char in the buffer - * 2. the CRLF sequence are the last characters in the buffer - * 3. the CRLF sequence + one or more chars at the end of the buffer - * we need at least one char after the first CRLF sequence to - * set |aMore| correctly. - * 4. The LF character is the first char in the buffer when eollast is - * true. - */ - CharT* current = aBuffer->start; - if (eollast) { // Case 4 - if (*current == '\n') { - aBuffer->start = ++current; - *aMore = true; - return NS_OK; - } - else { - eollast = false; - aLine.Append('\r'); - } - } - // Cases 2 and 3 - for ( ; current < aBuffer->end-1; ++current) { - if (*current == '\r' && *(current+1) == '\n') { - *current++ = '\0'; - *current++ = '\0'; - aLine.Append(aBuffer->start); - aBuffer->start = current; - *aMore = true; - return NS_OK; - } - } - // Case 1 - if (*current == '\r') { - eollast = true; - *current++ = '\0'; - } - - aLine.Append(aBuffer->start); - aBuffer->start = aBuffer->end; // mark the buffer empty - } -} - -// Each client HTTP request results in a thread being spawned to process it. -// That thread has a single event dispatched to it which handles the HTTP -// protocol. It parses the headers and forwards data from the MediaResource -// associated with the URL back to client. When the request is complete it will -// shutdown the thread. -class ServeResourceEvent : public Runnable { -private: - // Reading from this reads the data sent from the client. - nsCOMPtr<nsIInputStream> mInput; - - // Writing to this sends data to the client. - nsCOMPtr<nsIOutputStream> mOutput; - - // The AndroidMediaResourceServer that owns the MediaResource instances - // served. This is used to lookup the MediaResource from the URL. - RefPtr<AndroidMediaResourceServer> mServer; - - // Write 'aBufferLength' bytes from 'aBuffer' to 'mOutput'. This - // method ensures all the data is written by checking the number - // of bytes returned from the output streams 'Write' method and - // looping until done. - nsresult WriteAll(char const* aBuffer, int32_t aBufferLength); - -public: - ServeResourceEvent(nsIInputStream* aInput, nsIOutputStream* aOutput, - AndroidMediaResourceServer* aServer) - : mInput(aInput), mOutput(aOutput), mServer(aServer) {} - - // This method runs on the thread and exits when it has completed the - // HTTP request. - NS_IMETHOD Run(); - - // Given the first line of an HTTP request, parse the URL requested and - // return the MediaResource for that URL. - already_AddRefed<MediaResource> GetMediaResource(nsCString const& aHTTPRequest); - - // Gracefully shutdown the thread and cleanup resources - void Shutdown(); -}; - -nsresult -ServeResourceEvent::WriteAll(char const* aBuffer, int32_t aBufferLength) -{ - while (aBufferLength > 0) { - uint32_t written = 0; - nsresult rv = mOutput->Write(aBuffer, aBufferLength, &written); - if (NS_FAILED (rv)) return rv; - - aBufferLength -= written; - aBuffer += written; - } - - return NS_OK; -} - -already_AddRefed<MediaResource> -ServeResourceEvent::GetMediaResource(nsCString const& aHTTPRequest) -{ - // Check that the HTTP method is GET - const char* HTTP_METHOD = "GET "; - if (strncmp(aHTTPRequest.get(), HTTP_METHOD, strlen(HTTP_METHOD)) != 0) { - return nullptr; - } - - const char* url_start = strchr(aHTTPRequest.get(), ' '); - if (!url_start) { - return nullptr; - } - - const char* url_end = strrchr(++url_start, ' '); - if (!url_end) { - return nullptr; - } - - // The path extracted from the HTTP request is used as a key in hash - // table. It is not related to retrieving data from the filesystem so - // we don't need to do any sanity checking on ".." paths and similar - // exploits. - nsCString relative(url_start, url_end - url_start); - RefPtr<MediaResource> resource = - mServer->GetResource(mServer->GetURLPrefix() + relative); - return resource.forget(); -} - -NS_IMETHODIMP -ServeResourceEvent::Run() { - bool more = false; // Are there HTTP headers to read after the first line - nsCString line; // Contains the current line read from input stream - nsLineBuffer<char>* buffer = new nsLineBuffer<char>(); - nsresult rv = ReadCRLF(mInput.get(), buffer, line, &more); - if (NS_FAILED(rv)) { Shutdown(); return rv; } - - // First line contains the HTTP GET request. Extract the URL and obtain - // the MediaResource for it. - RefPtr<MediaResource> resource = GetMediaResource(line); - if (!resource) { - const char* response_404 = "HTTP/1.1 404 Not Found\r\n" - "Content-Length: 0\r\n\r\n"; - rv = WriteAll(response_404, strlen(response_404)); - Shutdown(); - return rv; - } - - // Offset in bytes to start reading from resource. - // This is zero by default but can be set to another starting value if - // this HTTP request includes a byte range request header. - int64_t start = 0; - - // Keep reading lines until we get a zero length line, which is the HTTP - // protocol's way of signifying the end of headers and start of body, or - // until we have no more data to read. - while (more && line.Length() > 0) { - rv = ReadCRLF(mInput.get(), buffer, line, &more); - if (NS_FAILED(rv)) { Shutdown(); return rv; } - - // Look for a byte range request header. If there is one, set the - // media resource offset to start from to that requested. Here we - // only check for the range request format used by Android rather - // than implementing all possibilities in the HTTP specification. - // That is, the range request is of the form: - // Range: bytes=nnnn- - // Were 'nnnn' is an integer number. - // The end of the range is not checked, instead we return up to - // the end of the resource and the client is informed of this via - // the content-range header. - NS_NAMED_LITERAL_CSTRING(byteRange, "Range: bytes="); - const char* s = strstr(line.get(), byteRange.get()); - if (s) { - start = strtoll(s+byteRange.Length(), nullptr, 10); - - // Clamp 'start' to be between 0 and the resource length. - start = std::max(int64_t(0), std::min(resource->GetLength(), start)); - } - } - - // HTTP response to use if this is a non byte range request - const char* response_normal = "HTTP/1.1 200 OK\r\n"; - - // HTTP response to use if this is a byte range request - const char* response_range = "HTTP/1.1 206 Partial Content\r\n"; - - // End of HTTP reponse headers is indicated by an empty line. - const char* response_end = "\r\n"; - - // If the request was a byte range request, we need to read from the - // requested offset. If the resource is non-seekable, or the seek - // fails, then the start offset is set back to zero. This results in all - // HTTP response data being as if the byte range request was not made. - if (start > 0 && !resource->IsTransportSeekable()) { - start = 0; - } - - const char* response_line = start > 0 ? - response_range : - response_normal; - rv = WriteAll(response_line, strlen(response_line)); - if (NS_FAILED(rv)) { Shutdown(); return NS_OK; } - - // Buffer used for reading from the input stream and writing to - // the output stream. The buffer size should be big enough for the - // HTTP response headers sent below. A static_assert ensures - // this where the buffer is used. - const int buffer_size = 32768; - auto b = MakeUnique<char[]>(buffer_size); - - // If we know the length of the resource, send a Content-Length header. - int64_t contentlength = resource->GetLength() - start; - if (contentlength > 0) { - static_assert (buffer_size > 1024, - "buffer_size must be large enough " - "to hold response headers"); - snprintf(b.get(), buffer_size, "Content-Length: %" PRId64 "\r\n", contentlength); - rv = WriteAll(b.get(), strlen(b.get())); - if (NS_FAILED(rv)) { Shutdown(); return NS_OK; } - } - - // If the request was a byte range request, respond with a Content-Range - // header which details the extent of the data returned. - if (start > 0) { - static_assert (buffer_size > 1024, - "buffer_size must be large enough " - "to hold response headers"); - snprintf(b.get(), buffer_size, "Content-Range: " - "bytes %" PRId64 "-%" PRId64 "/%" PRId64 "\r\n", - start, resource->GetLength() - 1, resource->GetLength()); - rv = WriteAll(b.get(), strlen(b.get())); - if (NS_FAILED(rv)) { Shutdown(); return NS_OK; } - } - - rv = WriteAll(response_end, strlen(response_end)); - if (NS_FAILED(rv)) { Shutdown(); return NS_OK; } - - rv = mOutput->Flush(); - if (NS_FAILED(rv)) { Shutdown(); return NS_OK; } - - // Read data from media resource - uint32_t bytesRead = 0; // Number of bytes read/written to streams - rv = resource->ReadAt(start, b.get(), buffer_size, &bytesRead); - while (NS_SUCCEEDED(rv) && bytesRead != 0) { - // Keep track of what we think the starting position for the next read - // is. This is used in subsequent ReadAt calls to ensure we are reading - // from the correct offset in the case where another thread is reading - // from th same MediaResource. - start += bytesRead; - - // Write data obtained from media resource to output stream - rv = WriteAll(b.get(), bytesRead); - if (NS_FAILED (rv)) break; - - rv = resource->ReadAt(start, b.get(), 32768, &bytesRead); - } - - Shutdown(); - return NS_OK; -} - -void -ServeResourceEvent::Shutdown() -{ - // Cleanup resources and exit. - mInput->Close(); - mOutput->Close(); - - // To shutdown the current thread we need to first exit this event. - // The Shutdown event below is posted to the main thread to do this. - nsCOMPtr<nsIRunnable> event = new ShutdownThreadEvent(NS_GetCurrentThread()); - NS_DispatchToMainThread(event); -} - -/* - This is the listener attached to the server socket. When an HTTP - request is made by the client the OnSocketAccepted method is - called. This method will spawn a thread to process the request. - The thread receives a single event which does the parsing of - the HTTP request and forwarding the data from the MediaResource - to the output stream of the request. - - The MediaResource used for providing the request data is obtained - from the AndroidMediaResourceServer that created this listener, using the - URL the client requested. -*/ -class ResourceSocketListener : public nsIServerSocketListener -{ -public: - // The AndroidMediaResourceServer used to look up the MediaResource - // on requests. - RefPtr<AndroidMediaResourceServer> mServer; - - NS_DECL_THREADSAFE_ISUPPORTS - NS_DECL_NSISERVERSOCKETLISTENER - - ResourceSocketListener(AndroidMediaResourceServer* aServer) : - mServer(aServer) - { - } - -private: - virtual ~ResourceSocketListener() { } -}; - -NS_IMPL_ISUPPORTS(ResourceSocketListener, nsIServerSocketListener) - -NS_IMETHODIMP -ResourceSocketListener::OnSocketAccepted(nsIServerSocket* aServ, - nsISocketTransport* aTrans) -{ - nsCOMPtr<nsIInputStream> input; - nsCOMPtr<nsIOutputStream> output; - nsresult rv; - - rv = aTrans->OpenInputStream(nsITransport::OPEN_BLOCKING, 0, 0, getter_AddRefs(input)); - if (NS_FAILED(rv)) return rv; - - rv = aTrans->OpenOutputStream(nsITransport::OPEN_BLOCKING, 0, 0, getter_AddRefs(output)); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr<nsIThread> thread; - rv = NS_NewThread(getter_AddRefs(thread)); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr<nsIRunnable> event = new ServeResourceEvent(input.get(), output.get(), mServer); - return thread->Dispatch(event, NS_DISPATCH_NORMAL); -} - -NS_IMETHODIMP -ResourceSocketListener::OnStopListening(nsIServerSocket* aServ, nsresult aStatus) -{ - return NS_OK; -} - -AndroidMediaResourceServer::AndroidMediaResourceServer() : - mMutex("AndroidMediaResourceServer") -{ -} - -NS_IMETHODIMP -AndroidMediaResourceServer::Run() -{ - MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread()); - MutexAutoLock lock(mMutex); - - nsresult rv; - mSocket = do_CreateInstance(NS_SERVERSOCKET_CONTRACTID, &rv); - if (NS_FAILED(rv)) return rv; - - rv = mSocket->InitSpecialConnection(-1, - nsIServerSocket::LoopbackOnly - | nsIServerSocket::KeepWhenOffline, - -1); - if (NS_FAILED(rv)) return rv; - - rv = mSocket->AsyncListen(new ResourceSocketListener(this)); - if (NS_FAILED(rv)) return rv; - - return NS_OK; -} - -/* static */ -already_AddRefed<AndroidMediaResourceServer> -AndroidMediaResourceServer::Start() -{ - MOZ_ASSERT(NS_IsMainThread()); - RefPtr<AndroidMediaResourceServer> server = new AndroidMediaResourceServer(); - server->Run(); - return server.forget(); -} - -void -AndroidMediaResourceServer::Stop() -{ - MutexAutoLock lock(mMutex); - mSocket->Close(); - mSocket = nullptr; -} - -nsresult -AndroidMediaResourceServer::AppendRandomPath(nsCString& aUrl) -{ - // Use a cryptographic quality PRNG to generate raw random bytes - // and convert that to a base64 string for use as an URL path. This - // is based on code from nsExternalAppHandler::SetUpTempFile. - nsresult rv; - nsAutoCString salt; - rv = GenerateRandomPathName(salt, 16); - if (NS_FAILED(rv)) return rv; - aUrl += "/"; - aUrl += salt; - return NS_OK; -} - -nsresult -AndroidMediaResourceServer::AddResource(mozilla::MediaResource* aResource, nsCString& aUrl) -{ - nsCString url = GetURLPrefix(); - nsresult rv = AppendRandomPath(url); - if (NS_FAILED (rv)) return rv; - - { - MutexAutoLock lock(mMutex); - - // Adding a resource URL that already exists is considered an error. - if (mResources.find(url) != mResources.end()) return NS_ERROR_FAILURE; - mResources[url] = aResource; - } - - aUrl = url; - - return NS_OK; -} - -void -AndroidMediaResourceServer::RemoveResource(nsCString const& aUrl) -{ - MutexAutoLock lock(mMutex); - mResources.erase(aUrl); -} - -nsCString -AndroidMediaResourceServer::GetURLPrefix() -{ - MutexAutoLock lock(mMutex); - - int32_t port = 0; - nsresult rv = mSocket->GetPort(&port); - if (NS_FAILED (rv) || port < 0) { - return nsCString(""); - } - - char buffer[256]; - snprintf(buffer, sizeof(buffer), "http://127.0.0.1:%d", port >= 0 ? port : 0); - return nsCString(buffer); -} - -already_AddRefed<MediaResource> -AndroidMediaResourceServer::GetResource(nsCString const& aUrl) -{ - MutexAutoLock lock(mMutex); - ResourceMap::const_iterator it = mResources.find(aUrl); - if (it == mResources.end()) return nullptr; - - RefPtr<MediaResource> resource = it->second; - return resource.forget(); -} diff --git a/dom/media/android/AndroidMediaResourceServer.h b/dom/media/android/AndroidMediaResourceServer.h deleted file mode 100644 index 68200f9c0..000000000 --- a/dom/media/android/AndroidMediaResourceServer.h +++ /dev/null @@ -1,96 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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/. */ -#if !defined(AndroidMediaResourceServer_h_) -#define AndroidMediaResourceServer_h_ - -#include <map> -#include "nsIServerSocket.h" -#include "MediaResource.h" - -namespace mozilla { - -class MediaResource; - -/* - AndroidMediaResourceServer instantiates a socket server that understands - HTTP requests for MediaResource instances. The server runs on an - automatically selected port and MediaResource instances are registered. - The registration returns a string URL than can be used to fetch the - resource. That URL contains a randomly generated path to make it - difficult for other local applications on the device to guess it. - - The HTTP protocol is limited in that it supports only what the - Android DataSource implementation uses to fetch media. It - understands HTTP GET and byte range requests. - - The intent of this class is to be used in Media backends that - have a system component that does its own network requests. These - requests are made against this server which then uses standard - Gecko network requests and media cache usage. - - The AndroidMediaResourceServer can be instantiated on any thread and - its methods are threadsafe - they can be called on any thread. - The server socket itself is always run on the main thread and - this is done by the Start() static method by synchronously - dispatching to the main thread. -*/ -class AndroidMediaResourceServer : public Runnable -{ -private: - // Mutex protecting private members of AndroidMediaResourceServer. - // All member variables below this point in the class definition - // must acquire the mutex before access. - mozilla::Mutex mMutex; - - // Server socket used to listen for incoming connections - nsCOMPtr<nsIServerSocket> mSocket; - - // Mapping between MediaResource URL's to the MediaResource - // object served at that URL. - typedef std::map<nsCString, - RefPtr<mozilla::MediaResource> > ResourceMap; - ResourceMap mResources; - - // Create a AndroidMediaResourceServer that will listen on an automatically - // selected port when started. This is private as it should only be - // called internally from the public 'Start' method. - AndroidMediaResourceServer(); - NS_IMETHOD Run(); - - // Append a random URL path to a string. This is used for creating a - // unique URl for a resource which helps prevent malicious software - // running on the same machine as the server from guessing the URL - // and accessing video data. - nsresult AppendRandomPath(nsCString& aURL); - -public: - // Create a AndroidMediaResourceServer and start it listening. This call will - // perform a synchronous request on the main thread. - static already_AddRefed<AndroidMediaResourceServer> Start(); - - // Stops the server from listening and accepting further connections. - void Stop(); - - // Add a MediaResource to be served by this server. Stores the - // absolute URL that can be used to access the resource in 'aUrl'. - nsresult AddResource(mozilla::MediaResource* aResource, nsCString& aUrl); - - // Remove a MediaResource so it is no longer served by this server. - // The URL provided must match exactly that provided by a previous - // call to "AddResource". - void RemoveResource(nsCString const& aUrl); - - // Returns the prefix for HTTP requests to the server. This plus - // the result of AddResource results in an Absolute URL. - nsCString GetURLPrefix(); - - // Returns the resource asociated with a given URL - already_AddRefed<mozilla::MediaResource> GetResource(nsCString const& aUrl); -}; - -} // namespace mozilla - -#endif diff --git a/dom/media/android/MPAPI.h b/dom/media/android/MPAPI.h deleted file mode 100644 index 9b289ca09..000000000 --- a/dom/media/android/MPAPI.h +++ /dev/null @@ -1,165 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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/. */ -#if !defined(MPAPI_h_) -#define MPAPI_h_ - -#include <stdint.h> - -namespace MPAPI { - -enum ColorFormat { - I420, - RGB565 -}; - -/* - * A callback for the plugin to use to request a buffer owned by gecko. This can - * save us a copy or two down the line. - */ -class BufferCallback { -public: - virtual void *operator()(size_t aWidth, size_t aHeight, - ColorFormat aColorFormat) = 0; -}; - -struct VideoPlane { - VideoPlane() : - mData(0), - mStride(0), - mWidth(0), - mHeight(0), - mOffset(0), - mSkip(0) - {} - - void *mData; - int32_t mStride; - int32_t mWidth; - int32_t mHeight; - int32_t mOffset; - int32_t mSkip; -}; - -struct VideoFrame { - int64_t mTimeUs; - bool mKeyFrame; - void *mData; - size_t mSize; - int32_t mStride; - int32_t mSliceHeight; - int32_t mRotation; - VideoPlane Y; - VideoPlane Cb; - VideoPlane Cr; - - VideoFrame() : - mTimeUs(0), - mKeyFrame(false), - mData(0), - mSize(0), - mStride(0), - mSliceHeight(0), - mRotation(0) - {} - - void Set(int64_t aTimeUs, bool aKeyFrame, - void *aData, size_t aSize, int32_t aStride, int32_t aSliceHeight, int32_t aRotation, - void *aYData, int32_t aYStride, int32_t aYWidth, int32_t aYHeight, int32_t aYOffset, int32_t aYSkip, - void *aCbData, int32_t aCbStride, int32_t aCbWidth, int32_t aCbHeight, int32_t aCbOffset, int32_t aCbSkip, - void *aCrData, int32_t aCrStride, int32_t aCrWidth, int32_t aCrHeight, int32_t aCrOffset, int32_t aCrSkip) - { - mTimeUs = aTimeUs; - mKeyFrame = aKeyFrame; - mData = aData; - mSize = aSize; - mStride = aStride; - mSliceHeight = aSliceHeight; - mRotation = aRotation; - Y.mData = aYData; - Y.mStride = aYStride; - Y.mWidth = aYWidth; - Y.mHeight = aYHeight; - Y.mOffset = aYOffset; - Y.mSkip = aYSkip; - Cb.mData = aCbData; - Cb.mStride = aCbStride; - Cb.mWidth = aCbWidth; - Cb.mHeight = aCbHeight; - Cb.mOffset = aCbOffset; - Cb.mSkip = aCbSkip; - Cr.mData = aCrData; - Cr.mStride = aCrStride; - Cr.mWidth = aCrWidth; - Cr.mHeight = aCrHeight; - Cr.mOffset = aCrOffset; - Cr.mSkip = aCrSkip; - } -}; - -struct AudioFrame { - int64_t mTimeUs; - void *mData; // 16PCM interleaved - size_t mSize; // Size of mData in bytes - int32_t mAudioChannels; - int32_t mAudioSampleRate; - - AudioFrame() : - mTimeUs(0), - mData(0), - mSize(0), - mAudioChannels(0), - mAudioSampleRate(0) - { - } - - void Set(int64_t aTimeUs, - void *aData, size_t aSize, - int32_t aAudioChannels, int32_t aAudioSampleRate) - { - mTimeUs = aTimeUs; - mData = aData; - mSize = aSize; - mAudioChannels = aAudioChannels; - mAudioSampleRate = aAudioSampleRate; - } -}; - -struct Decoder; - -struct PluginHost { - bool (*Read)(Decoder *aDecoder, char *aBuffer, int64_t aOffset, uint32_t aCount, uint32_t* aBytes); - uint64_t (*GetLength)(Decoder *aDecoder); - void (*SetMetaDataReadMode)(Decoder *aDecoder); - void (*SetPlaybackReadMode)(Decoder *aDecoder); - bool (*GetIntPref)(const char *aPref, int32_t *aResult); - bool (*GetSystemInfoString)(const char *aKey, char *aResult, size_t aResultLen); -}; - -struct Decoder { - void *mResource; - void *mPrivate; - - Decoder(); - - void (*GetDuration)(Decoder *aDecoder, int64_t *durationUs); - void (*GetVideoParameters)(Decoder *aDecoder, int32_t *aWidth, int32_t *aHeight); - void (*GetAudioParameters)(Decoder *aDecoder, int32_t *aNumChannels, int32_t *aSampleRate); - bool (*HasVideo)(Decoder *aDecoder); - bool (*HasAudio)(Decoder *aDecoder); - bool (*ReadVideo)(Decoder *aDecoder, VideoFrame *aFrame, int64_t aSeekTimeUs, BufferCallback *aBufferCallback); - bool (*ReadAudio)(Decoder *aDecoder, AudioFrame *aFrame, int64_t aSeekTimeUs); - void (*DestroyDecoder)(Decoder *); -}; - -struct Manifest { - bool (*CanDecode)(const char *aMimeChars, size_t aMimeLen, const char* const**aCodecs); - bool (*CreateDecoder)(PluginHost *aPluginHost, Decoder *aDecoder, - const char *aMimeChars, size_t aMimeLen); -}; - -} - -#endif diff --git a/dom/media/android/moz.build b/dom/media/android/moz.build deleted file mode 100644 index 3ad43cd50..000000000 --- a/dom/media/android/moz.build +++ /dev/null @@ -1,27 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# 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/. - -EXPORTS += [ - 'AndroidMediaDecoder.h', - 'AndroidMediaPluginHost.h', - 'AndroidMediaReader.h', - 'AndroidMediaResourceServer.h', - 'MPAPI.h', -] - -UNIFIED_SOURCES += [ - 'AndroidMediaDecoder.cpp', - 'AndroidMediaPluginHost.cpp', - 'AndroidMediaReader.cpp', - 'AndroidMediaResourceServer.cpp', -] - -LOCAL_INCLUDES += [ - '/dom/base', - '/dom/html', -] - -FINAL_LIBRARY = 'xul' diff --git a/dom/media/directshow/AudioSinkFilter.cpp b/dom/media/directshow/AudioSinkFilter.cpp deleted file mode 100644 index 9f23c0e00..000000000 --- a/dom/media/directshow/AudioSinkFilter.cpp +++ /dev/null @@ -1,285 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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 "SampleSink.h" -#include "AudioSinkFilter.h" -#include "AudioSinkInputPin.h" -#include "VideoUtils.h" -#include "mozilla/Logging.h" - - -#include <initguid.h> -#include <wmsdkidl.h> - -#define DELETE_RESET(p) { delete (p) ; (p) = nullptr ;} - -DEFINE_GUID(CLSID_MozAudioSinkFilter, 0x1872d8c8, 0xea8d, 0x4c34, 0xae, 0x96, 0x69, 0xde, - 0xf1, 0x33, 0x7b, 0x33); - -using namespace mozilla::media; - -namespace mozilla { - -static LazyLogModule gDirectShowLog("DirectShowDecoder"); -#define LOG(...) MOZ_LOG(gDirectShowLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) - -AudioSinkFilter::AudioSinkFilter(const wchar_t* aObjectName, HRESULT* aOutResult) - : BaseFilter(aObjectName, CLSID_MozAudioSinkFilter), - mFilterCritSec("AudioSinkFilter::mFilterCritSec") -{ - (*aOutResult) = S_OK; - mInputPin = new AudioSinkInputPin(L"AudioSinkInputPin", - this, - &mFilterCritSec, - aOutResult); -} - -AudioSinkFilter::~AudioSinkFilter() -{ -} - -int -AudioSinkFilter::GetPinCount() -{ - return 1; -} - -BasePin* -AudioSinkFilter::GetPin(int aIndex) -{ - CriticalSectionAutoEnter lockFilter(mFilterCritSec); - return (aIndex == 0) ? static_cast<BasePin*>(mInputPin) : nullptr; -} - -HRESULT -AudioSinkFilter::Pause() -{ - CriticalSectionAutoEnter lockFilter(mFilterCritSec); - if (mState == State_Stopped) { - // Change the state, THEN activate the input pin. - mState = State_Paused; - if (mInputPin && mInputPin->IsConnected()) { - mInputPin->Active(); - } - } else if (mState == State_Running) { - mState = State_Paused; - } - return S_OK; -} - -HRESULT -AudioSinkFilter::Stop() -{ - CriticalSectionAutoEnter lockFilter(mFilterCritSec); - mState = State_Stopped; - if (mInputPin) { - mInputPin->Inactive(); - } - - GetSampleSink()->Flush(); - - return S_OK; -} - -HRESULT -AudioSinkFilter::Run(REFERENCE_TIME tStart) -{ - LOG("AudioSinkFilter::Run(%lld) [%4.2lf]", - RefTimeToUsecs(tStart), - double(RefTimeToUsecs(tStart)) / USECS_PER_S); - return media::BaseFilter::Run(tStart); -} - -HRESULT -AudioSinkFilter::GetClassID( OUT CLSID * pCLSID ) -{ - (* pCLSID) = CLSID_MozAudioSinkFilter; - return S_OK; -} - -HRESULT -AudioSinkFilter::QueryInterface(REFIID aIId, void **aInterface) -{ - if (aIId == IID_IMediaSeeking) { - *aInterface = static_cast<IMediaSeeking*>(this); - AddRef(); - return S_OK; - } - return mozilla::media::BaseFilter::QueryInterface(aIId, aInterface); -} - -ULONG -AudioSinkFilter::AddRef() -{ - return ::InterlockedIncrement(&mRefCnt); -} - -ULONG -AudioSinkFilter::Release() -{ - unsigned long newRefCnt = ::InterlockedDecrement(&mRefCnt); - if (!newRefCnt) { - delete this; - } - return newRefCnt; -} - -SampleSink* -AudioSinkFilter::GetSampleSink() -{ - return mInputPin->GetSampleSink(); -} - - -// IMediaSeeking implementation. -// -// Calls to IMediaSeeking are forwarded to the output pin that the -// AudioSinkInputPin is connected to, i.e. upstream towards the parser and -// source filters, which actually implement seeking. -#define ENSURE_CONNECTED_PIN_SEEKING \ - if (!mInputPin) { \ - return E_NOTIMPL; \ - } \ - RefPtr<IMediaSeeking> pinSeeking = mInputPin->GetConnectedPinSeeking(); \ - if (!pinSeeking) { \ - return E_NOTIMPL; \ - } - -HRESULT -AudioSinkFilter::GetCapabilities(DWORD* aCapabilities) -{ - ENSURE_CONNECTED_PIN_SEEKING - return pinSeeking->GetCapabilities(aCapabilities); -} - -HRESULT -AudioSinkFilter::CheckCapabilities(DWORD* aCapabilities) -{ - ENSURE_CONNECTED_PIN_SEEKING - return pinSeeking->CheckCapabilities(aCapabilities); -} - -HRESULT -AudioSinkFilter::IsFormatSupported(const GUID* aFormat) -{ - ENSURE_CONNECTED_PIN_SEEKING - return pinSeeking->IsFormatSupported(aFormat); -} - -HRESULT -AudioSinkFilter::QueryPreferredFormat(GUID* aFormat) -{ - ENSURE_CONNECTED_PIN_SEEKING - return pinSeeking->QueryPreferredFormat(aFormat); -} - -HRESULT -AudioSinkFilter::GetTimeFormat(GUID* aFormat) -{ - ENSURE_CONNECTED_PIN_SEEKING - return pinSeeking->GetTimeFormat(aFormat); -} - -HRESULT -AudioSinkFilter::IsUsingTimeFormat(const GUID* aFormat) -{ - ENSURE_CONNECTED_PIN_SEEKING - return pinSeeking->IsUsingTimeFormat(aFormat); -} - -HRESULT -AudioSinkFilter::SetTimeFormat(const GUID* aFormat) -{ - ENSURE_CONNECTED_PIN_SEEKING - return pinSeeking->SetTimeFormat(aFormat); -} - -HRESULT -AudioSinkFilter::GetDuration(LONGLONG* aDuration) -{ - ENSURE_CONNECTED_PIN_SEEKING - return pinSeeking->GetDuration(aDuration); -} - -HRESULT -AudioSinkFilter::GetStopPosition(LONGLONG* aStop) -{ - ENSURE_CONNECTED_PIN_SEEKING - return pinSeeking->GetStopPosition(aStop); -} - -HRESULT -AudioSinkFilter::GetCurrentPosition(LONGLONG* aCurrent) -{ - ENSURE_CONNECTED_PIN_SEEKING - return pinSeeking->GetCurrentPosition(aCurrent); -} - -HRESULT -AudioSinkFilter::ConvertTimeFormat(LONGLONG* aTarget, - const GUID* aTargetFormat, - LONGLONG aSource, - const GUID* aSourceFormat) -{ - ENSURE_CONNECTED_PIN_SEEKING - return pinSeeking->ConvertTimeFormat(aTarget, - aTargetFormat, - aSource, - aSourceFormat); -} - -HRESULT -AudioSinkFilter::SetPositions(LONGLONG* aCurrent, - DWORD aCurrentFlags, - LONGLONG* aStop, - DWORD aStopFlags) -{ - ENSURE_CONNECTED_PIN_SEEKING - return pinSeeking->SetPositions(aCurrent, - aCurrentFlags, - aStop, - aStopFlags); -} - -HRESULT -AudioSinkFilter::GetPositions(LONGLONG* aCurrent, - LONGLONG* aStop) -{ - ENSURE_CONNECTED_PIN_SEEKING - return pinSeeking->GetPositions(aCurrent, aStop); -} - -HRESULT -AudioSinkFilter::GetAvailable(LONGLONG* aEarliest, - LONGLONG* aLatest) -{ - ENSURE_CONNECTED_PIN_SEEKING - return pinSeeking->GetAvailable(aEarliest, aLatest); -} - -HRESULT -AudioSinkFilter::SetRate(double aRate) -{ - ENSURE_CONNECTED_PIN_SEEKING - return pinSeeking->SetRate(aRate); -} - -HRESULT -AudioSinkFilter::GetRate(double* aRate) -{ - ENSURE_CONNECTED_PIN_SEEKING - return pinSeeking->GetRate(aRate); -} - -HRESULT -AudioSinkFilter::GetPreroll(LONGLONG* aPreroll) -{ - ENSURE_CONNECTED_PIN_SEEKING - return pinSeeking->GetPreroll(aPreroll); -} - -} // namespace mozilla - diff --git a/dom/media/directshow/AudioSinkFilter.h b/dom/media/directshow/AudioSinkFilter.h deleted file mode 100644 index 85abdfccf..000000000 --- a/dom/media/directshow/AudioSinkFilter.h +++ /dev/null @@ -1,95 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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/. */ - -#if !defined(AudioSinkFilter_h_) -#define AudioSinkFilter_h_ - -#include "BaseFilter.h" -#include "DirectShowUtils.h" -#include "nsAutoPtr.h" -#include "mozilla/RefPtr.h" - -namespace mozilla { - -class AudioSinkInputPin; -class SampleSink; - -// Filter that acts as the end of the graph. Audio samples input into -// this filter block the calling thread, and the calling thread is -// unblocked when the decode thread extracts the sample. The samples -// input into this filter are stored in the SampleSink, where the blocking -// is implemented. The input pin owns the SampleSink. -class AudioSinkFilter: public mozilla::media::BaseFilter, - public IMediaSeeking -{ - -public: - AudioSinkFilter(const wchar_t* aObjectName, HRESULT* aOutResult); - virtual ~AudioSinkFilter(); - - // Gets the input pin's sample sink. - SampleSink* GetSampleSink(); - - // IUnknown implementation. - STDMETHODIMP QueryInterface(REFIID aIId, void **aInterface); - STDMETHODIMP_(ULONG) AddRef(); - STDMETHODIMP_(ULONG) Release(); - - // -------------------------------------------------------------------- - // CBaseFilter methods - int GetPinCount (); - mozilla::media::BasePin* GetPin ( IN int Index); - STDMETHODIMP Pause (); - STDMETHODIMP Stop (); - STDMETHODIMP GetClassID ( OUT CLSID * pCLSID); - STDMETHODIMP Run(REFERENCE_TIME tStart); - // IMediaSeeking Methods... - - // We defer to SourceFilter, but we must expose the interface on - // the output pins. Seeking commands come upstream from the renderers, - // but they must be actioned at the source filters. - STDMETHODIMP GetCapabilities(DWORD* aCapabilities); - STDMETHODIMP CheckCapabilities(DWORD* aCapabilities); - STDMETHODIMP IsFormatSupported(const GUID* aFormat); - STDMETHODIMP QueryPreferredFormat(GUID* aFormat); - STDMETHODIMP GetTimeFormat(GUID* aFormat); - STDMETHODIMP IsUsingTimeFormat(const GUID* aFormat); - STDMETHODIMP SetTimeFormat(const GUID* aFormat); - STDMETHODIMP GetDuration(LONGLONG* pDuration); - STDMETHODIMP GetStopPosition(LONGLONG* pStop); - STDMETHODIMP GetCurrentPosition(LONGLONG* aCurrent); - STDMETHODIMP ConvertTimeFormat(LONGLONG* aTarget, - const GUID* aTargetFormat, - LONGLONG aSource, - const GUID* aSourceFormat); - STDMETHODIMP SetPositions(LONGLONG* aCurrent, - DWORD aCurrentFlags, - LONGLONG* aStop, - DWORD aStopFlags); - STDMETHODIMP GetPositions(LONGLONG* aCurrent, - LONGLONG* aStop); - STDMETHODIMP GetAvailable(LONGLONG* aEarliest, - LONGLONG* aLatest); - STDMETHODIMP SetRate(double aRate); - STDMETHODIMP GetRate(double* aRate); - STDMETHODIMP GetPreroll(LONGLONG* aPreroll); - - // -------------------------------------------------------------------- - // class factory calls this - static IUnknown * CreateInstance (IN LPUNKNOWN punk, OUT HRESULT * phr); - -private: - CriticalSection mFilterCritSec; - - // Note: The input pin defers its refcounting to the sink filter, so when - // the input pin is addrefed, what actually happens is the sink filter is - // addrefed. - nsAutoPtr<AudioSinkInputPin> mInputPin; -}; - -} // namespace mozilla - -#endif // AudioSinkFilter_h_ diff --git a/dom/media/directshow/AudioSinkInputPin.cpp b/dom/media/directshow/AudioSinkInputPin.cpp deleted file mode 100644 index 85a6e3da3..000000000 --- a/dom/media/directshow/AudioSinkInputPin.cpp +++ /dev/null @@ -1,195 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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 "AudioSinkInputPin.h" -#include "AudioSinkFilter.h" -#include "SampleSink.h" -#include "mozilla/Logging.h" - -#include <wmsdkidl.h> - -using namespace mozilla::media; - -namespace mozilla { - -static LazyLogModule gDirectShowLog("DirectShowDecoder"); -#define LOG(...) MOZ_LOG(gDirectShowLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) - -AudioSinkInputPin::AudioSinkInputPin(wchar_t* aObjectName, - AudioSinkFilter* aFilter, - mozilla::CriticalSection* aLock, - HRESULT* aOutResult) - : BaseInputPin(aObjectName, aFilter, aLock, aOutResult, aObjectName), - mSegmentStartTime(0) -{ - MOZ_COUNT_CTOR(AudioSinkInputPin); - mSampleSink = new SampleSink(); -} - -AudioSinkInputPin::~AudioSinkInputPin() -{ - MOZ_COUNT_DTOR(AudioSinkInputPin); -} - -HRESULT -AudioSinkInputPin::GetMediaType(int aPosition, MediaType* aOutMediaType) -{ - NS_ENSURE_TRUE(aPosition >= 0, E_INVALIDARG); - NS_ENSURE_TRUE(aOutMediaType, E_POINTER); - - if (aPosition > 0) { - return S_FALSE; - } - - // Note: We set output as PCM, as IEEE_FLOAT only works when using the - // MP3 decoder as an MFT, and we can't do that while using DirectShow. - aOutMediaType->SetType(&MEDIATYPE_Audio); - aOutMediaType->SetSubtype(&MEDIASUBTYPE_PCM); - aOutMediaType->SetType(&FORMAT_WaveFormatEx); - aOutMediaType->SetTemporalCompression(FALSE); - - return S_OK; -} - -HRESULT -AudioSinkInputPin::CheckMediaType(const MediaType* aMediaType) -{ - if (!aMediaType) { - return E_INVALIDARG; - } - - GUID majorType = *aMediaType->Type(); - if (majorType != MEDIATYPE_Audio && majorType != WMMEDIATYPE_Audio) { - return E_INVALIDARG; - } - - if (*aMediaType->Subtype() != MEDIASUBTYPE_PCM) { - return E_INVALIDARG; - } - - if (*aMediaType->FormatType() != FORMAT_WaveFormatEx) { - return E_INVALIDARG; - } - - // We accept the media type, stash its layout format! - WAVEFORMATEX* wfx = (WAVEFORMATEX*)(aMediaType->pbFormat); - GetSampleSink()->SetAudioFormat(wfx); - - return S_OK; -} - -AudioSinkFilter* -AudioSinkInputPin::GetAudioSinkFilter() -{ - return reinterpret_cast<AudioSinkFilter*>(mFilter); -} - -SampleSink* -AudioSinkInputPin::GetSampleSink() -{ - return mSampleSink; -} - -HRESULT -AudioSinkInputPin::SetAbsoluteMediaTime(IMediaSample* aSample) -{ - HRESULT hr; - REFERENCE_TIME start = 0, end = 0; - hr = aSample->GetTime(&start, &end); - NS_ENSURE_TRUE(SUCCEEDED(hr), E_FAIL); - { - CriticalSectionAutoEnter lock(*mLock); - start += mSegmentStartTime; - end += mSegmentStartTime; - } - hr = aSample->SetMediaTime(&start, &end); - NS_ENSURE_TRUE(SUCCEEDED(hr), E_FAIL); - return S_OK; -} - -HRESULT -AudioSinkInputPin::Receive(IMediaSample* aSample ) -{ - HRESULT hr; - NS_ENSURE_TRUE(aSample, E_POINTER); - - hr = BaseInputPin::Receive(aSample); - if (SUCCEEDED(hr) && hr != S_FALSE) { // S_FALSE == flushing - // Set the timestamp of the sample after being adjusted for - // seeking/segments in the "media time" attribute. When we seek, - // DirectShow starts a new "segment", and starts labeling samples - // from time=0 again, so we need to correct for this to get the - // actual timestamps after seeking. - hr = SetAbsoluteMediaTime(aSample); - NS_ENSURE_TRUE(SUCCEEDED(hr), hr); - hr = GetSampleSink()->Receive(aSample); - NS_ENSURE_TRUE(SUCCEEDED(hr), hr); - } - return S_OK; -} - -already_AddRefed<IMediaSeeking> -AudioSinkInputPin::GetConnectedPinSeeking() -{ - RefPtr<IPin> peer = GetConnected(); - if (!peer) - return nullptr; - RefPtr<IMediaSeeking> seeking; - peer->QueryInterface(static_cast<IMediaSeeking**>(getter_AddRefs(seeking))); - return seeking.forget(); -} - -HRESULT -AudioSinkInputPin::BeginFlush() -{ - HRESULT hr = media::BaseInputPin::BeginFlush(); - NS_ENSURE_TRUE(SUCCEEDED(hr), hr); - - GetSampleSink()->Flush(); - - return S_OK; -} - -HRESULT -AudioSinkInputPin::EndFlush() -{ - HRESULT hr = media::BaseInputPin::EndFlush(); - NS_ENSURE_TRUE(SUCCEEDED(hr), hr); - - // Reset the EOS flag, so that if we're called after a seek we still work. - GetSampleSink()->Reset(); - - return S_OK; -} - -HRESULT -AudioSinkInputPin::EndOfStream(void) -{ - HRESULT hr = media::BaseInputPin::EndOfStream(); - if (FAILED(hr) || hr == S_FALSE) { - // Pin is stil flushing. - return hr; - } - GetSampleSink()->SetEOS(); - - return S_OK; -} - - -HRESULT -AudioSinkInputPin::NewSegment(REFERENCE_TIME tStart, - REFERENCE_TIME tStop, - double dRate) -{ - CriticalSectionAutoEnter lock(*mLock); - // Record the start time of the new segment, so that we can store the - // correct absolute timestamp in the "media time" each incoming sample. - mSegmentStartTime = tStart; - return S_OK; -} - -} // namespace mozilla - diff --git a/dom/media/directshow/AudioSinkInputPin.h b/dom/media/directshow/AudioSinkInputPin.h deleted file mode 100644 index 80503c641..000000000 --- a/dom/media/directshow/AudioSinkInputPin.h +++ /dev/null @@ -1,76 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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/. */ - -#if !defined(AudioSinkInputPin_h_) -#define AudioSinkInputPin_h_ - -#include "BaseInputPin.h" -#include "DirectShowUtils.h" -#include "mozilla/RefPtr.h" -#include "nsAutoPtr.h" - -namespace mozilla { - -namespace media { - class MediaType; -} - -class AudioSinkFilter; -class SampleSink; - - -// Input pin for capturing audio output of a DirectShow filter graph. -// This is the input pin for the AudioSinkFilter. -class AudioSinkInputPin: public mozilla::media::BaseInputPin -{ -public: - AudioSinkInputPin(wchar_t* aObjectName, - AudioSinkFilter* aFilter, - mozilla::CriticalSection* aLock, - HRESULT* aOutResult); - virtual ~AudioSinkInputPin(); - - HRESULT GetMediaType (IN int iPos, OUT mozilla::media::MediaType * pmt); - HRESULT CheckMediaType (IN const mozilla::media::MediaType * pmt); - STDMETHODIMP Receive (IN IMediaSample *); - STDMETHODIMP BeginFlush() override; - STDMETHODIMP EndFlush() override; - - // Called when we start decoding a new segment, that happens directly after - // a seek. This captures the segment's start time. Samples decoded by the - // MP3 decoder have their timestamps offset from the segment start time. - // Storing the segment start time enables us to set each sample's MediaTime - // as an offset in the stream relative to the start of the stream, rather - // than the start of the segment, i.e. its absolute time in the stream. - STDMETHODIMP NewSegment(REFERENCE_TIME tStart, - REFERENCE_TIME tStop, - double dRate) override; - - STDMETHODIMP EndOfStream() override; - - // Returns the IMediaSeeking interface of the connected output pin. - // We forward seeking requests upstream from the sink to the source - // filters. - already_AddRefed<IMediaSeeking> GetConnectedPinSeeking(); - - SampleSink* GetSampleSink(); - -private: - AudioSinkFilter* GetAudioSinkFilter(); - - // Sets the media time on the media sample, relative to the segment - // start time. - HRESULT SetAbsoluteMediaTime(IMediaSample* aSample); - - nsAutoPtr<SampleSink> mSampleSink; - - // Synchronized by the filter lock; BaseInputPin::mLock. - REFERENCE_TIME mSegmentStartTime; -}; - -} // namespace mozilla - -#endif // AudioSinkInputPin_h_ diff --git a/dom/media/directshow/DirectShowDecoder.cpp b/dom/media/directshow/DirectShowDecoder.cpp deleted file mode 100644 index da68b4daa..000000000 --- a/dom/media/directshow/DirectShowDecoder.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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 "DirectShowDecoder.h" -#include "DirectShowReader.h" -#include "DirectShowUtils.h" -#include "MediaDecoderStateMachine.h" -#include "mozilla/Preferences.h" -#include "mozilla/WindowsVersion.h" - -namespace mozilla { - -MediaDecoderStateMachine* DirectShowDecoder::CreateStateMachine() -{ - return new MediaDecoderStateMachine(this, new DirectShowReader(this)); -} - -/* static */ -bool -DirectShowDecoder::GetSupportedCodecs(const nsACString& aType, - char const *const ** aCodecList) -{ - if (!IsEnabled()) { - return false; - } - - static char const *const mp3AudioCodecs[] = { - "mp3", - nullptr - }; - if (aType.EqualsASCII("audio/mpeg") || - aType.EqualsASCII("audio/mp3")) { - if (aCodecList) { - *aCodecList = mp3AudioCodecs; - } - return true; - } - - return false; -} - -/* static */ -bool -DirectShowDecoder::IsEnabled() -{ - return CanDecodeMP3UsingDirectShow() && - Preferences::GetBool("media.directshow.enabled"); -} - -DirectShowDecoder::DirectShowDecoder(MediaDecoderOwner* aOwner) - : MediaDecoder(aOwner) -{ - MOZ_COUNT_CTOR(DirectShowDecoder); -} - -DirectShowDecoder::~DirectShowDecoder() -{ - MOZ_COUNT_DTOR(DirectShowDecoder); -} - -} // namespace mozilla - diff --git a/dom/media/directshow/DirectShowDecoder.h b/dom/media/directshow/DirectShowDecoder.h deleted file mode 100644 index c4d371fbf..000000000 --- a/dom/media/directshow/DirectShowDecoder.h +++ /dev/null @@ -1,45 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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/. */ - -#if !defined(DirectShowDecoder_h_) -#define DirectShowDecoder_h_ - -#include "MediaDecoder.h" - -namespace mozilla { - -// Decoder that uses DirectShow to playback MP3 files only. -class DirectShowDecoder : public MediaDecoder -{ -public: - - explicit DirectShowDecoder(MediaDecoderOwner* aOwner); - virtual ~DirectShowDecoder(); - - MediaDecoder* Clone(MediaDecoderOwner* aOwner) override { - if (!IsEnabled()) { - return nullptr; - } - return new DirectShowDecoder(aOwner); - } - - MediaDecoderStateMachine* CreateStateMachine() override; - - // Returns true if aType is a MIME type that we render with the - // DirectShow backend. If aCodecList is non null, - // it is filled with a (static const) null-terminated list of strings - // denoting the codecs we'll playback. Note that playback is strictly - // limited to MP3 only. - static bool GetSupportedCodecs(const nsACString& aType, - char const *const ** aCodecList); - - // Returns true if the DirectShow backend is preffed on. - static bool IsEnabled(); -}; - -} // namespace mozilla - -#endif diff --git a/dom/media/directshow/DirectShowReader.cpp b/dom/media/directshow/DirectShowReader.cpp deleted file mode 100644 index cacf6f8de..000000000 --- a/dom/media/directshow/DirectShowReader.cpp +++ /dev/null @@ -1,360 +0,0 @@ -/* -*- 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 "DirectShowReader.h" -#include "MediaDecoderReader.h" -#include "mozilla/RefPtr.h" -#include "DirectShowUtils.h" -#include "AudioSinkFilter.h" -#include "SourceFilter.h" -#include "SampleSink.h" -#include "VideoUtils.h" - -using namespace mozilla::media; - -namespace mozilla { - -// Windows XP's MP3 decoder filter. This is available on XP only, on Vista -// and later we can use the DMO Wrapper filter and MP3 decoder DMO. -const GUID DirectShowReader::CLSID_MPEG_LAYER_3_DECODER_FILTER = -{ 0x38BE3000, 0xDBF4, 0x11D0, {0x86, 0x0E, 0x00, 0xA0, 0x24, 0xCF, 0xEF, 0x6D} }; - - -static LazyLogModule gDirectShowLog("DirectShowDecoder"); -#define LOG(...) MOZ_LOG(gDirectShowLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) - -DirectShowReader::DirectShowReader(AbstractMediaDecoder* aDecoder) - : MediaDecoderReader(aDecoder), - mMP3FrameParser(aDecoder->GetResource()->GetLength()), -#ifdef DIRECTSHOW_REGISTER_GRAPH - mRotRegister(0), -#endif - mNumChannels(0), - mAudioRate(0), - mBytesPerSample(0) -{ - MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread."); - MOZ_COUNT_CTOR(DirectShowReader); -} - -DirectShowReader::~DirectShowReader() -{ - MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread."); - MOZ_COUNT_DTOR(DirectShowReader); -#ifdef DIRECTSHOW_REGISTER_GRAPH - if (mRotRegister) { - RemoveGraphFromRunningObjectTable(mRotRegister); - } -#endif -} - -// Try to parse the MP3 stream to make sure this is indeed an MP3, get the -// estimated duration of the stream, and find the offset of the actual MP3 -// frames in the stream, as DirectShow doesn't like large ID3 sections. -static nsresult -ParseMP3Headers(MP3FrameParser *aParser, MediaResource *aResource) -{ - const uint32_t MAX_READ_SIZE = 4096; - - uint64_t offset = 0; - while (aParser->NeedsData() && !aParser->ParsedHeaders()) { - uint32_t bytesRead; - char buffer[MAX_READ_SIZE]; - nsresult rv = aResource->ReadAt(offset, buffer, - MAX_READ_SIZE, &bytesRead); - NS_ENSURE_SUCCESS(rv, rv); - - if (!bytesRead) { - // End of stream. - return NS_ERROR_FAILURE; - } - - aParser->Parse(reinterpret_cast<uint8_t*>(buffer), bytesRead, offset); - offset += bytesRead; - } - - return aParser->IsMP3() ? NS_OK : NS_ERROR_FAILURE; -} - -nsresult -DirectShowReader::ReadMetadata(MediaInfo* aInfo, - MetadataTags** aTags) -{ - MOZ_ASSERT(OnTaskQueue()); - HRESULT hr; - nsresult rv; - - // Create the filter graph, reference it by the GraphBuilder interface, - // to make graph building more convenient. - hr = CoCreateInstance(CLSID_FilterGraph, - nullptr, - CLSCTX_INPROC_SERVER, - IID_IGraphBuilder, - reinterpret_cast<void**>(static_cast<IGraphBuilder**>(getter_AddRefs(mGraph)))); - NS_ENSURE_TRUE(SUCCEEDED(hr) && mGraph, NS_ERROR_FAILURE); - - rv = ParseMP3Headers(&mMP3FrameParser, mDecoder->GetResource()); - NS_ENSURE_SUCCESS(rv, rv); - - #ifdef DIRECTSHOW_REGISTER_GRAPH - hr = AddGraphToRunningObjectTable(mGraph, &mRotRegister); - NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); - #endif - - // Extract the interface pointers we'll need from the filter graph. - hr = mGraph->QueryInterface(static_cast<IMediaControl**>(getter_AddRefs(mControl))); - NS_ENSURE_TRUE(SUCCEEDED(hr) && mControl, NS_ERROR_FAILURE); - - hr = mGraph->QueryInterface(static_cast<IMediaSeeking**>(getter_AddRefs(mMediaSeeking))); - NS_ENSURE_TRUE(SUCCEEDED(hr) && mMediaSeeking, NS_ERROR_FAILURE); - - // Build the graph. Create the filters we need, and connect them. We - // build the entire graph ourselves to prevent other decoders installed - // on the system being created and used. - - // Our source filters, wraps the MediaResource. - mSourceFilter = new SourceFilter(MEDIATYPE_Stream, MEDIASUBTYPE_MPEG1Audio); - NS_ENSURE_TRUE(mSourceFilter, NS_ERROR_FAILURE); - - rv = mSourceFilter->Init(mDecoder->GetResource(), mMP3FrameParser.GetMP3Offset()); - NS_ENSURE_SUCCESS(rv, rv); - - hr = mGraph->AddFilter(mSourceFilter, L"MozillaDirectShowSource"); - NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); - - // The MPEG demuxer. - RefPtr<IBaseFilter> demuxer; - hr = CreateAndAddFilter(mGraph, - CLSID_MPEG1Splitter, - L"MPEG1Splitter", - getter_AddRefs(demuxer)); - NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); - - // Platform MP3 decoder. - RefPtr<IBaseFilter> decoder; - // Firstly try to create the MP3 decoder filter that ships with WinXP - // directly. This filter doesn't normally exist on later versions of - // Windows. - hr = CreateAndAddFilter(mGraph, - CLSID_MPEG_LAYER_3_DECODER_FILTER, - L"MPEG Layer 3 Decoder", - getter_AddRefs(decoder)); - if (FAILED(hr)) { - // Failed to create MP3 decoder filter. Try to instantiate - // the MP3 decoder DMO. - hr = AddMP3DMOWrapperFilter(mGraph, getter_AddRefs(decoder)); - NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); - } - - // Sink, captures audio samples and inserts them into our pipeline. - static const wchar_t* AudioSinkFilterName = L"MozAudioSinkFilter"; - mAudioSinkFilter = new AudioSinkFilter(AudioSinkFilterName, &hr); - NS_ENSURE_TRUE(mAudioSinkFilter && SUCCEEDED(hr), NS_ERROR_FAILURE); - hr = mGraph->AddFilter(mAudioSinkFilter, AudioSinkFilterName); - NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); - - // Join the filters. - hr = ConnectFilters(mGraph, mSourceFilter, demuxer); - NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); - - hr = ConnectFilters(mGraph, demuxer, decoder); - NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); - - hr = ConnectFilters(mGraph, decoder, mAudioSinkFilter); - NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); - - WAVEFORMATEX format; - mAudioSinkFilter->GetSampleSink()->GetAudioFormat(&format); - NS_ENSURE_TRUE(format.wFormatTag == WAVE_FORMAT_PCM, NS_ERROR_FAILURE); - - mInfo.mAudio.mChannels = mNumChannels = format.nChannels; - mInfo.mAudio.mRate = mAudioRate = format.nSamplesPerSec; - mInfo.mAudio.mBitDepth = format.wBitsPerSample; - mBytesPerSample = format.wBitsPerSample / 8; - - // Begin decoding! - hr = mControl->Run(); - NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); - - DWORD seekCaps = 0; - hr = mMediaSeeking->GetCapabilities(&seekCaps); - mInfo.mMediaSeekable = SUCCEEDED(hr) && (AM_SEEKING_CanSeekAbsolute & seekCaps); - - int64_t duration = mMP3FrameParser.GetDuration(); - if (SUCCEEDED(hr)) { - mInfo.mMetadataDuration.emplace(TimeUnit::FromMicroseconds(duration)); - } - - LOG("Successfully initialized DirectShow MP3 decoder."); - LOG("Channels=%u Hz=%u duration=%lld bytesPerSample=%d", - mInfo.mAudio.mChannels, - mInfo.mAudio.mRate, - RefTimeToUsecs(duration), - mBytesPerSample); - - *aInfo = mInfo; - // Note: The SourceFilter strips ID3v2 tags out of the stream. - *aTags = nullptr; - - return NS_OK; -} - -inline float -UnsignedByteToAudioSample(uint8_t aValue) -{ - return aValue * (2.0f / UINT8_MAX) - 1.0f; -} - -bool -DirectShowReader::Finish(HRESULT aStatus) -{ - MOZ_ASSERT(OnTaskQueue()); - - LOG("DirectShowReader::Finish(0x%x)", aStatus); - // Notify the filter graph of end of stream. - RefPtr<IMediaEventSink> eventSink; - HRESULT hr = mGraph->QueryInterface(static_cast<IMediaEventSink**>(getter_AddRefs(eventSink))); - if (SUCCEEDED(hr) && eventSink) { - eventSink->Notify(EC_COMPLETE, aStatus, 0); - } - return false; -} - -class DirectShowCopy -{ -public: - DirectShowCopy(uint8_t *aSource, uint32_t aBytesPerSample, - uint32_t aSamples, uint32_t aChannels) - : mSource(aSource) - , mBytesPerSample(aBytesPerSample) - , mSamples(aSamples) - , mChannels(aChannels) - , mNextSample(0) - { } - - uint32_t operator()(AudioDataValue *aBuffer, uint32_t aSamples) - { - uint32_t maxSamples = std::min(aSamples, mSamples - mNextSample); - uint32_t frames = maxSamples / mChannels; - size_t byteOffset = mNextSample * mBytesPerSample; - if (mBytesPerSample == 1) { - for (uint32_t i = 0; i < maxSamples; ++i) { - uint8_t *sample = mSource + byteOffset; - aBuffer[i] = UnsignedByteToAudioSample(*sample); - byteOffset += mBytesPerSample; - } - } else if (mBytesPerSample == 2) { - for (uint32_t i = 0; i < maxSamples; ++i) { - int16_t *sample = reinterpret_cast<int16_t *>(mSource + byteOffset); - aBuffer[i] = AudioSampleToFloat(*sample); - byteOffset += mBytesPerSample; - } - } - mNextSample += maxSamples; - return frames; - } - -private: - uint8_t * const mSource; - const uint32_t mBytesPerSample; - const uint32_t mSamples; - const uint32_t mChannels; - uint32_t mNextSample; -}; - -bool -DirectShowReader::DecodeAudioData() -{ - MOZ_ASSERT(OnTaskQueue()); - HRESULT hr; - - SampleSink* sink = mAudioSinkFilter->GetSampleSink(); - if (sink->AtEOS()) { - // End of stream. - return Finish(S_OK); - } - - // Get the next chunk of audio samples. This blocks until the sample - // arrives, or an error occurs (like the stream is shutdown). - RefPtr<IMediaSample> sample; - hr = sink->Extract(sample); - if (FAILED(hr) || hr == S_FALSE) { - return Finish(hr); - } - - int64_t start = 0, end = 0; - sample->GetMediaTime(&start, &end); - LOG("DirectShowReader::DecodeAudioData [%4.2lf-%4.2lf]", - RefTimeToSeconds(start), - RefTimeToSeconds(end)); - - LONG length = sample->GetActualDataLength(); - LONG numSamples = length / mBytesPerSample; - LONG numFrames = length / mBytesPerSample / mNumChannels; - - BYTE* data = nullptr; - hr = sample->GetPointer(&data); - NS_ENSURE_TRUE(SUCCEEDED(hr), Finish(hr)); - - mAudioCompactor.Push(mDecoder->GetResource()->Tell(), - RefTimeToUsecs(start), - mInfo.mAudio.mRate, - numFrames, - mNumChannels, - DirectShowCopy(reinterpret_cast<uint8_t *>(data), - mBytesPerSample, - numSamples, - mNumChannels)); - return true; -} - -bool -DirectShowReader::DecodeVideoFrame(bool &aKeyframeSkip, - int64_t aTimeThreshold) -{ - MOZ_ASSERT(OnTaskQueue()); - return false; -} - -RefPtr<MediaDecoderReader::SeekPromise> -DirectShowReader::Seek(SeekTarget aTarget, int64_t aEndTime) -{ - nsresult res = SeekInternal(aTarget.GetTime().ToMicroseconds()); - if (NS_FAILED(res)) { - return SeekPromise::CreateAndReject(res, __func__); - } else { - return SeekPromise::CreateAndResolve(aTarget.GetTime(), __func__); - } -} - -nsresult -DirectShowReader::SeekInternal(int64_t aTargetUs) -{ - HRESULT hr; - MOZ_ASSERT(OnTaskQueue()); - - LOG("DirectShowReader::Seek() target=%lld", aTargetUs); - - hr = mControl->Pause(); - NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); - - nsresult rv = ResetDecode(); - NS_ENSURE_SUCCESS(rv, rv); - - LONGLONG seekPosition = UsecsToRefTime(aTargetUs); - hr = mMediaSeeking->SetPositions(&seekPosition, - AM_SEEKING_AbsolutePositioning, - nullptr, - AM_SEEKING_NoPositioning); - NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); - - hr = mControl->Run(); - NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); - - return NS_OK; -} - -} // namespace mozilla diff --git a/dom/media/directshow/DirectShowReader.h b/dom/media/directshow/DirectShowReader.h deleted file mode 100644 index e1326d416..000000000 --- a/dom/media/directshow/DirectShowReader.h +++ /dev/null @@ -1,110 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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/. */ - -#if !defined(DirectShowReader_h_) -#define DirectShowReader_h_ - -#include "windows.h" // HRESULT, DWORD -#include "MediaDecoderReader.h" -#include "MediaResource.h" -#include "mozilla/RefPtr.h" -#include "MP3FrameParser.h" - -// Add the graph to the Running Object Table so that we can connect -// to this graph with GraphEdit/GraphStudio. Note: on Vista and up you must -// also regsvr32 proppage.dll from the Windows SDK. -// See: http://msdn.microsoft.com/en-us/library/ms787252(VS.85).aspx -// #define DIRECTSHOW_REGISTER_GRAPH - -struct IGraphBuilder; -struct IMediaControl; -struct IMediaSeeking; - -namespace mozilla { - -class AudioSinkFilter; -class SourceFilter; - -// Decoder backend for decoding MP3 using DirectShow. DirectShow operates as -// a filter graph. The basic design of the DirectShowReader is that we have -// a SourceFilter that wraps the MediaResource that connects to the -// MP3 decoder filter. The MP3 decoder filter "pulls" data as it requires it -// downstream on its own thread. When the MP3 decoder has produced a block of -// decoded samples, its thread calls downstream into our AudioSinkFilter, -// passing the decoded buffer in. The AudioSinkFilter inserts the samples into -// a SampleSink object. The SampleSink blocks the MP3 decoder's thread until -// the decode thread calls DecodeAudioData(), whereupon the SampleSink -// releases the decoded samples to the decode thread, and unblocks the MP3 -// decoder's thread. The MP3 decoder can then request more data from the -// SourceFilter, and decode more data. If the decode thread calls -// DecodeAudioData() and there's no decoded samples waiting to be extracted -// in the SampleSink, the SampleSink blocks the decode thread until the MP3 -// decoder produces a decoded sample. -class DirectShowReader : public MediaDecoderReader -{ -public: - DirectShowReader(AbstractMediaDecoder* aDecoder); - - virtual ~DirectShowReader(); - - bool DecodeAudioData() override; - bool DecodeVideoFrame(bool &aKeyframeSkip, - int64_t aTimeThreshold) override; - - nsresult ReadMetadata(MediaInfo* aInfo, - MetadataTags** aTags) override; - - RefPtr<SeekPromise> - Seek(SeekTarget aTarget, int64_t aEndTime) override; - - static const GUID CLSID_MPEG_LAYER_3_DECODER_FILTER; - -private: - // Notifies the filter graph that playback is complete. aStatus is - // the code to send to the filter graph. Always returns false, so - // that we can just "return Finish()" from DecodeAudioData(). - bool Finish(HRESULT aStatus); - - nsresult SeekInternal(int64_t aTime); - - // DirectShow filter graph, and associated playback and seeking - // control interfaces. - RefPtr<IGraphBuilder> mGraph; - RefPtr<IMediaControl> mControl; - RefPtr<IMediaSeeking> mMediaSeeking; - - // Wraps the MediaResource, and feeds undecoded data into the filter graph. - RefPtr<SourceFilter> mSourceFilter; - - // Sits at the end of the graph, removing decoded samples from the graph. - // The graph will block while this is blocked, i.e. it will pause decoding. - RefPtr<AudioSinkFilter> mAudioSinkFilter; - - // Some MP3s are variable bitrate, so DirectShow's duration estimation - // can make its duration estimation based on the wrong bitrate. So we parse - // the MP3 frames to get a more accuate estimate of the duration. - MP3FrameParser mMP3FrameParser; - -#ifdef DIRECTSHOW_REGISTER_GRAPH - // Used to add/remove the filter graph to the Running Object Table. You can - // connect GraphEdit/GraphStudio to the graph to observe and/or debug its - // topology and state. - DWORD mRotRegister; -#endif - - // Number of channels in the audio stream. - uint32_t mNumChannels; - - // Samples per second in the audio stream. - uint32_t mAudioRate; - - // Number of bytes per sample. Can be either 1 or 2. - uint32_t mBytesPerSample; -}; - -} // namespace mozilla - -#endif diff --git a/dom/media/directshow/DirectShowUtils.cpp b/dom/media/directshow/DirectShowUtils.cpp deleted file mode 100644 index b2afa7528..000000000 --- a/dom/media/directshow/DirectShowUtils.cpp +++ /dev/null @@ -1,369 +0,0 @@ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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 "DirectShowUtils.h" -#include "dmodshow.h" -#include "wmcodecdsp.h" -#include "dmoreg.h" -#include "mozilla/ArrayUtils.h" -#include "mozilla/RefPtr.h" -#include "nsPrintfCString.h" - -#define WARN(...) NS_WARNING(nsPrintfCString(__VA_ARGS__).get()) - -namespace mozilla { - -// Create a table which maps GUIDs to a string representation of the GUID. -// This is useful for debugging purposes, for logging the GUIDs of media types. -// This is only available when logging is enabled, i.e. not in release builds. -struct GuidToName { - const char* name; - const GUID guid; -}; - -#pragma push_macro("OUR_GUID_ENTRY") -#undef OUR_GUID_ENTRY -#define OUR_GUID_ENTRY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ - { #name, {l, w1, w2, {b1, b2, b3, b4, b5, b6, b7, b8}} }, - -static const GuidToName GuidToNameTable[] = { -#include <uuids.h> -}; - -#pragma pop_macro("OUR_GUID_ENTRY") - -const char* -GetDirectShowGuidName(const GUID& aGuid) -{ - const size_t len = ArrayLength(GuidToNameTable); - for (unsigned i = 0; i < len; i++) { - if (IsEqualGUID(aGuid, GuidToNameTable[i].guid)) { - return GuidToNameTable[i].name; - } - } - return "Unknown"; -} - -void -RemoveGraphFromRunningObjectTable(DWORD aRotRegister) -{ - RefPtr<IRunningObjectTable> runningObjectTable; - if (SUCCEEDED(GetRunningObjectTable(0, getter_AddRefs(runningObjectTable)))) { - runningObjectTable->Revoke(aRotRegister); - } -} - -HRESULT -AddGraphToRunningObjectTable(IUnknown *aUnkGraph, DWORD *aOutRotRegister) -{ - HRESULT hr; - - RefPtr<IMoniker> moniker; - RefPtr<IRunningObjectTable> runningObjectTable; - - hr = GetRunningObjectTable(0, getter_AddRefs(runningObjectTable)); - NS_ENSURE_TRUE(SUCCEEDED(hr), hr); - - const size_t STRING_LENGTH = 256; - WCHAR wsz[STRING_LENGTH]; - - StringCchPrintfW(wsz, - STRING_LENGTH, - L"FilterGraph %08x pid %08x", - (DWORD_PTR)aUnkGraph, - GetCurrentProcessId()); - - hr = CreateItemMoniker(L"!", wsz, getter_AddRefs(moniker)); - NS_ENSURE_TRUE(SUCCEEDED(hr), hr); - - hr = runningObjectTable->Register(ROTFLAGS_REGISTRATIONKEEPSALIVE, - aUnkGraph, - moniker, - aOutRotRegister); - NS_ENSURE_TRUE(SUCCEEDED(hr), hr); - - return S_OK; -} - -const char* -GetGraphNotifyString(long evCode) -{ -#define CASE(x) case x: return #x - switch(evCode) { - CASE(EC_ACTIVATE); // A video window is being activated or deactivated. - CASE(EC_BANDWIDTHCHANGE); // Not supported. - CASE(EC_BUFFERING_DATA); // The graph is buffering data, or has stopped buffering data. - CASE(EC_BUILT); // Send by the Video Control when a graph has been built. Not forwarded to applications. - CASE(EC_CLOCK_CHANGED); // The reference clock has changed. - CASE(EC_CLOCK_UNSET); // The clock provider was disconnected. - CASE(EC_CODECAPI_EVENT); // Sent by an encoder to signal an encoding event. - CASE(EC_COMPLETE); // All data from a particular stream has been rendered. - CASE(EC_CONTENTPROPERTY_CHANGED); // Not supported. - CASE(EC_DEVICE_LOST); // A Plug and Play device was removed or has become available again. - CASE(EC_DISPLAY_CHANGED); // The display mode has changed. - CASE(EC_END_OF_SEGMENT); // The end of a segment has been reached. - CASE(EC_EOS_SOON); // Not supported. - CASE(EC_ERROR_STILLPLAYING); // An asynchronous command to run the graph has failed. - CASE(EC_ERRORABORT); // An operation was aborted because of an error. - CASE(EC_ERRORABORTEX); // An operation was aborted because of an error. - CASE(EC_EXTDEVICE_MODE_CHANGE); // Not supported. - CASE(EC_FILE_CLOSED); // The source file was closed because of an unexpected event. - CASE(EC_FULLSCREEN_LOST); // The video renderer is switching out of full-screen mode. - CASE(EC_GRAPH_CHANGED); // The filter graph has changed. - CASE(EC_LENGTH_CHANGED); // The length of a source has changed. - CASE(EC_LOADSTATUS); // Notifies the application of progress when opening a network file. - CASE(EC_MARKER_HIT); // Not supported. - CASE(EC_NEED_RESTART); // A filter is requesting that the graph be restarted. - CASE(EC_NEW_PIN); // Not supported. - CASE(EC_NOTIFY_WINDOW); // Notifies a filter of the video renderer's window. - CASE(EC_OLE_EVENT); // A filter is passing a text string to the application. - CASE(EC_OPENING_FILE); // The graph is opening a file, or has finished opening a file. - CASE(EC_PALETTE_CHANGED); // The video palette has changed. - CASE(EC_PAUSED); // A pause request has completed. - CASE(EC_PLEASE_REOPEN); // The source file has changed. - CASE(EC_PREPROCESS_COMPLETE); // Sent by the WM ASF Writer filter when it completes the pre-processing for multipass encoding. - CASE(EC_PROCESSING_LATENCY); // Indicates the amount of time that a component is taking to process each sample. - CASE(EC_QUALITY_CHANGE); // The graph is dropping samples, for quality control. - //CASE(EC_RENDER_FINISHED); // Not supported. - CASE(EC_REPAINT); // A video renderer requires a repaint. - CASE(EC_SAMPLE_LATENCY); // Specifies how far behind schedule a component is for processing samples. - //CASE(EC_SAMPLE_NEEDED); // Requests a new input sample from the Enhanced Video Renderer (EVR) filter. - CASE(EC_SCRUB_TIME); // Specifies the time stamp for the most recent frame step. - CASE(EC_SEGMENT_STARTED); // A new segment has started. - CASE(EC_SHUTTING_DOWN); // The filter graph is shutting down, prior to being destroyed. - CASE(EC_SNDDEV_IN_ERROR); // A device error has occurred in an audio capture filter. - CASE(EC_SNDDEV_OUT_ERROR); // A device error has occurred in an audio renderer filter. - CASE(EC_STARVATION); // A filter is not receiving enough data. - CASE(EC_STATE_CHANGE); // The filter graph has changed state. - CASE(EC_STATUS); // Contains two arbitrary status strings. - CASE(EC_STEP_COMPLETE); // A filter performing frame stepping has stepped the specified number of frames. - CASE(EC_STREAM_CONTROL_STARTED); // A stream-control start command has taken effect. - CASE(EC_STREAM_CONTROL_STOPPED); // A stream-control stop command has taken effect. - CASE(EC_STREAM_ERROR_STILLPLAYING); // An error has occurred in a stream. The stream is still playing. - CASE(EC_STREAM_ERROR_STOPPED); // A stream has stopped because of an error. - CASE(EC_TIMECODE_AVAILABLE); // Not supported. - CASE(EC_UNBUILT); // Send by the Video Control when a graph has been torn down. Not forwarded to applications. - CASE(EC_USERABORT); // The user has terminated playback. - CASE(EC_VIDEO_SIZE_CHANGED); // The native video size has changed. - CASE(EC_VIDEOFRAMEREADY); // A video frame is ready for display. - CASE(EC_VMR_RECONNECTION_FAILED); // Sent by the VMR-7 and the VMR-9 when it was unable to accept a dynamic format change request from the upstream decoder. - CASE(EC_VMR_RENDERDEVICE_SET); // Sent when the VMR has selected its rendering mechanism. - CASE(EC_VMR_SURFACE_FLIPPED); // Sent when the VMR-7's allocator presenter has called the DirectDraw Flip method on the surface being presented. - CASE(EC_WINDOW_DESTROYED); // The video renderer was destroyed or removed from the graph. - CASE(EC_WMT_EVENT); // Sent by the WM ASF Reader filter when it reads ASF files protected by digital rights management (DRM). - CASE(EC_WMT_INDEX_EVENT); // Sent when an application uses the WM ASF Writer to index Windows Media Video files. - CASE(S_OK); // Success. - CASE(VFW_S_AUDIO_NOT_RENDERED); // Partial success; the audio was not rendered. - CASE(VFW_S_DUPLICATE_NAME); // Success; the Filter Graph Manager modified a filter name to avoid duplication. - CASE(VFW_S_PARTIAL_RENDER); // Partial success; some of the streams in this movie are in an unsupported format. - CASE(VFW_S_VIDEO_NOT_RENDERED); // Partial success; the video was not rendered. - CASE(E_ABORT); // Operation aborted. - CASE(E_OUTOFMEMORY); // Insufficient memory. - CASE(E_POINTER); // Null pointer argument. - CASE(VFW_E_CANNOT_CONNECT); // No combination of intermediate filters could be found to make the connection. - CASE(VFW_E_CANNOT_RENDER); // No combination of filters could be found to render the stream. - CASE(VFW_E_NO_ACCEPTABLE_TYPES); // There is no common media type between these pins. - CASE(VFW_E_NOT_IN_GRAPH); - - default: - return "Unknown Code"; - }; -#undef CASE -} - -HRESULT -CreateAndAddFilter(IGraphBuilder* aGraph, - REFGUID aFilterClsId, - LPCWSTR aFilterName, - IBaseFilter **aOutFilter) -{ - NS_ENSURE_TRUE(aGraph, E_POINTER); - NS_ENSURE_TRUE(aOutFilter, E_POINTER); - HRESULT hr; - - RefPtr<IBaseFilter> filter; - hr = CoCreateInstance(aFilterClsId, - nullptr, - CLSCTX_INPROC_SERVER, - IID_IBaseFilter, - getter_AddRefs(filter)); - if (FAILED(hr)) { - // Object probably not available on this system. - WARN("CoCreateInstance failed, hr=%x", hr); - return hr; - } - - hr = aGraph->AddFilter(filter, aFilterName); - if (FAILED(hr)) { - WARN("AddFilter failed, hr=%x", hr); - return hr; - } - - filter.forget(aOutFilter); - - return S_OK; -} - -HRESULT -CreateMP3DMOWrapperFilter(IBaseFilter **aOutFilter) -{ - NS_ENSURE_TRUE(aOutFilter, E_POINTER); - HRESULT hr; - - // Create the wrapper filter. - RefPtr<IBaseFilter> filter; - hr = CoCreateInstance(CLSID_DMOWrapperFilter, - nullptr, - CLSCTX_INPROC_SERVER, - IID_IBaseFilter, - getter_AddRefs(filter)); - if (FAILED(hr)) { - WARN("CoCreateInstance failed, hr=%x", hr); - return hr; - } - - // Query for IDMOWrapperFilter. - RefPtr<IDMOWrapperFilter> dmoWrapper; - hr = filter->QueryInterface(IID_IDMOWrapperFilter, - getter_AddRefs(dmoWrapper)); - if (FAILED(hr)) { - WARN("QueryInterface failed, hr=%x", hr); - return hr; - } - - hr = dmoWrapper->Init(CLSID_CMP3DecMediaObject, DMOCATEGORY_AUDIO_DECODER); - if (FAILED(hr)) { - // Can't instantiate MP3 DMO. It doesn't exist on Windows XP, we're - // probably hitting that. Don't log warning to console, this is an - // expected error. - WARN("dmoWrapper Init failed, hr=%x", hr); - return hr; - } - - filter.forget(aOutFilter); - - return S_OK; -} - -HRESULT -AddMP3DMOWrapperFilter(IGraphBuilder* aGraph, - IBaseFilter **aOutFilter) -{ - NS_ENSURE_TRUE(aGraph, E_POINTER); - NS_ENSURE_TRUE(aOutFilter, E_POINTER); - HRESULT hr; - - // Create the wrapper filter. - RefPtr<IBaseFilter> filter; - hr = CreateMP3DMOWrapperFilter(getter_AddRefs(filter)); - NS_ENSURE_TRUE(SUCCEEDED(hr), hr); - - // Add the wrapper filter to graph. - hr = aGraph->AddFilter(filter, L"MP3 Decoder DMO"); - if (FAILED(hr)) { - WARN("AddFilter failed, hr=%x", hr); - return hr; - } - - filter.forget(aOutFilter); - - return S_OK; -} - -bool -CanDecodeMP3UsingDirectShow() -{ - RefPtr<IBaseFilter> filter; - - // Can we create the MP3 demuxer filter? - if (FAILED(CoCreateInstance(CLSID_MPEG1Splitter, - nullptr, - CLSCTX_INPROC_SERVER, - IID_IBaseFilter, - getter_AddRefs(filter)))) { - return false; - } - - // Can we create either the WinXP MP3 decoder filter or the MP3 DMO decoder? - if (FAILED(CoCreateInstance(DirectShowReader::CLSID_MPEG_LAYER_3_DECODER_FILTER, - nullptr, - CLSCTX_INPROC_SERVER, - IID_IBaseFilter, - getter_AddRefs(filter))) && - FAILED(CreateMP3DMOWrapperFilter(getter_AddRefs(filter)))) { - return false; - } - - // Else, we can create all of the components we need. Assume - // DirectShow is going to work... - return true; -} - -// Match a pin by pin direction and connection state. -HRESULT -MatchUnconnectedPin(IPin* aPin, - PIN_DIRECTION aPinDir, - bool *aOutMatches) -{ - NS_ENSURE_TRUE(aPin, E_POINTER); - NS_ENSURE_TRUE(aOutMatches, E_POINTER); - - // Ensure the pin is unconnected. - RefPtr<IPin> peer; - HRESULT hr = aPin->ConnectedTo(getter_AddRefs(peer)); - if (hr != VFW_E_NOT_CONNECTED) { - *aOutMatches = false; - return hr; - } - - // Ensure the pin is of the specified direction. - PIN_DIRECTION pinDir; - hr = aPin->QueryDirection(&pinDir); - NS_ENSURE_TRUE(SUCCEEDED(hr), hr); - - *aOutMatches = (pinDir == aPinDir); - return S_OK; -} - -// Return the first unconnected input pin or output pin. -already_AddRefed<IPin> -GetUnconnectedPin(IBaseFilter* aFilter, PIN_DIRECTION aPinDir) -{ - RefPtr<IEnumPins> enumPins; - - HRESULT hr = aFilter->EnumPins(getter_AddRefs(enumPins)); - NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr); - - // Test each pin to see if it matches the direction we're looking for. - RefPtr<IPin> pin; - while (S_OK == enumPins->Next(1, getter_AddRefs(pin), nullptr)) { - bool matches = FALSE; - if (SUCCEEDED(MatchUnconnectedPin(pin, aPinDir, &matches)) && - matches) { - return pin.forget(); - } - } - - return nullptr; -} - -HRESULT -ConnectFilters(IGraphBuilder* aGraph, - IBaseFilter* aOutputFilter, - IBaseFilter* aInputFilter) -{ - RefPtr<IPin> output = GetUnconnectedPin(aOutputFilter, PINDIR_OUTPUT); - NS_ENSURE_TRUE(output, E_FAIL); - - RefPtr<IPin> input = GetUnconnectedPin(aInputFilter, PINDIR_INPUT); - NS_ENSURE_TRUE(output, E_FAIL); - - return aGraph->Connect(output, input); -} - -} // namespace mozilla - -// avoid redefined macro in unified build -#undef WARN diff --git a/dom/media/directshow/DirectShowUtils.h b/dom/media/directshow/DirectShowUtils.h deleted file mode 100644 index 3bbc122fc..000000000 --- a/dom/media/directshow/DirectShowUtils.h +++ /dev/null @@ -1,125 +0,0 @@ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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/. */ - -#ifndef _DirectShowUtils_h_ -#define _DirectShowUtils_h_ - -#include <stdint.h> -#include "dshow.h" - -// XXXbz windowsx.h defines GetFirstChild, GetNextSibling, -// GetPrevSibling are macros, apparently... Eeevil. We have functions -// called that on some classes, so undef them. -#undef GetFirstChild -#undef GetNextSibling -#undef GetPrevSibling - -#include "DShowTools.h" -#include "mozilla/Logging.h" - -namespace mozilla { - -// Win32 "Event" wrapper. Must be paired with a CriticalSection to create a -// Java-style "monitor". -class Signal { -public: - - Signal(CriticalSection* aLock) - : mLock(aLock) - { - CriticalSectionAutoEnter lock(*mLock); - mEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); - } - - ~Signal() { - CriticalSectionAutoEnter lock(*mLock); - CloseHandle(mEvent); - } - - // Lock must be held. - void Notify() { - SetEvent(mEvent); - } - - // Lock must be held. Check the wait condition before waiting! - HRESULT Wait() { - mLock->Leave(); - DWORD result = WaitForSingleObject(mEvent, INFINITE); - mLock->Enter(); - return result == WAIT_OBJECT_0 ? S_OK : E_FAIL; - } - -private: - CriticalSection* mLock; - HANDLE mEvent; -}; - -HRESULT -AddGraphToRunningObjectTable(IUnknown *aUnkGraph, DWORD *aOutRotRegister); - -void -RemoveGraphFromRunningObjectTable(DWORD aRotRegister); - -const char* -GetGraphNotifyString(long evCode); - -// Creates a filter and adds it to a graph. -HRESULT -CreateAndAddFilter(IGraphBuilder* aGraph, - REFGUID aFilterClsId, - LPCWSTR aFilterName, - IBaseFilter **aOutFilter); - -HRESULT -AddMP3DMOWrapperFilter(IGraphBuilder* aGraph, - IBaseFilter **aOutFilter); - -// Connects the output pin on aOutputFilter to an input pin on -// aInputFilter, in aGraph. -HRESULT -ConnectFilters(IGraphBuilder* aGraph, - IBaseFilter* aOutputFilter, - IBaseFilter* aInputFilter); - -HRESULT -MatchUnconnectedPin(IPin* aPin, - PIN_DIRECTION aPinDir, - bool *aOutMatches); - -// Converts from microseconds to DirectShow "Reference Time" -// (hundreds of nanoseconds). -inline int64_t -UsecsToRefTime(const int64_t aUsecs) -{ - return aUsecs * 10; -} - -// Converts from DirectShow "Reference Time" (hundreds of nanoseconds) -// to microseconds. -inline int64_t -RefTimeToUsecs(const int64_t hRefTime) -{ - return hRefTime / 10; -} - -// Converts from DirectShow "Reference Time" (hundreds of nanoseconds) -// to seconds. -inline double -RefTimeToSeconds(const REFERENCE_TIME aRefTime) -{ - return double(aRefTime) / 10000000; -} - -const char* -GetDirectShowGuidName(const GUID& aGuid); - -// Returns true if we can instantiate an MP3 demuxer and decoder filters. -// Use this to detect whether MP3 support is installed. -bool -CanDecodeMP3UsingDirectShow(); - -} // namespace mozilla - -#endif diff --git a/dom/media/directshow/SampleSink.cpp b/dom/media/directshow/SampleSink.cpp deleted file mode 100644 index fa5dc8d19..000000000 --- a/dom/media/directshow/SampleSink.cpp +++ /dev/null @@ -1,159 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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 "SampleSink.h" -#include "AudioSinkFilter.h" -#include "AudioSinkInputPin.h" -#include "VideoUtils.h" -#include "mozilla/Logging.h" - -using namespace mozilla::media; - -namespace mozilla { - -static LazyLogModule gDirectShowLog("DirectShowDecoder"); -#define LOG(...) MOZ_LOG(gDirectShowLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) - -SampleSink::SampleSink() - : mMonitor("SampleSink"), - mIsFlushing(false), - mAtEOS(false) -{ - MOZ_COUNT_CTOR(SampleSink); -} - -SampleSink::~SampleSink() -{ - MOZ_COUNT_DTOR(SampleSink); -} - -void -SampleSink::SetAudioFormat(const WAVEFORMATEX* aInFormat) -{ - NS_ENSURE_TRUE(aInFormat, ); - ReentrantMonitorAutoEnter mon(mMonitor); - memcpy(&mAudioFormat, aInFormat, sizeof(WAVEFORMATEX)); -} - -void -SampleSink::GetAudioFormat(WAVEFORMATEX* aOutFormat) -{ - MOZ_ASSERT(aOutFormat); - ReentrantMonitorAutoEnter mon(mMonitor); - memcpy(aOutFormat, &mAudioFormat, sizeof(WAVEFORMATEX)); -} - -HRESULT -SampleSink::Receive(IMediaSample* aSample) -{ - ReentrantMonitorAutoEnter mon(mMonitor); - - while (true) { - if (mIsFlushing) { - return S_FALSE; - } - if (!mSample) { - break; - } - if (mAtEOS) { - return E_UNEXPECTED; - } - // Wait until the consumer thread consumes the sample. - mon.Wait(); - } - - if (MOZ_LOG_TEST(gDirectShowLog, LogLevel::Debug)) { - REFERENCE_TIME start = 0, end = 0; - HRESULT hr = aSample->GetMediaTime(&start, &end); - LOG("SampleSink::Receive() [%4.2lf-%4.2lf]", - (double)RefTimeToUsecs(start) / USECS_PER_S, - (double)RefTimeToUsecs(end) / USECS_PER_S); - } - - mSample = aSample; - // Notify the signal, to awaken the consumer thread in WaitForSample() - // if necessary. - mon.NotifyAll(); - return S_OK; -} - -HRESULT -SampleSink::Extract(RefPtr<IMediaSample>& aOutSample) -{ - ReentrantMonitorAutoEnter mon(mMonitor); - // Loop until we have a sample, or we should abort. - while (true) { - if (mIsFlushing) { - return S_FALSE; - } - if (mSample) { - break; - } - if (mAtEOS) { - // Order is important here, if we have a sample, we should return it - // before reporting EOS. - return E_UNEXPECTED; - } - // Wait until the producer thread gives us a sample. - mon.Wait(); - } - aOutSample = mSample; - - if (MOZ_LOG_TEST(gDirectShowLog, LogLevel::Debug)) { - int64_t start = 0, end = 0; - mSample->GetMediaTime(&start, &end); - LOG("SampleSink::Extract() [%4.2lf-%4.2lf]", - (double)RefTimeToUsecs(start) / USECS_PER_S, - (double)RefTimeToUsecs(end) / USECS_PER_S); - } - - mSample = nullptr; - // Notify the signal, to awaken the producer thread in Receive() - // if necessary. - mon.NotifyAll(); - return S_OK; -} - -void -SampleSink::Flush() -{ - LOG("SampleSink::Flush()"); - ReentrantMonitorAutoEnter mon(mMonitor); - mIsFlushing = true; - mSample = nullptr; - mon.NotifyAll(); -} - -void -SampleSink::Reset() -{ - LOG("SampleSink::Reset()"); - ReentrantMonitorAutoEnter mon(mMonitor); - mIsFlushing = false; - mAtEOS = false; -} - -void -SampleSink::SetEOS() -{ - LOG("SampleSink::SetEOS()"); - ReentrantMonitorAutoEnter mon(mMonitor); - mAtEOS = true; - // Notify to unblock any threads waiting for samples in - // Extract() or Receive(). Now that we're at EOS, no more samples - // will come! - mon.NotifyAll(); -} - -bool -SampleSink::AtEOS() -{ - ReentrantMonitorAutoEnter mon(mMonitor); - return mAtEOS && !mSample; -} - -} // namespace mozilla - diff --git a/dom/media/directshow/SampleSink.h b/dom/media/directshow/SampleSink.h deleted file mode 100644 index 6a1af9fee..000000000 --- a/dom/media/directshow/SampleSink.h +++ /dev/null @@ -1,67 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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/. */ - -#if !defined(SampleSink_h_) -#define SampleSink_h_ - -#include "BaseFilter.h" -#include "DirectShowUtils.h" -#include "mozilla/RefPtr.h" -#include "mozilla/ReentrantMonitor.h" - -namespace mozilla { - -class SampleSink { -public: - SampleSink(); - virtual ~SampleSink(); - - // Sets the audio format of the incoming samples. The upstream filter - // calls this. This makes a copy. - void SetAudioFormat(const WAVEFORMATEX* aInFormat); - - // Copies the format of incoming audio samples into into *aOutFormat. - void GetAudioFormat(WAVEFORMATEX* aOutFormat); - - // Called when a sample is delivered by the DirectShow graph to the sink. - // The decode thread retrieves the sample by calling WaitForSample(). - // Blocks if there's already a sample waiting to be consumed by the decode - // thread. - HRESULT Receive(IMediaSample* aSample); - - // Retrieves a sample from the sample queue, blocking until one becomes - // available, or until an error occurs. Returns S_FALSE on EOS. - HRESULT Extract(RefPtr<IMediaSample>& aOutSample); - - // Unblocks any threads waiting in GetSample(). - // Clears mSample, which unblocks upstream stream. - void Flush(); - - // Opens up the sink to receive more samples in PutSample(). - // Clears EOS flag. - void Reset(); - - // Marks that we've reacehd the end of stream. - void SetEOS(); - - // Returns whether we're at end of stream. - bool AtEOS(); - -private: - // All data in this class is syncronized by mMonitor. - ReentrantMonitor mMonitor; - RefPtr<IMediaSample> mSample; - - // Format of the audio stream we're receiving. - WAVEFORMATEX mAudioFormat; - - bool mIsFlushing; - bool mAtEOS; -}; - -} // namespace mozilla - -#endif // SampleSink_h_ diff --git a/dom/media/directshow/SourceFilter.cpp b/dom/media/directshow/SourceFilter.cpp deleted file mode 100644 index 4c5a0882c..000000000 --- a/dom/media/directshow/SourceFilter.cpp +++ /dev/null @@ -1,683 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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 "SourceFilter.h" -#include "MediaResource.h" -#include "mozilla/RefPtr.h" -#include "DirectShowUtils.h" -#include "MP3FrameParser.h" -#include "mozilla/Logging.h" -#include <algorithm> - -using namespace mozilla::media; - -namespace mozilla { - -// Define to trace what's on... -//#define DEBUG_SOURCE_TRACE 1 - -#if defined (DEBUG_SOURCE_TRACE) -static LazyLogModule gDirectShowLog("DirectShowDecoder"); -#define DIRECTSHOW_LOG(...) MOZ_LOG(gDirectShowLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) -#else -#define DIRECTSHOW_LOG(...) -#endif - -static HRESULT -DoGetInterface(IUnknown* aUnknown, void** aInterface) -{ - if (!aInterface) - return E_POINTER; - *aInterface = aUnknown; - aUnknown->AddRef(); - return S_OK; -} - -// Stores details of IAsyncReader::Request(). -class ReadRequest { -public: - - ReadRequest(IMediaSample* aSample, - DWORD_PTR aDwUser, - uint32_t aOffset, - uint32_t aCount) - : mSample(aSample), - mDwUser(aDwUser), - mOffset(aOffset), - mCount(aCount) - { - MOZ_COUNT_CTOR(ReadRequest); - } - - ~ReadRequest() { - MOZ_COUNT_DTOR(ReadRequest); - } - - RefPtr<IMediaSample> mSample; - DWORD_PTR mDwUser; - uint32_t mOffset; - uint32_t mCount; -}; - -// A wrapper around media resource that presents only a partition of the -// underlying resource to the caller to use. The partition returned is from -// an offset to the end of stream, and this object deals with ensuring -// the offsets and lengths etc are translated from the reduced partition -// exposed to the caller, to the absolute offsets of the underlying stream. -class MediaResourcePartition { -public: - MediaResourcePartition(MediaResource* aResource, - int64_t aDataStart) - : mResource(aResource), - mDataOffset(aDataStart) - {} - - int64_t GetLength() { - int64_t len = mResource.GetLength(); - if (len == -1) { - return len; - } - return std::max<int64_t>(0, len - mDataOffset); - } - nsresult ReadAt(int64_t aOffset, char* aBuffer, - uint32_t aCount, uint32_t* aBytes) - { - return mResource.ReadAt(aOffset + mDataOffset, - aBuffer, - aCount, - aBytes); - } - int64_t GetCachedDataEnd() { - int64_t tell = mResource.GetResource()->Tell(); - int64_t dataEnd = - mResource.GetResource()->GetCachedDataEnd(tell) - mDataOffset; - return dataEnd; - } -private: - // MediaResource from which we read data. - MediaResourceIndex mResource; - int64_t mDataOffset; -}; - - -// Output pin for SourceFilter, which implements IAsyncReader, to -// allow downstream filters to pull/read data from it. Downstream pins -// register to read data using Request(), and asynchronously wait for the -// reads to complete using WaitForNext(). They may also synchronously read -// using SyncRead(). This class is a delegate (tear off) of -// SourceFilter. -// -// We can expose only a segment of the MediaResource to the filter graph. -// This is used to strip off the ID3v2 tags from the stream, as DirectShow -// has trouble parsing some headers. -// -// Implements: -// * IAsyncReader -// * IPin -// * IQualityControl -// * IUnknown -// -class DECLSPEC_UUID("18e5cfb2-1015-440c-a65c-e63853235894") -OutputPin : public IAsyncReader, - public BasePin -{ -public: - - OutputPin(MediaResource* aMediaResource, - SourceFilter* aParent, - CriticalSection& aFilterLock, - int64_t aMP3DataStart); - virtual ~OutputPin(); - - // IUnknown - // Defer to ref counting to BasePin, which defers to owning nsBaseFilter. - STDMETHODIMP_(ULONG) AddRef() override { return BasePin::AddRef(); } - STDMETHODIMP_(ULONG) Release() override { return BasePin::Release(); } - STDMETHODIMP QueryInterface(REFIID iid, void** ppv) override; - - // BasePin Overrides. - // Determines if the pin accepts a specific media type. - HRESULT CheckMediaType(const MediaType* aMediaType) override; - - // Retrieves a preferred media type, by index value. - HRESULT GetMediaType(int aPosition, MediaType* aMediaType) override; - - // Releases the pin from a connection. - HRESULT BreakConnect(void) override; - - // Determines whether a pin connection is suitable. - HRESULT CheckConnect(IPin* aPin) override; - - - // IAsyncReader overrides - - // The RequestAllocator method requests an allocator during the - // pin connection. - STDMETHODIMP RequestAllocator(IMemAllocator* aPreferred, - ALLOCATOR_PROPERTIES* aProps, - IMemAllocator** aActual) override; - - // The Request method queues an asynchronous request for data. Downstream - // will call WaitForNext() when they want to retrieve the result. - STDMETHODIMP Request(IMediaSample* aSample, DWORD_PTR aUserData) override; - - // The WaitForNext method waits for the next pending read request - // to complete. This method fails if the graph is flushing. - // Defers to SyncRead/5. - STDMETHODIMP WaitForNext(DWORD aTimeout, - IMediaSample** aSamples, - DWORD_PTR* aUserData) override; - - // The SyncReadAligned method performs a synchronous read. The method - // blocks until the request is completed. Defers to SyncRead/5. This - // method does not fail if the graph is flushing. - STDMETHODIMP SyncReadAligned(IMediaSample* aSample) override; - - // The SyncRead method performs a synchronous read. The method blocks - // until the request is completed. Defers to SyncRead/5. This - // method does not fail if the graph is flushing. - STDMETHODIMP SyncRead(LONGLONG aPosition, LONG aLength, BYTE* aBuffer) override; - - // The Length method retrieves the total length of the stream. - STDMETHODIMP Length(LONGLONG* aTotal, LONGLONG* aAvailable) override; - - // IPin Overrides - STDMETHODIMP BeginFlush(void) override; - STDMETHODIMP EndFlush(void) override; - - uint32_t GetAndResetBytesConsumedCount(); - -private: - - // Protects thread-shared data/structures (mFlushCount, mPendingReads). - // WaitForNext() also waits on this monitor - CriticalSection& mPinLock; - - // Signal used with mPinLock to implement WaitForNext(). - Signal mSignal; - - // The filter that owns us. Weak reference, as we're a delegate (tear off). - SourceFilter* mParentSource; - - MediaResourcePartition mResource; - - // Counter, inc'd in BeginFlush(), dec'd in EndFlush(). Calls to this can - // come from multiple threads and can interleave, hence the counter. - int32_t mFlushCount; - - // Number of bytes that have been read from the output pin since the last - // time GetAndResetBytesConsumedCount() was called. - uint32_t mBytesConsumed; - - // Deque of ReadRequest* for reads that are yet to be serviced. - // nsReadRequest's are stored on the heap, popper must delete them. - nsDeque mPendingReads; - - // Flags if the downstream pin has QI'd for IAsyncReader. We refuse - // connection if they don't query, as it means they're assuming that we're - // a push filter, and we're not. - bool mQueriedForAsyncReader; - -}; - -// For mingw __uuidof support -#ifdef __CRT_UUID_DECL -} -__CRT_UUID_DECL(mozilla::OutputPin, 0x18e5cfb2,0x1015,0x440c,0xa6,0x5c,0xe6,0x38,0x53,0x23,0x58,0x94); -namespace mozilla { -#endif - -OutputPin::OutputPin(MediaResource* aResource, - SourceFilter* aParent, - CriticalSection& aFilterLock, - int64_t aMP3DataStart) - : BasePin(static_cast<BaseFilter*>(aParent), - &aFilterLock, - L"MozillaOutputPin", - PINDIR_OUTPUT), - mPinLock(aFilterLock), - mSignal(&mPinLock), - mParentSource(aParent), - mResource(aResource, aMP3DataStart), - mFlushCount(0), - mBytesConsumed(0), - mQueriedForAsyncReader(false) -{ - MOZ_COUNT_CTOR(OutputPin); - DIRECTSHOW_LOG("OutputPin::OutputPin()"); -} - -OutputPin::~OutputPin() -{ - MOZ_COUNT_DTOR(OutputPin); - DIRECTSHOW_LOG("OutputPin::~OutputPin()"); -} - -HRESULT -OutputPin::BreakConnect() -{ - mQueriedForAsyncReader = false; - return BasePin::BreakConnect(); -} - -STDMETHODIMP -OutputPin::QueryInterface(REFIID aIId, void** aInterface) -{ - if (aIId == IID_IAsyncReader) { - mQueriedForAsyncReader = true; - return DoGetInterface(static_cast<IAsyncReader*>(this), aInterface); - } - - if (aIId == __uuidof(OutputPin)) { - AddRef(); - *aInterface = this; - return S_OK; - } - - return BasePin::QueryInterface(aIId, aInterface); -} - -HRESULT -OutputPin::CheckConnect(IPin* aPin) -{ - // Our connection is only suitable if the downstream pin knows - // that we're asynchronous (i.e. it queried for IAsyncReader). - return mQueriedForAsyncReader ? S_OK : S_FALSE; -} - -HRESULT -OutputPin::CheckMediaType(const MediaType* aMediaType) -{ - const MediaType *myMediaType = mParentSource->GetMediaType(); - - if (IsEqualGUID(aMediaType->majortype, myMediaType->majortype) && - IsEqualGUID(aMediaType->subtype, myMediaType->subtype) && - IsEqualGUID(aMediaType->formattype, myMediaType->formattype)) - { - DIRECTSHOW_LOG("OutputPin::CheckMediaType() Match: major=%s minor=%s TC=%d FSS=%d SS=%u", - GetDirectShowGuidName(aMediaType->majortype), - GetDirectShowGuidName(aMediaType->subtype), - aMediaType->TemporalCompression(), - aMediaType->bFixedSizeSamples, - aMediaType->SampleSize()); - return S_OK; - } - - DIRECTSHOW_LOG("OutputPin::CheckMediaType() Failed to match: major=%s minor=%s TC=%d FSS=%d SS=%u", - GetDirectShowGuidName(aMediaType->majortype), - GetDirectShowGuidName(aMediaType->subtype), - aMediaType->TemporalCompression(), - aMediaType->bFixedSizeSamples, - aMediaType->SampleSize()); - return S_FALSE; -} - -HRESULT -OutputPin::GetMediaType(int aPosition, MediaType* aMediaType) -{ - if (!aMediaType) - return E_POINTER; - - if (aPosition == 0) { - aMediaType->Assign(mParentSource->GetMediaType()); - return S_OK; - } - return VFW_S_NO_MORE_ITEMS; -} - -static inline bool -IsPowerOf2(int32_t x) { - return ((-x & x) != x); -} - -STDMETHODIMP -OutputPin::RequestAllocator(IMemAllocator* aPreferred, - ALLOCATOR_PROPERTIES* aProps, - IMemAllocator** aActual) -{ - // Require the downstream pin to suggest what they want... - if (!aPreferred) return E_POINTER; - if (!aProps) return E_POINTER; - if (!aActual) return E_POINTER; - - // We only care about alignment - our allocator will reject anything - // which isn't power-of-2 aligned, so so try a 4-byte aligned allocator. - ALLOCATOR_PROPERTIES props; - memcpy(&props, aProps, sizeof(ALLOCATOR_PROPERTIES)); - if (aProps->cbAlign == 0 || IsPowerOf2(aProps->cbAlign)) { - props.cbAlign = 4; - } - - // Limit allocator's number of buffers. We know that the media will most - // likely be bound by network speed, not by decoding speed. We also - // store the incoming data in a Gecko stream, if we don't limit buffers - // here we'll end up duplicating a lot of storage. We must have enough - // space for audio key frames to fit in the first batch of buffers however, - // else pausing may fail for some downstream decoders. - if (props.cBuffers > BaseFilter::sMaxNumBuffers) { - props.cBuffers = BaseFilter::sMaxNumBuffers; - } - - // The allocator properties that are actually used. We don't store - // this, we need it for SetProperties() below to succeed. - ALLOCATOR_PROPERTIES actualProps; - HRESULT hr; - - if (aPreferred) { - // Play nice and prefer the downstream pin's preferred allocator. - hr = aPreferred->SetProperties(&props, &actualProps); - if (SUCCEEDED(hr)) { - aPreferred->AddRef(); - *aActual = aPreferred; - return S_OK; - } - } - - // Else downstream hasn't requested a specific allocator, so create one... - - // Just create a default allocator. It's highly unlikely that we'll use - // this anyway, as most parsers insist on using their own allocators. - RefPtr<IMemAllocator> allocator; - hr = CoCreateInstance(CLSID_MemoryAllocator, - 0, - CLSCTX_INPROC_SERVER, - IID_IMemAllocator, - getter_AddRefs(allocator)); - if(FAILED(hr) || (allocator == nullptr)) { - NS_WARNING("Can't create our own DirectShow allocator."); - return hr; - } - - // See if we can make it suitable - hr = allocator->SetProperties(&props, &actualProps); - if (SUCCEEDED(hr)) { - // We need to release our refcount on pAlloc, and addref - // it to pass a refcount to the caller - this is a net nothing. - allocator.forget(aActual); - return S_OK; - } - - NS_WARNING("Failed to pick an allocator"); - return hr; -} - -STDMETHODIMP -OutputPin::Request(IMediaSample* aSample, DWORD_PTR aDwUser) -{ - if (!aSample) return E_FAIL; - - CriticalSectionAutoEnter lock(*mLock); - NS_ASSERTION(!mFlushCount, "Request() while flushing"); - - if (mFlushCount) - return VFW_E_WRONG_STATE; - - REFERENCE_TIME refStart = 0, refEnd = 0; - if (FAILED(aSample->GetTime(&refStart, &refEnd))) { - NS_WARNING("Sample incorrectly timestamped"); - return VFW_E_SAMPLE_TIME_NOT_SET; - } - - // Convert reference time to bytes. - uint32_t start = (uint32_t)(refStart / 10000000); - uint32_t end = (uint32_t)(refEnd / 10000000); - - uint32_t numBytes = end - start; - - ReadRequest* request = new ReadRequest(aSample, - aDwUser, - start, - numBytes); - // Memory for |request| is free when it's popped from the completed - // reads list. - - // Push this onto the queue of reads to be serviced. - mPendingReads.Push(request); - - // Notify any threads blocked in WaitForNext() which are waiting for mPendingReads - // to become non-empty. - mSignal.Notify(); - - return S_OK; -} - -STDMETHODIMP -OutputPin::WaitForNext(DWORD aTimeout, - IMediaSample** aOutSample, - DWORD_PTR* aOutDwUser) -{ - NS_ASSERTION(aTimeout == 0 || aTimeout == INFINITE, - "Oops, we don't handle this!"); - - *aOutSample = nullptr; - *aOutDwUser = 0; - - LONGLONG offset = 0; - LONG count = 0; - BYTE* buf = nullptr; - - { - CriticalSectionAutoEnter lock(*mLock); - - // Wait until there's a pending read to service. - while (aTimeout && mPendingReads.GetSize() == 0 && !mFlushCount) { - // Note: No need to guard against shutdown-during-wait here, as - // typically the thread doing the pull will have already called - // Request(), so we won't Wait() here anyway. SyncRead() will fail - // on shutdown. - mSignal.Wait(); - } - - nsAutoPtr<ReadRequest> request(reinterpret_cast<ReadRequest*>(mPendingReads.PopFront())); - if (!request) - return VFW_E_WRONG_STATE; - - *aOutSample = request->mSample; - *aOutDwUser = request->mDwUser; - - offset = request->mOffset; - count = request->mCount; - buf = nullptr; - request->mSample->GetPointer(&buf); - NS_ASSERTION(buf != nullptr, "Invalid buffer!"); - - if (mFlushCount) { - return VFW_E_TIMEOUT; - } - } - - return SyncRead(offset, count, buf); -} - -STDMETHODIMP -OutputPin::SyncReadAligned(IMediaSample* aSample) -{ - { - // Ignore reads while flushing. - CriticalSectionAutoEnter lock(*mLock); - if (mFlushCount) { - return S_FALSE; - } - } - - if (!aSample) - return E_FAIL; - - REFERENCE_TIME lStart = 0, lEnd = 0; - if (FAILED(aSample->GetTime(&lStart, &lEnd))) { - NS_WARNING("Sample incorrectly timestamped"); - return VFW_E_SAMPLE_TIME_NOT_SET; - } - - // Convert reference time to bytes. - int32_t start = (int32_t)(lStart / 10000000); - int32_t end = (int32_t)(lEnd / 10000000); - - int32_t numBytes = end - start; - - // If the range extends off the end of stream, truncate to the end of stream - // as per IAsyncReader specificiation. - int64_t streamLength = mResource.GetLength(); - if (streamLength != -1) { - // We know the exact length of the stream, fail if the requested offset - // is beyond it. - if (start > streamLength) { - return VFW_E_BADALIGN; - } - - // If the end of the chunk to read is off the end of the stream, - // truncate it to the end of the stream. - if ((start + numBytes) > streamLength) { - numBytes = (uint32_t)(streamLength - start); - } - } - - BYTE* buf=0; - aSample->GetPointer(&buf); - - return SyncRead(start, numBytes, buf); -} - -STDMETHODIMP -OutputPin::SyncRead(LONGLONG aPosition, - LONG aLength, - BYTE* aBuffer) -{ - MOZ_ASSERT(!NS_IsMainThread()); - NS_ENSURE_TRUE(aPosition >= 0, E_FAIL); - NS_ENSURE_TRUE(aLength > 0, E_FAIL); - NS_ENSURE_TRUE(aBuffer, E_POINTER); - - DIRECTSHOW_LOG("OutputPin::SyncRead(%lld, %d)", aPosition, aLength); - { - // Ignore reads while flushing. - CriticalSectionAutoEnter lock(*mLock); - if (mFlushCount) { - return S_FALSE; - } - } - - uint32_t totalBytesRead = 0; - nsresult rv = mResource.ReadAt(aPosition, - reinterpret_cast<char*>(aBuffer), - aLength, - &totalBytesRead); - if (NS_FAILED(rv)) { - return E_FAIL; - } - if (totalBytesRead > 0) { - CriticalSectionAutoEnter lock(*mLock); - mBytesConsumed += totalBytesRead; - } - return (totalBytesRead == aLength) ? S_OK : S_FALSE; -} - -STDMETHODIMP -OutputPin::Length(LONGLONG* aTotal, LONGLONG* aAvailable) -{ - HRESULT hr = S_OK; - int64_t length = mResource.GetLength(); - if (length == -1) { - hr = VFW_S_ESTIMATED; - // Don't have a length. Just lie, it seems to work... - *aTotal = INT32_MAX; - } else { - *aTotal = length; - } - if (aAvailable) { - *aAvailable = mResource.GetCachedDataEnd(); - } - - DIRECTSHOW_LOG("OutputPin::Length() len=%lld avail=%lld", *aTotal, *aAvailable); - - return hr; -} - -STDMETHODIMP -OutputPin::BeginFlush() -{ - CriticalSectionAutoEnter lock(*mLock); - mFlushCount++; - mSignal.Notify(); - return S_OK; -} - -STDMETHODIMP -OutputPin::EndFlush(void) -{ - CriticalSectionAutoEnter lock(*mLock); - mFlushCount--; - return S_OK; -} - -uint32_t -OutputPin::GetAndResetBytesConsumedCount() -{ - CriticalSectionAutoEnter lock(*mLock); - uint32_t bytesConsumed = mBytesConsumed; - mBytesConsumed = 0; - return bytesConsumed; -} - -SourceFilter::SourceFilter(const GUID& aMajorType, - const GUID& aSubType) - : BaseFilter(L"MozillaDirectShowSource", __uuidof(SourceFilter)) -{ - MOZ_COUNT_CTOR(SourceFilter); - mMediaType.majortype = aMajorType; - mMediaType.subtype = aSubType; - - DIRECTSHOW_LOG("SourceFilter Constructor(%s, %s)", - GetDirectShowGuidName(aMajorType), - GetDirectShowGuidName(aSubType)); -} - -SourceFilter::~SourceFilter() -{ - MOZ_COUNT_DTOR(SourceFilter); - DIRECTSHOW_LOG("SourceFilter Destructor()"); -} - -BasePin* -SourceFilter::GetPin(int n) -{ - if (n == 0) { - NS_ASSERTION(mOutputPin != 0, "GetPin with no pin!"); - return static_cast<BasePin*>(mOutputPin); - } else { - return nullptr; - } -} - -// Get's the media type we're supplying. -const MediaType* -SourceFilter::GetMediaType() const -{ - return &mMediaType; -} - -nsresult -SourceFilter::Init(MediaResource* aResource, int64_t aMP3Offset) -{ - DIRECTSHOW_LOG("SourceFilter::Init()"); - - mOutputPin = new OutputPin(aResource, - this, - mLock, - aMP3Offset); - NS_ENSURE_TRUE(mOutputPin != nullptr, NS_ERROR_FAILURE); - - return NS_OK; -} - -uint32_t -SourceFilter::GetAndResetBytesConsumedCount() -{ - return mOutputPin->GetAndResetBytesConsumedCount(); -} - - -} // namespace mozilla diff --git a/dom/media/directshow/SourceFilter.h b/dom/media/directshow/SourceFilter.h deleted file mode 100644 index d5ce2770e..000000000 --- a/dom/media/directshow/SourceFilter.h +++ /dev/null @@ -1,75 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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/. */ - -#if !defined(nsDirectShowSource_h___) -#define nsDirectShowSource_h___ - -#include "BaseFilter.h" -#include "BasePin.h" -#include "MediaType.h" - -#include "nsDeque.h" -#include "nsAutoPtr.h" -#include "DirectShowUtils.h" -#include "mozilla/RefPtr.h" - -namespace mozilla { - -class MediaResource; -class OutputPin; - - -// SourceFilter is an asynchronous DirectShow source filter which -// reads from an MediaResource, and supplies data via a pull model downstream -// using OutputPin. It us used to supply a generic byte stream into -// DirectShow. -// -// Implements: -// * IBaseFilter -// * IMediaFilter -// * IPersist -// * IUnknown -// -class DECLSPEC_UUID("5c2a7ad0-ba82-4659-9178-c4719a2765d6") -SourceFilter : public media::BaseFilter -{ -public: - - // Constructs source filter to deliver given media type. - SourceFilter(const GUID& aMajorType, const GUID& aSubType); - ~SourceFilter(); - - nsresult Init(MediaResource *aResource, int64_t aMP3Offset); - - // BaseFilter overrides. - // Only one output - the byte stream. - int GetPinCount() override { return 1; } - - media::BasePin* GetPin(int n) override; - - // Get's the media type we're supplying. - const media::MediaType* GetMediaType() const; - - uint32_t GetAndResetBytesConsumedCount(); - -protected: - - // Our async pull output pin. - nsAutoPtr<OutputPin> mOutputPin; - - // Type of byte stream we output. - media::MediaType mMediaType; - -}; - -} // namespace mozilla - -// For mingw __uuidof support -#ifdef __CRT_UUID_DECL -__CRT_UUID_DECL(mozilla::SourceFilter, 0x5c2a7ad0,0xba82,0x4659,0x91,0x78,0xc4,0x71,0x9a,0x27,0x65,0xd6); -#endif - -#endif diff --git a/dom/media/directshow/moz.build b/dom/media/directshow/moz.build deleted file mode 100644 index 8a9b76200..000000000 --- a/dom/media/directshow/moz.build +++ /dev/null @@ -1,41 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# 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/. - -EXPORTS += [ - 'AudioSinkFilter.h', - 'AudioSinkInputPin.h', - 'DirectShowDecoder.h', - 'DirectShowReader.h', - 'DirectShowUtils.h', -] - -UNIFIED_SOURCES += [ - 'DirectShowDecoder.cpp', - 'DirectShowUtils.cpp', - 'SourceFilter.cpp', -] - -SOURCES += [ - 'AudioSinkFilter.cpp', - 'AudioSinkInputPin.cpp', - 'DirectShowReader.cpp', - 'SampleSink.cpp', -] - -# If WebRTC isn't being built, we need to compile the DirectShow base classes so that -# they're available at link time. -if not CONFIG['MOZ_WEBRTC']: - SOURCES += [ - '/media/webrtc/trunk/webrtc/modules/video_capture/windows/BaseFilter.cpp', - '/media/webrtc/trunk/webrtc/modules/video_capture/windows/BaseInputPin.cpp', - '/media/webrtc/trunk/webrtc/modules/video_capture/windows/BasePin.cpp', - '/media/webrtc/trunk/webrtc/modules/video_capture/windows/MediaType.cpp', - ] - -FINAL_LIBRARY = 'xul' -LOCAL_INCLUDES += [ - '/media/webrtc/trunk/webrtc/modules/video_capture/windows', -] diff --git a/dom/media/eme/DetailedPromise.cpp b/dom/media/eme/DetailedPromise.cpp index 5893bea2e..d443e3336 100644 --- a/dom/media/eme/DetailedPromise.cpp +++ b/dom/media/eme/DetailedPromise.cpp @@ -96,9 +96,6 @@ DetailedPromise::MaybeReportTelemetry(Status aStatus) uint32_t latency = (TimeStamp::Now() - mStartTime).ToMilliseconds(); EME_LOG("%s %s latency %ums reported via telemetry", mName.get(), ((aStatus == Succeeded) ? "succcess" : "failure"), latency); - Telemetry::ID tid = (aStatus == Succeeded) ? mSuccessLatencyProbe.Value() - : mFailureLatencyProbe.Value(); - Telemetry::Accumulate(tid, latency); } } // namespace dom diff --git a/dom/media/eme/MediaKeySession.cpp b/dom/media/eme/MediaKeySession.cpp index d5eff3f77..9c002b5ba 100644 --- a/dom/media/eme/MediaKeySession.cpp +++ b/dom/media/eme/MediaKeySession.cpp @@ -315,9 +315,6 @@ MediaKeySession::GenerateRequest(const nsAString& aInitDataType, // Note: Remaining steps of generateRequest method continue in CDM. - Telemetry::Accumulate(Telemetry::VIDEO_CDM_GENERATE_REQUEST_CALLED, - ToCDMTypeTelemetryEnum(mKeySystem)); - // Convert initData to base64 for easier logging. // Note: CreateSession() Move()s the data out of the array, so we have // to copy it here. diff --git a/dom/media/eme/MediaKeys.cpp b/dom/media/eme/MediaKeys.cpp index eedd675e4..fea548698 100644 --- a/dom/media/eme/MediaKeys.cpp +++ b/dom/media/eme/MediaKeys.cpp @@ -13,7 +13,6 @@ #include "mozilla/dom/MediaKeySession.h" #include "mozilla/dom/DOMException.h" #include "mozilla/dom/UnionTypes.h" -#include "mozilla/Telemetry.h" #include "GMPCDMProxy.h" #ifdef MOZ_WIDGET_ANDROID #include "mozilla/MediaDrmCDMProxy.h" @@ -457,7 +456,6 @@ MediaKeys::OnCDMCreated(PromiseId aId, const nsACString& aNodeId, const uint32_t mKeySystem, MediaKeySystemStatus::Cdm_created); - Telemetry::Accumulate(Telemetry::VIDEO_CDM_CREATED, ToCDMTypeTelemetryEnum(mKeySystem)); } static bool diff --git a/dom/media/fmp4/MP4Decoder.cpp b/dom/media/fmp4/MP4Decoder.cpp index fdd6f2c7e..6954e9757 100644 --- a/dom/media/fmp4/MP4Decoder.cpp +++ b/dom/media/fmp4/MP4Decoder.cpp @@ -83,10 +83,6 @@ MP4Decoder::CanHandleMediaType(const MediaContentType& aType, const bool isMP4Audio = aType.GetMIMEType().EqualsASCII("audio/mp4") || aType.GetMIMEType().EqualsASCII("audio/x-m4a"); const bool isMP4Video = - // On B2G, treat 3GPP as MP4 when Gonk PDM is available. -#ifdef MOZ_GONK_MEDIACODEC - aType.GetMIMEType().EqualsASCII(VIDEO_3GPP) || -#endif aType.GetMIMEType().EqualsASCII("video/mp4") || aType.GetMIMEType().EqualsASCII("video/quicktime") || aType.GetMIMEType().EqualsASCII("video/x-m4v"); @@ -139,6 +135,14 @@ MP4Decoder::CanHandleMediaType(const MediaContentType& aType, NS_LITERAL_CSTRING("audio/flac"), aType)); continue; } +#ifdef MOZ_AV1 + if (IsAV1CodecString(codec)) { + trackInfos.AppendElement( + CreateTrackInfoWithMIMETypeAndContentTypeExtraParameters( + NS_LITERAL_CSTRING("video/av1"), aType)); + continue; + } +#endif // Note: Only accept H.264 in a video content type, not in an audio // content type. if (IsWhitelistedH264Codec(codec) && isMP4Video) { diff --git a/dom/media/fmp4/MP4Demuxer.cpp b/dom/media/fmp4/MP4Demuxer.cpp index 646897468..ef68d5dca 100644 --- a/dom/media/fmp4/MP4Demuxer.cpp +++ b/dom/media/fmp4/MP4Demuxer.cpp @@ -16,9 +16,6 @@ #include "mp4_demuxer/Index.h" #include "nsPrintfCString.h" -// Used for telemetry -#include "mozilla/Telemetry.h" -#include "mp4_demuxer/AnnexB.h" #include "mp4_demuxer/H264.h" #include "nsAutoPtr.h" @@ -72,47 +69,10 @@ private: // Queued samples extracted by the demuxer, but not yet returned. RefPtr<MediaRawData> mQueuedSample; bool mNeedReIndex; - bool mNeedSPSForTelemetry; bool mIsH264 = false; }; -// Returns true if no SPS was found and search for it should continue. -bool -AccumulateSPSTelemetry(const MediaByteBuffer* aExtradata) -{ - mp4_demuxer::SPSData spsdata; - if (mp4_demuxer::H264::DecodeSPSFromExtraData(aExtradata, spsdata)) { - uint8_t constraints = (spsdata.constraint_set0_flag ? (1 << 0) : 0) | - (spsdata.constraint_set1_flag ? (1 << 1) : 0) | - (spsdata.constraint_set2_flag ? (1 << 2) : 0) | - (spsdata.constraint_set3_flag ? (1 << 3) : 0) | - (spsdata.constraint_set4_flag ? (1 << 4) : 0) | - (spsdata.constraint_set5_flag ? (1 << 5) : 0); - Telemetry::Accumulate(Telemetry::VIDEO_DECODED_H264_SPS_CONSTRAINT_SET_FLAG, - constraints); - - // Collect profile_idc values up to 244, otherwise 0 for unknown. - Telemetry::Accumulate(Telemetry::VIDEO_DECODED_H264_SPS_PROFILE, - spsdata.profile_idc <= 244 ? spsdata.profile_idc : 0); - - // Make sure level_idc represents a value between levels 1 and 5.2, - // otherwise collect 0 for unknown level. - Telemetry::Accumulate(Telemetry::VIDEO_DECODED_H264_SPS_LEVEL, - (spsdata.level_idc >= 10 && spsdata.level_idc <= 52) ? - spsdata.level_idc : 0); - - // max_num_ref_frames should be between 0 and 16, anything larger will - // be treated as invalid. - Telemetry::Accumulate(Telemetry::VIDEO_H264_SPS_MAX_NUM_REF_FRAMES, - std::min(spsdata.max_num_ref_frames, 17u)); - - return false; - } - - return true; -} - MP4Demuxer::MP4Demuxer(MediaResource* aResource) : mResource(aResource) , mStream(new mp4_demuxer::ResourceStream(aResource)) @@ -243,25 +203,10 @@ MP4TrackDemuxer::MP4TrackDemuxer(MP4Demuxer* aParent, EnsureUpToDateIndex(); // Force update of index VideoInfo* videoInfo = mInfo->GetAsVideoInfo(); - // Collect telemetry from h264 AVCC SPS. if (videoInfo && (mInfo->mMimeType.EqualsLiteral("video/mp4") || mInfo->mMimeType.EqualsLiteral("video/avc"))) { mIsH264 = true; - RefPtr<MediaByteBuffer> extraData = videoInfo->mExtraData; - mNeedSPSForTelemetry = AccumulateSPSTelemetry(extraData); - mp4_demuxer::SPSData spsdata; - if (mp4_demuxer::H264::DecodeSPSFromExtraData(extraData, spsdata) && - spsdata.pic_width > 0 && spsdata.pic_height > 0 && - mp4_demuxer::H264::EnsureSPSIsSane(spsdata)) { - videoInfo->mImage.width = spsdata.pic_width; - videoInfo->mImage.height = spsdata.pic_height; - videoInfo->mDisplay.width = spsdata.display_width; - videoInfo->mDisplay.height = spsdata.display_height; - } - } else { - // No SPS to be found. - mNeedSPSForTelemetry = false; } } @@ -388,15 +333,6 @@ MP4TrackDemuxer::GetSamples(int32_t aNumSamples) if (samples->mSamples.IsEmpty()) { return SamplesPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__); } else { - for (const auto& sample : samples->mSamples) { - // Collect telemetry from h264 Annex B SPS. - if (mNeedSPSForTelemetry && mp4_demuxer::AnnexB::HasSPS(sample)) { - RefPtr<MediaByteBuffer> extradata = - mp4_demuxer::AnnexB::ExtractExtraData(sample); - mNeedSPSForTelemetry = AccumulateSPSTelemetry(extradata); - } - } - if (mNextKeyframeTime.isNothing() || samples->mSamples.LastElement()->mTime >= mNextKeyframeTime.value().ToMicroseconds()) { SetNextKeyFrameTime(); diff --git a/dom/media/fmp4/MP4Stream.cpp b/dom/media/fmp4/MP4Stream.cpp index 615a7dc01..9a79cac7a 100644 --- a/dom/media/fmp4/MP4Stream.cpp +++ b/dom/media/fmp4/MP4Stream.cpp @@ -48,9 +48,6 @@ MP4Stream::BlockingReadIntoCache(int64_t aOffset, size_t aCount, Monitor* aToUnl return true; } -// We surreptitiously reimplement the supposedly-blocking ReadAt as a non- -// blocking CachedReadAt, and record when it fails. This allows MP4Reader -// to retry the read as an actual blocking read without holding the lock. bool MP4Stream::ReadAt(int64_t aOffset, void* aBuffer, size_t aCount, size_t* aBytesRead) diff --git a/dom/media/fmp4/moz.build b/dom/media/fmp4/moz.build index 6a249ae3e..a79fb0229 100644 --- a/dom/media/fmp4/moz.build +++ b/dom/media/fmp4/moz.build @@ -20,6 +20,3 @@ SOURCES += [ ] FINAL_LIBRARY = 'xul' - -if CONFIG['MOZ_GONK_MEDIACODEC']: - DEFINES['MOZ_GONK_MEDIACODEC'] = True diff --git a/dom/media/gmp/GMPParent.cpp b/dom/media/gmp/GMPParent.cpp index 40c3e5141..418f14736 100644 --- a/dom/media/gmp/GMPParent.cpp +++ b/dom/media/gmp/GMPParent.cpp @@ -516,8 +516,7 @@ GMPCapability::Supports(const nsTArray<GMPCapability>& aCapabilities, #ifdef XP_WIN // Clearkey on Windows advertises that it can decode in its GMP info // file, but uses Windows Media Foundation to decode. That's not present - // on Windows XP, and on some Vista, Windows N, and KN variants without - // certain services packs. + // on Windows N and KN variants without certain services packs. if (tag.Equals(kEMEKeySystemClearkey)) { if (capabilities.mAPIName.EqualsLiteral(GMP_API_VIDEO_DECODER)) { if (!WMFDecoderModule::HasH264()) { diff --git a/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp b/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp index 74b5c38e8..57d4ecec2 100644 --- a/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp +++ b/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp @@ -46,7 +46,7 @@ void* GetCdmHost(int aHostInterfaceVersion, void* aUserData) Log("GetCdmHostFunc(%d, %p)", aHostInterfaceVersion, aUserData); WidevineDecryptor* decryptor = reinterpret_cast<WidevineDecryptor*>(aUserData); MOZ_ASSERT(decryptor); - return static_cast<cdm::Host_8*>(decryptor); + return static_cast<cdm::Host_9*>(decryptor); } #define STRINGIFY(s) _STRINGIFY(s) @@ -106,8 +106,8 @@ WidevineAdapter::GMPGetAPI(const char* aAPIName, WidevineDecryptor* decryptor = new WidevineDecryptor(); - auto cdm = reinterpret_cast<cdm::ContentDecryptionModule*>( - create(cdm::ContentDecryptionModule::kVersion, + auto cdm = reinterpret_cast<cdm::ContentDecryptionModule_9*>( + create(cdm::ContentDecryptionModule_9::kVersion, kEMEKeySystemWidevine.get(), kEMEKeySystemWidevine.Length(), &GetCdmHost, @@ -161,8 +161,8 @@ WidevineAdapter::Supports(int32_t aModuleVersion, int32_t aHostVersion) { return aModuleVersion == CDM_MODULE_VERSION && - aInterfaceVersion == cdm::ContentDecryptionModule::kVersion && - aHostVersion == cdm::Host_8::kVersion; + aInterfaceVersion == cdm::ContentDecryptionModule_9::kVersion && + aHostVersion == cdm::Host_9::kVersion; } } // namespace mozilla diff --git a/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp b/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp index 149fa1701..4d3408804 100644 --- a/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp +++ b/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp @@ -102,7 +102,7 @@ WidevineDecryptor::CreateSession(uint32_t aCreateSessionToken, } else { // Invalid init data type const char* errorMsg = "Invalid init data type when creating session."; - OnRejectPromise(aPromiseId, kNotSupportedError, 0, errorMsg, sizeof(errorMsg)); + OnRejectPromise(aPromiseId, kExceptionNotSupportedError, 0, errorMsg, sizeof(errorMsg)); return; } mPromiseIdToNewSessionTokens[aPromiseId] = aCreateSessionToken; @@ -302,6 +302,12 @@ WidevineDecryptor::GetCurrentWallTime() } void +WidevineDecryptor::OnResolveKeyStatusPromise(uint32_t aPromiseId, + cdm::KeyStatus aKeyStatus) { + //TODO: The callback of GetStatusForPolicy. See Mozilla bug 1404230. +} + +void WidevineDecryptor::OnResolveNewSessionPromise(uint32_t aPromiseId, const char* aSessionId, uint32_t aSessionIdSize) @@ -333,41 +339,59 @@ WidevineDecryptor::OnResolvePromise(uint32_t aPromiseId) } static GMPDOMException -ToGMPDOMException(cdm::Error aError) -{ - switch (aError) { - case kNotSupportedError: return kGMPNotSupportedError; - case kInvalidStateError: return kGMPInvalidStateError; - case kInvalidAccessError: - // Note: Chrome converts kInvalidAccessError to TypeError, since the - // Chromium CDM API doesn't have a type error enum value. The EME spec - // requires TypeError in some places, so we do the same conversion. - // See bug 1313202. - return kGMPTypeError; - case kQuotaExceededError: return kGMPQuotaExceededError; +ConvertCDMExceptionToGMPDOMException(cdm::Exception aException) +{ + switch (aException) { + case kExceptionNotSupportedError: return kGMPNotSupportedError; + case kExceptionInvalidStateError: return kGMPInvalidStateError; + case kExceptionTypeError: return kGMPTypeError; + case kExceptionQuotaExceededError: return kGMPQuotaExceededError; case kUnknownError: return kGMPInvalidModificationError; // Note: Unique placeholder. case kClientError: return kGMPAbortError; // Note: Unique placeholder. case kOutputError: return kGMPSecurityError; // Note: Unique placeholder. }; - return kGMPTimeoutError; // Note: Unique placeholder. + return kGMPInvalidStateError; // Note: Unique placeholder. +} + +// Align with spec, the Exceptions used by CDM to reject promises . +// https://w3c.github.io/encrypted-media/#exceptions +cdm::Exception +ConvertCDMErrorToCDMException(cdm::Error error) { + switch (error) { + case cdm::kNotSupportedError: + return cdm::Exception::kExceptionNotSupportedError; + case cdm::kInvalidStateError: + return cdm::Exception::kExceptionInvalidStateError; + case cdm::kInvalidAccessError: + return cdm::Exception::kExceptionTypeError; + case cdm::kQuotaExceededError: + return cdm::Exception::kExceptionQuotaExceededError; + + case cdm::kUnknownError: + case cdm::kClientError: + case cdm::kOutputError: + break; + } + + return cdm::Exception::kExceptionInvalidStateError; } void WidevineDecryptor::OnRejectPromise(uint32_t aPromiseId, - Error aError, + cdm::Exception aException, uint32_t aSystemCode, const char* aErrorMessage, uint32_t aErrorMessageSize) { if (!mCallback) { Log("Decryptor::OnRejectPromise(aPromiseId=%d, err=%d, sysCode=%u, msg=%s) FAIL; !mCallback", - aPromiseId, (int)aError, aSystemCode, aErrorMessage); + aPromiseId, (int)aException, aSystemCode, aErrorMessage); return; } Log("Decryptor::OnRejectPromise(aPromiseId=%d, err=%d, sysCode=%u, msg=%s)", - aPromiseId, (int)aError, aSystemCode, aErrorMessage); + aPromiseId, (int)aException, aSystemCode, aErrorMessage); mCallback->RejectPromise(aPromiseId, - ToGMPDOMException(aError), + ConvertCDMExceptionToGMPDOMException(aException), !aErrorMessageSize ? "" : aErrorMessage, aErrorMessageSize); } @@ -386,11 +410,9 @@ ToGMPMessageType(MessageType message_type) void WidevineDecryptor::OnSessionMessage(const char* aSessionId, uint32_t aSessionIdSize, - MessageType aMessageType, + cdm::MessageType aMessageType, const char* aMessage, - uint32_t aMessageSize, - const char* aLegacyDestinationUrl, - uint32_t aLegacyDestinationUrlLength) + uint32_t aMessageSize) { if (!mCallback) { Log("Decryptor::OnSessionMessage() FAIL; !mCallback"); @@ -479,28 +501,6 @@ WidevineDecryptor::OnSessionClosed(const char* aSessionId, } void -WidevineDecryptor::OnLegacySessionError(const char* aSessionId, - uint32_t aSessionIdLength, - Error aError, - uint32_t aSystemCode, - const char* aErrorMessage, - uint32_t aErrorMessageLength) -{ - if (!mCallback) { - Log("Decryptor::OnLegacySessionError(sid=%s, error=%d) FAIL; !mCallback", - aSessionId, (int)aError); - return; - } - Log("Decryptor::OnLegacySessionError(sid=%s, error=%d)", aSessionId, (int)aError); - mCallback->SessionError(aSessionId, - aSessionIdLength, - ToGMPDOMException(aError), - aSystemCode, - aErrorMessage, - aErrorMessageLength); -} - -void WidevineDecryptor::SendPlatformChallenge(const char* aServiceId, uint32_t aServiceIdSize, const char* aChallenge, @@ -538,4 +538,17 @@ WidevineDecryptor::CreateFileIO(FileIOClient* aClient) return new WidevineFileIO(aClient); } +void +WidevineDecryptor::RequestStorageId(uint32_t aVersion) +{ + Log("Decryptor::RequestStorageId() aVersion = %u", aVersion); + if (aVersion >= 0x80000000) { + mCDM->OnStorageId(aVersion, nullptr, 0); + return; + } + + //TODO: Need to provide a menaingful buffer instead of a dummy one. + mCDM->OnStorageId(aVersion, new uint8_t[1024*1024], 1024 * 1024); +} + } // namespace mozilla diff --git a/dom/media/gmp/widevine-adapter/WidevineDecryptor.h b/dom/media/gmp/widevine-adapter/WidevineDecryptor.h index d5185192b..f291c321d 100644 --- a/dom/media/gmp/widevine-adapter/WidevineDecryptor.h +++ b/dom/media/gmp/widevine-adapter/WidevineDecryptor.h @@ -16,7 +16,7 @@ namespace mozilla { class WidevineDecryptor : public GMPDecryptor - , public cdm::Host_8 + , public cdm::Host_9 { public: @@ -69,16 +69,19 @@ public: void DecryptingComplete() override; - // cdm::Host_8 + // cdm::Host_9 implementation cdm::Buffer* Allocate(uint32_t aCapacity) override; void SetTimer(int64_t aDelayMs, void* aContext) override; cdm::Time GetCurrentWallTime() override; + // cdm::Host_9 interface + void OnResolveKeyStatusPromise(uint32_t aPromiseId, + cdm::KeyStatus aKeyStatus) override; void OnResolveNewSessionPromise(uint32_t aPromiseId, const char* aSessionId, uint32_t aSessionIdSize) override; void OnResolvePromise(uint32_t aPromiseId) override; void OnRejectPromise(uint32_t aPromiseId, - cdm::Error aError, + cdm::Exception aException, uint32_t aSystemCode, const char* aErrorMessage, uint32_t aErrorMessageSize) override; @@ -86,9 +89,7 @@ public: uint32_t aSessionIdSize, cdm::MessageType aMessageType, const char* aMessage, - uint32_t aMessageSize, - const char* aLegacyDestinationUrl, - uint32_t aLegacyDestinationUrlLength) override; + uint32_t aMessageSize) override; void OnSessionKeysChange(const char* aSessionId, uint32_t aSessionIdSize, bool aHasAdditionalUsableKey, @@ -99,12 +100,6 @@ public: cdm::Time aNewExpiryTime) override; void OnSessionClosed(const char* aSessionId, uint32_t aSessionIdSize) override; - void OnLegacySessionError(const char* aSessionId, - uint32_t aSessionId_length, - cdm::Error aError, - uint32_t aSystemCode, - const char* aErrorMessage, - uint32_t aErrorMessageLength) override; void SendPlatformChallenge(const char* aServiceId, uint32_t aServiceIdSize, const char* aChallenge, @@ -113,6 +108,9 @@ public: void QueryOutputProtectionStatus() override; void OnDeferredInitializationDone(cdm::StreamType aStreamType, cdm::Status aDecoderStatus) override; + // cdm::Host_9 interface + // NOTE: the interface has changed upstream. + void RequestStorageId(uint32_t aVersion) override; cdm::FileIO* CreateFileIO(cdm::FileIOClient* aClient) override; GMPDecryptorCallback* Callback() const { return mCallback; } @@ -120,7 +118,7 @@ public: private: ~WidevineDecryptor(); RefPtr<CDMWrapper> mCDM; - cdm::ContentDecryptionModule_8* CDM() { return mCDM->GetCDM(); } + cdm::ContentDecryptionModule_9* CDM() { return mCDM->GetCDM(); } GMPDecryptorCallback* mCallback; std::map<uint32_t, uint32_t> mPromiseIdToNewSessionTokens; diff --git a/dom/media/gmp/widevine-adapter/WidevineUtils.cpp b/dom/media/gmp/widevine-adapter/WidevineUtils.cpp index 925dfe1a1..10c6c2e18 100644 --- a/dom/media/gmp/widevine-adapter/WidevineUtils.cpp +++ b/dom/media/gmp/widevine-adapter/WidevineUtils.cpp @@ -43,7 +43,7 @@ ToGMPErr(cdm::Status aStatus) case cdm::kSuccess: return GMPNoErr; case cdm::kNeedMoreData: return GMPGenericErr; case cdm::kNoKey: return GMPNoKeyErr; - case cdm::kSessionError: return GMPGenericErr; + case cdm::kInitializationError: return GMPGenericErr; case cdm::kDecryptError: return GMPCryptoErr; case cdm::kDecodeError: return GMPDecodeErr; case cdm::kDeferredInitialization: return GMPGenericErr; @@ -77,7 +77,7 @@ void InitInputBuffer(const GMPEncryptedBufferMetadata* aCrypto, aInputBuffer.timestamp = aTimestamp; } -CDMWrapper::CDMWrapper(cdm::ContentDecryptionModule_8* aCDM, +CDMWrapper::CDMWrapper(cdm::ContentDecryptionModule_9* aCDM, WidevineDecryptor* aDecryptor) : mCDM(aCDM) , mDecryptor(aDecryptor) diff --git a/dom/media/gmp/widevine-adapter/WidevineUtils.h b/dom/media/gmp/widevine-adapter/WidevineUtils.h index 57c004a87..2f6137fe3 100644 --- a/dom/media/gmp/widevine-adapter/WidevineUtils.h +++ b/dom/media/gmp/widevine-adapter/WidevineUtils.h @@ -48,12 +48,16 @@ class CDMWrapper { public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CDMWrapper) - explicit CDMWrapper(cdm::ContentDecryptionModule_8* aCDM, + explicit CDMWrapper(cdm::ContentDecryptionModule_9* aCDM, WidevineDecryptor* aDecryptor); - cdm::ContentDecryptionModule_8* GetCDM() const { return mCDM; } + cdm::ContentDecryptionModule_9* GetCDM() const { return mCDM; } + void OnStorageId(uint32_t aVersion, const uint8_t* aStorageId, + uint32_t aStorageIdSize) { + mCDM->OnStorageId(aVersion, aStorageId, aStorageIdSize); + } private: ~CDMWrapper(); - cdm::ContentDecryptionModule_8* mCDM; + cdm::ContentDecryptionModule_9* mCDM; RefPtr<WidevineDecryptor> mDecryptor; }; diff --git a/dom/media/gmp/widevine-adapter/WidevineVideoDecoder.h b/dom/media/gmp/widevine-adapter/WidevineVideoDecoder.h index b143f75f7..f5e63519b 100644 --- a/dom/media/gmp/widevine-adapter/WidevineVideoDecoder.h +++ b/dom/media/gmp/widevine-adapter/WidevineVideoDecoder.h @@ -45,7 +45,7 @@ private: ~WidevineVideoDecoder(); - cdm::ContentDecryptionModule_8* CDM() const { + cdm::ContentDecryptionModule_9* CDM() const { // CDM should only be accessed before 'DecodingComplete'. MOZ_ASSERT(mCDMWrapper); // CDMWrapper ensure the CDM is non-null, no need to check again. diff --git a/dom/media/gmp/widevine-adapter/content_decryption_module.h b/dom/media/gmp/widevine-adapter/content_decryption_module.h index 512ca9768..0539135fb 100644 --- a/dom/media/gmp/widevine-adapter/content_decryption_module.h +++ b/dom/media/gmp/widevine-adapter/content_decryption_module.h @@ -5,6 +5,8 @@ #ifndef CDM_CONTENT_DECRYPTION_MODULE_H_ #define CDM_CONTENT_DECRYPTION_MODULE_H_ +#include "content_decryption_module_export.h" + #if defined(_MSC_VER) typedef unsigned char uint8_t; typedef unsigned int uint32_t; @@ -14,25 +16,21 @@ typedef __int64 int64_t; #include <stdint.h> #endif -// Define CDM_EXPORT so that functionality implemented by the CDM module -// can be exported to consumers. -#if defined(WIN32) - -#if defined(CDM_IMPLEMENTATION) -#define CDM_EXPORT __declspec(dllexport) -#else -#define CDM_EXPORT __declspec(dllimport) -#endif // defined(CDM_IMPLEMENTATION) - -#else // defined(WIN32) - -#if defined(CDM_IMPLEMENTATION) -#define CDM_EXPORT __attribute__((visibility("default"))) +// Define CDM_CLASS_API to export class types. We have to add visibility +// attributes to make sure virtual tables in CDM consumer and CDM implementation +// are the same. Generally, it was always a good idea, as there're no guarantees +// about that for the internal symbols, but it has only become a practical issue +// after introduction of LTO devirtualization. See more details on +// https://crbug.com/609564#c35 +#if defined(_WIN32) +#if defined(__clang__) +#define CDM_CLASS_API [[clang::lto_visibility_public]] #else -#define CDM_EXPORT +#define CDM_CLASS_API #endif - -#endif // defined(WIN32) +#else // defined(_WIN32) +#define CDM_CLASS_API __attribute__((visibility("default"))) +#endif // defined(_WIN32) // The version number must be rolled when the exported functions are updated! // If the CDM and the adapter use different versions of these functions, the @@ -48,9 +46,9 @@ typedef __int64 int64_t; #define BUILD_ENTRYPOINT_NO_EXPANSION(name, version) name##_##version extern "C" { -CDM_EXPORT void INITIALIZE_CDM_MODULE(); +CDM_API void INITIALIZE_CDM_MODULE(); -CDM_EXPORT void DeinitializeCdmModule(); +CDM_API void DeinitializeCdmModule(); // Returns a pointer to the requested CDM Host interface upon success. // Returns NULL if the requested CDM Host interface is not supported. @@ -65,30 +63,30 @@ typedef void* (*GetCdmHostFunc)(int host_interface_version, void* user_data); // |cdm_interface_version|. // Caller retains ownership of arguments and must call Destroy() on the returned // object. -CDM_EXPORT void* CreateCdmInstance( +CDM_API void* CreateCdmInstance( int cdm_interface_version, const char* key_system, uint32_t key_system_size, GetCdmHostFunc get_cdm_host_func, void* user_data); -CDM_EXPORT const char* GetCdmVersion(); +CDM_API const char* GetCdmVersion(); } namespace cdm { -class AudioFrames; -class DecryptedBlock; -class VideoFrame; +class CDM_CLASS_API AudioFrames; +class CDM_CLASS_API DecryptedBlock; +class CDM_CLASS_API VideoFrame; -class Host_7; -class Host_8; +class CDM_CLASS_API Host_8; +class CDM_CLASS_API Host_9; enum Status { kSuccess = 0, kNeedMoreData, // Decoder needs more data to produce a decoded frame/sample. - kNoKey, // The required decryption key is not available. - kSessionError, // Session management error. - kDecryptError, // Decryption failed. - kDecodeError, // Error decoding audio or video. + kNoKey, // The required decryption key is not available. + kInitializationError, // Initialization error. + kDecryptError, // Decryption failed. + kDecodeError, // Error decoding audio or video. kDeferredInitialization // Decoder is not ready for initialization. }; @@ -97,6 +95,7 @@ enum Status { // The following starts with the list of DOM4 exceptions from: // http://www.w3.org/TR/dom/#domexception // Some DOM4 exceptions are not included as they are not expected to be used. +// Should only be used on Host_8 and before. enum Error { kNotSupportedError = 9, kInvalidStateError = 11, @@ -113,8 +112,20 @@ enum Error { kOutputError = 101 }; -// Time is defined as the number of seconds since the -// Epoch (00:00:00 UTC, January 1, 1970). +// Exceptions used by the CDM to reject promises. +// https://w3c.github.io/encrypted-media/#exceptions +enum Exception { + kExceptionTypeError, + kExceptionNotSupportedError, + kExceptionInvalidStateError, + kExceptionQuotaExceededError +}; + +// Time is defined as the number of seconds since the Epoch +// (00:00:00 UTC, January 1, 1970), not including any added leap second. +// Also see Time definition in spec: https://w3c.github.io/encrypted-media/#time +// Note that Time is defined in millisecond accuracy in the spec but in second +// accuracy here. typedef double Time; // An input buffer can be split into several continuous subsamples. @@ -151,13 +162,13 @@ struct SubsampleEntry { // unencrypted. struct InputBuffer { InputBuffer() - : data(NULL), + : data(nullptr), data_size(0), - key_id(NULL), + key_id(nullptr), key_id_size(0), - iv(NULL), + iv(nullptr), iv_size(0), - subsamples(NULL), + subsamples(nullptr), num_subsamples(0), timestamp(0) {} @@ -188,7 +199,7 @@ struct AudioDecoderConfig { channel_count(0), bits_per_channel(0), samples_per_second(0), - extra_data(NULL), + extra_data(nullptr), extra_data_size(0) {} AudioCodec codec; @@ -214,10 +225,25 @@ enum AudioFormat { }; // Surface formats based on FOURCC labels, see: http://www.fourcc.org/yuv.php +// Values are chosen to be consistent with Chromium's VideoPixelFormat values. enum VideoFormat { kUnknownVideoFormat = 0, // Unknown format value. Used for error reporting. - kYv12, // 12bpp YVU planar 1x1 Y, 2x2 VU samples. - kI420 // 12bpp YVU planar 1x1 Y, 2x2 UV samples. + kYv12 = 1, // 12bpp YVU planar 1x1 Y, 2x2 VU samples. + kI420 = 2, // 12bpp YUV planar 1x1 Y, 2x2 UV samples. + + // In the following formats, each sample uses 16-bit in storage, while the + // sample value is stored in the least significant N bits where N is + // specified by the number after "P". For example, for YUV420P9, each Y, U, + // and V sample is stored in the least significant 9 bits in a 2-byte block. + kYUV420P9 = 16, + kYUV420P10 = 17, + kYUV422P9 = 18, + kYUV422P10 = 19, + kYUV444P9 = 20, + kYUV444P10 = 21, + kYUV420P12 = 22, + kYUV422P12 = 23, + kYUV444P12 = 24, }; struct Size { @@ -245,14 +271,19 @@ struct VideoDecoderConfig { kH264ProfileHigh, kH264ProfileHigh10, kH264ProfileHigh422, - kH264ProfileHigh444Predictive + kH264ProfileHigh444Predictive, + // VP9 Profiles are only passed in starting from CDM_9. + kVP9Profile0, + kVP9Profile1, + kVP9Profile2, + kVP9Profile3 }; VideoDecoderConfig() : codec(kUnknownVideoCodec), profile(kUnknownVideoCodecProfile), format(kUnknownVideoFormat), - extra_data(NULL), + extra_data(nullptr), extra_data_size(0) {} VideoCodec codec; @@ -294,7 +325,7 @@ struct PlatformChallengeResponse { // Used when passing arrays of binary data. Does not own the referenced data. struct BinaryData { - BinaryData() : data(NULL), length(0) {} + BinaryData() : data(nullptr), length(0) {} const uint8_t* data; uint32_t length; }; @@ -316,7 +347,10 @@ enum KeyStatus { // should be 0 when |status| == kUsable. struct KeyInformation { KeyInformation() - : key_id(NULL), key_id_size(0), status(kInternalError), system_code(0) {} + : key_id(nullptr), + key_id_size(0), + status(kInternalError), + system_code(0) {} const uint8_t* key_id; uint32_t key_id_size; KeyStatus status; @@ -372,6 +406,24 @@ enum MessageType { kLicenseRelease = 2 }; +enum HdcpVersion { + kHdcpVersionNone, + kHdcpVersion1_0, + kHdcpVersion1_1, + kHdcpVersion1_2, + kHdcpVersion1_3, + kHdcpVersion1_4, + kHdcpVersion2_0, + kHdcpVersion2_1, + kHdcpVersion2_2 +}; + +struct Policy { + Policy() : min_hdcp_version(kHdcpVersionNone) {} + + HdcpVersion min_hdcp_version; +}; + // FileIO interface provides a way for the CDM to store data in a file in // persistent storage. This interface aims only at providing basic read/write // capabilities and should not be used as a full fledged file IO API. @@ -381,7 +433,7 @@ enum MessageType { // Note to implementors of this interface: // Per-origin storage and the ability for users to clear it are important. // See http://www.w3.org/TR/encrypted-media/#privacy-storedinfo. -class FileIO { +class CDM_CLASS_API FileIO { public: // Opens the file with |file_name| for read and write. // FileIOClient::OnOpenComplete() will be called after the opening @@ -389,8 +441,9 @@ class FileIO { // - When the file is opened by a CDM instance, it will be classified as "in // use". In this case other CDM instances in the same domain may receive // kInUse status when trying to open it. - // - |file_name| must not contain forward slash ('/') or backslash ('\'), and - // must not start with an underscore ('_'). + // - |file_name| must only contain letters (A-Za-z), digits(0-9), or "._-". + // It must not start with an underscore ('_'), and must be at least 1 + // character and no more than 256 characters long. virtual void Open(const char* file_name, uint32_t file_name_size) = 0; // Reads the contents of the file. FileIOClient::OnReadComplete() will be @@ -421,7 +474,7 @@ class FileIO { // When kError is returned, the FileIO object could be in an error state. All // following calls (other than Close()) could return kError. The CDM should // still call Close() to destroy the FileIO object. -class FileIOClient { +class CDM_CLASS_API FileIOClient { public: enum Status { kSuccess = 0, @@ -462,10 +515,20 @@ class FileIOClient { // provided in CreateCdmInstance() to allocate any Buffer that needs to // be passed back to the caller. Implementations must call Buffer::Destroy() // when a Buffer is created that will never be returned to the caller. -class ContentDecryptionModule_7 { +class CDM_CLASS_API ContentDecryptionModule_8 { public: - static const int kVersion = 7; - typedef Host_7 Host; + static const int kVersion = 8; + typedef Host_8 Host; + + // Initializes the CDM instance, providing information about permitted + // functionalities. + // If |allow_distinctive_identifier| is false, messages from the CDM, + // such as message events, must not contain a Distinctive Identifier, + // even in an encrypted form. + // If |allow_persistent_state| is false, the CDM must not attempt to + // persist state. Calls to CreateFileIO() will fail. + virtual void Initialize(bool allow_distinctive_identifier, + bool allow_persistent_state) = 0; // SetServerCertificate(), CreateSessionAndGenerateRequest(), LoadSession(), // UpdateSession(), CloseSession(), and RemoveSession() all accept a @@ -484,8 +547,7 @@ class ContentDecryptionModule_7 { // or Host::OnRejectPromise(). virtual void CreateSessionAndGenerateRequest(uint32_t promise_id, SessionType session_type, - const char* init_data_type, - uint32_t init_data_type_size, + InitDataType init_data_type, const uint8_t* init_data, uint32_t init_data_size) = 0; @@ -631,8 +693,8 @@ class ContentDecryptionModule_7 { virtual void Destroy() = 0; protected: - ContentDecryptionModule_7() {} - virtual ~ContentDecryptionModule_7() {} + ContentDecryptionModule_8() {} + virtual ~ContentDecryptionModule_8() {} }; // ContentDecryptionModule interface that all CDMs need to implement. @@ -641,10 +703,10 @@ class ContentDecryptionModule_7 { // provided in CreateCdmInstance() to allocate any Buffer that needs to // be passed back to the caller. Implementations must call Buffer::Destroy() // when a Buffer is created that will never be returned to the caller. -class ContentDecryptionModule_8 { +class CDM_CLASS_API ContentDecryptionModule_9 { public: - static const int kVersion = 8; - typedef Host_8 Host; + static const int kVersion = 9; + typedef Host_9 Host; // Initializes the CDM instance, providing information about permitted // functionalities. @@ -656,6 +718,13 @@ class ContentDecryptionModule_8 { virtual void Initialize(bool allow_distinctive_identifier, bool allow_persistent_state) = 0; + // Gets the key status if the CDM has a hypothetical key with the |policy|. + // The CDM must respond by calling either Host::OnResolveKeyStatusPromise() + // with the result key status or Host::OnRejectPromise() if an unexpected + // error happened or this method is not supported. + virtual void GetStatusForPolicy(uint32_t promise_id, + const Policy& policy) = 0; + // SetServerCertificate(), CreateSessionAndGenerateRequest(), LoadSession(), // UpdateSession(), CloseSession(), and RemoveSession() all accept a // |promise_id|, which must be passed to the completion Host method @@ -731,8 +800,8 @@ class ContentDecryptionModule_8 { // // Returns kSuccess if the |audio_decoder_config| is supported and the CDM // audio decoder is successfully initialized. - // Returns kSessionError if |audio_decoder_config| is not supported. The CDM - // may still be able to do Decrypt(). + // Returns kInitializationError if |audio_decoder_config| is not supported. + // The CDM may still be able to do Decrypt(). // Returns kDeferredInitialization if the CDM is not ready to initialize the // decoder at this time. Must call Host::OnDeferredInitializationDone() once // initialization is complete. @@ -744,8 +813,8 @@ class ContentDecryptionModule_8 { // // Returns kSuccess if the |video_decoder_config| is supported and the CDM // video decoder is successfully initialized. - // Returns kSessionError if |video_decoder_config| is not supported. The CDM - // may still be able to do Decrypt(). + // Returns kInitializationError if |video_decoder_config| is not supported. + // The CDM may still be able to do Decrypt(). // Returns kDeferredInitialization if the CDM is not ready to initialize the // decoder at this time. Must call Host::OnDeferredInitializationDone() once // initialization is complete. @@ -815,18 +884,30 @@ class ContentDecryptionModule_8 { uint32_t link_mask, uint32_t output_protection_mask) = 0; + // Called by the host after a call to Host::RequestStorageId(). If the + // version of the storage ID requested is available, |storage_id| and + // |storage_id_size| are set appropriately. |version| will be the same as + // what was requested, unless 0 (latest) was requested, in which case + // |version| will be the actual version number for the |storage_id| returned. + // If the requested version is not available, null/zero will be provided as + // |storage_id| and |storage_id_size|, respectively, and |version| should be + // ignored. + virtual void OnStorageId(uint32_t version, + const uint8_t* storage_id, + uint32_t storage_id_size) = 0; + // Destroys the object in the same context as it was created. virtual void Destroy() = 0; protected: - ContentDecryptionModule_8() {} - virtual ~ContentDecryptionModule_8() {} + ContentDecryptionModule_9() {} + virtual ~ContentDecryptionModule_9() {} }; -typedef ContentDecryptionModule_8 ContentDecryptionModule; +typedef ContentDecryptionModule_9 ContentDecryptionModule; // Represents a buffer created by Allocator implementations. -class Buffer { +class CDM_CLASS_API Buffer { public: // Destroys the buffer in the same context as it was created. virtual void Destroy() = 0; @@ -845,9 +926,9 @@ class Buffer { void operator=(const Buffer&); }; -class Host_7 { +class CDM_CLASS_API Host_8 { public: - static const int kVersion = 7; + static const int kVersion = 8; // Returns a Buffer* containing non-zero members upon success, or NULL on // failure. The caller owns the Buffer* after this call. The buffer is not @@ -859,7 +940,7 @@ class Host_7 { // from now with |context|. virtual void SetTimer(int64_t delay_ms, void* context) = 0; - // Returns the current wall time in seconds. + // Returns the current wall time. virtual Time GetCurrentWallTime() = 0; // Called by the CDM when a session is created or loaded and the value for the @@ -917,8 +998,10 @@ class Host_7 { // session |session_id|. This can happen as the result of an Update() call // or some other event. If this happens as a result of a call to Update(), // it must be called before resolving the Update() promise. |new_expiry_time| - // can be 0 to represent "undefined". Size parameter should not include - // null termination. + // represents the time after which the key(s) in the session will no longer + // be usable for decryption. It can be 0 if no such time exists or if the + // license explicitly never expires. Size parameter should not include null + // termination. virtual void OnExpirationChange(const char* session_id, uint32_t session_id_size, Time new_expiry_time) = 0; @@ -978,13 +1061,13 @@ class Host_7 { virtual FileIO* CreateFileIO(FileIOClient* client) = 0; protected: - Host_7() {} - virtual ~Host_7() {} + Host_8() {} + virtual ~Host_8() {} }; -class Host_8 { +class CDM_CLASS_API Host_9 { public: - static const int kVersion = 8; + static const int kVersion = 9; // Returns a Buffer* containing non-zero members upon success, or NULL on // failure. The caller owns the Buffer* after this call. The buffer is not @@ -996,9 +1079,14 @@ class Host_8 { // from now with |context|. virtual void SetTimer(int64_t delay_ms, void* context) = 0; - // Returns the current wall time in seconds. + // Returns the current wall time. virtual Time GetCurrentWallTime() = 0; + // Called by the CDM when a key status is available in response to + // GetStatusForPolicy(). + virtual void OnResolveKeyStatusPromise(uint32_t promise_id, + KeyStatus key_status) = 0; + // Called by the CDM when a session is created or loaded and the value for the // MediaKeySession's sessionId attribute is available (|session_id|). // This must be called before OnSessionMessage() or @@ -1016,26 +1104,21 @@ class Host_8 { // Called by the CDM when an error occurs as a result of one of the // ContentDecryptionModule calls that accept a |promise_id|. - // |error| must be specified, |error_message| and |system_code| + // |exception| must be specified. |error_message| and |system_code| // are optional. |error_message_size| should not include null termination. virtual void OnRejectPromise(uint32_t promise_id, - Error error, + Exception exception, uint32_t system_code, const char* error_message, uint32_t error_message_size) = 0; // Called by the CDM when it has a message for session |session_id|. // Size parameters should not include null termination. - // |legacy_destination_url| is only for supporting the prefixed EME API and - // is ignored by unprefixed EME. It should only be non-null if |message_type| - // is kLicenseRenewal. virtual void OnSessionMessage(const char* session_id, uint32_t session_id_size, MessageType message_type, const char* message, - uint32_t message_size, - const char* legacy_destination_url, - uint32_t legacy_destination_url_length) = 0; + uint32_t message_size) = 0; // Called by the CDM when there has been a change in keys or their status for // session |session_id|. |has_additional_usable_key| should be set if a @@ -1054,8 +1137,10 @@ class Host_8 { // session |session_id|. This can happen as the result of an Update() call // or some other event. If this happens as a result of a call to Update(), // it must be called before resolving the Update() promise. |new_expiry_time| - // can be 0 to represent "undefined". Size parameter should not include - // null termination. + // represents the time after which the key(s) in the session will no longer + // be usable for decryption. It can be 0 if no such time exists or if the + // license explicitly never expires. Size parameter should not include null + // termination. virtual void OnExpirationChange(const char* session_id, uint32_t session_id_size, Time new_expiry_time) = 0; @@ -1065,21 +1150,6 @@ class Host_8 { virtual void OnSessionClosed(const char* session_id, uint32_t session_id_size) = 0; - // Called by the CDM when an error occurs in session |session_id| - // unrelated to one of the ContentDecryptionModule calls that accept a - // |promise_id|. |error| must be specified, |error_message| and - // |system_code| are optional. Length parameters should not include null - // termination. - // Note: - // - This method is only for supporting prefixed EME API. - // - This method will be ignored by unprefixed EME. All errors reported - // in this method should probably also be reported by one of other methods. - virtual void OnLegacySessionError( - const char* session_id, uint32_t session_id_length, - Error error, - uint32_t system_code, - const char* error_message, uint32_t error_message_length) = 0; - // The following are optional methods that may not be implemented on all // platforms. @@ -1114,13 +1184,22 @@ class Host_8 { // CDM can call this method multiple times to operate on different files. virtual FileIO* CreateFileIO(FileIOClient* client) = 0; + // Requests a specific version of the storage ID. A storage ID is a stable, + // device specific ID used by the CDM to securely store persistent data. The + // ID will be returned by the host via ContentDecryptionModule::OnStorageId(). + // If |version| is 0, the latest version will be returned. All |version|s + // that are greater than or equal to 0x80000000 are reserved for the CDM and + // should not be supported or returned by the host. The CDM must not expose + // the ID outside the client device, even in encrypted form. + virtual void RequestStorageId(uint32_t version) = 0; + protected: - Host_8() {} - virtual ~Host_8() {} + Host_9() {} + virtual ~Host_9() {} }; // Represents a decrypted block that has not been decoded. -class DecryptedBlock { +class CDM_CLASS_API DecryptedBlock { public: virtual void SetDecryptedBuffer(Buffer* buffer) = 0; virtual Buffer* DecryptedBuffer() = 0; @@ -1135,7 +1214,7 @@ class DecryptedBlock { virtual ~DecryptedBlock() {} }; -class VideoFrame { +class CDM_CLASS_API VideoFrame { public: enum VideoPlane { kYPlane = 0, @@ -1178,7 +1257,7 @@ class VideoFrame { // // |<----------------- AudioFrames ------------------>| // | audio buffer 0 | audio buffer 1 | audio buffer 2 | -class AudioFrames { +class CDM_CLASS_API AudioFrames { public: virtual void SetFrameBuffer(Buffer* buffer) = 0; virtual Buffer* FrameBuffer() = 0; diff --git a/dom/media/gmp/widevine-adapter/content_decryption_module_export.h b/dom/media/gmp/widevine-adapter/content_decryption_module_export.h new file mode 100644 index 000000000..51d485892 --- /dev/null +++ b/dom/media/gmp/widevine-adapter/content_decryption_module_export.h @@ -0,0 +1,22 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CDM_CONTENT_DECRYPTION_MODULE_EXPORT_H_ +#define CDM_CONTENT_DECRYPTION_MODULE_EXPORT_H_ + +// Define CDM_API so that functionality implemented by the CDM module +// can be exported to consumers. +#if defined(_WIN32) + +#if defined(CDM_IMPLEMENTATION) +#define CDM_API __declspec(dllexport) +#else +#define CDM_API __declspec(dllimport) +#endif // defined(CDM_IMPLEMENTATION) + +#else // defined(_WIN32) +#define CDM_API __attribute__((visibility("default"))) +#endif // defined(_WIN32) + +#endif // CDM_CONTENT_DECRYPTION_MODULE_EXPORT_H_ diff --git a/dom/media/gmp/widevine-adapter/content_decryption_module_ext.h b/dom/media/gmp/widevine-adapter/content_decryption_module_ext.h new file mode 100644 index 000000000..5df8344e6 --- /dev/null +++ b/dom/media/gmp/widevine-adapter/content_decryption_module_ext.h @@ -0,0 +1,64 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CDM_CONTENT_DECRYPTION_MODULE_EXT_H_ +#define CDM_CONTENT_DECRYPTION_MODULE_EXT_H_ + +#if defined(_WIN32) +#include <windows.h> +#endif + +#include "content_decryption_module_export.h" + +#if defined(_MSC_VER) +typedef unsigned int uint32_t; +#else +#include <stdint.h> +#endif + +namespace cdm { + +#if defined(_WIN32) +typedef wchar_t FilePathCharType; +typedef HANDLE PlatformFile; +const PlatformFile kInvalidPlatformFile = INVALID_HANDLE_VALUE; +#else +typedef char FilePathCharType; +typedef int PlatformFile; +const PlatformFile kInvalidPlatformFile = -1; +#endif // defined(_WIN32) + +struct HostFile { + HostFile(const FilePathCharType* file_path, + PlatformFile file, + PlatformFile sig_file) + : file_path(file_path), file(file), sig_file(sig_file) {} + + // File that is part of the host of the CDM. + const FilePathCharType* file_path = nullptr; + PlatformFile file = kInvalidPlatformFile; + + // Signature file for |file|. + PlatformFile sig_file = kInvalidPlatformFile; +}; + +} // namespace cdm + +extern "C" { + +// Functions in this file are dynamically retrieved by their versioned function +// names. Increment the version number for any backward incompatible API +// changes. + +// Verifies CDM host. All files in |host_files| are opened in read-only mode. +// +// Returns false and closes all files if there is an immediate failure. +// Otherwise returns true as soon as possible and processes the files +// asynchronously. All files MUST be closed by the CDM after this one-time +// processing is finished. +CDM_API bool VerifyCdmHost_0(const cdm::HostFile* host_files, + uint32_t num_files); +} + +#endif // CDM_CONTENT_DECRYPTION_MODULE_EXT_H_ diff --git a/dom/media/gtest/Cargo.toml b/dom/media/gtest/Cargo.toml deleted file mode 100644 index a55f8fb68..000000000 --- a/dom/media/gtest/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "mp4parse-gtest" -version = "0.1.0" -authors = ["nobody@mozilla.org"] - -[lib] -path = "hello.rs" diff --git a/dom/media/gtest/TestMP3Demuxer.cpp b/dom/media/gtest/TestMP3Demuxer.cpp index 8d2109f00..934acb60e 100644 --- a/dom/media/gtest/TestMP3Demuxer.cpp +++ b/dom/media/gtest/TestMP3Demuxer.cpp @@ -11,7 +11,6 @@ #include "MockMediaResource.h" using namespace mozilla; -using namespace mozilla::mp3; using media::TimeUnit; diff --git a/dom/media/gtest/TestMP4Reader.cpp b/dom/media/gtest/TestMP4Reader.cpp deleted file mode 100644 index f08f7a40d..000000000 --- a/dom/media/gtest/TestMP4Reader.cpp +++ /dev/null @@ -1,217 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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 "gtest/gtest.h" -#include "MP4Reader.h" -#include "MP4Decoder.h" -#include "mozilla/SharedThreadPool.h" -#include "MockMediaResource.h" -#include "MockMediaDecoderOwner.h" -#include "mozilla/Preferences.h" -#include "TimeUnits.h" - -using namespace mozilla; -using namespace mozilla::dom; - -class TestBinding -{ -public: - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestBinding); - - RefPtr<MP4Decoder> decoder; - RefPtr<MockMediaResource> resource; - RefPtr<MP4Reader> reader; - - explicit TestBinding(const char* aFileName = "gizmo.mp4") - : decoder(new MP4Decoder()) - , resource(new MockMediaResource(aFileName)) - , reader(new MP4Reader(decoder)) - { - EXPECT_EQ(NS_OK, Preferences::SetBool( - "media.use-blank-decoder", true)); - - EXPECT_EQ(NS_OK, resource->Open(nullptr)); - decoder->SetResource(resource); - - reader->Init(nullptr); - // This needs to be done before invoking GetBuffered. This is normally - // done by MediaDecoderStateMachine. - reader->DispatchSetStartTime(0); - } - - void Init() { - nsCOMPtr<nsIThread> thread; - nsCOMPtr<nsIRunnable> r = NewRunnableMethod(this, &TestBinding::ReadMetadata); - nsresult rv = NS_NewThread(getter_AddRefs(thread), r); - EXPECT_EQ(NS_OK, rv); - thread->Shutdown(); - } - -private: - virtual ~TestBinding() - { - { - RefPtr<TaskQueue> queue = reader->OwnerThread(); - nsCOMPtr<nsIRunnable> task = NewRunnableMethod(reader, &MP4Reader::Shutdown); - // Hackily bypass the tail dispatcher so that we can AwaitShutdownAndIdle. - // In production code we'd use BeginShutdown + promises. - queue->Dispatch(task.forget(), AbstractThread::AssertDispatchSuccess, - AbstractThread::TailDispatch); - queue->AwaitShutdownAndIdle(); - } - decoder = nullptr; - resource = nullptr; - reader = nullptr; - SharedThreadPool::SpinUntilEmpty(); - } - - void ReadMetadata() - { - MediaInfo info; - MetadataTags* tags; - EXPECT_EQ(NS_OK, reader->ReadMetadata(&info, &tags)); - } -}; - -TEST(MP4Reader, BufferedRange) -{ - RefPtr<TestBinding> b = new TestBinding(); - b->Init(); - - // Video 3-4 sec, audio 2.986666-4.010666 sec - b->resource->MockAddBufferedRange(248400, 327455); - - media::TimeIntervals ranges = b->reader->GetBuffered(); - EXPECT_EQ(1U, ranges.Length()); - EXPECT_NEAR(270000 / 90000.0, ranges.Start(0).ToSeconds(), 0.000001); - EXPECT_NEAR(360000 / 90000.0, ranges.End(0).ToSeconds(), 0.000001); -} - -TEST(MP4Reader, BufferedRangeMissingLastByte) -{ - RefPtr<TestBinding> b = new TestBinding(); - b->Init(); - - // Dropping the last byte of the video - b->resource->MockClearBufferedRanges(); - b->resource->MockAddBufferedRange(248400, 324912); - b->resource->MockAddBufferedRange(324913, 327455); - - media::TimeIntervals ranges = b->reader->GetBuffered(); - EXPECT_EQ(1U, ranges.Length()); - EXPECT_NEAR(270000.0 / 90000.0, ranges.Start(0).ToSeconds(), 0.000001); - EXPECT_NEAR(357000 / 90000.0, ranges.End(0).ToSeconds(), 0.000001); -} - -TEST(MP4Reader, BufferedRangeSyncFrame) -{ - RefPtr<TestBinding> b = new TestBinding(); - b->Init(); - - // Check that missing the first byte at 2 seconds skips right through to 3 - // seconds because of a missing sync frame - b->resource->MockClearBufferedRanges(); - b->resource->MockAddBufferedRange(146336, 327455); - - media::TimeIntervals ranges = b->reader->GetBuffered(); - EXPECT_EQ(1U, ranges.Length()); - EXPECT_NEAR(270000.0 / 90000.0, ranges.Start(0).ToSeconds(), 0.000001); - EXPECT_NEAR(360000 / 90000.0, ranges.End(0).ToSeconds(), 0.000001); -} - -TEST(MP4Reader, CompositionOrder) -{ - RefPtr<TestBinding> b = new TestBinding("mediasource_test.mp4"); - b->Init(); - - // The first 5 video samples of this file are: - // Video timescale=2500 - // Frame Start Size Time Duration Sync - // 1 48 5455 166 83 Yes - // 2 5503 145 249 83 - // 3 6228 575 581 83 - // 4 7383 235 415 83 - // 5 8779 183 332 83 - // 6 9543 191 498 83 - // - // Audio timescale=44100 - // 1 5648 580 0 1024 Yes - // 2 6803 580 1024 1058 Yes - // 3 7618 581 2082 1014 Yes - // 4 8199 580 3096 1015 Yes - // 5 8962 581 4111 1014 Yes - // 6 9734 580 5125 1014 Yes - // 7 10314 581 6139 1059 Yes - // 8 11207 580 7198 1014 Yes - // 9 12035 581 8212 1014 Yes - // 10 12616 580 9226 1015 Yes - // 11 13220 581 10241 1014 Yes - - b->resource->MockClearBufferedRanges(); - // First two frames in decoding + first audio frame - b->resource->MockAddBufferedRange(48, 5503); // Video 1 - b->resource->MockAddBufferedRange(5503, 5648); // Video 2 - b->resource->MockAddBufferedRange(6228, 6803); // Video 3 - - // Audio - 5 frames; 0 - 139206 us - b->resource->MockAddBufferedRange(5648, 6228); - b->resource->MockAddBufferedRange(6803, 7383); - b->resource->MockAddBufferedRange(7618, 8199); - b->resource->MockAddBufferedRange(8199, 8779); - b->resource->MockAddBufferedRange(8962, 9563); - b->resource->MockAddBufferedRange(9734, 10314); - b->resource->MockAddBufferedRange(10314, 10895); - b->resource->MockAddBufferedRange(11207, 11787); - b->resource->MockAddBufferedRange(12035, 12616); - b->resource->MockAddBufferedRange(12616, 13196); - b->resource->MockAddBufferedRange(13220, 13901); - - media::TimeIntervals ranges = b->reader->GetBuffered(); - EXPECT_EQ(2U, ranges.Length()); - - EXPECT_NEAR(166.0 / 2500.0, ranges.Start(0).ToSeconds(), 0.000001); - EXPECT_NEAR(332.0 / 2500.0, ranges.End(0).ToSeconds(), 0.000001); - - EXPECT_NEAR(581.0 / 2500.0, ranges.Start(1).ToSeconds(), 0.000001); - EXPECT_NEAR(11255.0 / 44100.0, ranges.End(1).ToSeconds(), 0.000001); -} - -TEST(MP4Reader, Normalised) -{ - RefPtr<TestBinding> b = new TestBinding("mediasource_test.mp4"); - b->Init(); - - // The first 5 video samples of this file are: - // Video timescale=2500 - // Frame Start Size Time Duration Sync - // 1 48 5455 166 83 Yes - // 2 5503 145 249 83 - // 3 6228 575 581 83 - // 4 7383 235 415 83 - // 5 8779 183 332 83 - // 6 9543 191 498 83 - // - // Audio timescale=44100 - // 1 5648 580 0 1024 Yes - // 2 6803 580 1024 1058 Yes - // 3 7618 581 2082 1014 Yes - // 4 8199 580 3096 1015 Yes - // 5 8962 581 4111 1014 Yes - // 6 9734 580 5125 1014 Yes - // 7 10314 581 6139 1059 Yes - // 8 11207 580 7198 1014 Yes - // 9 12035 581 8212 1014 Yes - // 10 12616 580 9226 1015 Yes - // 11 13220 581 10241 1014 Yes - - b->resource->MockClearBufferedRanges(); - b->resource->MockAddBufferedRange(48, 13901); - - media::TimeIntervals ranges = b->reader->GetBuffered(); - EXPECT_EQ(1U, ranges.Length()); - - EXPECT_NEAR(166.0 / 2500.0, ranges.Start(0).ToSeconds(), 0.000001); - EXPECT_NEAR(11255.0 / 44100.0, ranges.End(0).ToSeconds(), 0.000001); -} diff --git a/dom/media/gtest/TestRust.cpp b/dom/media/gtest/TestRust.cpp deleted file mode 100644 index 86d0e99b8..000000000 --- a/dom/media/gtest/TestRust.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include <stdint.h> -#include "gtest/gtest.h" - -extern "C" uint8_t* test_rust(); - -TEST(rust, CallFromCpp) { - auto greeting = test_rust(); - EXPECT_STREQ(reinterpret_cast<char*>(greeting), "hello from rust."); -} diff --git a/dom/media/gtest/hello.rs b/dom/media/gtest/hello.rs deleted file mode 100644 index cd111882a..000000000 --- a/dom/media/gtest/hello.rs +++ /dev/null @@ -1,6 +0,0 @@ -#[no_mangle] -pub extern fn test_rust() -> *const u8 { - // NB: rust &str aren't null terminated. - let greeting = "hello from rust.\0"; - greeting.as_ptr() -} diff --git a/dom/media/gtest/moz.build b/dom/media/gtest/moz.build index d5d02bced..a7ea73807 100644 --- a/dom/media/gtest/moz.build +++ b/dom/media/gtest/moz.build @@ -21,7 +21,6 @@ UNIFIED_SOURCES += [ 'TestMozPromise.cpp', 'TestMP3Demuxer.cpp', 'TestMP4Demuxer.cpp', - # 'TestMP4Reader.cpp', disabled so we can turn check tests back on (bug 1175752) 'TestTrackEncoder.cpp', 'TestVideoSegment.cpp', 'TestVideoUtils.cpp', diff --git a/dom/media/mediasource/MediaSource.cpp b/dom/media/mediasource/MediaSource.cpp index af541bbbb..152c0085a 100644 --- a/dom/media/mediasource/MediaSource.cpp +++ b/dom/media/mediasource/MediaSource.cpp @@ -62,8 +62,6 @@ namespace mozilla { // Returns true if we should enable MSE webm regardless of preferences. // 1. If MP4/H264 isn't supported: -// * Windows XP -// * Windows Vista and Server 2008 without the optional "Platform Update Supplement" // * N/KN editions (Europe and Korea) of Windows 7/8/8.1/10 without the // optional "Windows Media Feature Pack" // 2. If H264 hardware acceleration is not available. diff --git a/dom/media/mediasource/moz.build b/dom/media/mediasource/moz.build index 6ded1875d..a1689c216 100644 --- a/dom/media/mediasource/moz.build +++ b/dom/media/mediasource/moz.build @@ -38,9 +38,6 @@ TEST_DIRS += [ 'gtest', ] -if CONFIG['MOZ_GONK_MEDIACODEC']: - DEFINES['MOZ_GONK_MEDIACODEC'] = True - include('/ipc/chromium/chromium-config.mozbuild') FINAL_LIBRARY = 'xul' diff --git a/dom/media/moz.build b/dom/media/moz.build index 4d036a5f6..df8cb619d 100644 --- a/dom/media/moz.build +++ b/dom/media/moz.build @@ -30,6 +30,7 @@ DIRS += [ 'ipc', 'mediasink', 'mediasource', + 'mp3', 'ogg', 'platforms', 'systemservices', @@ -42,12 +43,6 @@ DIRS += [ 'standalone', ] -if CONFIG['MOZ_DIRECTSHOW']: - DIRS += ['directshow'] - -if CONFIG['MOZ_ANDROID_OMX']: - DIRS += ['android'] - if CONFIG['MOZ_FMP4']: DIRS += ['fmp4'] @@ -128,9 +123,6 @@ EXPORTS += [ 'MediaTimer.h', 'MediaTrack.h', 'MediaTrackList.h', - 'MP3Decoder.h', - 'MP3Demuxer.h', - 'MP3FrameParser.h', 'NextFrameSeekTask.h', 'nsIDocumentActivity.h', 'PrincipalChangeObserver.h', @@ -237,9 +229,6 @@ UNIFIED_SOURCES += [ 'MediaTimer.cpp', 'MediaTrack.cpp', 'MediaTrackList.cpp', - 'MP3Decoder.cpp', - 'MP3Demuxer.cpp', - 'MP3FrameParser.cpp', 'NextFrameSeekTask.cpp', 'QueueObject.cpp', 'SeekJob.cpp', @@ -294,11 +283,6 @@ LOCAL_INCLUDES += [ '/netwerk/base', ] -if CONFIG['MOZ_DIRECTSHOW']: - LOCAL_INCLUDES += [ - '/media/webrtc/trunk/webrtc/modules/video_capture/windows', - ] - if CONFIG['MOZ_WEBRTC']: LOCAL_INCLUDES += [ '/media/webrtc/signaling/src/common', diff --git a/dom/media/MP3Decoder.cpp b/dom/media/mp3/MP3Decoder.cpp index b71111e79..074a0866d 100644 --- a/dom/media/MP3Decoder.cpp +++ b/dom/media/mp3/MP3Decoder.cpp @@ -24,7 +24,7 @@ MP3Decoder::Clone(MediaDecoderOwner* aOwner) { MediaDecoderStateMachine* MP3Decoder::CreateStateMachine() { RefPtr<MediaDecoderReader> reader = - new MediaFormatReader(this, new mp3::MP3Demuxer(GetResource())); + new MediaFormatReader(this, new MP3Demuxer(GetResource())); return new MediaDecoderStateMachine(this, reader); } diff --git a/dom/media/MP3Decoder.h b/dom/media/mp3/MP3Decoder.h index 887251065..887251065 100644 --- a/dom/media/MP3Decoder.h +++ b/dom/media/mp3/MP3Decoder.h diff --git a/dom/media/MP3Demuxer.cpp b/dom/media/mp3/MP3Demuxer.cpp index 7d478a41b..5a98cabfe 100644 --- a/dom/media/MP3Demuxer.cpp +++ b/dom/media/mp3/MP3Demuxer.cpp @@ -33,7 +33,6 @@ using mozilla::media::TimeIntervals; using mp4_demuxer::ByteReader; namespace mozilla { -namespace mp3 { // MP3Demuxer @@ -1338,5 +1337,4 @@ ID3Parser::ID3Header::Update(uint8_t c) { return IsValid(mPos++); } -} // namespace mp3 } // namespace mozilla diff --git a/dom/media/MP3Demuxer.h b/dom/media/mp3/MP3Demuxer.h index 03e67b0d9..5331c4d54 100644 --- a/dom/media/MP3Demuxer.h +++ b/dom/media/mp3/MP3Demuxer.h @@ -13,7 +13,6 @@ #include <vector> namespace mozilla { -namespace mp3 { class MP3TrackDemuxer; @@ -468,7 +467,6 @@ private: UniquePtr<AudioInfo> mInfo; }; -} // namespace mp3 } // namespace mozilla #endif diff --git a/dom/media/mp3/moz.build b/dom/media/mp3/moz.build new file mode 100644 index 000000000..596d061f8 --- /dev/null +++ b/dom/media/mp3/moz.build @@ -0,0 +1,17 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +EXPORTS += [ + 'MP3Decoder.h', + 'MP3Demuxer.h', +] + +UNIFIED_SOURCES += [ + 'MP3Decoder.cpp', + 'MP3Demuxer.cpp', +] + +FINAL_LIBRARY = 'xul' diff --git a/dom/media/ogg/OggDemuxer.cpp b/dom/media/ogg/OggDemuxer.cpp index 591a5248f..0cc484687 100644 --- a/dom/media/ogg/OggDemuxer.cpp +++ b/dom/media/ogg/OggDemuxer.cpp @@ -12,7 +12,6 @@ #include "mozilla/Atomics.h" #include "mozilla/PodOperations.h" #include "mozilla/SharedThreadPool.h" -#include "mozilla/Telemetry.h" #include "mozilla/TimeStamp.h" #include "MediaDataDemuxer.h" #include "nsAutoRef.h" @@ -164,7 +163,6 @@ OggDemuxer::~OggDemuxer() MOZ_LOG(gMediaDemuxerLog, mozilla::LogLevel::Debug, ("OggDemuxer(%p)::%s: Reporting telemetry MEDIA_OGG_LOADED_IS_CHAINED=%d", ptr, __func__, isChained)); - Telemetry::Accumulate(Telemetry::ID::MEDIA_OGG_LOADED_IS_CHAINED, isChained); }); AbstractThread::MainThread()->Dispatch(task.forget()); } diff --git a/dom/media/platforms/MediaTelemetryConstants.h b/dom/media/platforms/MediaTelemetryConstants.h deleted file mode 100644 index 5024949a8..000000000 --- a/dom/media/platforms/MediaTelemetryConstants.h +++ /dev/null @@ -1,22 +0,0 @@ -/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * - * 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/. */ -#ifndef dom_media_platforms_MediaTelemetryConstants_h___ -#define dom_media_platforms_MediaTelemetryConstants_h___ - -namespace mozilla { -namespace media { - -enum class MediaDecoderBackend : uint32_t -{ - WMFSoftware = 0, - WMFDXVA2D3D9 = 1, - WMFDXVA2D3D11 = 2 -}; - -} // namespace media -} // namespace mozilla - -#endif // dom_media_platforms_MediaTelemetryConstants_h___ diff --git a/dom/media/platforms/PDMFactory.cpp b/dom/media/platforms/PDMFactory.cpp index c1e58fdc2..5bfdcffb7 100644 --- a/dom/media/platforms/PDMFactory.cpp +++ b/dom/media/platforms/PDMFactory.cpp @@ -19,9 +19,6 @@ #ifdef MOZ_APPLEMEDIA #include "AppleDecoderModule.h" #endif -#ifdef MOZ_GONK_MEDIACODEC -#include "GonkDecoderModule.h" -#endif #ifdef MOZ_WIDGET_ANDROID #include "AndroidDecoderModule.h" #endif @@ -390,12 +387,6 @@ PDMFactory::CreatePDMs() m = new AppleDecoderModule(); StartupPDM(m); #endif -#ifdef MOZ_GONK_MEDIACODEC - if (MediaPrefs::PDMGonkDecoderEnabled()) { - m = new GonkDecoderModule(); - StartupPDM(m); - } -#endif #ifdef MOZ_WIDGET_ANDROID if(MediaPrefs::PDMAndroidMediaCodecEnabled()){ m = new AndroidDecoderModule(); diff --git a/dom/media/platforms/agnostic/AOMDecoder.cpp b/dom/media/platforms/agnostic/AOMDecoder.cpp new file mode 100644 index 000000000..b5d21375e --- /dev/null +++ b/dom/media/platforms/agnostic/AOMDecoder.cpp @@ -0,0 +1,332 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* 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 "AOMDecoder.h" +#include "MediaResult.h" +#include "TimeUnits.h" +#include "aom/aomdx.h" +#include "aom/aom_image.h" +#include "gfx2DGlue.h" +#include "mozilla/PodOperations.h" +#include "mozilla/SyncRunnable.h" +#include "nsError.h" +#include "prsystem.h" + +#include <algorithm> + +#undef LOG +#define LOG(arg, ...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, ("AOMDecoder(%p)::%s: " arg, this, __func__, ##__VA_ARGS__)) + +namespace mozilla { + +using namespace gfx; +using namespace layers; + +AOMDecoder::AOMDecoder(const CreateDecoderParams& aParams) + : mImageContainer(aParams.mImageContainer) + , mTaskQueue(aParams.mTaskQueue) + , mCallback(aParams.mCallback) + , mIsFlushing(false) + , mInfo(aParams.VideoConfig()) +{ + PodZero(&mCodec); +} + +AOMDecoder::~AOMDecoder() +{ +} + +void +AOMDecoder::Shutdown() +{ + aom_codec_destroy(&mCodec); +} + +RefPtr<MediaDataDecoder::InitPromise> +AOMDecoder::Init() +{ + int decode_threads = 2; + + aom_codec_iface_t* dx = aom_codec_av1_dx(); + if (mInfo.mDisplay.width >= 2048) { + decode_threads = 8; + } + else if (mInfo.mDisplay.width >= 1024) { + decode_threads = 4; + } + decode_threads = std::min(decode_threads, PR_GetNumberOfProcessors()); + + aom_codec_dec_cfg_t config; + PodZero(&config); + config.threads = decode_threads; + config.w = config.h = 0; // set after decode + config.allow_lowbitdepth = true; + + aom_codec_flags_t flags = 0; + + if (!dx || aom_codec_dec_init(&mCodec, dx, &config, flags)) { + return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__); + } + return InitPromise::CreateAndResolve(TrackInfo::kVideoTrack, __func__); +} + +void +AOMDecoder::Flush() +{ + MOZ_ASSERT(mCallback->OnReaderTaskQueue()); + mIsFlushing = true; + nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([this] () { + // nothing to do for now. + }); + SyncRunnable::DispatchToThread(mTaskQueue, r); + mIsFlushing = false; +} + +// Ported from third_party/aom/tools_common.c. +static aom_codec_err_t +highbd_img_downshift(aom_image_t *dst, aom_image_t *src, int down_shift) { + int plane; + if (dst->d_w != src->d_w || dst->d_h != src->d_h) + return AOM_CODEC_INVALID_PARAM; + if (dst->x_chroma_shift != src->x_chroma_shift) + return AOM_CODEC_INVALID_PARAM; + if (dst->y_chroma_shift != src->y_chroma_shift) + return AOM_CODEC_INVALID_PARAM; + if (dst->fmt != (src->fmt & ~AOM_IMG_FMT_HIGHBITDEPTH)) + return AOM_CODEC_INVALID_PARAM; + if (down_shift < 0) + return AOM_CODEC_INVALID_PARAM; + switch (dst->fmt) { + case AOM_IMG_FMT_I420: + case AOM_IMG_FMT_I422: + case AOM_IMG_FMT_I444: + break; + default: + return AOM_CODEC_INVALID_PARAM; + } + switch (src->fmt) { + case AOM_IMG_FMT_I42016: + case AOM_IMG_FMT_I42216: + case AOM_IMG_FMT_I44416: + break; + default: + // We don't support anything that's not 16 bit + return AOM_CODEC_UNSUP_BITSTREAM; + } + for (plane = 0; plane < 3; plane++) { + int w = src->d_w; + int h = src->d_h; + int x, y; + if (plane) { + w = (w + src->x_chroma_shift) >> src->x_chroma_shift; + h = (h + src->y_chroma_shift) >> src->y_chroma_shift; + } + for (y = 0; y < h; y++) { + uint16_t *p_src = + (uint16_t *)(src->planes[plane] + y * src->stride[plane]); + uint8_t *p_dst = + dst->planes[plane] + y * dst->stride[plane]; + for (x = 0; x < w; x++) *p_dst++ = (*p_src++ >> down_shift) & 0xFF; + } + } + return AOM_CODEC_OK; +} + +// UniquePtr dtor wrapper for aom_image_t. +struct AomImageFree { + void operator()(aom_image_t* img) { aom_img_free(img); } +}; + +MediaResult +AOMDecoder::DoDecode(MediaRawData* aSample) +{ + MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); + +#if defined(DEBUG) + NS_ASSERTION(IsKeyframe(*aSample) == aSample->mKeyframe, + "AOM Decode Keyframe error sample->mKeyframe and si.si_kf out of sync"); +#endif + + if (aom_codec_err_t r = aom_codec_decode(&mCodec, aSample->Data(), aSample->Size(), nullptr)) { + LOG("AOM Decode error: %s", aom_codec_err_to_string(r)); + return MediaResult( + NS_ERROR_DOM_MEDIA_DECODE_ERR, + RESULT_DETAIL("AOM error decoding AV1 sample: %s", aom_codec_err_to_string(r))); + } + + aom_codec_iter_t iter = nullptr; + aom_image_t *img; + UniquePtr<aom_image_t, AomImageFree> img8; + + while ((img = aom_codec_get_frame(&mCodec, &iter))) { + // Track whether the underlying buffer is 8 or 16 bits per channel. + bool highbd = bool(img->fmt & AOM_IMG_FMT_HIGHBITDEPTH); + if (highbd) { + // Downsample images with more than 8 bits per channel. + aom_img_fmt_t fmt8 = static_cast<aom_img_fmt_t>(img->fmt ^ AOM_IMG_FMT_HIGHBITDEPTH); + img8.reset(aom_img_alloc(NULL, fmt8, img->d_w, img->d_h, 16)); + if (img8 == nullptr) { + LOG("Couldn't allocate bitdepth reduction target!"); + return MediaResult( + NS_ERROR_OUT_OF_MEMORY, + RESULT_DETAIL("Couldn't allocate conversion buffer for AV1 frame")); + } + if (aom_codec_err_t r = highbd_img_downshift(img8.get(), img, img->bit_depth - 8)) { + return MediaResult( + NS_ERROR_DOM_MEDIA_DECODE_ERR, + RESULT_DETAIL("Error converting AV1 frame to 8 bits: %s", + aom_codec_err_to_string(r))); + } + // img normally points to storage owned by mCodec, so it is not freed. + // To copy out the contents of img8 we can overwrite img with an alias. + // Since img is assigned at the start of the while loop and img8 is held + // outside that loop, the alias won't outlive the storage it points to. + img = img8.get(); + highbd = false; + } + + NS_ASSERTION(img->fmt == AOM_IMG_FMT_I420 || + img->fmt == AOM_IMG_FMT_I42016 || + img->fmt == AOM_IMG_FMT_I444 || + img->fmt == AOM_IMG_FMT_I44416, + "AV1 image format not I420 or I444"); + + // Chroma shifts are rounded down as per the decoding examples in the SDK + VideoData::YCbCrBuffer b; + b.mPlanes[0].mData = img->planes[0]; + b.mPlanes[0].mStride = img->stride[0]; + b.mPlanes[0].mHeight = img->d_h; + b.mPlanes[0].mWidth = img->d_w; + b.mPlanes[0].mOffset = 0; + b.mPlanes[0].mSkip = highbd ? 1 : 0; + + b.mPlanes[1].mData = img->planes[1]; + b.mPlanes[1].mStride = img->stride[1]; + b.mPlanes[1].mOffset = 0; + b.mPlanes[1].mSkip = highbd ? 1 : 0; + + b.mPlanes[2].mData = img->planes[2]; + b.mPlanes[2].mStride = img->stride[2]; + b.mPlanes[2].mOffset = 0; + b.mPlanes[2].mSkip = highbd ? 1 : 0; + + if (img->fmt == AOM_IMG_FMT_I420 || + img->fmt == AOM_IMG_FMT_I42016) { + b.mPlanes[1].mHeight = (img->d_h + 1) >> img->y_chroma_shift; + b.mPlanes[1].mWidth = (img->d_w + 1) >> img->x_chroma_shift; + + b.mPlanes[2].mHeight = (img->d_h + 1) >> img->y_chroma_shift; + b.mPlanes[2].mWidth = (img->d_w + 1) >> img->x_chroma_shift; + } else if (img->fmt == AOM_IMG_FMT_I444) { + b.mPlanes[1].mHeight = img->d_h; + b.mPlanes[1].mWidth = img->d_w; + + b.mPlanes[2].mHeight = img->d_h; + b.mPlanes[2].mWidth = img->d_w; + } else { + LOG("AOM Unknown image format"); + return MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR, + RESULT_DETAIL("AOM Unknown image format")); + } + + RefPtr<VideoData> v = + VideoData::CreateAndCopyData(mInfo, + mImageContainer, + aSample->mOffset, + aSample->mTime, + aSample->mDuration, + b, + aSample->mKeyframe, + aSample->mTimecode, + mInfo.ScaledImageRect(img->d_w, + img->d_h)); + + if (!v) { + LOG("Image allocation error source %ux%u display %ux%u picture %ux%u", + img->d_w, img->d_h, mInfo.mDisplay.width, mInfo.mDisplay.height, + mInfo.mImage.width, mInfo.mImage.height); + return MediaResult(NS_ERROR_OUT_OF_MEMORY, __func__); + } + mCallback->Output(v); + } + return NS_OK; +} + +void +AOMDecoder::ProcessDecode(MediaRawData* aSample) +{ + MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); + if (mIsFlushing) { + return; + } + MediaResult rv = DoDecode(aSample); + if (NS_FAILED(rv)) { + mCallback->Error(rv); + } else { + mCallback->InputExhausted(); + } +} + +void +AOMDecoder::Input(MediaRawData* aSample) +{ + MOZ_ASSERT(mCallback->OnReaderTaskQueue()); + mTaskQueue->Dispatch(NewRunnableMethod<RefPtr<MediaRawData>>( + this, &AOMDecoder::ProcessDecode, aSample)); +} + +void +AOMDecoder::ProcessDrain() +{ + MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); + mCallback->DrainComplete(); +} + +void +AOMDecoder::Drain() +{ + MOZ_ASSERT(mCallback->OnReaderTaskQueue()); + mTaskQueue->Dispatch(NewRunnableMethod(this, &AOMDecoder::ProcessDrain)); +} + +/* static */ +bool +AOMDecoder::IsAV1(const nsACString& aMimeType) +{ + return aMimeType.EqualsLiteral("video/webm; codecs=av1") || + aMimeType.EqualsLiteral("video/av1"); +} + +/* static */ +bool +AOMDecoder::IsKeyframe(Span<const uint8_t> aBuffer) { + aom_codec_stream_info_t info; + PodZero(&info); + + aom_codec_peek_stream_info(aom_codec_av1_dx(), + aBuffer.Elements(), + aBuffer.Length(), + &info); + + return bool(info.is_kf); +} + +/* static */ +nsIntSize +AOMDecoder::GetFrameSize(Span<const uint8_t> aBuffer) { + aom_codec_stream_info_t info; + PodZero(&info); + + aom_codec_peek_stream_info(aom_codec_av1_dx(), + aBuffer.Elements(), + aBuffer.Length(), + &info); + + return nsIntSize(info.w, info.h); +} + +} // namespace mozilla +#undef LOG diff --git a/dom/media/platforms/agnostic/AOMDecoder.h b/dom/media/platforms/agnostic/AOMDecoder.h new file mode 100644 index 000000000..ec6b1f95a --- /dev/null +++ b/dom/media/platforms/agnostic/AOMDecoder.h @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* 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/. */ + +#if !defined(AOMDecoder_h_) +#define AOMDecoder_h_ + +#include "PlatformDecoderModule.h" +#include "mozilla/Span.h" + +#include <stdint.h> +#include "aom/aom_decoder.h" + +namespace mozilla { + +class AOMDecoder : public MediaDataDecoder +{ +public: + explicit AOMDecoder(const CreateDecoderParams& aParams); + + RefPtr<InitPromise> Init() override; + void Input(MediaRawData* aSample) override; + void Flush() override; + void Drain() override; + void Shutdown() override; + const char* GetDescriptionName() const override + { + return "libaom (AV1) video decoder"; + } + + // Return true if aMimeType is a one of the strings used + // by our demuxers to identify AV1 streams. + static bool IsAV1(const nsACString& aMimeType); + + // Return true if a sample is a keyframe. + static bool IsKeyframe(Span<const uint8_t> aBuffer); + + // Return the frame dimensions for a sample. + static nsIntSize GetFrameSize(Span<const uint8_t> aBuffer); + +private: + ~AOMDecoder(); + void ProcessDecode(MediaRawData* aSample); + MediaResult DoDecode(MediaRawData* aSample); + void ProcessDrain(); + + const RefPtr<layers::ImageContainer> mImageContainer; + const RefPtr<TaskQueue> mTaskQueue; + MediaDataDecoderCallback* mCallback; + Atomic<bool> mIsFlushing; + + // AOM decoder state + aom_codec_ctx_t mCodec; + + const VideoInfo& mInfo; +}; + +} // namespace mozilla + +#endif // AOMDecoder_h_ diff --git a/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp b/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp index 7bd75b7fe..cf5ed3d22 100644 --- a/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp +++ b/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp @@ -5,6 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "AgnosticDecoderModule.h" +#include "MediaPrefs.h" #include "mozilla/Logging.h" #include "OpusDecoder.h" #include "VorbisDecoder.h" @@ -12,6 +13,10 @@ #include "WAVDecoder.h" #include "TheoraDecoder.h" +#ifdef MOZ_AV1 +#include "AOMDecoder.h" +#endif + namespace mozilla { bool @@ -24,6 +29,11 @@ AgnosticDecoderModule::SupportsMimeType(const nsACString& aMimeType, VorbisDataDecoder::IsVorbis(aMimeType) || WaveDataDecoder::IsWave(aMimeType) || TheoraDecoder::IsTheora(aMimeType); +#ifdef MOZ_AV1 + if (MediaPrefs::AV1Enabled()) { + supports |= AOMDecoder::IsAV1(aMimeType); + } +#endif MOZ_LOG(sPDMLog, LogLevel::Debug, ("Agnostic decoder %s requested type", supports ? "supports" : "rejects")); return supports; @@ -36,7 +46,14 @@ AgnosticDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams) if (VPXDecoder::IsVPX(aParams.mConfig.mMimeType)) { m = new VPXDecoder(aParams); - } else if (TheoraDecoder::IsTheora(aParams.mConfig.mMimeType)) { + } +#ifdef MOZ_AV1 + else if (AOMDecoder::IsAV1(aParams.mConfig.mMimeType) && + MediaPrefs::AV1Enabled()) { + m = new AOMDecoder(aParams); + } +#endif + else if (TheoraDecoder::IsTheora(aParams.mConfig.mMimeType)) { m = new TheoraDecoder(aParams); } diff --git a/dom/media/platforms/agnostic/VPXDecoder.cpp b/dom/media/platforms/agnostic/VPXDecoder.cpp index 77c81b51b..f2f84487f 100644 --- a/dom/media/platforms/agnostic/VPXDecoder.cpp +++ b/dom/media/platforms/agnostic/VPXDecoder.cpp @@ -22,7 +22,7 @@ namespace mozilla { using namespace gfx; using namespace layers; -static int MimeTypeToCodec(const nsACString& aMimeType) +static VPXDecoder::Codec MimeTypeToCodec(const nsACString& aMimeType) { if (aMimeType.EqualsLiteral("video/webm; codecs=vp8")) { return VPXDecoder::Codec::VP8; @@ -31,7 +31,7 @@ static int MimeTypeToCodec(const nsACString& aMimeType) } else if (aMimeType.EqualsLiteral("video/vp9")) { return VPXDecoder::Codec::VP9; } - return -1; + return VPXDecoder::Codec::Unknown; } VPXDecoder::VPXDecoder(const CreateDecoderParams& aParams) @@ -101,17 +101,10 @@ MediaResult VPXDecoder::DoDecode(MediaRawData* aSample) { MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); + #if defined(DEBUG) - vpx_codec_stream_info_t si; - PodZero(&si); - si.sz = sizeof(si); - if (mCodec == Codec::VP8) { - vpx_codec_peek_stream_info(vpx_codec_vp8_dx(), aSample->Data(), aSample->Size(), &si); - } else if (mCodec == Codec::VP9) { - vpx_codec_peek_stream_info(vpx_codec_vp9_dx(), aSample->Data(), aSample->Size(), &si); - } - NS_ASSERTION(bool(si.is_kf) == aSample->mKeyframe, - "VPX Decode Keyframe error sample->mKeyframe and si.si_kf out of sync"); + NS_ASSERTION(IsKeyframe(*aSample, mCodec) == aSample->mKeyframe, + "VPX Decode Keyframe error sample->mKeyframe and sample data out of sync"); #endif if (vpx_codec_err_t r = vpx_codec_decode(&mVPX, aSample->Data(), aSample->Size(), nullptr, 0)) { @@ -249,5 +242,41 @@ VPXDecoder::IsVP9(const nsACString& aMimeType) return IsVPX(aMimeType, VPXDecoder::VP9); } +/* static */ +bool +VPXDecoder::IsKeyframe(Span<const uint8_t> aBuffer, Codec aCodec) +{ + vpx_codec_stream_info_t si; + PodZero(&si); + si.sz = sizeof(si); + + if (aCodec == Codec::VP8) { + vpx_codec_peek_stream_info(vpx_codec_vp8_dx(), aBuffer.Elements(), aBuffer.Length(), &si); + return bool(si.is_kf); + } else if (aCodec == Codec::VP9) { + vpx_codec_peek_stream_info(vpx_codec_vp9_dx(), aBuffer.Elements(), aBuffer.Length(), &si); + return bool(si.is_kf); + } + + return false; +} + +/* static */ +nsIntSize +VPXDecoder::GetFrameSize(Span<const uint8_t> aBuffer, Codec aCodec) +{ + vpx_codec_stream_info_t si; + PodZero(&si); + si.sz = sizeof(si); + + if (aCodec == Codec::VP8) { + vpx_codec_peek_stream_info(vpx_codec_vp8_dx(), aBuffer.Elements(), aBuffer.Length(), &si); + } else if (aCodec == Codec::VP9) { + vpx_codec_peek_stream_info(vpx_codec_vp9_dx(), aBuffer.Elements(), aBuffer.Length(), &si); + } + + return nsIntSize(si.w, si.h); +} + } // namespace mozilla #undef LOG diff --git a/dom/media/platforms/agnostic/VPXDecoder.h b/dom/media/platforms/agnostic/VPXDecoder.h index d420ec069..4e8d83617 100644 --- a/dom/media/platforms/agnostic/VPXDecoder.h +++ b/dom/media/platforms/agnostic/VPXDecoder.h @@ -7,6 +7,7 @@ #define VPXDecoder_h_ #include "PlatformDecoderModule.h" +#include "mozilla/Span.h" #include <stdint.h> #define VPX_DONT_DEFINE_STDINT_TYPES @@ -36,7 +37,8 @@ public: enum Codec: uint8_t { VP8 = 1 << 0, - VP9 = 1 << 1 + VP9 = 1 << 1, + Unknown = 1 << 7, }; // Return true if aMimeType is a one of the strings used by our demuxers to @@ -46,6 +48,12 @@ public: static bool IsVP8(const nsACString& aMimeType); static bool IsVP9(const nsACString& aMimeType); + // Return true if a sample is a keyframe for the specified codec. + static bool IsKeyframe(Span<const uint8_t> aBuffer, Codec aCodec); + + // Return the frame dimensions for a sample for the specified codec. + static nsIntSize GetFrameSize(Span<const uint8_t> aBuffer, Codec aCodec); + private: void ProcessDecode(MediaRawData* aSample); MediaResult DoDecode(MediaRawData* aSample); @@ -61,7 +69,7 @@ private: const VideoInfo& mInfo; - const int mCodec; + const Codec mCodec; }; } // namespace mozilla diff --git a/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp b/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp index 8cb5c8578..8655ce25f 100644 --- a/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp +++ b/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp @@ -69,12 +69,21 @@ FFmpegDataDecoder<LIBAV_VER>::InitDecoder() mCodecContext->extradata_size = mExtraData->Length(); // FFmpeg may use SIMD instructions to access the data which reads the // data in 32 bytes block. Must ensure we have enough data to read. + uint32_t padding_size = #if LIBAVCODEC_VERSION_MAJOR >= 58 - mExtraData->AppendElements(AV_INPUT_BUFFER_PADDING_SIZE); + AV_INPUT_BUFFER_PADDING_SIZE; #else - mExtraData->AppendElements(FF_INPUT_BUFFER_PADDING_SIZE); + FF_INPUT_BUFFER_PADDING_SIZE; #endif - mCodecContext->extradata = mExtraData->Elements(); + mCodecContext->extradata = static_cast<uint8_t*>( + mLib->av_malloc(mExtraData->Length() + padding_size)); + if (!mCodecContext->extradata) { + return MediaResult(NS_ERROR_OUT_OF_MEMORY, + RESULT_DETAIL("Couldn't init ffmpeg extradata")); + } + memcpy(mCodecContext->extradata, + mExtraData->Elements(), + mExtraData->Length()); } else { mCodecContext->extradata_size = 0; } @@ -165,6 +174,9 @@ FFmpegDataDecoder<LIBAV_VER>::ProcessShutdown() StaticMutexAutoLock mon(sMonitor); if (mCodecContext) { + if (mCodecContext->extradata) { + mLib->av_freep(&mCodecContext->extradata); + } mLib->avcodec_close(mCodecContext); mLib->av_freep(&mCodecContext); #if LIBAVCODEC_VERSION_MAJOR >= 55 diff --git a/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp b/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp index 6302882a6..426e9f74b 100644 --- a/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp +++ b/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp @@ -7,6 +7,7 @@ #include "MediaPrefs.h" #include "mozilla/PodOperations.h" #include "mozilla/Types.h" +#include "PlatformDecoderModule.h" #include "prlink.h" #define AV_LOG_DEBUG 48 @@ -144,6 +145,8 @@ FFmpegLibWrapper::Link() AV_FUNC(avcodec_alloc_frame, (AV_FUNC_53 | AV_FUNC_54)) AV_FUNC(avcodec_get_frame_defaults, (AV_FUNC_53 | AV_FUNC_54)) AV_FUNC(avcodec_free_frame, AV_FUNC_54) + AV_FUNC(avcodec_send_packet, AV_FUNC_58) + AV_FUNC(avcodec_receive_frame, AV_FUNC_58) AV_FUNC(av_log_set_level, AV_FUNC_AVUTIL_ALL) AV_FUNC(av_malloc, AV_FUNC_AVUTIL_ALL) AV_FUNC(av_freep, AV_FUNC_AVUTIL_ALL) diff --git a/dom/media/platforms/ffmpeg/FFmpegLibWrapper.h b/dom/media/platforms/ffmpeg/FFmpegLibWrapper.h index d6944a1d8..b968edd32 100644 --- a/dom/media/platforms/ffmpeg/FFmpegLibWrapper.h +++ b/dom/media/platforms/ffmpeg/FFmpegLibWrapper.h @@ -5,6 +5,7 @@ #ifndef __FFmpegLibWrapper_h__ #define __FFmpegLibWrapper_h__ +#include "mozilla/Attributes.h" #include "mozilla/Types.h" struct AVCodec; @@ -70,6 +71,10 @@ struct FFmpegLibWrapper // libavcodec v54 only void (*avcodec_free_frame)(AVFrame** frame); + // libavcodec v58 and later only + int (*avcodec_send_packet)(AVCodecContext* avctx, const AVPacket* avpkt); + int (*avcodec_receive_frame)(AVCodecContext* avctx, AVFrame* frame); + // libavutil void (*av_log_set_level)(int level); void* (*av_malloc)(size_t size); @@ -91,4 +96,4 @@ private: } // namespace mozilla -#endif // FFmpegLibWrapper
\ No newline at end of file +#endif // FFmpegLibWrapper diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp index aec1e9136..f3101e44c 100644 --- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp +++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp @@ -174,12 +174,15 @@ FFmpegVideoDecoder<LIBAV_VER>::DoDecode(MediaRawData* aSample, bool* aGotFrame) uint8_t* inputData = const_cast<uint8_t*>(aSample->Data()); size_t inputSize = aSample->Size(); -#if LIBAVCODEC_VERSION_MAJOR >= 54 +#if LIBAVCODEC_VERSION_MAJOR >= 54 && LIBAVCODEC_VERSION_MAJOR < 58 if (inputSize && mCodecParser && (mCodecID == AV_CODEC_ID_VP8 -#if LIBAVCODEC_VERSION_MAJOR >= 55 +#if LIBAVCODEC_VERSION_MAJOR >= 55 && LIBAVCODEC_VERSION_MAJOR < 58 || mCodecID == AV_CODEC_ID_VP9 #endif - )) { + )) +#endif +#if LIBAVCODEC_VERSION_MAJOR >= 54 + { while (inputSize) { uint8_t* data = inputData; int size = inputSize; @@ -224,6 +227,48 @@ FFmpegVideoDecoder<LIBAV_VER>::DoDecode(MediaRawData* aSample, packet.flags = aSample->mKeyframe ? AV_PKT_FLAG_KEY : 0; packet.pos = aSample->mOffset; +#if LIBAVCODEC_VERSION_MAJOR >= 58 + packet.duration = aSample->mDuration; + int res = mLib->avcodec_send_packet(mCodecContext, &packet); + if (res < 0) { + // In theory, avcodec_send_packet could sent -EAGAIN should its internal + // buffers be full. In practice this can't happen as we only feed one frame + // at a time, and we immediately call avcodec_receive_frame right after. + FFMPEG_LOG("avcodec_send_packet error: %d", res); + return MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR, + RESULT_DETAIL("avcodec_send_packet error: %d", res)); + } + + if (aGotFrame) { + *aGotFrame = false; + } + do { + if (!PrepareFrame()) { + NS_WARNING("FFmpeg h264 decoder failed to allocate frame."); + return MediaResult(NS_ERROR_OUT_OF_MEMORY, __func__); + } + res = mLib->avcodec_receive_frame(mCodecContext, mFrame); + if (res == int(AVERROR_EOF)) { + return NS_ERROR_DOM_MEDIA_END_OF_STREAM; + } + if (res == AVERROR(EAGAIN)) { + return NS_OK; + } + if (res < 0) { + FFMPEG_LOG("avcodec_receive_frame error: %d", res); + return MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR, + RESULT_DETAIL("avcodec_receive_frame error: %d", res)); + } + MediaResult rv = CreateImage(mFrame->pkt_pos, mFrame->pkt_pts, + mFrame->pkt_duration); + if (NS_FAILED(rv)) { + return rv; + } + if (aGotFrame) { + *aGotFrame = true; + } + } while (true); +#else // LibAV provides no API to retrieve the decoded sample's duration. // (FFmpeg >= 1.0 provides av_frame_get_pkt_duration) // As such we instead use a map using the dts as key that we will retrieve @@ -276,8 +321,21 @@ FFmpegVideoDecoder<LIBAV_VER>::DoDecode(MediaRawData* aSample, // against the map becoming extremely big. mDurationMap.Clear(); } + + MediaResult rv = CreateImage(aSample->mOffset, pts, duration); + if (NS_SUCCEEDED(rv) && aGotFrame) { + *aGotFrame = true; + } + return rv; +#endif +} + +MediaResult +FFmpegVideoDecoder<LIBAV_VER>::CreateImage(int64_t aOffset, int64_t aPts, + int64_t aDuration) +{ FFMPEG_LOG("Got one frame output with pts=%lld dts=%lld duration=%lld opaque=%lld", - pts, mFrame->pkt_dts, duration, mCodecContext->reordered_opaque); + aPts, mFrame->pkt_dts, aDuration, mCodecContext->reordered_opaque); VideoData::YCbCrBuffer b; b.mPlanes[0].mData = mFrame->data[0]; @@ -317,9 +375,9 @@ FFmpegVideoDecoder<LIBAV_VER>::DoDecode(MediaRawData* aSample, RefPtr<VideoData> v = VideoData::CreateAndCopyData(mInfo, mImageContainer, - aSample->mOffset, - pts, - duration, + aOffset, + aPts, + aDuration, b, !!mFrame->key_frame, -1, @@ -331,9 +389,6 @@ FFmpegVideoDecoder<LIBAV_VER>::DoDecode(MediaRawData* aSample, RESULT_DETAIL("image allocation error")); } mCallback->Output(v); - if (aGotFrame) { - *aGotFrame = true; - } return NS_OK; } diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h index 786df0da1..49a55e8a6 100644 --- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h +++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h @@ -49,6 +49,7 @@ private: MediaResult DoDecode(MediaRawData* aSample) override; MediaResult DoDecode(MediaRawData* aSample, bool* aGotFrame); MediaResult DoDecode(MediaRawData* aSample, uint8_t* aData, int aSize, bool* aGotFrame); + MediaResult CreateImage(int64_t aOffset, int64_t aPts, int64_t aDuration); void ProcessDrain() override; void ProcessFlush() override; void OutputDelayedFrames(); diff --git a/dom/media/platforms/ffmpeg/ffvpx/moz.build b/dom/media/platforms/ffmpeg/ffvpx/moz.build index aee58b5b0..c0041a4d4 100644 --- a/dom/media/platforms/ffmpeg/ffvpx/moz.build +++ b/dom/media/platforms/ffmpeg/ffvpx/moz.build @@ -20,7 +20,7 @@ SOURCES += [ ] LOCAL_INCLUDES += [ '..', - '../ffmpeg57/include', + '../ffmpeg58/include', ] if CONFIG['OS_ARCH'] == 'WINNT': diff --git a/dom/media/platforms/moz.build b/dom/media/platforms/moz.build index 3fb0cc842..f5fb72c5d 100644 --- a/dom/media/platforms/moz.build +++ b/dom/media/platforms/moz.build @@ -10,7 +10,6 @@ EXPORTS += [ 'agnostic/TheoraDecoder.h', 'agnostic/VorbisDecoder.h', 'agnostic/VPXDecoder.h', - 'MediaTelemetryConstants.h', 'PDMFactory.h', 'PlatformDecoderModule.h', 'wrappers/FuzzingWrapper.h', @@ -55,6 +54,14 @@ if CONFIG['MOZ_FFMPEG']: 'ffmpeg', ] +if CONFIG['MOZ_AV1']: + EXPORTS += [ + 'agnostic/AOMDecoder.h', + ] + UNIFIED_SOURCES += [ + 'agnostic/AOMDecoder.cpp', + ] + if CONFIG['MOZ_APPLEMEDIA']: EXPORTS += [ 'apple/AppleDecoderModule.h', diff --git a/dom/media/platforms/omx/OmxPlatformLayer.cpp b/dom/media/platforms/omx/OmxPlatformLayer.cpp index 039b4a22f..15b3062a4 100644 --- a/dom/media/platforms/omx/OmxPlatformLayer.cpp +++ b/dom/media/platforms/omx/OmxPlatformLayer.cpp @@ -282,26 +282,7 @@ OmxPlatformLayer::CompressionFormat() } } -// Implementations for different platforms will be defined in their own files. -#ifdef OMX_PLATFORM_GONK - -bool -OmxPlatformLayer::SupportsMimeType(const nsACString& aMimeType) -{ - return GonkOmxPlatformLayer::FindComponents(aMimeType); -} - -OmxPlatformLayer* -OmxPlatformLayer::Create(OmxDataDecoder* aDataDecoder, - OmxPromiseLayer* aPromiseLayer, - TaskQueue* aTaskQueue, - layers::ImageContainer* aImageContainer) -{ - return new GonkOmxPlatformLayer(aDataDecoder, aPromiseLayer, aTaskQueue, aImageContainer); -} - -#else // For platforms without OMX IL support. - +// For platforms without OMX IL support. bool OmxPlatformLayer::SupportsMimeType(const nsACString& aMimeType) { @@ -317,6 +298,4 @@ OmxPlatformLayer::Create(OmxDataDecoder* aDataDecoder, return nullptr; } -#endif - } diff --git a/dom/media/platforms/wmf/DXVA2Manager.cpp b/dom/media/platforms/wmf/DXVA2Manager.cpp index 0c1734c54..69e002f7f 100644 --- a/dom/media/platforms/wmf/DXVA2Manager.cpp +++ b/dom/media/platforms/wmf/DXVA2Manager.cpp @@ -14,8 +14,6 @@ #include "mozilla/layers/D3D11ShareHandleImage.h" #include "mozilla/layers/ImageBridgeChild.h" #include "mozilla/layers/TextureForwarder.h" -#include "mozilla/Telemetry.h" -#include "MediaTelemetryConstants.h" #include "mfapi.h" #include "gfxPrefs.h" #include "MFTDecoder.h" @@ -442,9 +440,6 @@ D3D9DXVA2Manager::Init(layers::KnowsCompositor* aKnowsCompositor, } mTextureClientAllocator->SetMaxPoolSize(5); - Telemetry::Accumulate(Telemetry::MEDIA_DECODER_BACKEND_USED, - uint32_t(media::MediaDecoderBackend::WMFDXVA2D3D9)); - return S_OK; } @@ -775,9 +770,6 @@ D3D11DXVA2Manager::Init(layers::KnowsCompositor* aKnowsCompositor, } mTextureClientAllocator->SetMaxPoolSize(5); - Telemetry::Accumulate(Telemetry::MEDIA_DECODER_BACKEND_USED, - uint32_t(media::MediaDecoderBackend::WMFDXVA2D3D11)); - return S_OK; } diff --git a/dom/media/platforms/wmf/WMFAudioMFTManager.cpp b/dom/media/platforms/wmf/WMFAudioMFTManager.cpp index 69b62da51..3dacdf0aa 100644 --- a/dom/media/platforms/wmf/WMFAudioMFTManager.cpp +++ b/dom/media/platforms/wmf/WMFAudioMFTManager.cpp @@ -252,7 +252,6 @@ WMFAudioMFTManager::Output(int64_t aStreamOffset, LOG("Audio MFTDecoder returned success but null output."); nsCOMPtr<nsIRunnable> task = NS_NewRunnableFunction([]() -> void { LOG("Reporting telemetry AUDIO_MFT_OUTPUT_NULL_SAMPLES"); - Telemetry::Accumulate(Telemetry::ID::AUDIO_MFT_OUTPUT_NULL_SAMPLES, 1); }); AbstractThread::MainThread()->Dispatch(task.forget()); return E_FAIL; diff --git a/dom/media/platforms/wmf/WMFDecoderModule.h b/dom/media/platforms/wmf/WMFDecoderModule.h index cd7b8c660..6582f8056 100644 --- a/dom/media/platforms/wmf/WMFDecoderModule.h +++ b/dom/media/platforms/wmf/WMFDecoderModule.h @@ -40,10 +40,8 @@ public: static int GetNumDecoderThreads(); // Accessors that report whether we have the required MFTs available - // on the system to play various codecs. Windows Vista doesn't have the - // H.264/AAC decoders if the "Platform Update Supplement for Windows Vista" - // is not installed, and Window N and KN variants also require a "Media - // Feature Pack" to be installed. Windows XP doesn't have WMF. + // on the system to play various codecs. Windows N and KN variants + // require a "Media Feature Pack" to be installed. static bool HasAAC(); static bool HasH264(); diff --git a/dom/media/platforms/wmf/WMFMediaDataDecoder.cpp b/dom/media/platforms/wmf/WMFMediaDataDecoder.cpp index d2c13eac7..e6dd29c6d 100644 --- a/dom/media/platforms/wmf/WMFMediaDataDecoder.cpp +++ b/dom/media/platforms/wmf/WMFMediaDataDecoder.cpp @@ -8,7 +8,6 @@ #include "VideoUtils.h" #include "WMFUtils.h" #include "nsTArray.h" -#include "mozilla/Telemetry.h" #include "mozilla/Logging.h" #include "mozilla/SyncRunnable.h" @@ -39,39 +38,6 @@ WMFMediaDataDecoder::Init() return InitPromise::CreateAndResolve(mMFTManager->GetType(), __func__); } -// A single telemetry sample is reported for each MediaDataDecoder object -// that has detected error or produced output successfully. -static void -SendTelemetry(unsigned long hr) -{ - // Collapse the error codes into a range of 0-0xff that can be viewed in - // telemetry histograms. For most MF_E_* errors, unique samples are used, - // retaining the least significant 7 or 8 bits. Other error codes are - // bucketed. - uint32_t sample; - if (SUCCEEDED(hr)) { - sample = 0; - } else if (hr < 0xc00d36b0) { - sample = 1; // low bucket - } else if (hr < 0xc00d3700) { - sample = hr & 0xffU; // MF_E_* - } else if (hr <= 0xc00d3705) { - sample = 0x80 + (hr & 0xfU); // more MF_E_* - } else if (hr < 0xc00d6d60) { - sample = 2; // mid bucket - } else if (hr <= 0xc00d6d78) { - sample = hr & 0xffU; // MF_E_TRANSFORM_* - } else { - sample = 3; // high bucket - } - - nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableFunction( - [sample] { - Telemetry::Accumulate(Telemetry::MEDIA_WMF_DECODE_ERROR, sample); - }); - NS_DispatchToMainThread(runnable); -} - void WMFMediaDataDecoder::Shutdown() { @@ -91,9 +57,6 @@ WMFMediaDataDecoder::ProcessShutdown() if (mMFTManager) { mMFTManager->Shutdown(); mMFTManager = nullptr; - if (!mRecordedError && mHasSuccessfulOutput) { - SendTelemetry(S_OK); - } } } @@ -125,10 +88,6 @@ WMFMediaDataDecoder::ProcessDecode(MediaRawData* aSample) NS_WARNING("MFTManager rejected sample"); mCallback->Error(MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR, RESULT_DETAIL("MFTManager::Input:%x", hr))); - if (!mRecordedError) { - SendTelemetry(hr); - mRecordedError = true; - } return; } @@ -144,7 +103,6 @@ WMFMediaDataDecoder::ProcessOutput() HRESULT hr = S_OK; while (SUCCEEDED(hr = mMFTManager->Output(mLastStreamOffset, output)) && output) { - mHasSuccessfulOutput = true; mCallback->Output(output); } if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { @@ -153,10 +111,6 @@ WMFMediaDataDecoder::ProcessOutput() NS_WARNING("WMFMediaDataDecoder failed to output data"); mCallback->Error(MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR, RESULT_DETAIL("MFTManager::Output:%x", hr))); - if (!mRecordedError) { - SendTelemetry(hr); - mRecordedError = true; - } } } diff --git a/dom/media/platforms/wmf/WMFMediaDataDecoder.h b/dom/media/platforms/wmf/WMFMediaDataDecoder.h index a4dd49f56..f869012e7 100644 --- a/dom/media/platforms/wmf/WMFMediaDataDecoder.h +++ b/dom/media/platforms/wmf/WMFMediaDataDecoder.h @@ -33,7 +33,7 @@ public: // Returns S_OK on success, or MF_E_TRANSFORM_NEED_MORE_INPUT if there's not // enough data to produce more output. If this returns a failure code other // than MF_E_TRANSFORM_NEED_MORE_INPUT, an error will be reported to the - // MP4Reader. + // MP4Demuxer. virtual HRESULT Output(int64_t aStreamOffset, RefPtr<MediaData>& aOutput) = 0; @@ -136,10 +136,6 @@ private: Atomic<bool> mIsFlushing; bool mIsShutDown; - - // For telemetry - bool mHasSuccessfulOutput = false; - bool mRecordedError = false; }; } // namespace mozilla diff --git a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp index 291bc5b74..a7633a7de 100644 --- a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp +++ b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp @@ -27,7 +27,6 @@ #include "mozilla/WindowsVersion.h" #include "mozilla/Telemetry.h" #include "nsPrintfCString.h" -#include "MediaTelemetryConstants.h" #include "GMPUtils.h" // For SplitAt. TODO: Move SplitAt to a central place. #include "MP4Decoder.h" #include "VPXDecoder.h" @@ -128,7 +127,6 @@ WMFVideoMFTManager::~WMFVideoMFTManager() nsCOMPtr<nsIRunnable> task = NS_NewRunnableFunction([=]() -> void { LOG(nsPrintfCString("Reporting telemetry VIDEO_MFT_OUTPUT_NULL_SAMPLES=%d", telemetry).get()); - Telemetry::Accumulate(Telemetry::ID::VIDEO_MFT_OUTPUT_NULL_SAMPLES, telemetry); }); AbstractThread::MainThread()->Dispatch(task.forget()); } @@ -511,8 +509,6 @@ WMFVideoMFTManager::InitInternal(bool aForceD3D9) if (mStreamType == VP9 || mStreamType == VP8) { return false; } - Telemetry::Accumulate(Telemetry::MEDIA_DECODER_BACKEND_USED, - uint32_t(media::MediaDecoderBackend::WMFSoftware)); } mDecoder = decoder; diff --git a/dom/media/systemservices/LoadManager.cpp b/dom/media/systemservices/LoadManager.cpp index f0f4f83a7..34b8fc7e0 100644 --- a/dom/media/systemservices/LoadManager.cpp +++ b/dom/media/systemservices/LoadManager.cpp @@ -15,7 +15,6 @@ #include "nsThreadUtils.h" #include "nsReadableUtils.h" #include "nsIObserverService.h" -#include "mozilla/Telemetry.h" #include "mozilla/ArrayUtils.h" // MOZ_LOG=LoadManager:5 @@ -192,23 +191,6 @@ LoadManagerSingleton::RemoveObserver(webrtc::CPULoadStateObserver * aObserver) for (size_t i = 0; i < MOZ_ARRAY_LENGTH(mTimeInState); i++) { total += mTimeInState[i]; } - // Don't include short calls; we don't have reasonable load data, and - // such short calls rarely reach a stable state. Keep relatively - // short calls separate from longer ones - bool log = total > 5*PR_MSEC_PER_SEC; - bool small = log && total < 30*PR_MSEC_PER_SEC; - if (log) { - // Note: We don't care about rounding here; thus total may be < 100 - Telemetry::Accumulate(small ? Telemetry::WEBRTC_LOAD_STATE_RELAXED_SHORT : - Telemetry::WEBRTC_LOAD_STATE_RELAXED, - (uint32_t) (mTimeInState[webrtc::CPULoadState::kLoadRelaxed]/total * 100)); - Telemetry::Accumulate(small ? Telemetry::WEBRTC_LOAD_STATE_NORMAL_SHORT : - Telemetry::WEBRTC_LOAD_STATE_NORMAL, - (uint32_t) (mTimeInState[webrtc::CPULoadState::kLoadNormal]/total * 100)); - Telemetry::Accumulate(small ? Telemetry::WEBRTC_LOAD_STATE_STRESSED_SHORT : - Telemetry::WEBRTC_LOAD_STATE_STRESSED, - (uint32_t) (mTimeInState[webrtc::CPULoadState::kLoadStressed]/total * 100)); - } for (auto &in_state : mTimeInState) { in_state = 0; } diff --git a/dom/media/test/bug580982.webm b/dom/media/test/bug1377278.webm Binary files differindex 802019f39..802019f39 100644 --- a/dom/media/test/bug580982.webm +++ b/dom/media/test/bug1377278.webm diff --git a/dom/media/test/bug580982.webm^headers^ b/dom/media/test/bug1377278.webm^headers^ index 4030ea1d3..4030ea1d3 100644 --- a/dom/media/test/bug580982.webm^headers^ +++ b/dom/media/test/bug1377278.webm^headers^ diff --git a/dom/media/test/crashtests/1228484.html b/dom/media/test/crashtests/1228484.html deleted file mode 100644 index 2b2e9b0f9..000000000 --- a/dom/media/test/crashtests/1228484.html +++ /dev/null @@ -1,13 +0,0 @@ -<!DOCTYPE html> -<html> -<head> -<script> - -var htmlAudio = new Audio(URL.createObjectURL(new window.MediaSource())); - -(new window.AudioContext("ringer")).createMediaElementSource(htmlAudio); -(new window.AudioContext("alarm")).createMediaElementSource(htmlAudio); - -</script> -</head> -</html> diff --git a/dom/media/test/crashtests/crashtests.list b/dom/media/test/crashtests/crashtests.list index 496fe5ee5..e4f25ca8d 100644 --- a/dom/media/test/crashtests/crashtests.list +++ b/dom/media/test/crashtests/crashtests.list @@ -81,8 +81,6 @@ load 1157994.html load 1158427.html load 1185176.html load 1185192.html -load 1223670.html -load 1228484.html load 1304948.html load 1319486.html load 1291702.html diff --git a/dom/media/test/manifest.js b/dom/media/test/manifest.js index c6d533c1b..52e53a271 100644 --- a/dom/media/test/manifest.js +++ b/dom/media/test/manifest.js @@ -224,6 +224,9 @@ var gPlayTests = [ // Test playback of a webm file { name:"seek-short.webm", type:"video/webm", duration:0.23 }, + // Test playback of a webm file with 'matroska' doctype + { name:"bug1377278.webm", type:"video/webm", duration:4.0 }, + // Test playback of a WebM file with non-zero start time. { name:"split.webm", type:"video/webm", duration:1.967 }, @@ -263,10 +266,10 @@ var gPlayTests = [ { name:"small-shot.mp3", type:"audio/mpeg", duration:0.27 }, { name:"owl.mp3", type:"audio/mpeg", duration:3.343 }, // owl.mp3 as above, but with something funny going on in the ID3v2 tag - // that causes DirectShow to fail. + // that caused DirectShow to fail. { name:"owl-funny-id3.mp3", type:"audio/mpeg", duration:3.343 }, // owl.mp3 as above, but with something even funnier going on in the ID3v2 tag - // that causes DirectShow to fail. + // that caused DirectShow to fail. { name:"owl-funnier-id3.mp3", type:"audio/mpeg", duration:3.343 }, // One second of silence with ~140KB of ID3 tags. Usually when the first MP3 // frame is at such a high offset into the file, MP3FrameParser will give up @@ -532,7 +535,6 @@ var gErrorTests = [ { name:"448636.ogv", type:"video/ogg" }, { name:"bug504843.ogv", type:"video/ogg" }, { name:"bug501279.ogg", type:"audio/ogg" }, - { name:"bug580982.webm", type:"video/webm" }, { name:"bug603918.webm", type:"video/webm" }, { name:"bug604067.webm", type:"video/webm" }, { name:"bogus.duh", type:"bogus/duh" } diff --git a/dom/media/test/mochitest.ini b/dom/media/test/mochitest.ini index ddabf78b6..742ac1b1c 100644 --- a/dom/media/test/mochitest.ini +++ b/dom/media/test/mochitest.ini @@ -382,8 +382,6 @@ support-files = bug556821.ogv^headers^ bug557094.ogv bug557094.ogv^headers^ - bug580982.webm - bug580982.webm^headers^ bug603918.webm bug603918.webm^headers^ bug604067.webm @@ -395,6 +393,8 @@ support-files = bug1301226.wav^headers^ bug1301226-odd.wav bug1301226-odd.wav^headers^ + bug1377278.webm + bug1377278.webm^headers^ can_play_type_dash.js can_play_type_ogg.js can_play_type_wave.js diff --git a/dom/media/test/test_can_play_type_mpeg.html b/dom/media/test/test_can_play_type_mpeg.html index 89e5fabef..514b5cc2f 100644 --- a/dom/media/test/test_can_play_type_mpeg.html +++ b/dom/media/test/test_can_play_type_mpeg.html @@ -151,8 +151,7 @@ var haveMp4 = (getPref("media.wmf.enabled") && IsWindowsVistaOrLater()) || check_mp4(document.getElementById('v'), haveMp4); -var haveMp3 = getPref("media.directshow.enabled") || - (getPref("media.wmf.enabled") && IsWindowsVistaOrLater()) || +var haveMp3 = getPref("media.wmf.enabled") || (IsLinux() && getPref("media.ffmpeg.enabled")) || (IsSupportedAndroid() && ((IsJellyBeanOrLater() && getPref("media.android-media-codec.enabled")) || diff --git a/dom/media/webaudio/AudioBuffer.cpp b/dom/media/webaudio/AudioBuffer.cpp index cb834f6a5..e7eba2d48 100644 --- a/dom/media/webaudio/AudioBuffer.cpp +++ b/dom/media/webaudio/AudioBuffer.cpp @@ -27,7 +27,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AudioBuffer) NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AudioBuffer) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(AudioBuffer) diff --git a/dom/media/webaudio/AudioContext.cpp b/dom/media/webaudio/AudioContext.cpp index 85842c811..d58441309 100755 --- a/dom/media/webaudio/AudioContext.cpp +++ b/dom/media/webaudio/AudioContext.cpp @@ -179,23 +179,13 @@ AudioContext::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) AudioContext::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv) { - return AudioContext::Constructor(aGlobal, - AudioChannelService::GetDefaultAudioChannel(), - aRv); -} - -/* static */ already_AddRefed<AudioContext> -AudioContext::Constructor(const GlobalObject& aGlobal, - AudioChannel aChannel, - ErrorResult& aRv) -{ nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports()); if (!window) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } - RefPtr<AudioContext> object = new AudioContext(window, false, aChannel); + RefPtr<AudioContext> object = new AudioContext(window, false, AudioChannelService::GetDefaultAudioChannel()); aRv = object->Init(); if (NS_WARN_IF(aRv.Failed())) { return nullptr; diff --git a/dom/media/webaudio/AudioContext.h b/dom/media/webaudio/AudioContext.h index 069efa986..599debef8 100644 --- a/dom/media/webaudio/AudioContext.h +++ b/dom/media/webaudio/AudioContext.h @@ -151,12 +151,6 @@ public: static already_AddRefed<AudioContext> Constructor(const GlobalObject& aGlobal, ErrorResult& aRv); - // Constructor for regular AudioContext. A default audio channel is needed. - static already_AddRefed<AudioContext> - Constructor(const GlobalObject& aGlobal, - AudioChannel aChannel, - ErrorResult& aRv); - // Constructor for offline AudioContext static already_AddRefed<AudioContext> Constructor(const GlobalObject& aGlobal, diff --git a/dom/media/webaudio/AudioParam.cpp b/dom/media/webaudio/AudioParam.cpp index 6f5574993..c1a874264 100644 --- a/dom/media/webaudio/AudioParam.cpp +++ b/dom/media/webaudio/AudioParam.cpp @@ -22,7 +22,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AudioParam) NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AudioParam) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNode) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(AudioParam) diff --git a/dom/media/webaudio/MediaBufferDecoder.cpp b/dom/media/webaudio/MediaBufferDecoder.cpp index e9f1d5a47..f3b75ca1a 100644 --- a/dom/media/webaudio/MediaBufferDecoder.cpp +++ b/dom/media/webaudio/MediaBufferDecoder.cpp @@ -23,7 +23,6 @@ #include "VideoUtils.h" #include "WebAudioUtils.h" #include "mozilla/dom/Promise.h" -#include "mozilla/Telemetry.h" #include "nsPrintfCString.h" #include "GMPService.h" @@ -45,7 +44,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(WebAudioDecodeJob) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOutput) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSuccessCallback) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFailureCallback) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(WebAudioDecodeJob) @@ -302,7 +300,6 @@ MediaDecodeTask::OnMetadataRead(MetadataHolder* aMetadata) MOZ_LOG(gMediaDecoderLog, LogLevel::Debug, ("Telemetry (WebAudio) MEDIA_CODEC_USED= '%s'", codec.get())); - Telemetry::Accumulate(Telemetry::ID::MEDIA_CODEC_USED, codec); }); AbstractThread::MainThread()->Dispatch(task.forget()); diff --git a/dom/media/webaudio/WaveShaperNode.cpp b/dom/media/webaudio/WaveShaperNode.cpp index d5c617dcd..4c50f2f1d 100644 --- a/dom/media/webaudio/WaveShaperNode.cpp +++ b/dom/media/webaudio/WaveShaperNode.cpp @@ -23,7 +23,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WaveShaperNode, AudioNode) NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WaveShaperNode, AudioNode) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(WaveShaperNode) diff --git a/dom/media/webm/WebMDecoder.cpp b/dom/media/webm/WebMDecoder.cpp index b41de6d40..9575d6e42 100644 --- a/dom/media/webm/WebMDecoder.cpp +++ b/dom/media/webm/WebMDecoder.cpp @@ -5,6 +5,10 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/Preferences.h" +#ifdef MOZ_AV1 +#include "AOMDecoder.h" +#endif +#include "MediaPrefs.h" #include "MediaDecoderStateMachine.h" #include "WebMDemuxer.h" #include "WebMDecoder.h" @@ -65,6 +69,11 @@ WebMDecoder::CanHandleMediaType(const nsACString& aMIMETypeExcludingCodecs, continue; } +#ifdef MOZ_AV1 + if (MediaPrefs::AV1Enabled() && IsAV1CodecString(codec)) { + continue; + } +#endif // Some unsupported codec. return false; } diff --git a/dom/media/webm/WebMDemuxer.cpp b/dom/media/webm/WebMDemuxer.cpp index 20ed71581..013da9b2c 100644 --- a/dom/media/webm/WebMDemuxer.cpp +++ b/dom/media/webm/WebMDemuxer.cpp @@ -8,7 +8,11 @@ #include "MediaDecoderStateMachine.h" #include "AbstractMediaDecoder.h" #include "MediaResource.h" +#ifdef MOZ_AV1 +#include "AOMDecoder.h" +#endif #include "OpusDecoder.h" +#include "VPXDecoder.h" #include "WebMDemuxer.h" #include "WebMBufferedParser.h" #include "gfx2DGlue.h" @@ -24,12 +28,9 @@ #include "mozilla/Sprintf.h" #include <algorithm> +#include <numeric> #include <stdint.h> -#define VPX_DONT_DEFINE_STDINT_TYPES -#include "vpx/vp8dx.h" -#include "vpx/vpx_decoder.h" - #define WEBM_DEBUG(arg, ...) MOZ_LOG(gMediaDemuxerLog, mozilla::LogLevel::Debug, ("WebMDemuxer(%p)::%s: " arg, this, __func__, ##__VA_ARGS__)) extern mozilla::LazyLogModule gMediaDemuxerLog; @@ -322,6 +323,9 @@ WebMDemuxer::ReadMetadata() case NESTEGG_CODEC_VP9: mInfo.mVideo.mMimeType = "video/webm; codecs=vp9"; break; + case NESTEGG_CODEC_AV1: + mInfo.mVideo.mMimeType = "video/webm; codecs=av1"; + break; default: NS_WARNING("Unknown WebM video codec"); return NS_ERROR_FAILURE; @@ -549,7 +553,7 @@ WebMDemuxer::GetTrackCrypto(TrackInfo::TrackType aType, size_t aTrackNumber) { return crypto; } -bool +nsresult WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSamples) { if (mIsMediaSource) { @@ -557,17 +561,18 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl EnsureUpToDateIndex(); } - RefPtr<NesteggPacketHolder> holder(NextPacket(aType)); + RefPtr<NesteggPacketHolder> holder; + nsresult rv = NextPacket(aType, holder); - if (!holder) { - return false; + if (NS_FAILED(rv)) { + return rv; } int r = 0; unsigned int count = 0; r = nestegg_packet_count(holder->Packet(), &count); if (r == -1) { - return false; + return NS_ERROR_DOM_MEDIA_DEMUXER_ERR; } int64_t tstamp = holder->Timestamp(); int64_t duration = holder->Duration(); @@ -578,7 +583,11 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl // video frame. int64_t next_tstamp = INT64_MIN; if (aType == TrackInfo::kAudioTrack) { - RefPtr<NesteggPacketHolder> next_holder(NextPacket(aType)); + RefPtr<NesteggPacketHolder> next_holder; + rv = NextPacket(aType, next_holder); + if (NS_FAILED(rv) && rv != NS_ERROR_DOM_MEDIA_END_OF_STREAM) { + return rv; + } if (next_holder) { next_tstamp = next_holder->Timestamp(); PushAudioPacket(next_holder); @@ -593,7 +602,11 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl } mLastAudioFrameTime = Some(tstamp); } else if (aType == TrackInfo::kVideoTrack) { - RefPtr<NesteggPacketHolder> next_holder(NextPacket(aType)); + RefPtr<NesteggPacketHolder> next_holder; + rv = NextPacket(aType, next_holder); + if (NS_FAILED(rv) && rv != NS_ERROR_DOM_MEDIA_END_OF_STREAM) { + return rv; + } if (next_holder) { next_tstamp = next_holder->Timestamp(); PushVideoPacket(next_holder); @@ -610,7 +623,7 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl } if (mIsMediaSource && next_tstamp == INT64_MIN) { - return false; + return NS_ERROR_DOM_MEDIA_END_OF_STREAM; } int64_t discardPadding = 0; @@ -626,7 +639,7 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl r = nestegg_packet_data(holder->Packet(), i, &data, &length); if (r == -1) { WEBM_DEBUG("nestegg_packet_data failed r=%d", r); - return false; + return NS_ERROR_DOM_MEDIA_DEMUXER_ERR; } bool isKeyframe = false; if (aType == TrackInfo::kAudioTrack) { @@ -636,29 +649,46 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl // Packet is encrypted, can't peek, use packet info isKeyframe = nestegg_packet_has_keyframe(holder->Packet()) == NESTEGG_PACKET_HAS_KEYFRAME_TRUE; } else { - vpx_codec_stream_info_t si; - PodZero(&si); - si.sz = sizeof(si); + auto sample = MakeSpan(data, length); switch (mVideoCodec) { case NESTEGG_CODEC_VP8: - vpx_codec_peek_stream_info(vpx_codec_vp8_dx(), data, length, &si); + isKeyframe = VPXDecoder::IsKeyframe(sample, VPXDecoder::Codec::VP8); break; case NESTEGG_CODEC_VP9: - vpx_codec_peek_stream_info(vpx_codec_vp9_dx(), data, length, &si); + isKeyframe = VPXDecoder::IsKeyframe(sample, VPXDecoder::Codec::VP9); + break; +#ifdef MOZ_AV1 + case NESTEGG_CODEC_AV1: + isKeyframe = AOMDecoder::IsKeyframe(sample); break; +#endif + default: + NS_WARNING("Cannot detect keyframes in unknown WebM video codec"); + return NS_ERROR_FAILURE; } - isKeyframe = si.is_kf; if (isKeyframe) { - // We only look for resolution changes on keyframes for both VP8 and - // VP9. Other resolution changes are invalid. - if (mLastSeenFrameWidth.isSome() && mLastSeenFrameHeight.isSome() && - (si.w != mLastSeenFrameWidth.value() || - si.h != mLastSeenFrameHeight.value())) { - mInfo.mVideo.mDisplay = nsIntSize(si.w, si.h); + // For both VP8 and VP9, we only look for resolution changes + // on keyframes. Other resolution changes are invalid. + auto dimensions = nsIntSize(0, 0); + switch (mVideoCodec) { + case NESTEGG_CODEC_VP8: + dimensions = VPXDecoder::GetFrameSize(sample, VPXDecoder::Codec::VP8); + break; + case NESTEGG_CODEC_VP9: + dimensions = VPXDecoder::GetFrameSize(sample, VPXDecoder::Codec::VP9); + break; +#ifdef MOZ_AV1 + case NESTEGG_CODEC_AV1: + dimensions = AOMDecoder::GetFrameSize(sample); + break; +#endif + } + if (mLastSeenFrameSize.isSome() + && (dimensions != mLastSeenFrameSize.value())) { + mInfo.mVideo.mDisplay = dimensions; mSharedVideoTrackInfo = new SharedTrackInfo(mInfo.mVideo, ++sStreamSourceID); } - mLastSeenFrameWidth = Some(si.w); - mLastSeenFrameHeight = Some(si.h); + mLastSeenFrameSize = Some(dimensions); } } } @@ -668,7 +698,7 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl RefPtr<MediaRawData> sample = new MediaRawData(data, length); if (length && !sample->Data()) { // OOM. - return false; + return NS_ERROR_OUT_OF_MEMORY; } sample->mTimecode = tstamp; sample->mTime = tstamp; @@ -721,11 +751,12 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl } aSamples->Push(sample); } - return true; + return NS_OK; } -RefPtr<NesteggPacketHolder> -WebMDemuxer::NextPacket(TrackInfo::TrackType aType) +nsresult +WebMDemuxer::NextPacket(TrackInfo::TrackType aType, + RefPtr<NesteggPacketHolder>& aPacket) { bool isVideo = aType == TrackInfo::kVideoTrack; @@ -734,56 +765,64 @@ WebMDemuxer::NextPacket(TrackInfo::TrackType aType) bool hasType = isVideo ? mHasVideo : mHasAudio; if (!hasType) { - return nullptr; + return NS_ERROR_DOM_MEDIA_DEMUXER_ERR; } // The packet queue for the type that we are interested in. WebMPacketQueue &packets = isVideo ? mVideoPackets : mAudioPackets; if (packets.GetSize() > 0) { - return packets.PopFront(); + aPacket = packets.PopFront(); + return NS_OK; } // Track we are interested in uint32_t ourTrack = isVideo ? mVideoTrack : mAudioTrack; do { - RefPtr<NesteggPacketHolder> holder = DemuxPacket(aType); + RefPtr<NesteggPacketHolder> holder; + nsresult rv = DemuxPacket(aType, holder); + if (NS_FAILED(rv)) { + return rv; + } if (!holder) { - return nullptr; + return NS_ERROR_DOM_MEDIA_DEMUXER_ERR; } if (ourTrack == holder->Track()) { - return holder; + aPacket = holder; + return NS_OK; } } while (true); } -RefPtr<NesteggPacketHolder> -WebMDemuxer::DemuxPacket(TrackInfo::TrackType aType) +nsresult +WebMDemuxer::DemuxPacket(TrackInfo::TrackType aType, + RefPtr<NesteggPacketHolder>& aPacket) { nestegg_packet* packet; int r = nestegg_read_packet(Context(aType), &packet); if (r == 0) { nestegg_read_reset(Context(aType)); - return nullptr; + return NS_ERROR_DOM_MEDIA_END_OF_STREAM; } else if (r < 0) { - return nullptr; + return NS_ERROR_DOM_MEDIA_DEMUXER_ERR; } unsigned int track = 0; r = nestegg_packet_track(packet, &track); if (r == -1) { - return nullptr; + return NS_ERROR_DOM_MEDIA_DEMUXER_ERR; } int64_t offset = Resource(aType).Tell(); RefPtr<NesteggPacketHolder> holder = new NesteggPacketHolder(); if (!holder->Init(packet, offset, track, false)) { - return nullptr; + return NS_ERROR_DOM_MEDIA_DEMUXER_ERR; } - return holder; + aPacket = holder; + return NS_OK; } void @@ -943,7 +982,14 @@ WebMTrackDemuxer::Seek(media::TimeUnit aTime) media::TimeUnit seekTime = aTime; mSamples.Reset(); mParent->SeekInternal(mType, aTime); - mParent->GetNextPacket(mType, &mSamples); + nsresult rv = mParent->GetNextPacket(mType, &mSamples); + if (NS_FAILED(rv)) { + if (rv == NS_ERROR_DOM_MEDIA_END_OF_STREAM) { + // Ignore the error for now, the next GetSample will be rejected with EOS. + return SeekPromise::CreateAndResolve(media::TimeUnit(), __func__); + } + return SeekPromise::CreateAndReject(rv, __func__); + } mNeedKeyframe = true; // Check what time we actually seeked to. @@ -956,15 +1002,18 @@ WebMTrackDemuxer::Seek(media::TimeUnit aTime) return SeekPromise::CreateAndResolve(seekTime, __func__); } -RefPtr<MediaRawData> -WebMTrackDemuxer::NextSample() +nsresult +WebMTrackDemuxer::NextSample(RefPtr<MediaRawData>& aData) { - while (mSamples.GetSize() < 1 && mParent->GetNextPacket(mType, &mSamples)) { + nsresult rv; + while (mSamples.GetSize() < 1 && + NS_SUCCEEDED((rv = mParent->GetNextPacket(mType, &mSamples)))) { } if (mSamples.GetSize()) { - return mSamples.PopFront(); + aData = mSamples.PopFront(); + return NS_OK; } - return nullptr; + return rv; } RefPtr<WebMTrackDemuxer::SamplesPromise> @@ -973,9 +1022,12 @@ WebMTrackDemuxer::GetSamples(int32_t aNumSamples) RefPtr<SamplesHolder> samples = new SamplesHolder; MOZ_ASSERT(aNumSamples); + nsresult rv = NS_ERROR_DOM_MEDIA_END_OF_STREAM; + while (aNumSamples) { - RefPtr<MediaRawData> sample(NextSample()); - if (!sample) { + RefPtr<MediaRawData> sample; + rv = NextSample(sample); + if (NS_FAILED(rv)) { break; } if (mNeedKeyframe && !sample->mKeyframe) { @@ -987,7 +1039,7 @@ WebMTrackDemuxer::GetSamples(int32_t aNumSamples) } if (samples->mSamples.IsEmpty()) { - return SamplesPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__); + return SamplesPromise::CreateAndReject(rv, __func__); } else { UpdateSamples(samples->mSamples); return SamplesPromise::CreateAndResolve(samples, __func__); @@ -1022,7 +1074,8 @@ WebMTrackDemuxer::SetNextKeyFrameTime() } // Demux and buffer frames until we find a keyframe. RefPtr<MediaRawData> sample; - while (!foundKeyframe && (sample = NextSample())) { + nsresult rv = NS_OK; + while (!foundKeyframe && NS_SUCCEEDED((rv = NextSample(sample)))) { if (sample->mKeyframe) { frameTime = sample->mTime; foundKeyframe = true; @@ -1104,10 +1157,11 @@ WebMTrackDemuxer::SkipToNextRandomAccessPoint(media::TimeUnit aTimeThreshold) uint32_t parsed = 0; bool found = false; RefPtr<MediaRawData> sample; + nsresult rv = NS_OK; int64_t sampleTime; WEBM_DEBUG("TimeThreshold: %f", aTimeThreshold.ToSeconds()); - while (!found && (sample = NextSample())) { + while (!found && NS_SUCCEEDED((rv = NextSample(sample)))) { parsed++; sampleTime = sample->mTime; if (sample->mKeyframe && sampleTime >= aTimeThreshold.ToMicroseconds()) { @@ -1116,7 +1170,9 @@ WebMTrackDemuxer::SkipToNextRandomAccessPoint(media::TimeUnit aTimeThreshold) mSamples.PushFront(sample.forget()); } } - SetNextKeyFrameTime(); + if (NS_SUCCEEDED(rv)) { + SetNextKeyFrameTime(); + } if (found) { WEBM_DEBUG("next sample: %f (parsed: %d)", media::TimeUnit::FromMicroseconds(sampleTime).ToSeconds(), diff --git a/dom/media/webm/WebMDemuxer.h b/dom/media/webm/WebMDemuxer.h index 6fff38e7d..36d381e57 100644 --- a/dom/media/webm/WebMDemuxer.h +++ b/dom/media/webm/WebMDemuxer.h @@ -8,9 +8,13 @@ #include "nsTArray.h" #include "MediaDataDemuxer.h" +#include "MediaResource.h" #include "NesteggPacketHolder.h" #include "mozilla/Move.h" +#include <deque> +#include <stdint.h> + typedef struct nestegg nestegg; namespace mozilla { @@ -111,7 +115,8 @@ public: bool GetOffsetForTime(uint64_t aTime, int64_t* aOffset); // Demux next WebM packet and append samples to MediaRawDataQueue - bool GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSamples); + nsresult GetNextPacket(TrackInfo::TrackType aType, + MediaRawDataQueue *aSamples); nsresult Reset(TrackInfo::TrackType aType); @@ -175,11 +180,13 @@ private: // Read a packet from the nestegg file. Returns nullptr if all packets for // the particular track have been read. Pass TrackInfo::kVideoTrack or // TrackInfo::kVideoTrack to indicate the type of the packet we want to read. - RefPtr<NesteggPacketHolder> NextPacket(TrackInfo::TrackType aType); + nsresult NextPacket(TrackInfo::TrackType aType, + RefPtr<NesteggPacketHolder>& aPacket); // Internal method that demuxes the next packet from the stream. The caller // is responsible for making sure it doesn't get lost. - RefPtr<NesteggPacketHolder> DemuxPacket(TrackInfo::TrackType aType); + nsresult DemuxPacket(TrackInfo::TrackType aType, + RefPtr<NesteggPacketHolder>& aPacket); // libnestegg audio and video context for webm container. // Access on reader's thread only. @@ -237,8 +244,7 @@ private: int64_t mLastWebMBlockOffset; const bool mIsMediaSource; - Maybe<uint32_t> mLastSeenFrameWidth; - Maybe<uint32_t> mLastSeenFrameHeight; + Maybe<nsIntSize> mLastSeenFrameSize; // This will be populated only if a resolution change occurs, otherwise it // will be left as null so the original metadata is used RefPtr<SharedTrackInfo> mSharedVideoTrackInfo; @@ -276,7 +282,7 @@ private: ~WebMTrackDemuxer(); void UpdateSamples(nsTArray<RefPtr<MediaRawData>>& aSamples); void SetNextKeyFrameTime(); - RefPtr<MediaRawData> NextSample (); + nsresult NextSample(RefPtr<MediaRawData>& aData); RefPtr<WebMDemuxer> mParent; TrackInfo::TrackType mType; UniquePtr<TrackInfo> mInfo; diff --git a/dom/media/webrtc/RTCCertificate.cpp b/dom/media/webrtc/RTCCertificate.cpp index 3f778bcbb..9f5e27c56 100644 --- a/dom/media/webrtc/RTCCertificate.cpp +++ b/dom/media/webrtc/RTCCertificate.cpp @@ -74,7 +74,7 @@ private: char buf[sizeof(randomName) * 2 + 4]; PL_strncpy(buf, "CN=", 3); for (size_t i = 0; i < sizeof(randomName); ++i) { - snprintf(&buf[i * 2 + 3], 2, "%.2x", randomName[i]); + snprintf(&buf[i * 2 + 3], 3, "%.2x", randomName[i]); } buf[sizeof(buf) - 1] = '\0'; diff --git a/dom/moz.build b/dom/moz.build index 358fc6411..54dc0510e 100644 --- a/dom/moz.build +++ b/dom/moz.build @@ -94,7 +94,6 @@ DIRS += [ 'xslt', 'xul', 'manifest', - 'vr', 'u2f', 'console', 'performance', diff --git a/dom/network/TCPSocketChild.cpp b/dom/network/TCPSocketChild.cpp index 8eb19a1db..72581ca9d 100644 --- a/dom/network/TCPSocketChild.cpp +++ b/dom/network/TCPSocketChild.cpp @@ -50,7 +50,6 @@ namespace dom { NS_IMPL_CYCLE_COLLECTION_CLASS(TCPSocketChildBase) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(TCPSocketChildBase) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSocket) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END diff --git a/dom/notification/Notification.cpp b/dom/notification/Notification.cpp index 1dd5724e4..a5aa48b00 100644 --- a/dom/notification/Notification.cpp +++ b/dom/notification/Notification.cpp @@ -11,7 +11,6 @@ #include "mozilla/OwningNonNull.h" #include "mozilla/Preferences.h" #include "mozilla/Services.h" -#include "mozilla/Telemetry.h" #include "mozilla/Unused.h" #include "mozilla/dom/AppNotificationServiceOptionsBinding.h" @@ -642,8 +641,6 @@ NotificationPermissionRequest::ResolvePromise() mCallback->Call(mPermission, error); rv = error.StealNSResult(); } - Telemetry::Accumulate( - Telemetry::WEB_NOTIFICATION_REQUEST_PERMISSION_CALLBACK, !!mCallback); mPromise->MaybeResolve(mPermission); return rv; } @@ -658,195 +655,6 @@ NotificationPermissionRequest::GetTypes(nsIArray** aTypes) aTypes); } -NS_IMPL_ISUPPORTS(NotificationTelemetryService, nsIObserver) - -NotificationTelemetryService::NotificationTelemetryService() - : mDNDRecorded(false) -{} - -NotificationTelemetryService::~NotificationTelemetryService() -{ - Unused << NS_WARN_IF(NS_FAILED(RemovePermissionChangeObserver())); -} - -/* static */ already_AddRefed<NotificationTelemetryService> -NotificationTelemetryService::GetInstance() -{ - nsCOMPtr<nsISupports> telemetrySupports = - do_GetService(NOTIFICATIONTELEMETRYSERVICE_CONTRACTID); - if (!telemetrySupports) { - return nullptr; - } - RefPtr<NotificationTelemetryService> telemetry = - static_cast<NotificationTelemetryService*>(telemetrySupports.get()); - return telemetry.forget(); -} - -nsresult -NotificationTelemetryService::Init() -{ - nsresult rv = AddPermissionChangeObserver(); - NS_ENSURE_SUCCESS(rv, rv); - - RecordPermissions(); - - return NS_OK; -} - -nsresult -NotificationTelemetryService::RemovePermissionChangeObserver() -{ - nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); - if (!obs) { - return NS_ERROR_OUT_OF_MEMORY; - } - return obs->RemoveObserver(this, "perm-changed"); -} - -nsresult -NotificationTelemetryService::AddPermissionChangeObserver() -{ - nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); - if (!obs) { - return NS_ERROR_OUT_OF_MEMORY; - } - return obs->AddObserver(this, "perm-changed", false); -} - -void -NotificationTelemetryService::RecordPermissions() -{ - if (!Telemetry::CanRecordBase() || !Telemetry::CanRecordExtended()) { - return; - } - - nsCOMPtr<nsIPermissionManager> permissionManager = - services::GetPermissionManager(); - if (!permissionManager) { - return; - } - - nsCOMPtr<nsISimpleEnumerator> enumerator; - nsresult rv = permissionManager->GetEnumerator(getter_AddRefs(enumerator)); - if (NS_WARN_IF(NS_FAILED(rv))) { - return; - } - - for (;;) { - bool hasMoreElements; - nsresult rv = enumerator->HasMoreElements(&hasMoreElements); - if (NS_WARN_IF(NS_FAILED(rv))) { - return; - } - if (!hasMoreElements) { - break; - } - nsCOMPtr<nsISupports> supportsPermission; - rv = enumerator->GetNext(getter_AddRefs(supportsPermission)); - if (NS_WARN_IF(NS_FAILED(rv))) { - return; - } - uint32_t capability; - if (!GetNotificationPermission(supportsPermission, &capability)) { - continue; - } - if (capability == nsIPermissionManager::DENY_ACTION) { - Telemetry::Accumulate(Telemetry::WEB_NOTIFICATION_PERMISSIONS, 0); - } else if (capability == nsIPermissionManager::ALLOW_ACTION) { - Telemetry::Accumulate(Telemetry::WEB_NOTIFICATION_PERMISSIONS, 1); - } - } -} - -bool -NotificationTelemetryService::GetNotificationPermission(nsISupports* aSupports, - uint32_t* aCapability) -{ - nsCOMPtr<nsIPermission> permission = do_QueryInterface(aSupports); - if (!permission) { - return false; - } - nsAutoCString type; - permission->GetType(type); - if (!type.Equals("desktop-notification")) { - return false; - } - permission->GetCapability(aCapability); - return true; -} - -void -NotificationTelemetryService::RecordDNDSupported() -{ - if (mDNDRecorded) { - return; - } - - nsCOMPtr<nsIAlertsService> alertService = - do_GetService(NS_ALERTSERVICE_CONTRACTID); - if (!alertService) { - return; - } - - nsCOMPtr<nsIAlertsDoNotDisturb> alertServiceDND = - do_QueryInterface(alertService); - if (!alertServiceDND) { - return; - } - - mDNDRecorded = true; - bool isEnabled; - nsresult rv = alertServiceDND->GetManualDoNotDisturb(&isEnabled); - if (NS_FAILED(rv)) { - return; - } - - Telemetry::Accumulate( - Telemetry::ALERTS_SERVICE_DND_SUPPORTED_FLAG, true); -} - -nsresult -NotificationTelemetryService::RecordSender(nsIPrincipal* aPrincipal) -{ - if (!Telemetry::CanRecordBase() || !Telemetry::CanRecordExtended() || - !nsAlertsUtils::IsActionablePrincipal(aPrincipal)) { - return NS_OK; - } - nsAutoString origin; - nsresult rv = Notification::GetOrigin(aPrincipal, origin); - if (NS_FAILED(rv)) { - return rv; - } - if (!mOrigins.Contains(origin)) { - mOrigins.PutEntry(origin); - Telemetry::Accumulate(Telemetry::WEB_NOTIFICATION_SENDERS, 1); - } - return NS_OK; -} - -NS_IMETHODIMP -NotificationTelemetryService::Observe(nsISupports* aSubject, - const char* aTopic, - const char16_t* aData) -{ - uint32_t capability; - if (strcmp("perm-changed", aTopic) || - !NS_strcmp(u"cleared", aData) || - !GetNotificationPermission(aSubject, &capability)) { - return NS_OK; - } - if (!NS_strcmp(u"deleted", aData)) { - if (capability == nsIPermissionManager::DENY_ACTION) { - Telemetry::Accumulate( - Telemetry::WEB_NOTIFICATION_PERMISSION_REMOVED, 0); - } else if (capability == nsIPermissionManager::ALLOW_ACTION) { - Telemetry::Accumulate( - Telemetry::WEB_NOTIFICATION_PERMISSION_REMOVED, 1); - } - } - return NS_OK; -} - // Observer that the alert service calls to do common tasks and/or dispatch to the // specific observer for the context e.g. main thread, worker, or service worker. class NotificationObserver final : public nsIObserver @@ -1407,7 +1215,6 @@ NotificationObserver::Observe(nsISupports* aSubject, const char* aTopic, AssertIsOnMainThread(); if (!strcmp("alertdisablecallback", aTopic)) { - Telemetry::Accumulate(Telemetry::WEB_NOTIFICATION_MENU, 1); if (XRE_IsParentProcess()) { return Notification::RemovePermission(mPrincipal); } @@ -1417,10 +1224,7 @@ NotificationObserver::Observe(nsISupports* aSubject, const char* aTopic, ContentChild::GetSingleton()->SendDisableNotifications( IPC::Principal(mPrincipal)); return NS_OK; - } else if (!strcmp("alertclickcallback", aTopic)) { - Telemetry::Accumulate(Telemetry::WEB_NOTIFICATION_CLICKED, 1); } else if (!strcmp("alertsettingscallback", aTopic)) { - Telemetry::Accumulate(Telemetry::WEB_NOTIFICATION_MENU, 2); if (XRE_IsParentProcess()) { return Notification::OpenSettings(mPrincipal); } @@ -1431,23 +1235,7 @@ NotificationObserver::Observe(nsISupports* aSubject, const char* aTopic, return NS_OK; } else if (!strcmp("alertshow", aTopic) || !strcmp("alertfinished", aTopic)) { - RefPtr<NotificationTelemetryService> telemetry = - NotificationTelemetryService::GetInstance(); - if (telemetry) { - // Record whether "do not disturb" is supported after the first - // notification, to account for falling back to XUL alerts. - telemetry->RecordDNDSupported(); - if (!mInPrivateBrowsing) { - // Ignore senders in private windows. - Unused << NS_WARN_IF(NS_FAILED(telemetry->RecordSender(mPrincipal))); - } - } Unused << NS_WARN_IF(NS_FAILED(AdjustPushQuota(aTopic))); - - if (!strcmp("alertshow", aTopic)) { - // Record notifications actually shown (e.g. don't count if DND is on). - Telemetry::Accumulate(Telemetry::WEB_NOTIFICATION_SHOWN, 1); - } } return mObserver->Observe(aSubject, aTopic, aData); diff --git a/dom/notification/Notification.h b/dom/notification/Notification.h index a2c4b5c68..11958f6ad 100644 --- a/dom/notification/Notification.h +++ b/dom/notification/Notification.h @@ -18,9 +18,6 @@ #include "nsTHashtable.h" #include "nsWeakReference.h" -#define NOTIFICATIONTELEMETRYSERVICE_CONTRACTID \ - "@mozilla.org/notificationTelemetryService;1" - class nsIPrincipal; class nsIVariant; @@ -49,36 +46,6 @@ public: Notify(workers::Status aStatus) override; }; -// Records telemetry probes at application startup, when a notification is -// shown, and when the notification permission is revoked for a site. -class NotificationTelemetryService final : public nsIObserver -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIOBSERVER - - NotificationTelemetryService(); - - static already_AddRefed<NotificationTelemetryService> GetInstance(); - - nsresult Init(); - void RecordDNDSupported(); - void RecordPermissions(); - nsresult RecordSender(nsIPrincipal* aPrincipal); - -private: - virtual ~NotificationTelemetryService(); - - nsresult AddPermissionChangeObserver(); - nsresult RemovePermissionChangeObserver(); - - bool GetNotificationPermission(nsISupports* aSupports, - uint32_t* aCapability); - - bool mDNDRecorded; - nsTHashtable<nsStringHashKey> mOrigins; -}; - /* * Notifications on workers introduce some lifetime issues. The property we * are trying to satisfy is: @@ -143,7 +110,6 @@ class Notification : public DOMEventTargetHelper friend class ServiceWorkerNotificationObserver; friend class WorkerGetRunnable; friend class WorkerNotificationObserver; - friend class NotificationTelemetryService; public: IMPL_EVENT_HANDLER(click) diff --git a/dom/performance/PerformanceMainThread.cpp b/dom/performance/PerformanceMainThread.cpp index 64c06d3ea..5a84f5fb1 100644 --- a/dom/performance/PerformanceMainThread.cpp +++ b/dom/performance/PerformanceMainThread.cpp @@ -27,7 +27,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PerformanceMainThread, NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTiming, mNavigation, mDocEntry) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(PerformanceMainThread, diff --git a/dom/performance/PerformanceObserver.cpp b/dom/performance/PerformanceObserver.cpp index d02acfb09..7bf194bb7 100644 --- a/dom/performance/PerformanceObserver.cpp +++ b/dom/performance/PerformanceObserver.cpp @@ -34,7 +34,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(PerformanceObserver) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCallback) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPerformance) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(PerformanceObserver) diff --git a/dom/plugins/base/nptypes.h b/dom/plugins/base/nptypes.h index 12a5fb78e..c36532472 100644 --- a/dom/plugins/base/nptypes.h +++ b/dom/plugins/base/nptypes.h @@ -22,18 +22,6 @@ typedef unsigned int uint32_t; typedef long long int64_t; typedef unsigned long long uint64_t; -#elif defined(_AIX) || defined(__sun) || defined(__osf__) || defined(IRIX) || defined(HPUX) - /* - * AIX and SunOS ship a inttypes.h header that defines [u]int32_t, - * but not bool for C. - */ - #include <inttypes.h> - - #ifndef __cplusplus - typedef int bool; - #define true 1 - #define false 0 - #endif #elif defined(bsdi) || defined(FREEBSD) || defined(OPENBSD) /* * BSD/OS, FreeBSD, and OpenBSD ship sys/types.h that define int32_t and diff --git a/dom/plugins/base/nsPluginHost.cpp b/dom/plugins/base/nsPluginHost.cpp index 916bdea0f..c3de136d0 100644 --- a/dom/plugins/base/nsPluginHost.cpp +++ b/dom/plugins/base/nsPluginHost.cpp @@ -2148,11 +2148,7 @@ nsresult nsPluginHost::ScanPluginsDirectory(nsIFile *pluginsDir, nsPluginInfo info; memset(&info, 0, sizeof(info)); nsresult res; - // Opening a block for the telemetry AutoTimer - { - Telemetry::AutoTimer<Telemetry::PLUGIN_LOAD_METADATA> telemetry; - res = pluginFile.GetPluginInfo(info, &library); - } + res = pluginFile.GetPluginInfo(info, &library); // if we don't have mime type don't proceed, this is not a plugin if (NS_FAILED(res) || !info.fMimeTypeArray) { RefPtr<nsInvalidPluginTag> invalidTag = new nsInvalidPluginTag(filePath.get(), @@ -2410,8 +2406,6 @@ nsPluginHost::FindPluginsInContent(bool aCreatePluginList, bool* aPluginsChanged // This is needed in ReloadPlugins to prevent possible recursive reloads nsresult nsPluginHost::FindPlugins(bool aCreatePluginList, bool * aPluginsChanged) { - Telemetry::AutoTimer<Telemetry::FIND_PLUGINS> telemetry; - NS_ENSURE_ARG_POINTER(aPluginsChanged); *aPluginsChanged = false; @@ -3412,7 +3406,6 @@ nsPluginHost::StopPluginInstance(nsNPAPIPluginInstance* aInstance) return NS_OK; } - Telemetry::AutoTimer<Telemetry::PLUGIN_SHUTDOWN_MS> timer; aInstance->Stop(); // if the instance does not want to be 'cached' just remove it diff --git a/dom/plugins/base/nsPluginsDirUnix.cpp b/dom/plugins/base/nsPluginsDirUnix.cpp index 6d112b4fe..e6956c34c 100644 --- a/dom/plugins/base/nsPluginsDirUnix.cpp +++ b/dom/plugins/base/nsPluginsDirUnix.cpp @@ -19,17 +19,7 @@ #include "nsIPrefService.h" #define LOCAL_PLUGIN_DLL_SUFFIX ".so" -#if defined(__hpux) -#define DEFAULT_X11_PATH "/usr/lib/X11R6/" -#undef LOCAL_PLUGIN_DLL_SUFFIX -#define LOCAL_PLUGIN_DLL_SUFFIX ".sl" -#define LOCAL_PLUGIN_DLL_ALT_SUFFIX ".so" -#elif defined(_AIX) -#define DEFAULT_X11_PATH "/usr/lib" -#define LOCAL_PLUGIN_DLL_ALT_SUFFIX ".a" -#elif defined(SOLARIS) -#define DEFAULT_X11_PATH "/usr/openwin/lib/" -#elif defined(LINUX) +#if defined(LINUX) #define DEFAULT_X11_PATH "/usr/X11R6/lib/" #elif defined(__APPLE__) #define DEFAULT_X11_PATH "/usr/X11R6/lib" @@ -102,11 +92,7 @@ static bool LoadExtraSharedLib(const char *name, char **soname, bool tryToGetSon #define PLUGIN_MAX_NUMBER_OF_EXTRA_LIBS 32 #define PREF_PLUGINS_SONAME "plugin.soname.list" -#if defined(SOLARIS) || defined(HPUX) -#define DEFAULT_EXTRA_LIBS_LIST "libXt" LOCAL_PLUGIN_DLL_SUFFIX ":libXext" LOCAL_PLUGIN_DLL_SUFFIX ":libXm" LOCAL_PLUGIN_DLL_SUFFIX -#else #define DEFAULT_EXTRA_LIBS_LIST "libXt" LOCAL_PLUGIN_DLL_SUFFIX ":libXext" LOCAL_PLUGIN_DLL_SUFFIX -#endif /* this function looks for user_pref("plugin.soname.list", "/usr/X11R6/lib/libXt.so.6:libXext.so"); @@ -280,15 +266,9 @@ nsresult nsPluginFile::LoadPlugin(PRLibrary **outLibrary) // work fine. -#if defined(SOLARIS) || defined(HPUX) - // Acrobat/libXm: Lazy resolving might cause crash later (bug 211587) - *outLibrary = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW); - pLibrary = *outLibrary; -#else // Some dlopen() doesn't recover from a failed PR_LD_NOW (bug 223744) *outLibrary = PR_LoadLibraryWithFlags(libSpec, 0); pLibrary = *outLibrary; -#endif if (!pLibrary) { LoadExtraSharedLibs(); // try reload plugin once more diff --git a/dom/plugins/ipc/PluginAsyncSurrogate.cpp b/dom/plugins/ipc/PluginAsyncSurrogate.cpp index da07116cc..3fe4c7168 100644 --- a/dom/plugins/ipc/PluginAsyncSurrogate.cpp +++ b/dom/plugins/ipc/PluginAsyncSurrogate.cpp @@ -504,8 +504,6 @@ PluginAsyncSurrogate::WaitForInit() if (mAcceptCalls) { return true; } - Telemetry::AutoTimer<Telemetry::BLOCKED_ON_PLUGINASYNCSURROGATE_WAITFORINIT_MS> - timer(mParent->GetHistogramKey()); bool result = false; MOZ_ASSERT(mParent); if (mParent->IsChrome()) { diff --git a/dom/plugins/ipc/PluginHangUIParent.cpp b/dom/plugins/ipc/PluginHangUIParent.cpp index 5114f2e9a..908182a22 100644 --- a/dom/plugins/ipc/PluginHangUIParent.cpp +++ b/dom/plugins/ipc/PluginHangUIParent.cpp @@ -8,7 +8,6 @@ #include "PluginHangUIParent.h" -#include "mozilla/Telemetry.h" #include "mozilla/ipc/ProtocolUtils.h" #include "mozilla/plugins/PluginModuleParent.h" @@ -48,14 +47,6 @@ public: NS_IMETHOD Run() override { - mozilla::Telemetry::Accumulate( - mozilla::Telemetry::PLUGIN_HANG_UI_USER_RESPONSE, mResponseCode); - mozilla::Telemetry::Accumulate( - mozilla::Telemetry::PLUGIN_HANG_UI_DONT_ASK, mDontAskCode); - mozilla::Telemetry::Accumulate( - mozilla::Telemetry::PLUGIN_HANG_UI_RESPONSE_TIME, mResponseTimeMs); - mozilla::Telemetry::Accumulate( - mozilla::Telemetry::PLUGIN_HANG_TIME, mTimeoutMs + mResponseTimeMs); return NS_OK; } diff --git a/dom/plugins/ipc/PluginInstanceParent.cpp b/dom/plugins/ipc/PluginInstanceParent.cpp index 02f0641f7..bdd15ca99 100644 --- a/dom/plugins/ipc/PluginInstanceParent.cpp +++ b/dom/plugins/ipc/PluginInstanceParent.cpp @@ -9,7 +9,6 @@ #include "mozilla/BasicEvents.h" #include "mozilla/Preferences.h" -#include "mozilla/Telemetry.h" #include "PluginInstanceParent.h" #include "BrowserStreamParent.h" #include "PluginAsyncSurrogate.h" @@ -206,12 +205,8 @@ NPError PluginInstanceParent::Destroy() { NPError retval; - { // Scope for timer - Telemetry::AutoTimer<Telemetry::BLOCKED_ON_PLUGIN_INSTANCE_DESTROY_MS> - timer(Module()->GetHistogramKey()); - if (!CallNPP_Destroy(&retval)) { - retval = NPERR_GENERIC_ERROR; - } + if (!CallNPP_Destroy(&retval)) { + retval = NPERR_GENERIC_ERROR; } #if defined(OS_WIN) @@ -1786,9 +1781,6 @@ PluginInstanceParent::NPP_NewStream(NPMIMEType type, NPStream* stream, return NPERR_GENERIC_ERROR; } - Telemetry::AutoTimer<Telemetry::BLOCKED_ON_PLUGIN_STREAM_INIT_MS> - timer(Module()->GetHistogramKey()); - NPError err = NPERR_NO_ERROR; if (mParent->IsStartingAsync()) { MOZ_ASSERT(mSurrogate); @@ -2504,6 +2496,5 @@ PluginInstanceParent::RecordDrawingModel() } MOZ_ASSERT(mode >= 0); - Telemetry::Accumulate(Telemetry::PLUGIN_DRAWING_MODEL, mode); mLastRecordedDrawingModel = mode; } diff --git a/dom/plugins/ipc/PluginModuleParent.cpp b/dom/plugins/ipc/PluginModuleParent.cpp index 2489baf16..4a509676d 100755 --- a/dom/plugins/ipc/PluginModuleParent.cpp +++ b/dom/plugins/ipc/PluginModuleParent.cpp @@ -20,7 +20,6 @@ #include "mozilla/Preferences.h" #include "mozilla/ProcessHangMonitor.h" #include "mozilla/Services.h" -#include "mozilla/Telemetry.h" #include "mozilla/Unused.h" #include "nsAutoPtr.h" #include "nsCRT.h" @@ -93,11 +92,6 @@ mozilla::plugins::SetupBridge(uint32_t aPluginId, return true; } PluginModuleChromeParent* chromeParent = static_cast<PluginModuleChromeParent*>(plugin->GetLibrary()); - /* - * We can't accumulate BLOCKED_ON_PLUGIN_MODULE_INIT_MS until here because - * its histogram key is not available until *after* NP_Initialize. - */ - chromeParent->AccumulateModuleInitBlockedTime(); *rv = chromeParent->GetRunID(runID); if (NS_FAILED(*rv)) { return true; @@ -336,16 +330,13 @@ PluginModuleContentParent::LoadModule(uint32_t aPluginId, dom::ContentChild* cp = dom::ContentChild::GetSingleton(); nsresult rv; uint32_t runID; - TimeStamp sendLoadPluginStart = TimeStamp::Now(); if (!cp->SendLoadPlugin(aPluginId, &rv, &runID) || NS_FAILED(rv)) { return nullptr; } - TimeStamp sendLoadPluginEnd = TimeStamp::Now(); PluginModuleContentParent* parent = mapping->GetModule(); MOZ_ASSERT(parent); - parent->mTimeBlocked += (sendLoadPluginEnd - sendLoadPluginStart); if (!mapping->IsChannelOpened()) { // mapping is linked into PluginModuleMapping::sModuleListHead and is @@ -441,7 +432,6 @@ PluginModuleChromeParent::LoadModule(const char* aFilePath, uint32_t aPluginId, aPluginTag->mSupportsAsyncInit)); UniquePtr<LaunchCompleteTask> onLaunchedRunnable(new LaunchedTask(parent)); parent->mSubprocess->SetCallRunnableImmediately(!parent->mIsStartingAsync); - TimeStamp launchStart = TimeStamp::Now(); bool launched = parent->mSubprocess->Launch(Move(onLaunchedRunnable), aPluginTag->mSandboxLevel); if (!launched) { @@ -460,8 +450,6 @@ PluginModuleChromeParent::LoadModule(const char* aFilePath, uint32_t aPluginId, return nullptr; } } - TimeStamp launchEnd = TimeStamp::Now(); - parent->mTimeBlocked = (launchEnd - launchStart); return parent.forget(); } @@ -1172,11 +1160,6 @@ PluginModuleParent::GetRunID(uint32_t* aRunID) void PluginModuleChromeParent::ActorDestroy(ActorDestroyReason why) { - if (why == AbnormalShutdown) { - Telemetry::Accumulate(Telemetry::SUBPROCESS_ABNORMAL_ABORT, - NS_LITERAL_CSTRING("plugin"), 1); - } - // We can't broadcast settings changes anymore. UnregisterSettingsCallbacks(); @@ -1764,15 +1747,12 @@ PluginModuleChromeParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* PluginSettings settings; GetSettings(&settings); - TimeStamp callNpInitStart = TimeStamp::Now(); // Asynchronous case if (mIsStartingAsync) { if (!SendAsyncNP_Initialize(settings)) { Close(); return NS_ERROR_FAILURE; } - TimeStamp callNpInitEnd = TimeStamp::Now(); - mTimeBlocked += (callNpInitEnd - callNpInitStart); return NS_OK; } @@ -1785,8 +1765,6 @@ PluginModuleChromeParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* Close(); return NS_ERROR_FAILURE; } - TimeStamp callNpInitEnd = TimeStamp::Now(); - mTimeBlocked += (callNpInitEnd - callNpInitStart); RecvNP_InitializeResult(*error); @@ -1888,13 +1866,10 @@ PluginModuleChromeParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPError* error) PluginSettings settings; GetSettings(&settings); - TimeStamp callNpInitStart = TimeStamp::Now(); if (mIsStartingAsync) { if (!SendAsyncNP_Initialize(settings)) { return NS_ERROR_FAILURE; } - TimeStamp callNpInitEnd = TimeStamp::Now(); - mTimeBlocked += (callNpInitEnd - callNpInitStart); return NS_OK; } @@ -1902,8 +1877,6 @@ PluginModuleChromeParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPError* error) Close(); return NS_ERROR_FAILURE; } - TimeStamp callNpInitEnd = TimeStamp::Now(); - mTimeBlocked += (callNpInitEnd - callNpInitStart); RecvNP_InitializeResult(*error); return NS_OK; } @@ -2200,18 +2173,6 @@ public: } }; -void -PluginModuleParent::AccumulateModuleInitBlockedTime() -{ - if (mPluginName.IsEmpty()) { - GetPluginDetails(); - } - Telemetry::Accumulate(Telemetry::BLOCKED_ON_PLUGIN_MODULE_INIT_MS, - GetHistogramKey(), - static_cast<uint32_t>(mTimeBlocked.ToMilliseconds())); - mTimeBlocked = TimeDuration(); -} - nsresult PluginModuleParent::NPP_NewInternal(NPMIMEType pluginType, NPP instance, uint16_t mode, @@ -2223,13 +2184,6 @@ PluginModuleParent::NPP_NewInternal(NPMIMEType pluginType, NPP instance, if (mPluginName.IsEmpty()) { GetPluginDetails(); InitQuirksModes(nsDependentCString(pluginType)); - /** mTimeBlocked measures the time that the main thread has been blocked - * on plugin module initialization. As implemented, this is the sum of - * plugin-container launch + toolhelp32 snapshot + NP_Initialize. - * We don't accumulate its value until here because the plugin info - * for its histogram key is not available until *after* NP_Initialize. - */ - AccumulateModuleInitBlockedTime(); } nsCaseInsensitiveUTF8StringArrayComparator comparator; @@ -2294,27 +2248,23 @@ PluginModuleParent::NPP_NewInternal(NPMIMEType pluginType, NPP instance, return NS_ERROR_FAILURE; } - { // Scope for timer - Telemetry::AutoTimer<Telemetry::BLOCKED_ON_PLUGIN_INSTANCE_INIT_MS> - timer(GetHistogramKey()); - if (mIsStartingAsync) { - MOZ_ASSERT(surrogate); - surrogate->AsyncCallDeparting(); - if (!SendAsyncNPP_New(parentInstance)) { + if (mIsStartingAsync) { + MOZ_ASSERT(surrogate); + surrogate->AsyncCallDeparting(); + if (!SendAsyncNPP_New(parentInstance)) { + *error = NPERR_GENERIC_ERROR; + return NS_ERROR_FAILURE; + } + *error = NPERR_NO_ERROR; + } else { + if (!CallSyncNPP_New(parentInstance, error)) { + // if IPC is down, we'll get an immediate "failed" return, but + // without *error being set. So make sure that the error + // condition is signaled to nsNPAPIPluginInstance + if (NPERR_NO_ERROR == *error) { *error = NPERR_GENERIC_ERROR; - return NS_ERROR_FAILURE; - } - *error = NPERR_NO_ERROR; - } else { - if (!CallSyncNPP_New(parentInstance, error)) { - // if IPC is down, we'll get an immediate "failed" return, but - // without *error being set. So make sure that the error - // condition is signaled to nsNPAPIPluginInstance - if (NPERR_NO_ERROR == *error) { - *error = NPERR_GENERIC_ERROR; - } - return NS_ERROR_FAILURE; } + return NS_ERROR_FAILURE; } } diff --git a/dom/plugins/ipc/PluginModuleParent.h b/dom/plugins/ipc/PluginModuleParent.h index 0ceed6efd..909e8fe35 100644 --- a/dom/plugins/ipc/PluginModuleParent.h +++ b/dom/plugins/ipc/PluginModuleParent.h @@ -115,8 +115,6 @@ public: return mPluginName + mPluginVersion; } - void AccumulateModuleInitBlockedTime(); - virtual nsresult GetRunID(uint32_t* aRunID) override; virtual void SetHasLocalInstance() override { mHadLocalInstance = true; @@ -315,7 +313,6 @@ protected: nsString mBrowserDumpID; nsString mHangID; RefPtr<nsIObserver> mProfilerObserver; - TimeDuration mTimeBlocked; nsCString mPluginName; nsCString mPluginVersion; int32_t mSandboxLevel; diff --git a/dom/presentation/provider/PresentationControlService.js b/dom/presentation/provider/PresentationControlService.js index fe61d26d6..e9f92247f 100644 --- a/dom/presentation/provider/PresentationControlService.js +++ b/dom/presentation/provider/PresentationControlService.js @@ -100,7 +100,6 @@ PresentationControlService.prototype = { if (aCert) { this._serverSocket.serverCert = aCert; - this._serverSocket.setSessionCache(false); this._serverSocket.setSessionTickets(false); let requestCert = Ci.nsITLSServerSocket.REQUEST_NEVER; this._serverSocket.setRequestClientCertificate(requestCert); diff --git a/dom/promise/Promise.cpp b/dom/promise/Promise.cpp index 557f3a1f9..f636a9101 100644 --- a/dom/promise/Promise.cpp +++ b/dom/promise/Promise.cpp @@ -413,7 +413,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Promise) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mResolveCallbacks) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRejectCallbacks) #endif // SPIDERMONKEY_PROMISE - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Promise) @@ -1995,7 +1994,6 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(CountdownHolder) NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CountdownHolder) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPromise) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END diff --git a/dom/promise/PromiseCallback.cpp b/dom/promise/PromiseCallback.cpp index 3f4a689ae..6ecf983b7 100644 --- a/dom/promise/PromiseCallback.cpp +++ b/dom/promise/PromiseCallback.cpp @@ -47,7 +47,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ResolvePromiseCallback, PromiseCallback) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPromise) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ResolvePromiseCallback) @@ -107,7 +106,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(RejectPromiseCallback, PromiseCallback) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPromise) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(RejectPromiseCallback) @@ -170,7 +168,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(InvokePromiseFuncCallback, PromiseCallback) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPromiseFunc) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(InvokePromiseFuncCallback) @@ -256,7 +253,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WrapperPromiseCallback, NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mResolveFunc) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRejectFunc) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCallback) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(WrapperPromiseCallback) diff --git a/dom/push/PushSubscriptionOptions.cpp b/dom/push/PushSubscriptionOptions.cpp index bc4fead1e..39252e9e8 100644 --- a/dom/push/PushSubscriptionOptions.cpp +++ b/dom/push/PushSubscriptionOptions.cpp @@ -36,7 +36,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(PushSubscriptionOptions) NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(PushSubscriptionOptions) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(PushSubscriptionOptions) NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER diff --git a/dom/security/nsContentSecurityManager.cpp b/dom/security/nsContentSecurityManager.cpp index 570730312..f2cbc8fcf 100644 --- a/dom/security/nsContentSecurityManager.cpp +++ b/dom/security/nsContentSecurityManager.cpp @@ -92,6 +92,55 @@ nsContentSecurityManager::AllowTopLevelNavigationToDataURI(nsIChannel* aChannel) return false; } +/* static */ nsresult +nsContentSecurityManager::CheckFTPSubresourceLoad(nsIChannel* aChannel) +{ + // We dissallow using FTP resources as a subresource everywhere. + // The only valid way to use FTP resources is loading it as + // a top level document. + + nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo(); + if (!loadInfo) { + return NS_OK; + } + + nsContentPolicyType type = loadInfo->GetExternalContentPolicyType(); + if (type == nsIContentPolicy::TYPE_DOCUMENT) { + return NS_OK; + } + + nsCOMPtr<nsIURI> uri; + nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri)); + NS_ENSURE_SUCCESS(rv, rv); + if (!uri) { + return NS_OK; + } + + bool isFtpURI = (NS_SUCCEEDED(uri->SchemeIs("ftp", &isFtpURI)) && isFtpURI); + if (!isFtpURI) { + return NS_OK; + } + + nsCOMPtr<nsIDocument> doc; + if (nsINode* node = loadInfo->LoadingNode()) { + doc = node->OwnerDoc(); + } + + nsAutoCString spec; + uri->GetSpec(spec); + NS_ConvertUTF8toUTF16 specUTF16(NS_UnescapeURL(spec)); + const char16_t* params[] = { specUTF16.get() }; + + nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, + NS_LITERAL_CSTRING("FTP_URI_BLOCKED"), + doc, + nsContentUtils::eSECURITY_PROPERTIES, + "BlockSubresourceFTP", + params, ArrayLength(params)); + + return NS_ERROR_CONTENT_BLOCKED; +} + static nsresult ValidateSecurityFlags(nsILoadInfo* aLoadInfo) { @@ -574,6 +623,10 @@ nsContentSecurityManager::doContentSecurityCheck(nsIChannel* aChannel, rv = DoContentSecurityChecks(aChannel, loadInfo); NS_ENSURE_SUCCESS(rv, rv); + // Apply this after CSP checks to allow CSP reporting. + rv = CheckFTPSubresourceLoad(aChannel); + NS_ENSURE_SUCCESS(rv, rv); + // now lets set the initalSecurityFlag for subsequent calls loadInfo->SetInitialSecurityCheckDone(true); @@ -591,6 +644,9 @@ nsContentSecurityManager::AsyncOnChannelRedirect(nsIChannel* aOldChannel, // Are we enforcing security using LoadInfo? if (loadInfo && loadInfo->GetEnforceSecurity()) { nsresult rv = CheckChannel(aNewChannel); + if (NS_SUCCEEDED(rv)) { + rv = CheckFTPSubresourceLoad(aNewChannel); + } if (NS_FAILED(rv)) { aOldChannel->Cancel(rv); return rv; diff --git a/dom/security/nsContentSecurityManager.h b/dom/security/nsContentSecurityManager.h index bab847743..750dd8803 100644 --- a/dom/security/nsContentSecurityManager.h +++ b/dom/security/nsContentSecurityManager.h @@ -36,6 +36,7 @@ public: private: static nsresult CheckChannel(nsIChannel* aChannel); + static nsresult CheckFTPSubresourceLoad(nsIChannel* aChannel); virtual ~nsContentSecurityManager() {} diff --git a/dom/security/nsMixedContentBlocker.cpp b/dom/security/nsMixedContentBlocker.cpp index c03628da0..543429aff 100644 --- a/dom/security/nsMixedContentBlocker.cpp +++ b/dom/security/nsMixedContentBlocker.cpp @@ -35,7 +35,6 @@ #include "nsISiteSecurityService.h" #include "mozilla/Logging.h" -#include "mozilla/Telemetry.h" #include "mozilla/dom/ContentChild.h" #include "mozilla/ipc/URIUtils.h" @@ -814,17 +813,13 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect, // // We do not count requests aHadInsecureImageRedirect=true, since these are // just an artifact of the image caching system. - bool active = (classification == eMixedScript); if (!aHadInsecureImageRedirect) { - if (XRE_IsParentProcess()) { - AccumulateMixedContentHSTS(innerContentLocation, active); - } else { + if (!XRE_IsParentProcess()) { // Ask the parent process to do the same call mozilla::dom::ContentChild* cc = mozilla::dom::ContentChild::GetSingleton(); if (cc) { mozilla::ipc::URIParams uri; SerializeURI(innerContentLocation, uri); - cc->SendAccumulateMixedContentHSTS(uri, active); } } } @@ -977,50 +972,3 @@ enum MixedContentHSTSState { MCB_HSTS_ACTIVE_NO_HSTS = 2, MCB_HSTS_ACTIVE_WITH_HSTS = 3 }; - -// Record information on when HSTS would have made mixed content not mixed -// content (regardless of whether it was actually blocked) -void -nsMixedContentBlocker::AccumulateMixedContentHSTS(nsIURI* aURI, bool aActive) -{ - // This method must only be called in the parent, because - // nsSiteSecurityService is only available in the parent - if (!XRE_IsParentProcess()) { - MOZ_ASSERT(false); - return; - } - - bool hsts; - nsresult rv; - nsCOMPtr<nsISiteSecurityService> sss = do_GetService(NS_SSSERVICE_CONTRACTID, &rv); - if (NS_FAILED(rv)) { - return; - } - rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, aURI, 0, nullptr, &hsts); - if (NS_FAILED(rv)) { - return; - } - - // states: would upgrade, hsts info cached - // active, passive - // - if (!aActive) { - if (!hsts) { - Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS, - MCB_HSTS_PASSIVE_NO_HSTS); - } - else { - Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS, - MCB_HSTS_PASSIVE_WITH_HSTS); - } - } else { - if (!hsts) { - Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS, - MCB_HSTS_ACTIVE_NO_HSTS); - } - else { - Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS, - MCB_HSTS_ACTIVE_WITH_HSTS); - } - } -}
\ No newline at end of file diff --git a/dom/security/nsMixedContentBlocker.h b/dom/security/nsMixedContentBlocker.h index 56ab9621f..068068b25 100644 --- a/dom/security/nsMixedContentBlocker.h +++ b/dom/security/nsMixedContentBlocker.h @@ -61,9 +61,6 @@ public: nsISupports* aExtra, nsIPrincipal* aRequestPrincipal, int16_t* aDecision); - static void AccumulateMixedContentHSTS(nsIURI* aURI, - bool aActive); - static bool sBlockMixedScript; static bool sBlockMixedDisplay; diff --git a/dom/security/test/cors/test_CrossSiteXHR.html b/dom/security/test/cors/test_CrossSiteXHR.html index b3cda3b87..d9aef5c60 100644 --- a/dom/security/test/cors/test_CrossSiteXHR.html +++ b/dom/security/test/cors/test_CrossSiteXHR.html @@ -743,7 +743,7 @@ function runTest() { is(res.responseHeaders[header], test.responseHeaders[header], "|xhr.getResponseHeader()|wrong response header (" + header + ") in test for " + test.toSource()); - is(res.allResponseHeaders[header], test.responseHeaders[header], + is(res.allResponseHeaders[header.toLowerCase()], test.responseHeaders[header], "|xhr.getAllResponseHeaderss()|wrong response header (" + header + ") in test for " + test.toSource()); } diff --git a/dom/smil/nsSMILAnimationController.cpp b/dom/smil/nsSMILAnimationController.cpp index 0dd616346..69956203e 100644 --- a/dom/smil/nsSMILAnimationController.cpp +++ b/dom/smil/nsSMILAnimationController.cpp @@ -233,7 +233,7 @@ void nsSMILAnimationController::NotifyRefreshDriverCreated( nsRefreshDriver* aRefreshDriver) { - if (!mPauseState) { + if (!mPauseState && mChildContainerTable.Count()) { MaybeStartSampling(aRefreshDriver); } } diff --git a/dom/storage/DOMStorageCache.cpp b/dom/storage/DOMStorageCache.cpp index 811f79fd3..a2b5a6f73 100644 --- a/dom/storage/DOMStorageCache.cpp +++ b/dom/storage/DOMStorageCache.cpp @@ -85,7 +85,6 @@ DOMStorageCache::DOMStorageCache(const nsACString* aOriginNoSuffix) , mInitialized(false) , mPersistent(false) , mSessionOnlyDataSetActive(false) -, mPreloadTelemetryRecorded(false) { MOZ_COUNT_CTOR(DOMStorageCache); } @@ -178,7 +177,7 @@ DOMStorageCache::DataSet(const DOMStorage* aStorage) // Session only data set is demanded but not filled with // current data set, copy to session only set now. - WaitForPreload(Telemetry::LOCALDOMSTORAGE_SESSIONONLY_PRELOAD_BLOCKING_MS); + WaitForPreload(); Data& defaultSet = mData[kDefaultSet]; Data& sessionSet = mData[kSessionSet]; @@ -298,49 +297,18 @@ DOMStorageCache::KeepAlive() mKeepAliveTimer.swap(timer); } -namespace { - -// The AutoTimer provided by telemetry headers is only using static, -// i.e. compile time known ID, but here we know the ID only at run time. -// Hence a new class. -class TelemetryAutoTimer -{ -public: - explicit TelemetryAutoTimer(Telemetry::ID aId) - : id(aId), start(TimeStamp::Now()) {} - ~TelemetryAutoTimer() - { Telemetry::AccumulateDelta_impl<Telemetry::Millisecond>::compute(id, start); } -private: - Telemetry::ID id; - const TimeStamp start; -}; - -} // namespace - void -DOMStorageCache::WaitForPreload(Telemetry::ID aTelemetryID) +DOMStorageCache::WaitForPreload() { if (!mPersistent) { return; } bool loaded = mLoaded; - - // Telemetry of rates of pending preloads - if (!mPreloadTelemetryRecorded) { - mPreloadTelemetryRecorded = true; - Telemetry::Accumulate( - Telemetry::LOCALDOMSTORAGE_PRELOAD_PENDING_ON_FIRST_ACCESS, - !loaded); - } - if (loaded) { return; } - // Measure which operation blocks and for how long - TelemetryAutoTimer timer(aTelemetryID); - // If preload already started (i.e. we got some first data, but not all) // SyncPreload will just wait for it to finish rather then synchronously // read from the database. It seems to me more optimal. @@ -357,7 +325,7 @@ nsresult DOMStorageCache::GetLength(const DOMStorage* aStorage, uint32_t* aRetval) { if (Persist(aStorage)) { - WaitForPreload(Telemetry::LOCALDOMSTORAGE_GETLENGTH_BLOCKING_MS); + WaitForPreload(); if (NS_FAILED(mLoadResult)) { return mLoadResult; } @@ -375,7 +343,7 @@ DOMStorageCache::GetKey(const DOMStorage* aStorage, uint32_t aIndex, nsAString& // maybe we need to have a lazily populated key array here or // something? if (Persist(aStorage)) { - WaitForPreload(Telemetry::LOCALDOMSTORAGE_GETKEY_BLOCKING_MS); + WaitForPreload(); if (NS_FAILED(mLoadResult)) { return mLoadResult; } @@ -397,7 +365,7 @@ void DOMStorageCache::GetKeys(const DOMStorage* aStorage, nsTArray<nsString>& aKeys) { if (Persist(aStorage)) { - WaitForPreload(Telemetry::LOCALDOMSTORAGE_GETALLKEYS_BLOCKING_MS); + WaitForPreload(); } if (NS_FAILED(mLoadResult)) { @@ -414,7 +382,7 @@ DOMStorageCache::GetItem(const DOMStorage* aStorage, const nsAString& aKey, nsAString& aRetval) { if (Persist(aStorage)) { - WaitForPreload(Telemetry::LOCALDOMSTORAGE_GETVALUE_BLOCKING_MS); + WaitForPreload(); if (NS_FAILED(mLoadResult)) { return mLoadResult; } @@ -439,7 +407,7 @@ DOMStorageCache::SetItem(const DOMStorage* aStorage, const nsAString& aKey, int64_t delta = 0; if (Persist(aStorage)) { - WaitForPreload(Telemetry::LOCALDOMSTORAGE_SETVALUE_BLOCKING_MS); + WaitForPreload(); if (NS_FAILED(mLoadResult)) { return mLoadResult; } @@ -488,7 +456,7 @@ DOMStorageCache::RemoveItem(const DOMStorage* aStorage, const nsAString& aKey, nsString& aOld) { if (Persist(aStorage)) { - WaitForPreload(Telemetry::LOCALDOMSTORAGE_REMOVEKEY_BLOCKING_MS); + WaitForPreload(); if (NS_FAILED(mLoadResult)) { return mLoadResult; } @@ -527,9 +495,8 @@ DOMStorageCache::Clear(const DOMStorage* aStorage) // We need to preload all data (know the size) before we can proceeed // to correctly decrease cached usage number. // XXX as in case of unload, this is not technically needed now, but - // after super-scope quota introduction we have to do this. Get telemetry - // right now. - WaitForPreload(Telemetry::LOCALDOMSTORAGE_CLEAR_BLOCKING_MS); + // after super-scope quota introduction we have to do this. + WaitForPreload(); if (NS_FAILED(mLoadResult)) { // When we failed to load data from the database, force delete of the // scope data and make use of the storage possible again. @@ -599,9 +566,8 @@ DOMStorageCache::UnloadItems(uint32_t aUnloadFlags) // Must wait for preload to pass correct usage to ProcessUsageDelta // XXX this is not technically needed right now since there is just // per-origin isolated quota handling, but when we introduce super- - // -scope quotas, we have to do this. Better to start getting - // telemetry right now. - WaitForPreload(Telemetry::LOCALDOMSTORAGE_UNLOAD_BLOCKING_MS); + // -scope quotas, we have to do this. + WaitForPreload(); mData[kDefaultSet].mKeys.Clear(); ProcessUsageDelta(kDefaultSet, -mData[kDefaultSet].mOriginQuotaUsage); @@ -620,7 +586,7 @@ DOMStorageCache::UnloadItems(uint32_t aUnloadFlags) #ifdef DOM_STORAGE_TESTS if (aUnloadFlags & kTestReload) { - WaitForPreload(Telemetry::LOCALDOMSTORAGE_UNLOAD_BLOCKING_MS); + WaitForPreload(); mData[kDefaultSet].mKeys.Clear(); mLoaded = false; // This is only used in testing code diff --git a/dom/storage/DOMStorageCache.h b/dom/storage/DOMStorageCache.h index 01cf6b3ea..4469152a2 100644 --- a/dom/storage/DOMStorageCache.h +++ b/dom/storage/DOMStorageCache.h @@ -14,7 +14,6 @@ #include "nsDataHashtable.h" #include "nsHashKeys.h" #include "mozilla/Monitor.h" -#include "mozilla/Telemetry.h" #include "mozilla/Atomics.h" namespace mozilla { @@ -168,7 +167,7 @@ private: private: // Synchronously blocks until the cache is fully loaded from the database - void WaitForPreload(mozilla::Telemetry::ID aTelemetryID); + void WaitForPreload(); // Helper to get one of the 3 data sets (regular, private, session) Data& DataSet(const DOMStorage* aStorage); @@ -241,9 +240,6 @@ private: // Drops back to false when session-only data are cleared from chrome. bool mSessionOnlyDataSetActive : 1; - // Whether we have already captured state of the cache preload on our first access. - bool mPreloadTelemetryRecorded : 1; - // DOMStorageDBThread on the parent or single process, // DOMStorageDBChild on the child process. static DOMStorageDBBridge* sDatabase; diff --git a/dom/storage/DOMStorageDBThread.cpp b/dom/storage/DOMStorageDBThread.cpp index 183be5c5c..f86dbad9c 100644 --- a/dom/storage/DOMStorageDBThread.cpp +++ b/dom/storage/DOMStorageDBThread.cpp @@ -163,8 +163,6 @@ DOMStorageDBThread::Shutdown() return NS_ERROR_NOT_INITIALIZED; } - Telemetry::AutoTimer<Telemetry::LOCALDOMSTORAGE_SHUTDOWN_DATABASE_MS> timer; - { MonitorAutoLock monitor(mThreadObserver->GetMonitor()); diff --git a/dom/svg/DOMSVGLength.cpp b/dom/svg/DOMSVGLength.cpp index 574617045..c72c3e383 100644 --- a/dom/svg/DOMSVGLength.cpp +++ b/dom/svg/DOMSVGLength.cpp @@ -43,7 +43,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMSVGLength) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mList) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSVGElement) -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMSVGLength) diff --git a/dom/svg/DOMSVGLengthList.cpp b/dom/svg/DOMSVGLengthList.cpp index 9d93546d9..88ecd6007 100644 --- a/dom/svg/DOMSVGLengthList.cpp +++ b/dom/svg/DOMSVGLengthList.cpp @@ -55,7 +55,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMSVGLengthList) NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMSVGLengthList) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAList) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMSVGLengthList) NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER diff --git a/dom/svg/DOMSVGNumber.cpp b/dom/svg/DOMSVGNumber.cpp index 97d80d4d0..6b9528606 100644 --- a/dom/svg/DOMSVGNumber.cpp +++ b/dom/svg/DOMSVGNumber.cpp @@ -35,7 +35,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMSVGNumber) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mList) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMSVGNumber) NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER diff --git a/dom/svg/DOMSVGNumberList.cpp b/dom/svg/DOMSVGNumberList.cpp index 00fb7ba4d..85322688f 100644 --- a/dom/svg/DOMSVGNumberList.cpp +++ b/dom/svg/DOMSVGNumberList.cpp @@ -55,7 +55,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMSVGNumberList) NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMSVGNumberList) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAList) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMSVGNumberList) NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER diff --git a/dom/svg/DOMSVGPathSeg.cpp b/dom/svg/DOMSVGPathSeg.cpp index 95be3521e..a15bf42e9 100644 --- a/dom/svg/DOMSVGPathSeg.cpp +++ b/dom/svg/DOMSVGPathSeg.cpp @@ -31,7 +31,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMSVGPathSeg) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mList) -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMSVGPathSeg) diff --git a/dom/svg/DOMSVGPathSegList.cpp b/dom/svg/DOMSVGPathSegList.cpp index 0b811cdb1..36768ea34 100644 --- a/dom/svg/DOMSVGPathSegList.cpp +++ b/dom/svg/DOMSVGPathSegList.cpp @@ -36,7 +36,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMSVGPathSegList) NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMSVGPathSegList) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mElement) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMSVGPathSegList) NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER diff --git a/dom/svg/DOMSVGPointList.cpp b/dom/svg/DOMSVGPointList.cpp index 966ef476e..ca06bd270 100644 --- a/dom/svg/DOMSVGPointList.cpp +++ b/dom/svg/DOMSVGPointList.cpp @@ -55,7 +55,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMSVGPointList) NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMSVGPointList) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mElement) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMSVGPointList) NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER diff --git a/dom/svg/DOMSVGTransformList.cpp b/dom/svg/DOMSVGTransformList.cpp index 30760bc6d..e4bde9aeb 100644 --- a/dom/svg/DOMSVGTransformList.cpp +++ b/dom/svg/DOMSVGTransformList.cpp @@ -54,7 +54,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMSVGTransformList) NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMSVGTransformList) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAList) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMSVGTransformList) NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER diff --git a/dom/svg/SVGTransform.cpp b/dom/svg/SVGTransform.cpp index b73018d1c..1cba997eb 100644 --- a/dom/svg/SVGTransform.cpp +++ b/dom/svg/SVGTransform.cpp @@ -51,7 +51,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mList) SVGMatrix* matrix = SVGMatrixTearoffTable().GetTearoff(tmp); CycleCollectionNoteChild(cb, matrix, "matrix"); -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(SVGTransform) diff --git a/dom/svg/SVGUseElement.cpp b/dom/svg/SVGUseElement.cpp index 4911e2cac..9212ab1aa 100644 --- a/dom/svg/SVGUseElement.cpp +++ b/dom/svg/SVGUseElement.cpp @@ -15,6 +15,7 @@ #include "mozilla/dom/Element.h" #include "nsContentUtils.h" #include "nsIURI.h" +#include "nsSVGEffects.h" NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Use) @@ -418,11 +419,15 @@ SVGUseElement::LookupHref() return; } + nsCOMPtr<nsIURI> originURI = + mOriginal ? mOriginal->GetBaseURI() : GetBaseURI(); + nsCOMPtr<nsIURI> baseURI = nsContentUtils::IsLocalRefURL(href) + ? nsSVGEffects::GetBaseURLForLocalRef(this, originURI) + : originURI; + nsCOMPtr<nsIURI> targetURI; - nsCOMPtr<nsIURI> baseURI = mOriginal ? mOriginal->GetBaseURI() : GetBaseURI(); nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI), href, GetComposedDoc(), baseURI); - mSource.Reset(this, targetURI); } diff --git a/dom/svg/nsISVGPoint.cpp b/dom/svg/nsISVGPoint.cpp index 1c1971004..f4fdb9dd0 100644 --- a/dom/svg/nsISVGPoint.cpp +++ b/dom/svg/nsISVGPoint.cpp @@ -32,7 +32,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsISVGPoint) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mList) -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsISVGPoint) diff --git a/dom/svg/nsSVGElement.h b/dom/svg/nsSVGElement.h index 42bc05746..257ed7a2e 100644 --- a/dom/svg/nsSVGElement.h +++ b/dom/svg/nsSVGElement.h @@ -715,7 +715,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER \ NS_IMPL_CYCLE_COLLECTION_UNLINK_END \ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_val) \ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_element) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS \ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END \ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(_val) \ NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER \ diff --git a/dom/svg/test/reftest_viewport_noninteger.html b/dom/svg/test/reftest_viewport_noninteger.html new file mode 100644 index 000000000..3f4852b53 --- /dev/null +++ b/dom/svg/test/reftest_viewport_noninteger.html @@ -0,0 +1,175 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>SVG size test</title> + <style> + body { + margin: 30px; + font-family: sans-serif; + } + + #tests { + display: grid; + grid-template-columns: repeat(4, 1fr); + grid-gap: 30px; + } + + #tests div:hover { + opacity: 1 !important; + } + + #tests p { + text-decoration: underline dotted black; + } + + svg { + background: lightgrey; + } + </style> + </head> + <body> + <h1>SVG size test</h1> + + <p>The grey boxes below are <code><svg></code> elements.</p> + <p>All SVGs in each row should have the exact same size.</p> + <p>Each row has its own viewBox width and height: <code>viewBox="0 0 width height"</code>.</p> + <p>Each column has its own width/height styling. For example, <code>style="width: 200px; height: auto;"</code>.</p> + <p>The first column has both an explicit widht and an explicit height, so there's not much that can go wrong there. It acts as a reference.</p> + <p>The first row has integer viewBox width and height. Firefox then sizes all SVGs correctly.</p> + <p>The remaining rows have at least one non-integer viewBox width and height. Firefox then sizes the SVGs a bit wrong.</p> + <p>Chrome, Safari and Edge seem to pass all tests.</p> + + <p id="summary"></p> + + <div id="tests"></div> + + <script> + const testsElement = document.getElementById("tests"); + const summaryElement = document.getElementById("summary"); + + // Turn for instance `2.3` into `230` (px). Round to avoid floating point + // issues. + const scale = (number) => Math.round(100 * number); + + const widths = [2, 2.3, 2.5, 2.8]; + const heights = [3, 3.3, 3.5, 3.8]; + + let numPassed = 0; + let numFailed = 0; + + for (const width of widths) { + for (const height of heights) { + const variations = [ + {width, height}, + {width: "auto", height}, + {width, height: "auto"}, + {width: "auto", height: "auto"}, + ]; + + for (const variation of variations) { + const cellElement = document.createElement("div"); + + const titleElement = document.createElement("h2"); + titleElement.appendChild(makeTitle(width, height, variation)); + + const sizeElement = document.createElement("p"); + + const svgWrapperElement = document.createElement("div"); + svgWrapperElement.style.width = + variation.width === "auto" && variation.height === "auto" + ? `${scale(width)}px` + : "auto"; + + const svgElement = document.createElementNS("http://www.w3.org/2000/svg", "svg"); + svgElement.setAttribute("viewBox", `0 0 ${width} ${height}`); + svgElement.style.width = + typeof variation.width === "number" + ? `${scale(variation.width)}px` + : variation.width; + svgElement.style.height = + typeof variation.height === "number" + ? `${scale(variation.height)}px` + : variation.height; + + svgWrapperElement.appendChild(svgElement); + + cellElement.appendChild(titleElement); + cellElement.appendChild(sizeElement); + cellElement.appendChild(svgWrapperElement); + + testsElement.appendChild(cellElement); + + const rect = svgElement.getBoundingClientRect(); + const actual = { + width: Math.round(rect.width), + height: Math.round(rect.height), + }; + const expected = { + width: scale(width), + height: scale(height), + }; + const passed = + actual.width === expected.width && + actual.height === expected.height; + + const icon = passed ? "✔" : "✘"; + const iconText = passed ? "PASS" : "FAIL"; + const expectedText = passed ? "" : `\nExpected size: ${expected.width}x${expected.height}`; + sizeElement.textContent = `${icon} ${actual.width}x${actual.height}`; + sizeElement.title = `${iconText}. Actual size, as measured by element.getBoundingClientRect().${expectedText}`; + sizeElement.style.color = passed ? "lime" : "red"; + sizeElement.style.fontWeight = passed ? "normal" : "bold"; + + cellElement.style.opacity = passed ? 0.5 : 1; + + if (passed) { + numPassed++; + } else { + numFailed++; + } + } + } + } + + const numTotal = numPassed + numFailed; + const passed = numFailed === 0; + const icon = passed ? "✔" : "✘"; + summaryElement.textContent = `${icon} ${numPassed}/${numTotal} tests passed.`; + summaryElement.style.color = passed ? "lime" : "red"; + summaryElement.style.fontWeight = "bold"; + + function makeTitle(width, height, variation) { + const fragment = document.createDocumentFragment(); + + const first = document.createElement("abbr"); + first.textContent = `${width}/${height}`; + first.title = `SVG viewBox width/height: viewBox="0 0 ${width} ${height}"`; + + const separator = document.createTextNode(" | "); + + const second = document.createElement("abbr"); + + const widthString = typeof variation.width === "number" ? "px" : variation.width; + const heightString = typeof variation.height === "number" ? "px" : variation.height; + second.textContent = `${widthString}/${heightString}`; + + const widthExplanation = + typeof variation.width === "number" + ? "explicit width (px)" + : `${variation.width} width` + const heightExplanation = + typeof variation.height === "number" + ? "explicit height (px)" + : `${variation.height} height` + second.title = `${widthExplanation}, ${heightExplanation}`; + + fragment.appendChild(first); + fragment.appendChild(separator); + fragment.appendChild(second); + + return fragment; + } + </script> + </body> +</html> diff --git a/dom/system/mac/CoreLocationLocationProvider.mm b/dom/system/mac/CoreLocationLocationProvider.mm index b39582a9e..7a3feba97 100644 --- a/dom/system/mac/CoreLocationLocationProvider.mm +++ b/dom/system/mac/CoreLocationLocationProvider.mm @@ -13,7 +13,6 @@ #include "CoreLocationLocationProvider.h" #include "nsCocoaFeatures.h" #include "prtime.h" -#include "mozilla/Telemetry.h" #include "MLSFallback.h" #include <CoreLocation/CLError.h> @@ -103,7 +102,6 @@ static const CLLocationAccuracy kDEFAULT_ACCURACY = kCLLocationAccuracyNearestTe PR_Now() / PR_USEC_PER_MSEC); mProvider->Update(geoPosition); - Telemetry::Accumulate(Telemetry::GEOLOCATION_OSX_SOURCE_IS_MLS, false); } @end @@ -127,7 +125,6 @@ CoreLocationLocationProvider::MLSUpdate::Update(nsIDOMGeoPosition *position) return NS_ERROR_FAILURE; } mParentLocationProvider.Update(position); - Telemetry::Accumulate(Telemetry::GEOLOCATION_OSX_SOURCE_IS_MLS, true); return NS_OK; } NS_IMETHODIMP diff --git a/dom/system/windows/WindowsLocationProvider.cpp b/dom/system/windows/WindowsLocationProvider.cpp index fa7f8d8be..9da7bcc30 100644 --- a/dom/system/windows/WindowsLocationProvider.cpp +++ b/dom/system/windows/WindowsLocationProvider.cpp @@ -10,7 +10,6 @@ #include "nsComponentManagerUtils.h" #include "prtime.h" #include "MLSFallback.h" -#include "mozilla/Telemetry.h" namespace mozilla { namespace dom { @@ -34,7 +33,6 @@ WindowsLocationProvider::MLSUpdate::Update(nsIDOMGeoPosition *aPosition) if (!coords) { return NS_ERROR_FAILURE; } - Telemetry::Accumulate(Telemetry::GEOLOCATION_WIN8_SOURCE_IS_MLS, true); return mCallback->Update(aPosition); } NS_IMETHODIMP @@ -176,8 +174,6 @@ LocationEvent::OnLocationChanged(REFIID aReportType, PR_Now() / PR_USEC_PER_MSEC); mCallback->Update(position); - Telemetry::Accumulate(Telemetry::GEOLOCATION_WIN8_SOURCE_IS_MLS, false); - return S_OK; } diff --git a/dom/url/URLSearchParams.cpp b/dom/url/URLSearchParams.cpp index d9492f81c..f762299f8 100644 --- a/dom/url/URLSearchParams.cpp +++ b/dom/url/URLSearchParams.cpp @@ -314,14 +314,6 @@ URLSearchParams::URLSearchParams(nsISupports* aParent, { } -URLSearchParams::URLSearchParams(nsISupports* aParent, - const URLSearchParams& aOther) - : mParams(new URLParams(*aOther.mParams.get())) - , mParent(aParent) - , mObserver(nullptr) -{ -} - URLSearchParams::~URLSearchParams() { DeleteAll(); @@ -335,34 +327,43 @@ URLSearchParams::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) /* static */ already_AddRefed<URLSearchParams> URLSearchParams::Constructor(const GlobalObject& aGlobal, - const nsAString& aInit, + const USVStringSequenceSequenceOrUSVStringUSVStringRecordOrUSVString& aInit, ErrorResult& aRv) { RefPtr<URLSearchParams> sp = new URLSearchParams(aGlobal.GetAsSupports(), nullptr); - NS_ConvertUTF16toUTF8 input(aInit); - - if (StringBeginsWith(input, NS_LITERAL_CSTRING("?"))) { - sp->ParseInput(Substring(input, 1, input.Length() - 1)); + if (aInit.IsUSVString()) { + NS_ConvertUTF16toUTF8 input(aInit.GetAsUSVString()); + if (StringBeginsWith(input, NS_LITERAL_CSTRING("?"))) { + sp->ParseInput(Substring(input, 1, input.Length() - 1)); + } else { + sp->ParseInput(input); + } + } else if (aInit.IsUSVStringSequenceSequence()) { + const Sequence<Sequence<nsString>>& list = + aInit.GetAsUSVStringSequenceSequence(); + for (uint32_t i = 0; i < list.Length(); ++i) { + const Sequence<nsString>& item = list[i]; + if (item.Length() != 2) { + aRv.Throw(NS_ERROR_DOM_TYPE_ERR); + return nullptr; + } + sp->Append(item[0], item[1]); + } + } else if (aInit.IsUSVStringUSVStringRecord()) { + const Record<nsString, nsString>& record = + aInit.GetAsUSVStringUSVStringRecord(); + for (auto& entry : record.Entries()) { + sp->Append(entry.mKey, entry.mValue); + } } else { - sp->ParseInput(input); + MOZ_CRASH("URLSearchParams: Invalid string"); } return sp.forget(); } -/* static */ already_AddRefed<URLSearchParams> -URLSearchParams::Constructor(const GlobalObject& aGlobal, - URLSearchParams& aInit, - ErrorResult& aRv) -{ - RefPtr<URLSearchParams> sp = - new URLSearchParams(aGlobal.GetAsSupports(), aInit); - - return sp.forget(); -} - void URLSearchParams::ParseInput(const nsACString& aInput) { diff --git a/dom/url/URLSearchParams.h b/dom/url/URLSearchParams.h index 4b0aaa991..9fefd78dd 100644 --- a/dom/url/URLSearchParams.h +++ b/dom/url/URLSearchParams.h @@ -20,6 +20,7 @@ namespace mozilla { namespace dom { class URLSearchParams; +class USVStringSequenceSequenceOrUSVStringUSVStringRecordOrUSVString; class URLSearchParamsObserver : public nsISupports { @@ -43,14 +44,6 @@ public: DeleteAll(); } - explicit URLParams(const URLParams& aOther) - : mParams(aOther.mParams) - {} - - URLParams(const URLParams&& aOther) - : mParams(Move(aOther.mParams)) - {} - class ForEachIterator { public: @@ -144,9 +137,6 @@ public: explicit URLSearchParams(nsISupports* aParent, URLSearchParamsObserver* aObserver=nullptr); - URLSearchParams(nsISupports* aParent, - const URLSearchParams& aOther); - // WebIDL methods nsISupports* GetParentObject() const { @@ -157,11 +147,8 @@ public: WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; static already_AddRefed<URLSearchParams> - Constructor(const GlobalObject& aGlobal, const nsAString& aInit, - ErrorResult& aRv); - - static already_AddRefed<URLSearchParams> - Constructor(const GlobalObject& aGlobal, URLSearchParams& aInit, + Constructor(const GlobalObject& aGlobal, + const USVStringSequenceSequenceOrUSVStringUSVStringRecordOrUSVString& aInit, ErrorResult& aRv); void ParseInput(const nsACString& aInput); diff --git a/dom/vr/VRDisplay.cpp b/dom/vr/VRDisplay.cpp deleted file mode 100644 index 80922422f..000000000 --- a/dom/vr/VRDisplay.cpp +++ /dev/null @@ -1,802 +0,0 @@ -/* -*- 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 "nsWrapperCache.h" - -#include "mozilla/dom/Element.h" -#include "mozilla/dom/ElementBinding.h" -#include "mozilla/dom/Promise.h" -#include "mozilla/dom/VRDisplay.h" -#include "mozilla/HoldDropJSObjects.h" -#include "mozilla/dom/VRDisplayBinding.h" -#include "Navigator.h" -#include "gfxVR.h" -#include "VRDisplayClient.h" -#include "VRManagerChild.h" -#include "VRDisplayPresentation.h" -#include "nsIObserverService.h" -#include "nsIFrame.h" -#include "nsISupportsPrimitives.h" - -using namespace mozilla::gfx; - -namespace mozilla { -namespace dom { - -VRFieldOfView::VRFieldOfView(nsISupports* aParent, - double aUpDegrees, double aRightDegrees, - double aDownDegrees, double aLeftDegrees) - : mParent(aParent) - , mUpDegrees(aUpDegrees) - , mRightDegrees(aRightDegrees) - , mDownDegrees(aDownDegrees) - , mLeftDegrees(aLeftDegrees) -{ -} - -VRFieldOfView::VRFieldOfView(nsISupports* aParent, const gfx::VRFieldOfView& aSrc) - : mParent(aParent) - , mUpDegrees(aSrc.upDegrees) - , mRightDegrees(aSrc.rightDegrees) - , mDownDegrees(aSrc.downDegrees) - , mLeftDegrees(aSrc.leftDegrees) -{ -} - -bool -VRDisplayCapabilities::HasPosition() const -{ - return bool(mFlags & gfx::VRDisplayCapabilityFlags::Cap_Position); -} - -bool -VRDisplayCapabilities::HasOrientation() const -{ - return bool(mFlags & gfx::VRDisplayCapabilityFlags::Cap_Orientation); -} - -bool -VRDisplayCapabilities::HasExternalDisplay() const -{ - return bool(mFlags & gfx::VRDisplayCapabilityFlags::Cap_External); -} - -bool -VRDisplayCapabilities::CanPresent() const -{ - return bool(mFlags & gfx::VRDisplayCapabilityFlags::Cap_Present); -} - -uint32_t -VRDisplayCapabilities::MaxLayers() const -{ - return CanPresent() ? 1 : 0; -} - -/*static*/ bool -VRDisplay::RefreshVRDisplays(uint64_t aWindowId) -{ - gfx::VRManagerChild* vm = gfx::VRManagerChild::Get(); - return vm && vm->RefreshVRDisplaysWithCallback(aWindowId); -} - -/*static*/ void -VRDisplay::UpdateVRDisplays(nsTArray<RefPtr<VRDisplay>>& aDisplays, nsPIDOMWindowInner* aWindow) -{ - nsTArray<RefPtr<VRDisplay>> displays; - - gfx::VRManagerChild* vm = gfx::VRManagerChild::Get(); - nsTArray<RefPtr<gfx::VRDisplayClient>> updatedDisplays; - if (vm && vm->GetVRDisplays(updatedDisplays)) { - for (size_t i = 0; i < updatedDisplays.Length(); i++) { - RefPtr<gfx::VRDisplayClient> display = updatedDisplays[i]; - bool isNewDisplay = true; - for (size_t j = 0; j < aDisplays.Length(); j++) { - if (aDisplays[j]->GetClient()->GetDisplayInfo() == display->GetDisplayInfo()) { - displays.AppendElement(aDisplays[j]); - isNewDisplay = false; - } - } - - if (isNewDisplay) { - displays.AppendElement(new VRDisplay(aWindow, display)); - } - } - } - - aDisplays = displays; -} - -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(VRFieldOfView, mParent) -NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(VRFieldOfView, AddRef) -NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(VRFieldOfView, Release) - - -JSObject* -VRFieldOfView::WrapObject(JSContext* aCx, - JS::Handle<JSObject*> aGivenProto) -{ - return VRFieldOfViewBinding::Wrap(aCx, this, aGivenProto); -} - -NS_IMPL_CYCLE_COLLECTION_CLASS(VREyeParameters) - -NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(VREyeParameters) - NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent, mFOV) - NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER - tmp->mOffset = nullptr; -NS_IMPL_CYCLE_COLLECTION_UNLINK_END - -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(VREyeParameters) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent, mFOV) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END - -NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(VREyeParameters) - NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER - NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mOffset) -NS_IMPL_CYCLE_COLLECTION_TRACE_END - -NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(VREyeParameters, AddRef) -NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(VREyeParameters, Release) - -VREyeParameters::VREyeParameters(nsISupports* aParent, - const gfx::Point3D& aEyeTranslation, - const gfx::VRFieldOfView& aFOV, - const gfx::IntSize& aRenderSize) - : mParent(aParent) - , mEyeTranslation(aEyeTranslation) - , mRenderSize(aRenderSize) -{ - mFOV = new VRFieldOfView(aParent, aFOV); - mozilla::HoldJSObjects(this); -} - -VREyeParameters::~VREyeParameters() -{ - mozilla::DropJSObjects(this); -} - -VRFieldOfView* -VREyeParameters::FieldOfView() -{ - return mFOV; -} - -void -VREyeParameters::GetOffset(JSContext* aCx, JS::MutableHandle<JSObject*> aRetval, ErrorResult& aRv) -{ - if (!mOffset) { - // Lazily create the Float32Array - mOffset = dom::Float32Array::Create(aCx, this, 3, mEyeTranslation.components); - if (!mOffset) { - aRv.NoteJSContextException(aCx); - return; - } - } - aRetval.set(mOffset); -} - -JSObject* -VREyeParameters::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) -{ - return VREyeParametersBinding::Wrap(aCx, this, aGivenProto); -} - -VRStageParameters::VRStageParameters(nsISupports* aParent, - const gfx::Matrix4x4& aSittingToStandingTransform, - const gfx::Size& aSize) - : mParent(aParent) - , mSittingToStandingTransform(aSittingToStandingTransform) - , mSittingToStandingTransformArray(nullptr) - , mSize(aSize) -{ - mozilla::HoldJSObjects(this); -} - -VRStageParameters::~VRStageParameters() -{ - mozilla::DropJSObjects(this); -} - -JSObject* -VRStageParameters::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) -{ - return VRStageParametersBinding::Wrap(aCx, this, aGivenProto); -} - -NS_IMPL_CYCLE_COLLECTION_CLASS(VRStageParameters) - -NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(VRStageParameters) - NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent) - NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER - tmp->mSittingToStandingTransformArray = nullptr; -NS_IMPL_CYCLE_COLLECTION_UNLINK_END - -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(VRStageParameters) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END - -NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(VRStageParameters) - NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER - NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mSittingToStandingTransformArray) -NS_IMPL_CYCLE_COLLECTION_TRACE_END - -NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(VRStageParameters, AddRef) -NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(VRStageParameters, Release) - -void -VRStageParameters::GetSittingToStandingTransform(JSContext* aCx, - JS::MutableHandle<JSObject*> aRetval, - ErrorResult& aRv) -{ - if (!mSittingToStandingTransformArray) { - // Lazily create the Float32Array - mSittingToStandingTransformArray = dom::Float32Array::Create(aCx, this, 16, - mSittingToStandingTransform.components); - if (!mSittingToStandingTransformArray) { - aRv.NoteJSContextException(aCx); - return; - } - } - aRetval.set(mSittingToStandingTransformArray); -} - -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(VRDisplayCapabilities, mParent) -NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(VRDisplayCapabilities, AddRef) -NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(VRDisplayCapabilities, Release) - -JSObject* -VRDisplayCapabilities::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) -{ - return VRDisplayCapabilitiesBinding::Wrap(aCx, this, aGivenProto); -} - -VRPose::VRPose(nsISupports* aParent, const gfx::VRHMDSensorState& aState) - : Pose(aParent) - , mVRState(aState) -{ - mFrameId = aState.inputFrameID; - mozilla::HoldJSObjects(this); -} - -VRPose::VRPose(nsISupports* aParent) - : Pose(aParent) -{ - mFrameId = 0; - mVRState.Clear(); - mozilla::HoldJSObjects(this); -} - -VRPose::~VRPose() -{ - mozilla::DropJSObjects(this); -} - -void -VRPose::GetPosition(JSContext* aCx, - JS::MutableHandle<JSObject*> aRetval, - ErrorResult& aRv) -{ - SetFloat32Array(aCx, aRetval, mPosition, mVRState.position, 3, - !mPosition && bool(mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Position), - aRv); -} - -void -VRPose::GetLinearVelocity(JSContext* aCx, - JS::MutableHandle<JSObject*> aRetval, - ErrorResult& aRv) -{ - SetFloat32Array(aCx, aRetval, mLinearVelocity, mVRState.linearVelocity, 3, - !mLinearVelocity && bool(mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Position), - aRv); -} - -void -VRPose::GetLinearAcceleration(JSContext* aCx, - JS::MutableHandle<JSObject*> aRetval, - ErrorResult& aRv) -{ - SetFloat32Array(aCx, aRetval, mLinearAcceleration, mVRState.linearAcceleration, 3, - !mLinearAcceleration && bool(mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_LinearAcceleration), - aRv); - -} - -void -VRPose::GetOrientation(JSContext* aCx, - JS::MutableHandle<JSObject*> aRetval, - ErrorResult& aRv) -{ - SetFloat32Array(aCx, aRetval, mOrientation, mVRState.orientation, 4, - !mOrientation && bool(mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Orientation), - aRv); -} - -void -VRPose::GetAngularVelocity(JSContext* aCx, - JS::MutableHandle<JSObject*> aRetval, - ErrorResult& aRv) -{ - SetFloat32Array(aCx, aRetval, mAngularVelocity, mVRState.angularVelocity, 3, - !mAngularVelocity && bool(mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Orientation), - aRv); -} - -void -VRPose::GetAngularAcceleration(JSContext* aCx, - JS::MutableHandle<JSObject*> aRetval, - ErrorResult& aRv) -{ - SetFloat32Array(aCx, aRetval, mAngularAcceleration, mVRState.angularAcceleration, 3, - !mAngularAcceleration && bool(mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_AngularAcceleration), - aRv); -} - -JSObject* -VRPose::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) -{ - return VRPoseBinding::Wrap(aCx, this, aGivenProto); -} - -/* virtual */ JSObject* -VRDisplay::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) -{ - return VRDisplayBinding::Wrap(aCx, this, aGivenProto); -} - -VRDisplay::VRDisplay(nsPIDOMWindowInner* aWindow, gfx::VRDisplayClient* aClient) - : DOMEventTargetHelper(aWindow) - , mClient(aClient) - , mDepthNear(0.01f) // Default value from WebVR Spec - , mDepthFar(10000.0f) // Default value from WebVR Spec -{ - const gfx::VRDisplayInfo& info = aClient->GetDisplayInfo(); - mDisplayId = info.GetDisplayID(); - mDisplayName = NS_ConvertASCIItoUTF16(info.GetDisplayName()); - mCapabilities = new VRDisplayCapabilities(aWindow, info.GetCapabilities()); - if (info.GetCapabilities() & gfx::VRDisplayCapabilityFlags::Cap_StageParameters) { - mStageParameters = new VRStageParameters(aWindow, - info.GetSittingToStandingTransform(), - info.GetStageSize()); - } - mozilla::HoldJSObjects(this); -} - -VRDisplay::~VRDisplay() -{ - ExitPresentInternal(); - mozilla::DropJSObjects(this); -} - -void -VRDisplay::LastRelease() -{ - // We don't want to wait for the CC to free up the presentation - // for use in other documents, so we do this in LastRelease(). - ExitPresentInternal(); -} - -already_AddRefed<VREyeParameters> -VRDisplay::GetEyeParameters(VREye aEye) -{ - gfx::VRDisplayInfo::Eye eye = aEye == VREye::Left ? gfx::VRDisplayInfo::Eye_Left : gfx::VRDisplayInfo::Eye_Right; - RefPtr<VREyeParameters> params = - new VREyeParameters(GetParentObject(), - mClient->GetDisplayInfo().GetEyeTranslation(eye), - mClient->GetDisplayInfo().GetEyeFOV(eye), - mClient->GetDisplayInfo().SuggestedEyeResolution()); - return params.forget(); -} - -VRDisplayCapabilities* -VRDisplay::Capabilities() -{ - return mCapabilities; -} - -VRStageParameters* -VRDisplay::GetStageParameters() -{ - return mStageParameters; -} - -void -VRDisplay::UpdateFrameInfo() -{ - /** - * The WebVR 1.1 spec Requires that VRDisplay.getPose and VRDisplay.getFrameData - * must return the same values until the next VRDisplay.submitFrame. - * - * mFrameInfo is marked dirty at the end of the frame or start of a new - * composition and lazily created here in order to receive mid-frame - * pose-prediction updates while still ensuring conformance to the WebVR spec - * requirements. - * - * If we are not presenting WebVR content, the frame will never end and we should - * return the latest frame data always. - */ - if (mFrameInfo.IsDirty() || !mPresentation) { - gfx::VRHMDSensorState state = mClient->GetSensorState(); - const gfx::VRDisplayInfo& info = mClient->GetDisplayInfo(); - mFrameInfo.Update(info, state, mDepthNear, mDepthFar); - } -} - -bool -VRDisplay::GetFrameData(VRFrameData& aFrameData) -{ - UpdateFrameInfo(); - aFrameData.Update(mFrameInfo); - return true; -} - -already_AddRefed<VRPose> -VRDisplay::GetPose() -{ - UpdateFrameInfo(); - RefPtr<VRPose> obj = new VRPose(GetParentObject(), mFrameInfo.mVRState); - - return obj.forget(); -} - -void -VRDisplay::ResetPose() -{ - mClient->ZeroSensor(); -} - -already_AddRefed<Promise> -VRDisplay::RequestPresent(const nsTArray<VRLayer>& aLayers, ErrorResult& aRv) -{ - nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject()); - if (!global) { - aRv.Throw(NS_ERROR_FAILURE); - return nullptr; - } - - RefPtr<Promise> promise = Promise::Create(global, aRv); - NS_ENSURE_TRUE(!aRv.Failed(), nullptr); - - nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); - NS_ENSURE_TRUE(obs, nullptr); - - if (mClient->GetIsPresenting()) { - // Only one presentation allowed per VRDisplay - // on a first-come-first-serve basis. - promise->MaybeRejectWithUndefined(); - } else { - mPresentation = mClient->BeginPresentation(aLayers); - mFrameInfo.Clear(); - - nsresult rv = obs->AddObserver(this, "inner-window-destroyed", false); - if (NS_WARN_IF(NS_FAILED(rv))) { - mPresentation = nullptr; - promise->MaybeRejectWithUndefined(); - } else { - promise->MaybeResolve(JS::UndefinedHandleValue); - } - } - return promise.forget(); -} - -NS_IMETHODIMP -VRDisplay::Observe(nsISupports* aSubject, const char* aTopic, - const char16_t* aData) -{ - MOZ_ASSERT(NS_IsMainThread()); - - if (strcmp(aTopic, "inner-window-destroyed") == 0) { - nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject); - NS_ENSURE_TRUE(wrapper, NS_ERROR_FAILURE); - - uint64_t innerID; - nsresult rv = wrapper->GetData(&innerID); - NS_ENSURE_SUCCESS(rv, rv); - - if (!GetOwner() || GetOwner()->WindowID() == innerID) { - ExitPresentInternal(); - } - - return NS_OK; - } - - // This should not happen. - return NS_ERROR_FAILURE; -} - -already_AddRefed<Promise> -VRDisplay::ExitPresent(ErrorResult& aRv) -{ - nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject()); - if (!global) { - aRv.Throw(NS_ERROR_FAILURE); - return nullptr; - } - - - RefPtr<Promise> promise = Promise::Create(global, aRv); - NS_ENSURE_TRUE(!aRv.Failed(), nullptr); - - if (!IsPresenting()) { - // We can not exit a presentation outside of the context that - // started the presentation. - promise->MaybeRejectWithUndefined(); - } else { - promise->MaybeResolve(JS::UndefinedHandleValue); - ExitPresentInternal(); - } - - return promise.forget(); -} - -void -VRDisplay::ExitPresentInternal() -{ - mPresentation = nullptr; -} - -void -VRDisplay::GetLayers(nsTArray<VRLayer>& result) -{ - if (mPresentation) { - mPresentation->GetDOMLayers(result); - } else { - result = nsTArray<VRLayer>(); - } -} - -void -VRDisplay::SubmitFrame() -{ - if (mPresentation) { - mPresentation->SubmitFrame(); - } - mFrameInfo.Clear(); -} - -int32_t -VRDisplay::RequestAnimationFrame(FrameRequestCallback& aCallback, -ErrorResult& aError) -{ - gfx::VRManagerChild* vm = gfx::VRManagerChild::Get(); - - int32_t handle; - aError = vm->ScheduleFrameRequestCallback(aCallback, &handle); - return handle; -} - -void -VRDisplay::CancelAnimationFrame(int32_t aHandle, ErrorResult& aError) -{ - gfx::VRManagerChild* vm = gfx::VRManagerChild::Get(); - vm->CancelFrameRequestCallback(aHandle); -} - - -bool -VRDisplay::IsPresenting() const -{ - // IsPresenting returns true only if this Javascript context is presenting - // and will return false if another context is presenting. - return mPresentation != nullptr; -} - -bool -VRDisplay::IsConnected() const -{ - return mClient->GetIsConnected(); -} - -NS_IMPL_CYCLE_COLLECTION_INHERITED(VRDisplay, DOMEventTargetHelper, mCapabilities, mStageParameters) - -NS_IMPL_ADDREF_INHERITED(VRDisplay, DOMEventTargetHelper) -NS_IMPL_RELEASE_INHERITED(VRDisplay, DOMEventTargetHelper) - -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(VRDisplay) -NS_INTERFACE_MAP_ENTRY(nsIObserver) -NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, DOMEventTargetHelper) -NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) - -NS_IMPL_CYCLE_COLLECTION_CLASS(VRFrameData) - -NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(VRFrameData) - NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent, mPose) - NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER - tmp->mLeftProjectionMatrix = nullptr; - tmp->mLeftViewMatrix = nullptr; - tmp->mRightProjectionMatrix = nullptr; - tmp->mRightViewMatrix = nullptr; -NS_IMPL_CYCLE_COLLECTION_UNLINK_END - -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(VRFrameData) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent, mPose) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END - -NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(VRFrameData) - NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER - NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mLeftProjectionMatrix) - NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mLeftViewMatrix) - NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mRightProjectionMatrix) - NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mRightViewMatrix) -NS_IMPL_CYCLE_COLLECTION_TRACE_END - -NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(VRFrameData, AddRef) -NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(VRFrameData, Release) - -VRFrameData::VRFrameData(nsISupports* aParent) - : mParent(aParent) - , mLeftProjectionMatrix(nullptr) - , mLeftViewMatrix(nullptr) - , mRightProjectionMatrix(nullptr) - , mRightViewMatrix(nullptr) -{ - mozilla::HoldJSObjects(this); - mPose = new VRPose(aParent); -} - -VRFrameData::~VRFrameData() -{ - mozilla::DropJSObjects(this); -} - -/* static */ already_AddRefed<VRFrameData> -VRFrameData::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv) -{ - RefPtr<VRFrameData> obj = new VRFrameData(aGlobal.GetAsSupports()); - return obj.forget(); -} - -JSObject* -VRFrameData::WrapObject(JSContext* aCx, - JS::Handle<JSObject*> aGivenProto) -{ - return VRFrameDataBinding::Wrap(aCx, this, aGivenProto); -} - -VRPose* -VRFrameData::Pose() -{ - return mPose; -} - -void -VRFrameData::LazyCreateMatrix(JS::Heap<JSObject*>& aArray, gfx::Matrix4x4& aMat, JSContext* aCx, - JS::MutableHandle<JSObject*> aRetval, ErrorResult& aRv) -{ - if (!aArray) { - // Lazily create the Float32Array - aArray = dom::Float32Array::Create(aCx, this, 16, aMat.components); - if (!aArray) { - aRv.NoteJSContextException(aCx); - return; - } - } - if (aArray) { - JS::ExposeObjectToActiveJS(aArray); - } - aRetval.set(aArray); -} - -double -VRFrameData::Timestamp() const -{ - // Converting from seconds to milliseconds - return mFrameInfo.mVRState.timestamp * 1000.0f; -} - -void -VRFrameData::GetLeftProjectionMatrix(JSContext* aCx, - JS::MutableHandle<JSObject*> aRetval, - ErrorResult& aRv) -{ - LazyCreateMatrix(mLeftProjectionMatrix, mFrameInfo.mLeftProjection, aCx, - aRetval, aRv); -} - -void -VRFrameData::GetLeftViewMatrix(JSContext* aCx, - JS::MutableHandle<JSObject*> aRetval, - ErrorResult& aRv) -{ - LazyCreateMatrix(mLeftViewMatrix, mFrameInfo.mLeftView, aCx, aRetval, aRv); -} - -void -VRFrameData::GetRightProjectionMatrix(JSContext* aCx, - JS::MutableHandle<JSObject*> aRetval, - ErrorResult& aRv) -{ - LazyCreateMatrix(mRightProjectionMatrix, mFrameInfo.mRightProjection, aCx, - aRetval, aRv); -} - -void -VRFrameData::GetRightViewMatrix(JSContext* aCx, - JS::MutableHandle<JSObject*> aRetval, - ErrorResult& aRv) -{ - LazyCreateMatrix(mRightViewMatrix, mFrameInfo.mRightView, aCx, aRetval, aRv); -} - -void -VRFrameData::Update(const VRFrameInfo& aFrameInfo) -{ - mFrameInfo = aFrameInfo; - - mLeftProjectionMatrix = nullptr; - mLeftViewMatrix = nullptr; - mRightProjectionMatrix = nullptr; - mRightViewMatrix = nullptr; - - mPose = new VRPose(GetParentObject(), mFrameInfo.mVRState); -} - -void -VRFrameInfo::Update(const gfx::VRDisplayInfo& aInfo, - const gfx::VRHMDSensorState& aState, - float aDepthNear, - float aDepthFar) -{ - mVRState = aState; - - gfx::Quaternion qt; - if (mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Orientation) { - qt.x = mVRState.orientation[0]; - qt.y = mVRState.orientation[1]; - qt.z = mVRState.orientation[2]; - qt.w = mVRState.orientation[3]; - } - gfx::Point3D pos; - if (mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Position) { - pos.x = -mVRState.position[0]; - pos.y = -mVRState.position[1]; - pos.z = -mVRState.position[2]; - } - gfx::Matrix4x4 matHead; - matHead.SetRotationFromQuaternion(qt); - matHead.PreTranslate(pos); - - mLeftView = matHead; - mLeftView.PostTranslate(-aInfo.mEyeTranslation[gfx::VRDisplayInfo::Eye_Left]); - - mRightView = matHead; - mRightView.PostTranslate(-aInfo.mEyeTranslation[gfx::VRDisplayInfo::Eye_Right]); - - // Avoid division by zero within ConstructProjectionMatrix - const float kEpsilon = 0.00001f; - if (fabs(aDepthFar - aDepthNear) < kEpsilon) { - aDepthFar = aDepthNear + kEpsilon; - } - - const gfx::VRFieldOfView leftFOV = aInfo.mEyeFOV[gfx::VRDisplayInfo::Eye_Left]; - mLeftProjection = leftFOV.ConstructProjectionMatrix(aDepthNear, aDepthFar, true); - const gfx::VRFieldOfView rightFOV = aInfo.mEyeFOV[gfx::VRDisplayInfo::Eye_Right]; - mRightProjection = rightFOV.ConstructProjectionMatrix(aDepthNear, aDepthFar, true); -} - -VRFrameInfo::VRFrameInfo() -{ - mVRState.Clear(); -} - -bool -VRFrameInfo::IsDirty() -{ - return mVRState.timestamp == 0; -} - -void -VRFrameInfo::Clear() -{ - mVRState.Clear(); -} - -} // namespace dom -} // namespace mozilla diff --git a/dom/vr/VRDisplay.h b/dom/vr/VRDisplay.h deleted file mode 100644 index d40d3d8ac..000000000 --- a/dom/vr/VRDisplay.h +++ /dev/null @@ -1,362 +0,0 @@ -/* -*- 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/. */ - -#ifndef mozilla_dom_VRDisplay_h_ -#define mozilla_dom_VRDisplay_h_ - -#include <stdint.h> - -#include "mozilla/ErrorResult.h" -#include "mozilla/dom/TypedArray.h" -#include "mozilla/dom/VRDisplayBinding.h" -#include "mozilla/DOMEventTargetHelper.h" -#include "mozilla/dom/DOMPoint.h" -#include "mozilla/dom/DOMRect.h" -#include "mozilla/dom/Pose.h" - -#include "nsCOMPtr.h" -#include "nsString.h" -#include "nsTArray.h" - -#include "gfxVR.h" - -namespace mozilla { -namespace gfx { -class VRDisplayClient; -class VRDisplayPresentation; -struct VRFieldOfView; -enum class VRDisplayCapabilityFlags : uint16_t; -struct VRHMDSensorState; -} -namespace dom { -class Navigator; - -class VRFieldOfView final : public nsWrapperCache -{ -public: - VRFieldOfView(nsISupports* aParent, - double aUpDegrees, double aRightDegrees, - double aDownDegrees, double aLeftDegrees); - VRFieldOfView(nsISupports* aParent, const gfx::VRFieldOfView& aSrc); - - NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(VRFieldOfView) - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(VRFieldOfView) - - double UpDegrees() const { return mUpDegrees; } - double RightDegrees() const { return mRightDegrees; } - double DownDegrees() const { return mDownDegrees; } - double LeftDegrees() const { return mLeftDegrees; } - - nsISupports* GetParentObject() const { return mParent; } - virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; - -protected: - virtual ~VRFieldOfView() {} - - nsCOMPtr<nsISupports> mParent; - - double mUpDegrees; - double mRightDegrees; - double mDownDegrees; - double mLeftDegrees; -}; - -class VRDisplayCapabilities final : public nsWrapperCache -{ -public: - VRDisplayCapabilities(nsISupports* aParent, const gfx::VRDisplayCapabilityFlags& aFlags) - : mParent(aParent) - , mFlags(aFlags) - { - } - - NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(VRDisplayCapabilities) - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(VRDisplayCapabilities) - - nsISupports* GetParentObject() const - { - return mParent; - } - - virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; - - bool HasPosition() const; - bool HasOrientation() const; - bool HasExternalDisplay() const; - bool CanPresent() const; - uint32_t MaxLayers() const; - -protected: - ~VRDisplayCapabilities() {} - nsCOMPtr<nsISupports> mParent; - gfx::VRDisplayCapabilityFlags mFlags; -}; - -class VRPose final : public Pose -{ - -public: - VRPose(nsISupports* aParent, const gfx::VRHMDSensorState& aState); - explicit VRPose(nsISupports* aParent); - - uint32_t FrameID() const { return mFrameId; } - - virtual void GetPosition(JSContext* aCx, - JS::MutableHandle<JSObject*> aRetval, - ErrorResult& aRv) override; - virtual void GetLinearVelocity(JSContext* aCx, - JS::MutableHandle<JSObject*> aRetval, - ErrorResult& aRv) override; - virtual void GetLinearAcceleration(JSContext* aCx, - JS::MutableHandle<JSObject*> aRetval, - ErrorResult& aRv) override; - virtual void GetOrientation(JSContext* aCx, - JS::MutableHandle<JSObject*> aRetval, - ErrorResult& aRv) override; - virtual void GetAngularVelocity(JSContext* aCx, - JS::MutableHandle<JSObject*> aRetval, - ErrorResult& aRv) override; - virtual void GetAngularAcceleration(JSContext* aCx, - JS::MutableHandle<JSObject*> aRetval, - ErrorResult& aRv) override; - - virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; - -protected: - ~VRPose(); - - uint32_t mFrameId; - gfx::VRHMDSensorState mVRState; -}; - -struct VRFrameInfo -{ - VRFrameInfo(); - - void Update(const gfx::VRDisplayInfo& aInfo, - const gfx::VRHMDSensorState& aState, - float aDepthNear, - float aDepthFar); - - void Clear(); - bool IsDirty(); - - gfx::VRHMDSensorState mVRState; - gfx::Matrix4x4 mLeftProjection; - gfx::Matrix4x4 mLeftView; - gfx::Matrix4x4 mRightProjection; - gfx::Matrix4x4 mRightView; - -}; - -class VRFrameData final : public nsWrapperCache -{ -public: - NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(VRFrameData) - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(VRFrameData) - - explicit VRFrameData(nsISupports* aParent); - static already_AddRefed<VRFrameData> Constructor(const GlobalObject& aGlobal, - ErrorResult& aRv); - - void Update(const VRFrameInfo& aFrameInfo); - - // WebIDL Members - double Timestamp() const; - void GetLeftProjectionMatrix(JSContext* aCx, - JS::MutableHandle<JSObject*> aRetval, - ErrorResult& aRv); - void GetLeftViewMatrix(JSContext* aCx, - JS::MutableHandle<JSObject*> aRetval, - ErrorResult& aRv); - void GetRightProjectionMatrix(JSContext* aCx, - JS::MutableHandle<JSObject*> aRetval, - ErrorResult& aRv); - void GetRightViewMatrix(JSContext* aCx, - JS::MutableHandle<JSObject*> aRetval, - ErrorResult& aRv); - - VRPose* Pose(); - - // WebIDL Boilerplate - nsISupports* GetParentObject() const { return mParent; } - virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; - -protected: - ~VRFrameData(); - nsCOMPtr<nsISupports> mParent; - - VRFrameInfo mFrameInfo; - RefPtr<VRPose> mPose; - JS::Heap<JSObject*> mLeftProjectionMatrix; - JS::Heap<JSObject*> mLeftViewMatrix; - JS::Heap<JSObject*> mRightProjectionMatrix; - JS::Heap<JSObject*> mRightViewMatrix; - - void LazyCreateMatrix(JS::Heap<JSObject*>& aArray, gfx::Matrix4x4& aMat, - JSContext* aCx, JS::MutableHandle<JSObject*> aRetval, - ErrorResult& aRv); -}; - -class VRStageParameters final : public nsWrapperCache -{ -public: - VRStageParameters(nsISupports* aParent, - const gfx::Matrix4x4& aSittingToStandingTransform, - const gfx::Size& aSize); - - NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(VRStageParameters) - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(VRStageParameters) - - void GetSittingToStandingTransform(JSContext* aCx, - JS::MutableHandle<JSObject*> aRetval, - ErrorResult& aRv); - float SizeX() const { return mSize.width; } - float SizeZ() const { return mSize.height; } - - nsISupports* GetParentObject() const { return mParent; } - virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; - -protected: - ~VRStageParameters(); - - nsCOMPtr<nsISupports> mParent; - - gfx::Matrix4x4 mSittingToStandingTransform; - JS::Heap<JSObject*> mSittingToStandingTransformArray; - gfx::Size mSize; -}; - -class VREyeParameters final : public nsWrapperCache -{ -public: - VREyeParameters(nsISupports* aParent, - const gfx::Point3D& aEyeTranslation, - const gfx::VRFieldOfView& aFOV, - const gfx::IntSize& aRenderSize); - - NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(VREyeParameters) - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(VREyeParameters) - - void GetOffset(JSContext* aCx, JS::MutableHandle<JSObject*> aRetVal, - ErrorResult& aRv); - - VRFieldOfView* FieldOfView(); - - uint32_t RenderWidth() const { return mRenderSize.width; } - uint32_t RenderHeight() const { return mRenderSize.height; } - - nsISupports* GetParentObject() const { return mParent; } - virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; -protected: - ~VREyeParameters(); - - nsCOMPtr<nsISupports> mParent; - - - gfx::Point3D mEyeTranslation; - gfx::IntSize mRenderSize; - JS::Heap<JSObject*> mOffset; - RefPtr<VRFieldOfView> mFOV; -}; - -class VRDisplay final : public DOMEventTargetHelper - , public nsIObserver -{ -public: - NS_DECL_ISUPPORTS_INHERITED - NS_DECL_NSIOBSERVER - NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(VRDisplay, DOMEventTargetHelper) - - virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; - - bool IsPresenting() const; - bool IsConnected() const; - - VRDisplayCapabilities* Capabilities(); - VRStageParameters* GetStageParameters(); - - uint32_t DisplayId() const { return mDisplayId; } - void GetDisplayName(nsAString& aDisplayName) const { aDisplayName = mDisplayName; } - - static bool RefreshVRDisplays(uint64_t aWindowId); - static void UpdateVRDisplays(nsTArray<RefPtr<VRDisplay> >& aDisplays, - nsPIDOMWindowInner* aWindow); - - gfx::VRDisplayClient *GetClient() { - return mClient; - } - - virtual already_AddRefed<VREyeParameters> GetEyeParameters(VREye aEye); - - bool GetFrameData(VRFrameData& aFrameData); - already_AddRefed<VRPose> GetPose(); - void ResetPose(); - - double DepthNear() { - return mDepthNear; - } - - double DepthFar() { - return mDepthFar; - } - - void SetDepthNear(double aDepthNear) { - // XXX When we start sending depth buffers to VRLayer's we will want - // to communicate this with the VRDisplayHost - mDepthNear = aDepthNear; - } - - void SetDepthFar(double aDepthFar) { - // XXX When we start sending depth buffers to VRLayer's we will want - // to communicate this with the VRDisplayHost - mDepthFar = aDepthFar; - } - - already_AddRefed<Promise> RequestPresent(const nsTArray<VRLayer>& aLayers, ErrorResult& aRv); - already_AddRefed<Promise> ExitPresent(ErrorResult& aRv); - void GetLayers(nsTArray<VRLayer>& result); - void SubmitFrame(); - - int32_t RequestAnimationFrame(mozilla::dom::FrameRequestCallback& aCallback, - mozilla::ErrorResult& aError); - void CancelAnimationFrame(int32_t aHandle, mozilla::ErrorResult& aError); - -protected: - VRDisplay(nsPIDOMWindowInner* aWindow, gfx::VRDisplayClient* aClient); - virtual ~VRDisplay(); - virtual void LastRelease() override; - - void ExitPresentInternal(); - void UpdateFrameInfo(); - - RefPtr<gfx::VRDisplayClient> mClient; - - uint32_t mDisplayId; - nsString mDisplayName; - - RefPtr<VRDisplayCapabilities> mCapabilities; - RefPtr<VRStageParameters> mStageParameters; - - double mDepthNear; - double mDepthFar; - - RefPtr<gfx::VRDisplayPresentation> mPresentation; - - /** - * The WebVR 1.1 spec Requires that VRDisplay.getPose and VRDisplay.getFrameData - * must return the same values until the next VRDisplay.submitFrame. - * mFrameInfo is updated only on the first call to either function within one - * frame. Subsequent calls before the next SubmitFrame or ExitPresent call - * will use these cached values. - */ - VRFrameInfo mFrameInfo; -}; - -} // namespace dom -} // namespace mozilla - -#endif diff --git a/dom/vr/VREventObserver.cpp b/dom/vr/VREventObserver.cpp deleted file mode 100644 index 1b6d1b978..000000000 --- a/dom/vr/VREventObserver.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* -*- 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 "VREventObserver.h" - -#include "nsContentUtils.h" -#include "nsGlobalWindow.h" -#include "VRManagerChild.h" - -namespace mozilla { -namespace dom { - -using namespace gfx; - -/** - * This class is used by nsGlobalWindow to implement window.onvrdisplayconnected, - * window.onvrdisplaydisconnected, and window.onvrdisplaypresentchange. - */ -VREventObserver::VREventObserver(nsGlobalWindow* aGlobalWindow) - : mWindow(aGlobalWindow) -{ - MOZ_ASSERT(aGlobalWindow && aGlobalWindow->IsInnerWindow()); - - VRManagerChild* vmc = VRManagerChild::Get(); - if (vmc) { - vmc->AddListener(this); - } -} - -VREventObserver::~VREventObserver() -{ - VRManagerChild* vmc = VRManagerChild::Get(); - if (vmc) { - vmc->RemoveListener(this); - } -} - -void -VREventObserver::NotifyVRDisplayConnect() -{ - /** - * We do not call nsGlobalWindow::NotifyActiveVRDisplaysChanged here, as we - * can assume that a newly enumerated display is not presenting WebVR - * content. - */ - if (mWindow->AsInner()->IsCurrentInnerWindow()) { - MOZ_ASSERT(nsContentUtils::IsSafeToRunScript()); - mWindow->GetOuterWindow()->DispatchCustomEvent( - NS_LITERAL_STRING("vrdisplayconnected")); - } -} - -void -VREventObserver::NotifyVRDisplayDisconnect() -{ - if (mWindow->AsInner()->IsCurrentInnerWindow()) { - mWindow->NotifyActiveVRDisplaysChanged(); - MOZ_ASSERT(nsContentUtils::IsSafeToRunScript()); - mWindow->GetOuterWindow()->DispatchCustomEvent( - NS_LITERAL_STRING("vrdisplaydisconnected")); - } -} - -void -VREventObserver::NotifyVRDisplayPresentChange() -{ - if (mWindow->AsInner()->IsCurrentInnerWindow()) { - mWindow->NotifyActiveVRDisplaysChanged(); - MOZ_ASSERT(nsContentUtils::IsSafeToRunScript()); - mWindow->GetOuterWindow()->DispatchCustomEvent( - NS_LITERAL_STRING("vrdisplaypresentchange")); - } -} - -} // namespace dom -} // namespace mozilla diff --git a/dom/vr/VREventObserver.h b/dom/vr/VREventObserver.h deleted file mode 100644 index a30bb5960..000000000 --- a/dom/vr/VREventObserver.h +++ /dev/null @@ -1,33 +0,0 @@ -/* -*- 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/. */ - -#ifndef mozilla_dom_VREventObserver_h -#define mozilla_dom_VREventObserver_h - -class nsGlobalWindow; - -namespace mozilla { -namespace dom { - -class VREventObserver final -{ -public: - ~VREventObserver(); - explicit VREventObserver(nsGlobalWindow* aGlobalWindow); - - void NotifyVRDisplayConnect(); - void NotifyVRDisplayDisconnect(); - void NotifyVRDisplayPresentChange(); - -private: - // Weak pointer, instance is owned by mWindow. - nsGlobalWindow* MOZ_NON_OWNING_REF mWindow; -}; - -} // namespace dom -} // namespace mozilla - -#endif // mozilla_dom_VREventObserver_h diff --git a/dom/vr/moz.build b/dom/vr/moz.build deleted file mode 100644 index a4aa8d69b..000000000 --- a/dom/vr/moz.build +++ /dev/null @@ -1,22 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# 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/. - -EXPORTS.mozilla.dom += [ - 'VRDisplay.h', - 'VREventObserver.h', - ] - -UNIFIED_SOURCES = [ - 'VRDisplay.cpp', - 'VREventObserver.cpp', - ] - -include('/ipc/chromium/chromium-config.mozbuild') - -FINAL_LIBRARY = 'xul' -LOCAL_INCLUDES += [ - '/dom/base' -] diff --git a/dom/webidl/AddonEvent.webidl b/dom/webidl/AddonEvent.webidl deleted file mode 100644 index 235f81ec2..000000000 --- a/dom/webidl/AddonEvent.webidl +++ /dev/null @@ -1,12 +0,0 @@ -[ Func="mozilla::AddonManagerWebAPI::IsAPIEnabled", - Constructor(DOMString type, AddonEventInit eventInitDict)] -interface AddonEvent : Event { - readonly attribute DOMString id; - readonly attribute boolean needsRestart; -}; - -dictionary AddonEventInit : EventInit { - required DOMString id; - required boolean needsRestart; -}; - diff --git a/dom/webidl/AddonManager.webidl b/dom/webidl/AddonManager.webidl deleted file mode 100644 index 02c7953e6..000000000 --- a/dom/webidl/AddonManager.webidl +++ /dev/null @@ -1,91 +0,0 @@ -/* 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/. - */ - -/* We need a JSImplementation but cannot get one without a contract ID. - Since Addon and AddonInstall are only ever created from JS they don't need - real contract IDs. */ -[ChromeOnly, JSImplementation="dummy"] -interface Addon { - // The add-on's ID. - readonly attribute DOMString id; - // The add-on's version. - readonly attribute DOMString version; - // The add-on's type (extension, theme, etc.). - readonly attribute DOMString type; - // The add-on's name in the current locale. - readonly attribute DOMString name; - // The add-on's description in the current locale. - readonly attribute DOMString description; - // If the user has enabled this add-on, note that it still may not be running - // depending on whether enabling requires a restart or if the add-on is - // incompatible in some way. - readonly attribute boolean isEnabled; - // If the add-on is currently active in the browser. - readonly attribute boolean isActive; - // If the add-on may be uninstalled - readonly attribute boolean canUninstall; - - Promise<boolean> uninstall(); - Promise<void> setEnabled(boolean value); -}; - -[ChromeOnly, JSImplementation="dummy"] -interface AddonInstall : EventTarget { - // One of the STATE_* symbols from AddonManager.jsm - readonly attribute DOMString state; - // One of the ERROR_* symbols from AddonManager.jsm, or null - readonly attribute DOMString? error; - // How many bytes have been downloaded - readonly attribute long long progress; - // How many total bytes will need to be downloaded or -1 if unknown - readonly attribute long long maxProgress; - - Promise<void> install(); - Promise<void> cancel(); -}; - -dictionary addonInstallOptions { - required DOMString url; - // If a non-empty string is passed for "hash", it is used to verify the - // checksum of the downloaded XPI before installing. If is omitted or if - // it is null or empty string, no checksum verification is performed. - DOMString? hash = null; -}; - -[HeaderFile="mozilla/AddonManagerWebAPI.h", - Func="mozilla::AddonManagerWebAPI::IsAPIEnabled", - NavigatorProperty="mozAddonManager", - JSImplementation="@mozilla.org/addon-web-api/manager;1"] -interface AddonManager : EventTarget { - /** - * Gets information about an add-on - * - * @param id - * The ID of the add-on to test for. - * @return A promise. It will resolve to an Addon if the add-on is installed. - */ - Promise<Addon> getAddonByID(DOMString id); - - /** - * Creates an AddonInstall object for a given URL. - * - * @param options - * Only one supported option: 'url', the URL of the addon to install. - * @return A promise that resolves to an instance of AddonInstall. - */ - Promise<AddonInstall> createInstall(optional addonInstallOptions options); - - /* Hooks for managing event listeners */ - [ChromeOnly] - void eventListenerWasAdded(DOMString type); - [ChromeOnly] - void eventListenerWasRemoved(DOMString type); -}; - -[ChromeOnly,Exposed=System,HeaderFile="mozilla/AddonManagerWebAPI.h"] -interface AddonManagerPermissions { - static boolean isHostPermitted(DOMString host); -}; - diff --git a/dom/webidl/AudioContext.webidl b/dom/webidl/AudioContext.webidl index c2f65abaf..9aa3d5567 100644 --- a/dom/webidl/AudioContext.webidl +++ b/dom/webidl/AudioContext.webidl @@ -24,7 +24,6 @@ dictionary PeriodicWaveConstraints { }; [Constructor, - Constructor(AudioChannel audioChannelType), Pref="dom.webaudio.enabled"] interface AudioContext : EventTarget { diff --git a/dom/webidl/CommandEvent.webidl b/dom/webidl/CommandEvent.webidl index 8c16e856c..9856c77c3 100644 --- a/dom/webidl/CommandEvent.webidl +++ b/dom/webidl/CommandEvent.webidl @@ -8,7 +8,7 @@ interface CommandEvent : Event { readonly attribute DOMString? command; void initCommandEvent(DOMString type, - boolean canBubble, - boolean cancelable, - DOMString? command); + optional boolean canBubble = false, + optional boolean cancelable = false, + optional DOMString? command = null); }; diff --git a/dom/webidl/CompositionEvent.webidl b/dom/webidl/CompositionEvent.webidl index c293683ce..e4a54d678 100644 --- a/dom/webidl/CompositionEvent.webidl +++ b/dom/webidl/CompositionEvent.webidl @@ -25,9 +25,9 @@ interface CompositionEvent : UIEvent partial interface CompositionEvent { void initCompositionEvent(DOMString typeArg, - boolean canBubbleArg, - boolean cancelableArg, - Window? viewArg, - DOMString? dataArg, - DOMString localeArg); + optional boolean canBubbleArg = false, + optional boolean cancelableArg = false, + optional Window? viewArg = null, + optional DOMString? dataArg = null, + optional DOMString localeArg = ""); }; diff --git a/dom/webidl/CustomEvent.webidl b/dom/webidl/CustomEvent.webidl index 299a41ec0..1ea5572b7 100644 --- a/dom/webidl/CustomEvent.webidl +++ b/dom/webidl/CustomEvent.webidl @@ -19,9 +19,9 @@ interface CustomEvent : Event // initCustomEvent is a Gecko specific deprecated method. [Throws] void initCustomEvent(DOMString type, - boolean canBubble, - boolean cancelable, - any detail); + optional boolean canBubble = false, + optional boolean cancelable = false, + optional any detail = null); }; dictionary CustomEventInit : EventInit diff --git a/dom/webidl/DeviceMotionEvent.webidl b/dom/webidl/DeviceMotionEvent.webidl index fa4ecf3ca..c26ab080c 100644 --- a/dom/webidl/DeviceMotionEvent.webidl +++ b/dom/webidl/DeviceMotionEvent.webidl @@ -48,10 +48,10 @@ dictionary DeviceMotionEventInit : EventInit { // Mozilla extensions. partial interface DeviceMotionEvent { void initDeviceMotionEvent(DOMString type, - boolean canBubble, - boolean cancelable, - DeviceAccelerationInit acceleration, - DeviceAccelerationInit accelerationIncludingGravity, - DeviceRotationRateInit rotationRate, - double? interval); + optional boolean canBubble = false, + optional boolean cancelable = false, + optional DeviceAccelerationInit acceleration, + optional DeviceAccelerationInit accelerationIncludingGravity, + optional DeviceRotationRateInit rotationRate, + optional double? interval = null); }; diff --git a/dom/webidl/DeviceOrientationEvent.webidl b/dom/webidl/DeviceOrientationEvent.webidl index 46194453e..9802b3681 100644 --- a/dom/webidl/DeviceOrientationEvent.webidl +++ b/dom/webidl/DeviceOrientationEvent.webidl @@ -14,12 +14,12 @@ interface DeviceOrientationEvent : Event // initDeviceOrientationEvent is a Gecko specific deprecated method. void initDeviceOrientationEvent(DOMString type, - boolean canBubble, - boolean cancelable, - double? alpha, - double? beta, - double? gamma, - boolean absolute); + optional boolean canBubble = false, + optional boolean cancelable = false, + optional double? alpha = null, + optional double? beta = null, + optional double? gamma = null, + optional boolean absolute = false); }; dictionary DeviceOrientationEventInit : EventInit diff --git a/dom/webidl/DragEvent.webidl b/dom/webidl/DragEvent.webidl index 2cc173d5c..806177790 100644 --- a/dom/webidl/DragEvent.webidl +++ b/dom/webidl/DragEvent.webidl @@ -10,21 +10,21 @@ interface DragEvent : MouseEvent readonly attribute DataTransfer? dataTransfer; void initDragEvent(DOMString type, - boolean canBubble, - boolean cancelable, - Window? aView, - long aDetail, - long aScreenX, - long aScreenY, - long aClientX, - long aClientY, - boolean aCtrlKey, - boolean aAltKey, - boolean aShiftKey, - boolean aMetaKey, - unsigned short aButton, - EventTarget? aRelatedTarget, - DataTransfer? aDataTransfer); + optional boolean canBubble = false, + optional boolean cancelable = false, + optional Window? aView = null, + optional long aDetail = 0, + optional long aScreenX = 0, + optional long aScreenY = 0, + optional long aClientX = 0, + optional long aClientY = 0, + optional boolean aCtrlKey = false, + optional boolean aAltKey = false, + optional boolean aShiftKey = false, + optional boolean aMetaKey = false, + optional unsigned short aButton = 0, + optional EventTarget? aRelatedTarget = null, + optional DataTransfer? aDataTransfer = null); }; dictionary DragEventInit : MouseEventInit diff --git a/dom/webidl/Element.webidl b/dom/webidl/Element.webidl index 97eb4ffe0..cf17523a5 100644 --- a/dom/webidl/Element.webidl +++ b/dom/webidl/Element.webidl @@ -164,9 +164,10 @@ interface Element : Node { }; // http://dev.w3.org/csswg/cssom-view/ -enum ScrollLogicalPosition { "start", "end" }; +enum ScrollLogicalPosition { "start", "center", "end", "nearest" }; dictionary ScrollIntoViewOptions : ScrollOptions { ScrollLogicalPosition block = "start"; + ScrollLogicalPosition inline = "nearest"; }; // http://dev.w3.org/csswg/cssom-view/#extensions-to-the-element-interface @@ -175,8 +176,7 @@ partial interface Element { DOMRect getBoundingClientRect(); // scrolling - void scrollIntoView(boolean top); - void scrollIntoView(optional ScrollIntoViewOptions options); + void scrollIntoView(optional (boolean or ScrollIntoViewOptions) arg); // None of the CSSOM attributes are [Pure], because they flush attribute long scrollTop; // scroll on setting attribute long scrollLeft; // scroll on setting diff --git a/dom/webidl/Event.webidl b/dom/webidl/Event.webidl index 70a0ef513..a5d7da7d4 100644 --- a/dom/webidl/Event.webidl +++ b/dom/webidl/Event.webidl @@ -51,7 +51,9 @@ interface Event { [Pure] readonly attribute DOMHighResTimeStamp timeStamp; - void initEvent(DOMString type, boolean bubbles, boolean cancelable); + void initEvent(DOMString type, + optional boolean bubbles = false, + optional boolean cancelable = false); attribute boolean cancelBubble; }; diff --git a/dom/webidl/HashChangeEvent.webidl b/dom/webidl/HashChangeEvent.webidl index 735e8eb28..6e8be455c 100644 --- a/dom/webidl/HashChangeEvent.webidl +++ b/dom/webidl/HashChangeEvent.webidl @@ -11,10 +11,10 @@ interface HashChangeEvent : Event readonly attribute DOMString newURL; void initHashChangeEvent(DOMString typeArg, - boolean canBubbleArg, - boolean cancelableArg, - DOMString oldURLArg, - DOMString newURLArg); + optional boolean canBubbleArg = false, + optional boolean cancelableArg = false, + optional DOMString oldURLArg = "", + optional DOMString newURLArg = ""); }; dictionary HashChangeEventInit : EventInit diff --git a/dom/webidl/Headers.webidl b/dom/webidl/Headers.webidl index 205ab9f9e..eef552a7f 100644 --- a/dom/webidl/Headers.webidl +++ b/dom/webidl/Headers.webidl @@ -8,7 +8,7 @@ * http://fetch.spec.whatwg.org/#headers-class */ -typedef (Headers or sequence<sequence<ByteString>> or MozMap<ByteString>) HeadersInit; +typedef (Headers or sequence<sequence<ByteString>> or record<ByteString, ByteString>) HeadersInit; enum HeadersGuardEnum { "none", diff --git a/dom/webidl/InstallTrigger.webidl b/dom/webidl/InstallTrigger.webidl index 789fb2bc4..68f48ddc6 100644 --- a/dom/webidl/InstallTrigger.webidl +++ b/dom/webidl/InstallTrigger.webidl @@ -57,7 +57,7 @@ interface InstallTriggerImpl { * A callback to call as each installation succeeds or fails * @return true if the installations were successfully started */ - boolean install(MozMap<(DOMString or InstallTriggerData)> installs, + boolean install(record<DOMString, (DOMString or InstallTriggerData)> installs, optional InstallTriggerCallback callback); /** diff --git a/dom/webidl/IntersectionObserver.webidl b/dom/webidl/IntersectionObserver.webidl index dbe8f428d..83200d950 100644 --- a/dom/webidl/IntersectionObserver.webidl +++ b/dom/webidl/IntersectionObserver.webidl @@ -7,7 +7,7 @@ * https://wicg.github.io/IntersectionObserver/ */ -[ProbablyShortLivingObject, Pref="dom.IntersectionObserver.enabled"] +[ProbablyShortLivingObject, Pref="dom.intersectionObserver.enabled"] interface IntersectionObserverEntry { [Constant] readonly attribute DOMHighResTimeStamp time; @@ -18,6 +18,8 @@ interface IntersectionObserverEntry { [Constant] readonly attribute DOMRectReadOnly intersectionRect; [Constant] + readonly attribute boolean isIntersecting; + [Constant] readonly attribute double intersectionRatio; [Constant] readonly attribute Element target; @@ -25,7 +27,7 @@ interface IntersectionObserverEntry { [Constructor(IntersectionCallback intersectionCallback, optional IntersectionObserverInit options), - Pref="dom.IntersectionObserver.enabled"] + Pref="dom.intersectionObserver.enabled"] interface IntersectionObserver { [Constant] readonly attribute Element? root; diff --git a/dom/webidl/KeyEvent.webidl b/dom/webidl/KeyEvent.webidl index 516632854..abb4b6a34 100644 --- a/dom/webidl/KeyEvent.webidl +++ b/dom/webidl/KeyEvent.webidl @@ -225,13 +225,13 @@ interface KeyEvent const unsigned long DOM_VK_WIN_OEM_CLEAR = 0xFE; void initKeyEvent(DOMString type, - boolean canBubble, - boolean cancelable, - Window? view, - boolean ctrlKey, - boolean altKey, - boolean shiftKey, - boolean metaKey, - unsigned long keyCode, - unsigned long charCode); + optional boolean canBubble = false, + optional boolean cancelable = false, + optional Window? view = null, + optional boolean ctrlKey = false, + optional boolean altKey = false, + optional boolean shiftKey = false, + optional boolean metaKey = false, + optional unsigned long keyCode = 0, + optional unsigned long charCode = 0); }; diff --git a/dom/webidl/MessageEvent.webidl b/dom/webidl/MessageEvent.webidl index 548f14520..be5022d67 100644 --- a/dom/webidl/MessageEvent.webidl +++ b/dom/webidl/MessageEvent.webidl @@ -43,10 +43,14 @@ interface MessageEvent : Event { [Pure, Cached, Frozen] readonly attribute sequence<MessagePort> ports; - void initMessageEvent(DOMString type, boolean bubbles, boolean cancelable, - any data, DOMString origin, DOMString lastEventId, - (WindowProxy or MessagePort)? source, - sequence<MessagePort> ports); + void initMessageEvent(DOMString type, + optional boolean bubbles = false, + optional boolean cancelable = false, + optional any data = null, + optional DOMString origin = "", + optional DOMString lastEventId = "", + optional (WindowProxy or MessagePort)? source = null, + optional sequence<MessagePort> ports = []); }; dictionary MessageEventInit : EventInit { diff --git a/dom/webidl/MouseEvent.webidl b/dom/webidl/MouseEvent.webidl index d21354801..192519d57 100644 --- a/dom/webidl/MouseEvent.webidl +++ b/dom/webidl/MouseEvent.webidl @@ -32,21 +32,21 @@ interface MouseEvent : UIEvent { readonly attribute long movementY; // Deprecated in DOM Level 3: - void initMouseEvent(DOMString typeArg, - boolean canBubbleArg, - boolean cancelableArg, - Window? viewArg, - long detailArg, - long screenXArg, - long screenYArg, - long clientXArg, - long clientYArg, - boolean ctrlKeyArg, - boolean altKeyArg, - boolean shiftKeyArg, - boolean metaKeyArg, - short buttonArg, - EventTarget? relatedTargetArg); +void initMouseEvent(DOMString typeArg, + optional boolean canBubbleArg = false, + optional boolean cancelableArg = false, + optional Window? viewArg = null, + optional long detailArg = 0, + optional long screenXArg = 0, + optional long screenYArg = 0, + optional long clientXArg = 0, + optional long clientYArg = 0, + optional boolean ctrlKeyArg = false, + optional boolean altKeyArg = false, + optional boolean shiftKeyArg = false, + optional boolean metaKeyArg = false, + optional short buttonArg = 0, + optional EventTarget? relatedTargetArg = null); // Introduced in DOM Level 3: boolean getModifierState(DOMString keyArg); }; @@ -90,23 +90,23 @@ partial interface MouseEvent readonly attribute unsigned short mozInputSource; - void initNSMouseEvent(DOMString typeArg, - boolean canBubbleArg, - boolean cancelableArg, - Window? viewArg, - long detailArg, - long screenXArg, - long screenYArg, - long clientXArg, - long clientYArg, - boolean ctrlKeyArg, - boolean altKeyArg, - boolean shiftKeyArg, - boolean metaKeyArg, - short buttonArg, - EventTarget? relatedTargetArg, - float pressure, - unsigned short inputSourceArg); + void initNSMouseEvent(DOMString typeArg, + optional boolean canBubbleArg = false, + optional boolean cancelableArg = false, + optional Window? viewArg = null, + optional long detailArg = 0, + optional long screenXArg = 0, + optional long screenYArg = 0, + optional long clientXArg = 0, + optional long clientYArg = 0, + optional boolean ctrlKeyArg = false, + optional boolean altKeyArg = false, + optional boolean shiftKeyArg = false, + optional boolean metaKeyArg = false, + optional short buttonArg = 0, + optional EventTarget? relatedTargetArg = null, + optional float pressure = 0, + optional unsigned short inputSourceArg = 0); [ChromeOnly] readonly attribute boolean hitCluster; // True when touch occurs in a cluster of links diff --git a/dom/webidl/MouseScrollEvent.webidl b/dom/webidl/MouseScrollEvent.webidl index aa9e30fd2..c1e52bd8c 100644 --- a/dom/webidl/MouseScrollEvent.webidl +++ b/dom/webidl/MouseScrollEvent.webidl @@ -12,19 +12,19 @@ interface MouseScrollEvent : MouseEvent readonly attribute long axis; void initMouseScrollEvent(DOMString type, - boolean canBubble, - boolean cancelable, - Window? view, - long detail, - long screenX, - long screenY, - long clientX, - long clientY, - boolean ctrlKey, - boolean altKey, - boolean shiftKey, - boolean metaKey, - unsigned short button, - EventTarget? relatedTarget, - long axis); + optional boolean canBubble = false, + optional boolean cancelable = false, + optional Window? view = null, + optional long detail = 0, + optional long screenX = 0, + optional long screenY = 0, + optional long clientX = 0, + optional long clientY = 0, + optional boolean ctrlKey = false, + optional boolean altKey = false, + optional boolean shiftKey = false, + optional boolean metaKey = false, + optional short button = 0, + optional EventTarget? relatedTarget = null, + optional long axis = 0); }; diff --git a/dom/webidl/MutationEvent.webidl b/dom/webidl/MutationEvent.webidl index 43c7b1cd0..53625b4f9 100644 --- a/dom/webidl/MutationEvent.webidl +++ b/dom/webidl/MutationEvent.webidl @@ -23,11 +23,11 @@ interface MutationEvent : Event [Throws] void initMutationEvent(DOMString type, - boolean canBubble, - boolean cancelable, - Node? relatedNode, - DOMString prevValue, - DOMString newValue, - DOMString attrName, - unsigned short attrChange); + optional boolean canBubble = false, + optional boolean cancelable = false, + optional Node? relatedNode = null, + optional DOMString prevValue = "", + optional DOMString newValue = "", + optional DOMString attrName = "", + optional unsigned short attrChange = 0); }; diff --git a/dom/webidl/Navigator.webidl b/dom/webidl/Navigator.webidl index 5452f3247..c353e8be7 100644 --- a/dom/webidl/Navigator.webidl +++ b/dom/webidl/Navigator.webidl @@ -268,14 +268,6 @@ partial interface Navigator { }; #endif // MOZ_GAMEPAD -partial interface Navigator { - [Throws, Pref="dom.vr.enabled"] - Promise<sequence<VRDisplay>> getVRDisplays(); - // TODO: Use FrozenArray once available. (Bug 1236777) - [Frozen, Cached, Pure, Pref="dom.vr.enabled"] - readonly attribute sequence<VRDisplay> activeVRDisplays; -}; - #ifdef MOZ_TIME_MANAGER // nsIDOMMozNavigatorTime partial interface Navigator { diff --git a/dom/webidl/ScrollAreaEvent.webidl b/dom/webidl/ScrollAreaEvent.webidl index 0f48b4bc8..f24b7c0ad 100644 --- a/dom/webidl/ScrollAreaEvent.webidl +++ b/dom/webidl/ScrollAreaEvent.webidl @@ -12,12 +12,12 @@ interface ScrollAreaEvent : UIEvent readonly attribute float height; void initScrollAreaEvent(DOMString type, - boolean canBubble, - boolean cancelable, - Window? view, - long detail, - float x, - float y, - float width, - float height); + optional boolean canBubble = false, + optional boolean cancelable = false, + optional Window? view = null, + optional long detail = 0, + optional float x = 0, + optional float y = 0, + optional float width = 0, + optional float height = 0); }; diff --git a/dom/webidl/SimpleGestureEvent.webidl b/dom/webidl/SimpleGestureEvent.webidl index 0829076dd..76d0d20f6 100644 --- a/dom/webidl/SimpleGestureEvent.webidl +++ b/dom/webidl/SimpleGestureEvent.webidl @@ -25,22 +25,22 @@ interface SimpleGestureEvent : MouseEvent readonly attribute unsigned long clickCount; void initSimpleGestureEvent(DOMString typeArg, - boolean canBubbleArg, - boolean cancelableArg, - Window? viewArg, - long detailArg, - long screenXArg, - long screenYArg, - long clientXArg, - long clientYArg, - boolean ctrlKeyArg, - boolean altKeyArg, - boolean shiftKeyArg, - boolean metaKeyArg, - unsigned short buttonArg, - EventTarget? relatedTargetArg, - unsigned long allowedDirectionsArg, - unsigned long directionArg, - double deltaArg, - unsigned long clickCount); + optional boolean canBubbleArg = false, + optional boolean cancelableArg = false, + optional Window? viewArg = null, + optional long detailArg = 0, + optional long screenXArg = 0, + optional long screenYArg = 0, + optional long clientXArg = 0, + optional long clientYArg = 0, + optional boolean ctrlKeyArg = false, + optional boolean altKeyArg = false, + optional boolean shiftKeyArg = false, + optional boolean metaKeyArg = false, + optional short buttonArg = 0, + optional EventTarget? relatedTargetArg = null, + optional unsigned long allowedDirectionsArg = 0, + optional unsigned long directionArg = 0, + optional double deltaArg = 0, + optional unsigned long clickCount = 0); }; diff --git a/dom/webidl/StorageEvent.webidl b/dom/webidl/StorageEvent.webidl index c3e9605eb..e03f8232c 100644 --- a/dom/webidl/StorageEvent.webidl +++ b/dom/webidl/StorageEvent.webidl @@ -21,13 +21,13 @@ interface StorageEvent : Event // Bug 1016053 - This is not spec compliant. void initStorageEvent(DOMString type, - boolean canBubble, - boolean cancelable, - DOMString? key, - DOMString? oldValue, - DOMString? newValue, - DOMString? url, - Storage? storageArea); + optional boolean canBubble = false, + optional boolean cancelable = false, + optional DOMString? key = null, + optional DOMString? oldValue = null, + optional DOMString? newValue = null, + optional DOMString? url = null, + optional Storage? storageArea = null); }; dictionary StorageEventInit : EventInit diff --git a/dom/webidl/TestInterfaceJS.webidl b/dom/webidl/TestInterfaceJS.webidl index 1ca629c39..2cf8d701a 100644 --- a/dom/webidl/TestInterfaceJS.webidl +++ b/dom/webidl/TestInterfaceJS.webidl @@ -24,7 +24,7 @@ interface TestInterfaceJS : EventTarget { any pingPongObjectOrString((object or DOMString) objOrString); TestInterfaceJSDictionary pingPongDictionary(optional TestInterfaceJSDictionary dict); long pingPongDictionaryOrLong(optional (TestInterfaceJSUnionableDictionary or long) dictOrLong); - DOMString pingPongMap(MozMap<any> map); + DOMString pingPongMap(record<DOMString, any> map); long objectSequenceLength(sequence<object> seq); long anySequenceLength(sequence<any> seq); diff --git a/dom/webidl/TimeEvent.webidl b/dom/webidl/TimeEvent.webidl index 40e7a0beb..8bbe4db53 100644 --- a/dom/webidl/TimeEvent.webidl +++ b/dom/webidl/TimeEvent.webidl @@ -15,6 +15,6 @@ interface TimeEvent : Event readonly attribute long detail; readonly attribute WindowProxy? view; void initTimeEvent(DOMString aType, - Window? aView, - long aDetail); + optional Window? aView = null, + optional long aDetail = 0); }; diff --git a/dom/webidl/TouchEvent.webidl b/dom/webidl/TouchEvent.webidl index d206fe0fb..fd677787a 100644 --- a/dom/webidl/TouchEvent.webidl +++ b/dom/webidl/TouchEvent.webidl @@ -23,15 +23,15 @@ interface TouchEvent : UIEvent { readonly attribute boolean shiftKey; void initTouchEvent(DOMString type, - boolean canBubble, - boolean cancelable, - Window? view, - long detail, - boolean ctrlKey, - boolean altKey, - boolean shiftKey, - boolean metaKey, - TouchList? touches, - TouchList? targetTouches, - TouchList? changedTouches); + optional boolean canBubble = false, + optional boolean cancelable = false, + optional Window? view = null, + optional long detail = 0, + optional boolean ctrlKey = false, + optional boolean altKey = false, + optional boolean shiftKey = false, + optional boolean metaKey = false, + optional TouchList? touches = null, + optional TouchList? targetTouches = null, + optional TouchList? changedTouches = null); }; diff --git a/dom/webidl/UIEvent.webidl b/dom/webidl/UIEvent.webidl index 9cc1d0cdf..5be6a443a 100644 --- a/dom/webidl/UIEvent.webidl +++ b/dom/webidl/UIEvent.webidl @@ -16,10 +16,10 @@ interface UIEvent : Event readonly attribute WindowProxy? view; readonly attribute long detail; void initUIEvent(DOMString aType, - boolean aCanBubble, - boolean aCancelable, - Window? aView, - long aDetail); + optional boolean aCanBubble = false, + optional boolean aCancelable = false, + optional Window? aView = null, + optional long aDetail = 0); }; // Additional DOM0 properties. diff --git a/dom/webidl/URLSearchParams.webidl b/dom/webidl/URLSearchParams.webidl index 93e846071..b93f4e8b1 100644 --- a/dom/webidl/URLSearchParams.webidl +++ b/dom/webidl/URLSearchParams.webidl @@ -13,8 +13,7 @@ * http://www.openwebfoundation.org/legal/the-owf-1-0-agreements/owfa-1-0. */ -[Constructor(optional USVString init = ""), - Constructor(URLSearchParams init), +[Constructor(optional (sequence<sequence<USVString>> or record<USVString, USVString> or USVString) init = ""), Exposed=(Window,Worker,WorkerDebugger,System)] interface URLSearchParams { void append(USVString name, USVString value); diff --git a/dom/webidl/VRDisplay.webidl b/dom/webidl/VRDisplay.webidl deleted file mode 100644 index 63ebd1205..000000000 --- a/dom/webidl/VRDisplay.webidl +++ /dev/null @@ -1,286 +0,0 @@ -/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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/. */ - -enum VREye { - "left", - "right" -}; - -[Pref="dom.vr.enabled", - HeaderFile="mozilla/dom/VRDisplay.h"] -interface VRFieldOfView { - readonly attribute double upDegrees; - readonly attribute double rightDegrees; - readonly attribute double downDegrees; - readonly attribute double leftDegrees; -}; - -typedef (HTMLCanvasElement or OffscreenCanvas) VRSource; - -dictionary VRLayer { - /** - * XXX - When WebVR in WebWorkers is implemented, HTMLCanvasElement below - * should be replaced with VRSource. - */ - HTMLCanvasElement? source = null; - - /** - * The left and right viewports contain 4 values defining the viewport - * rectangles within the canvas to present to the eye in UV space. - * [0] left offset of the viewport (0.0 - 1.0) - * [1] top offset of the viewport (0.0 - 1.0) - * [2] width of the viewport (0.0 - 1.0) - * [3] height of the viewport (0.0 - 1.0) - * - * When no values are passed, they will be processed as though the left - * and right sides of the viewport were passed: - * - * leftBounds: [0.0, 0.0, 0.5, 1.0] - * rightBounds: [0.5, 0.0, 0.5, 1.0] - */ - sequence<float> leftBounds = []; - sequence<float> rightBounds = []; -}; - -/** - * Values describing the capabilities of a VRDisplay. - * These are expected to be static per-device/per-user. - */ -[Pref="dom.vr.enabled", - HeaderFile="mozilla/dom/VRDisplay.h"] -interface VRDisplayCapabilities { - /** - * hasPosition is true if the VRDisplay is capable of tracking its position. - */ - readonly attribute boolean hasPosition; - - /** - * hasOrientation is true if the VRDisplay is capable of tracking its orientation. - */ - readonly attribute boolean hasOrientation; - - /** - * Whether the VRDisplay is separate from the device’s - * primary display. If presenting VR content will obscure - * other content on the device, this should be false. When - * false, the application should not attempt to mirror VR content - * or update non-VR UI because that content will not be visible. - */ - readonly attribute boolean hasExternalDisplay; - - /** - * Whether the VRDisplay is capable of presenting content to an HMD or similar device. - * Can be used to indicate “magic window” devices that are capable of 6DoF tracking but for - * which requestPresent is not meaningful. If false then calls to requestPresent should - * always fail, and getEyeParameters should return null. - */ - readonly attribute boolean canPresent; - - /** - * Indicates the maximum length of the array that requestPresent() will accept. MUST be 1 if - canPresent is true, 0 otherwise. - */ - readonly attribute unsigned long maxLayers; -}; - -/** - * Values describing the the stage / play area for devices - * that support room-scale experiences. - */ -[Pref="dom.vr.enabled", - HeaderFile="mozilla/dom/VRDisplay.h"] -interface VRStageParameters { - /** - * A 16-element array containing the components of a column-major 4x4 - * affine transform matrix. This matrix transforms the sitting-space position - * returned by get{Immediate}Pose() to a standing-space position. - */ - [Throws] readonly attribute Float32Array sittingToStandingTransform; - - /** - * Dimensions of the play-area bounds. The bounds are defined - * as an axis-aligned rectangle on the floor. - * The center of the rectangle is at (0,0,0) in standing-space - * coordinates. - * These bounds are defined for safety purposes. - * Content should not require the user to move beyond these - * bounds; however, it is possible for the user to ignore - * the bounds resulting in position values outside of - * this rectangle. - */ - readonly attribute float sizeX; - readonly attribute float sizeZ; -}; - -[Pref="dom.vr.enabled", - HeaderFile="mozilla/dom/VRDisplay.h"] -interface VRPose -{ - /** - * position, linearVelocity, and linearAcceleration are 3-component vectors. - * position is relative to a sitting space. Transforming this point with - * VRStageParameters.sittingToStandingTransform converts this to standing space. - */ - [Constant, Throws] readonly attribute Float32Array? position; - [Constant, Throws] readonly attribute Float32Array? linearVelocity; - [Constant, Throws] readonly attribute Float32Array? linearAcceleration; - - /* orientation is a 4-entry array representing the components of a quaternion. */ - [Constant, Throws] readonly attribute Float32Array? orientation; - /* angularVelocity and angularAcceleration are the components of 3-dimensional vectors. */ - [Constant, Throws] readonly attribute Float32Array? angularVelocity; - [Constant, Throws] readonly attribute Float32Array? angularAcceleration; -}; - -[Constructor, - Pref="dom.vr.enabled", - HeaderFile="mozilla/dom/VRDisplay.h"] -interface VRFrameData { - readonly attribute DOMHighResTimeStamp timestamp; - - [Throws, Pure] readonly attribute Float32Array leftProjectionMatrix; - [Throws, Pure] readonly attribute Float32Array leftViewMatrix; - - [Throws, Pure] readonly attribute Float32Array rightProjectionMatrix; - [Throws, Pure] readonly attribute Float32Array rightViewMatrix; - - [Pure] readonly attribute VRPose pose; -}; - -[Pref="dom.vr.enabled", - HeaderFile="mozilla/dom/VRDisplay.h"] -interface VREyeParameters { - /** - * offset is a 3-component vector representing an offset to - * translate the eye. This value may vary from frame - * to frame if the user adjusts their headset ipd. - */ - [Constant, Throws] readonly attribute Float32Array offset; - - /* These values may vary as the user adjusts their headset ipd. */ - [Constant] readonly attribute VRFieldOfView fieldOfView; - - /** - * renderWidth and renderHeight specify the recommended render target - * size of each eye viewport, in pixels. If multiple eyes are rendered - * in a single render target, then the render target should be made large - * enough to fit both viewports. - */ - [Constant] readonly attribute unsigned long renderWidth; - [Constant] readonly attribute unsigned long renderHeight; -}; - -[Pref="dom.vr.enabled", - HeaderFile="mozilla/dom/VRDisplay.h"] -interface VRDisplay : EventTarget { - readonly attribute boolean isConnected; - readonly attribute boolean isPresenting; - - /** - * Dictionary of capabilities describing the VRDisplay. - */ - [Constant] readonly attribute VRDisplayCapabilities capabilities; - - /** - * If this VRDisplay supports room-scale experiences, the optional - * stage attribute contains details on the room-scale parameters. - */ - readonly attribute VRStageParameters? stageParameters; - - /* Return the current VREyeParameters for the given eye. */ - VREyeParameters getEyeParameters(VREye whichEye); - - /** - * An identifier for this distinct VRDisplay. Used as an - * association point in the Gamepad API. - */ - [Constant] readonly attribute unsigned long displayId; - - /** - * A display name, a user-readable name identifying it. - */ - [Constant] readonly attribute DOMString displayName; - - /** - * Populates the passed VRFrameData with the information required to render - * the current frame. - */ - boolean getFrameData(VRFrameData frameData); - - /** - * Return a VRPose containing the future predicted pose of the VRDisplay - * when the current frame will be presented. Subsequent calls to getPose() - * MUST return a VRPose with the same values until the next call to - * submitFrame(). - * - * The VRPose will contain the position, orientation, velocity, - * and acceleration of each of these properties. - */ - [NewObject] VRPose getPose(); - - /** - * Reset the pose for this display, treating its current position and - * orientation as the "origin/zero" values. VRPose.position, - * VRPose.orientation, and VRStageParameters.sittingToStandingTransform may be - * updated when calling resetPose(). This should be called in only - * sitting-space experiences. - */ - void resetPose(); - - /** - * z-depth defining the near plane of the eye view frustum - * enables mapping of values in the render target depth - * attachment to scene coordinates. Initially set to 0.01. - */ - attribute double depthNear; - - /** - * z-depth defining the far plane of the eye view frustum - * enables mapping of values in the render target depth - * attachment to scene coordinates. Initially set to 10000.0. - */ - attribute double depthFar; - - /** - * The callback passed to `requestAnimationFrame` will be called - * any time a new frame should be rendered. When the VRDisplay is - * presenting the callback will be called at the native refresh - * rate of the HMD. When not presenting this function acts - * identically to how window.requestAnimationFrame acts. Content should - * make no assumptions of frame rate or vsync behavior as the HMD runs - * asynchronously from other displays and at differing refresh rates. - */ - [Throws] long requestAnimationFrame(FrameRequestCallback callback); - - /** - * Passing the value returned by `requestAnimationFrame` to - * `cancelAnimationFrame` will unregister the callback. - */ - [Throws] void cancelAnimationFrame(long handle); - - /** - * Begin presenting to the VRDisplay. Must be called in response to a user gesture. - * Repeat calls while already presenting will update the VRLayers being displayed. - */ - [Throws] Promise<void> requestPresent(sequence<VRLayer> layers); - - /** - * Stops presenting to the VRDisplay. - */ - [Throws] Promise<void> exitPresent(); - - /** - * Get the layers currently being presented. - */ - sequence<VRLayer> getLayers(); - - /** - * The VRLayer provided to the VRDisplay will be captured and presented - * in the HMD. Calling this function has the same effect on the source - * canvas as any other operation that uses its source image, and canvases - * created without preserveDrawingBuffer set to true will be cleared. - */ - void submitFrame(); -}; diff --git a/dom/webidl/XULCommandEvent.webidl b/dom/webidl/XULCommandEvent.webidl index 9c024edc1..72dc3802e 100644 --- a/dom/webidl/XULCommandEvent.webidl +++ b/dom/webidl/XULCommandEvent.webidl @@ -15,13 +15,13 @@ interface XULCommandEvent : UIEvent readonly attribute Event? sourceEvent; void initCommandEvent(DOMString type, - boolean canBubble, - boolean cancelable, - Window? view, - long detail, - boolean ctrlKey, - boolean altKey, - boolean shiftKey, - boolean metaKey, - Event? sourceEvent); + optional boolean canBubble = false, + optional boolean cancelable = false, + optional Window? view = null, + optional long detail = 0, + optional boolean ctrlKey = false, + optional boolean altKey = false, + optional boolean shiftKey = false, + optional boolean metaKey = false, + optional Event? sourceEvent = null); }; diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index 4c2567a1c..aae7e479c 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -555,7 +555,6 @@ WEBIDL_FILES = [ 'VideoStreamTrack.webidl', 'VideoTrack.webidl', 'VideoTrackList.webidl', - 'VRDisplay.webidl', 'VTTCue.webidl', 'VTTRegion.webidl', 'WaveShaperNode.webidl', @@ -592,9 +591,6 @@ WEBIDL_FILES = [ 'XULElement.webidl', ] -if CONFIG['MOZ_WEBEXTENSIONS']: - WEBIDL_FILES += ['AddonManager.webidl'] - if CONFIG['MOZ_AUDIO_CHANNEL_MANAGER']: WEBIDL_FILES += [ 'AudioChannelManager.webidl', @@ -723,9 +719,6 @@ GENERATED_EVENTS_WEBIDL_FILES = [ 'WebGLContextEvent.webidl', ] -if CONFIG['MOZ_WEBEXTENSIONS']: - GENERATED_EVENTS_WEBIDL_FILES += ['AddonEvent.webidl'] - if CONFIG['MOZ_WEBRTC']: GENERATED_EVENTS_WEBIDL_FILES += [ 'RTCDataChannelEvent.webidl', diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp index e1910536f..21f6d8ddf 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -30,7 +30,6 @@ #include "mozilla/AsyncEventDispatcher.h" #include "mozilla/Atomics.h" #include "mozilla/CycleCollectedJSContext.h" -#include "mozilla/Telemetry.h" #include "mozilla/TimeStamp.h" #include "mozilla/dom/asmjscache/AsmJSCache.h" #include "mozilla/dom/AtomList.h" @@ -1531,10 +1530,8 @@ RuntimeService::RegisterWorker(WorkerPrivate* aWorkerPrivate) const bool isServiceWorker = aWorkerPrivate->IsServiceWorker(); const bool isSharedWorker = aWorkerPrivate->IsSharedWorker(); - const bool isDedicatedWorker = aWorkerPrivate->IsDedicatedWorker(); if (isServiceWorker) { AssertIsOnMainThread(); - Telemetry::Accumulate(Telemetry::SERVICE_WORKER_SPAWN_ATTEMPTS, 1); } nsCString sharedWorkerScriptSpec; @@ -1586,14 +1583,6 @@ RuntimeService::RegisterWorker(WorkerPrivate* aWorkerPrivate) // Worker spawn gets queued due to hitting max workers per domain // limit so let's log a warning. WorkerPrivate::ReportErrorToConsole("HittingMaxWorkersPerDomain2"); - - if (isServiceWorker) { - Telemetry::Accumulate(Telemetry::SERVICE_WORKER_SPAWN_GETS_QUEUED, 1); - } else if (isSharedWorker) { - Telemetry::Accumulate(Telemetry::SHARED_WORKER_SPAWN_GETS_QUEUED, 1); - } else if (isDedicatedWorker) { - Telemetry::Accumulate(Telemetry::DEDICATED_WORKER_SPAWN_GETS_QUEUED, 1); - } } else if (parent) { domainInfo->mChildWorkerCount++; @@ -1669,7 +1658,6 @@ RuntimeService::RegisterWorker(WorkerPrivate* aWorkerPrivate) if (isServiceWorker) { AssertIsOnMainThread(); - Telemetry::Accumulate(Telemetry::SERVICE_WORKER_WAS_SPAWNED, 1); } return true; } @@ -1766,8 +1754,6 @@ RuntimeService::UnregisterWorker(WorkerPrivate* aWorkerPrivate) if (aWorkerPrivate->IsServiceWorker()) { AssertIsOnMainThread(); - Telemetry::AccumulateTimeDelta(Telemetry::SERVICE_WORKER_LIFE_TIME, - aWorkerPrivate->CreationTimeStamp()); } if (aWorkerPrivate->IsSharedWorker() || diff --git a/dom/workers/ServiceWorkerClient.cpp b/dom/workers/ServiceWorkerClient.cpp index 660512a5f..6ed3a6ea4 100644 --- a/dom/workers/ServiceWorkerClient.cpp +++ b/dom/workers/ServiceWorkerClient.cpp @@ -224,7 +224,7 @@ ServiceWorkerClient::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, return; } - aRv = workerPrivate->DispatchToMainThread(runnable.forget()); + aRv = NS_DispatchToMainThread(runnable); if (NS_WARN_IF(aRv.Failed())) { return; } diff --git a/dom/workers/ServiceWorkerClients.cpp b/dom/workers/ServiceWorkerClients.cpp index 11f864443..38f49e355 100644 --- a/dom/workers/ServiceWorkerClients.cpp +++ b/dom/workers/ServiceWorkerClients.cpp @@ -753,7 +753,7 @@ ServiceWorkerClients::Get(const nsAString& aClientId, ErrorResult& aRv) RefPtr<GetRunnable> r = new GetRunnable(promiseProxy, aClientId); - MOZ_ALWAYS_SUCCEEDS(workerPrivate->DispatchToMainThread(r.forget())); + MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r)); return promise.forget(); } @@ -789,7 +789,7 @@ ServiceWorkerClients::MatchAll(const ClientQueryOptions& aOptions, new MatchAllRunnable(promiseProxy, NS_ConvertUTF16toUTF8(scope), aOptions.mIncludeUncontrolled); - MOZ_ALWAYS_SUCCEEDS(workerPrivate->DispatchToMainThread(r.forget())); + MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r)); return promise.forget(); } @@ -830,7 +830,7 @@ ServiceWorkerClients::OpenWindow(const nsAString& aUrl, RefPtr<OpenWindowRunnable> r = new OpenWindowRunnable(promiseProxy, aUrl, scope); - MOZ_ALWAYS_SUCCEEDS(workerPrivate->DispatchToMainThread(r.forget())); + MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r)); return promise.forget(); } @@ -859,6 +859,6 @@ ServiceWorkerClients::Claim(ErrorResult& aRv) RefPtr<ClaimRunnable> runnable = new ClaimRunnable(promiseProxy, NS_ConvertUTF16toUTF8(scope)); - MOZ_ALWAYS_SUCCEEDS(workerPrivate->DispatchToMainThread(runnable.forget())); + MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable)); return promise.forget(); } diff --git a/dom/workers/ServiceWorkerEvents.cpp b/dom/workers/ServiceWorkerEvents.cpp index 1f79e2c92..8b375c635 100644 --- a/dom/workers/ServiceWorkerEvents.cpp +++ b/dom/workers/ServiceWorkerEvents.cpp @@ -400,13 +400,7 @@ void RespondWithCopyComplete(void* aClosure, nsresult aStatus) data->mScriptSpec, data->mResponseURLSpec); } - // In theory this can happen after the worker thread is terminated. - WorkerPrivate* worker = GetCurrentThreadWorkerPrivate(); - if (worker) { - MOZ_ALWAYS_SUCCEEDS(worker->DispatchToMainThread(event.forget())); - } else { - MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(event.forget())); - } + MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(event)); } namespace { @@ -734,13 +728,7 @@ RespondWithHandler::CancelRequest(nsresult aStatus) { nsCOMPtr<nsIRunnable> runnable = new CancelChannelRunnable(mInterceptedChannel, mRegistration, aStatus); - // Note, this may run off the worker thread during worker termination. - WorkerPrivate* worker = GetCurrentThreadWorkerPrivate(); - if (worker) { - MOZ_ALWAYS_SUCCEEDS(worker->DispatchToMainThread(runnable.forget())); - } else { - MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable.forget())); - } + NS_DispatchToMainThread(runnable); mRequestWasHandled = true; } @@ -873,8 +861,8 @@ public: mColumn = column; } - MOZ_ALWAYS_SUCCEEDS(mWorkerPrivate->DispatchToMainThread( - NewRunnableMethod(this, &WaitUntilHandler::ReportOnMainThread))); + MOZ_ALWAYS_SUCCEEDS( + NS_DispatchToMainThread(NewRunnableMethod(this, &WaitUntilHandler::ReportOnMainThread))); } void diff --git a/dom/workers/ServiceWorkerManager.cpp b/dom/workers/ServiceWorkerManager.cpp index a66df0731..a8f191f2e 100644 --- a/dom/workers/ServiceWorkerManager.cpp +++ b/dom/workers/ServiceWorkerManager.cpp @@ -33,7 +33,6 @@ #include "mozilla/ClearOnShutdown.h" #include "mozilla/ErrorNames.h" #include "mozilla/LoadContext.h" -#include "mozilla/Telemetry.h" #include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/ContentParent.h" #include "mozilla/dom/DOMError.h" @@ -676,7 +675,6 @@ ServiceWorkerManager::Register(mozIDOMWindow* aWindow, queue->ScheduleJob(job); AssertIsOnMainThread(); - Telemetry::Accumulate(Telemetry::SERVICE_WORKER_REGISTRATIONS, 1); promise.forget(aPromise); return NS_OK; @@ -2180,7 +2178,6 @@ ServiceWorkerManager::StartControllingADocument(ServiceWorkerRegistrationInfo* a if (!aDocumentId.IsEmpty()) { aDoc->SetId(aDocumentId); } - Telemetry::Accumulate(Telemetry::SERVICE_WORKER_CONTROLLED_DOCUMENTS, 1); } void diff --git a/dom/workers/ServiceWorkerPrivate.cpp b/dom/workers/ServiceWorkerPrivate.cpp index 24b2e11e6..23ae3b366 100644 --- a/dom/workers/ServiceWorkerPrivate.cpp +++ b/dom/workers/ServiceWorkerPrivate.cpp @@ -214,7 +214,7 @@ private: mDone = true; #endif mCallback->SetResult(aResult); - MOZ_ALWAYS_SUCCEEDS(mWorkerPrivate->DispatchToMainThread(mCallback)); + MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(mCallback)); } }; @@ -500,7 +500,7 @@ public: if (mRegistration) { nsCOMPtr<nsIRunnable> runnable = new RegistrationUpdateRunnable(mRegistration, true /* time check */); - aWorkerPrivate->DispatchToMainThread(runnable.forget()); + NS_DispatchToMainThread(runnable.forget()); } ExtendableEventWorkerRunnable::PostRun(aCx, aWorkerPrivate, aRunResult); @@ -541,7 +541,7 @@ public: Cancel() override { mCallback->SetResult(false); - MOZ_ALWAYS_SUCCEEDS(mWorkerPrivate->DispatchToMainThread(mCallback)); + MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(mCallback)); return WorkerRunnable::Cancel(); } @@ -637,7 +637,7 @@ public: mDone = true; mCallback->SetResult(aResult); - nsresult rv = mWorkerPrivate->DispatchToMainThread(mCallback); + nsresult rv = NS_DispatchToMainThread(mCallback); if (NS_WARN_IF(NS_FAILED(rv))) { NS_RUNTIMEABORT("Failed to dispatch life cycle event handler."); } @@ -768,7 +768,6 @@ public: void Report(uint16_t aReason = nsIPushErrorReporter::DELIVERY_INTERNAL_ERROR) { - WorkerPrivate* workerPrivate = mWorkerPrivate; mWorkerPrivate->AssertIsOnWorkerThread(); mWorkerPrivate = nullptr; @@ -780,7 +779,7 @@ public: NewRunnableMethod<uint16_t>(this, &PushErrorReporter::ReportOnMainThread, aReason); MOZ_ALWAYS_TRUE(NS_SUCCEEDED( - workerPrivate->DispatchToMainThread(runnable.forget()))); + NS_DispatchToMainThread(runnable.forget()))); } void ReportOnMainThread(uint16_t aReason) @@ -1434,7 +1433,7 @@ public: Cancel() override { nsCOMPtr<nsIRunnable> runnable = new ResumeRequest(mInterceptedChannel); - if (NS_FAILED(mWorkerPrivate->DispatchToMainThread(runnable))) { + if (NS_FAILED(NS_DispatchToMainThread(runnable))) { NS_WARNING("Failed to resume channel on FetchEventRunnable::Cancel()!\n"); } WorkerRunnable::Cancel(); @@ -1554,7 +1553,7 @@ private: NS_ERROR_INTERCEPTION_FAILED); } - MOZ_ALWAYS_SUCCEEDS(mWorkerPrivate->DispatchToMainThread(runnable.forget())); + MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable)); } RefPtr<Promise> waitUntilPromise = event->GetPromise(); diff --git a/dom/workers/ServiceWorkerRegistrar.cpp b/dom/workers/ServiceWorkerRegistrar.cpp index a4757ea54..7df129c2b 100644 --- a/dom/workers/ServiceWorkerRegistrar.cpp +++ b/dom/workers/ServiceWorkerRegistrar.cpp @@ -135,9 +135,6 @@ ServiceWorkerRegistrar::GetRegistrations( if (firstTime) { firstTime = false; - Telemetry::AccumulateTimeDelta( - Telemetry::SERVICE_WORKER_REGISTRATION_LOADING, - startTime); } } diff --git a/dom/workers/ServiceWorkerRegistration.cpp b/dom/workers/ServiceWorkerRegistration.cpp index 451bd2be9..b3cda2c10 100644 --- a/dom/workers/ServiceWorkerRegistration.cpp +++ b/dom/workers/ServiceWorkerRegistration.cpp @@ -1107,7 +1107,7 @@ ServiceWorkerRegistrationWorkerThread::Update(ErrorResult& aRv) } RefPtr<UpdateRunnable> r = new UpdateRunnable(proxy, mScope); - MOZ_ALWAYS_SUCCEEDS(worker->DispatchToMainThread(r.forget())); + MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r)); return promise.forget(); } @@ -1139,7 +1139,7 @@ ServiceWorkerRegistrationWorkerThread::Unregister(ErrorResult& aRv) } RefPtr<StartUnregisterRunnable> r = new StartUnregisterRunnable(proxy, mScope); - MOZ_ALWAYS_SUCCEEDS(worker->DispatchToMainThread(r.forget())); + MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r)); return promise.forget(); } @@ -1161,7 +1161,7 @@ ServiceWorkerRegistrationWorkerThread::InitListener() nsCOMPtr<nsIRunnable> r = NewRunnableMethod(mListener, &WorkerListener::StartListeningForEvents); - MOZ_ALWAYS_SUCCEEDS(worker->DispatchToMainThread(r.forget())); + MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r)); } void @@ -1183,7 +1183,7 @@ ServiceWorkerRegistrationWorkerThread::ReleaseListener() nsCOMPtr<nsIRunnable> r = NewRunnableMethod(mListener, &WorkerListener::StopListeningForEvents); - MOZ_ALWAYS_SUCCEEDS(mWorkerPrivate->DispatchToMainThread(r.forget())); + MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r)); mListener = nullptr; mWorkerPrivate = nullptr; diff --git a/dom/workers/ServiceWorkerUpdateJob.cpp b/dom/workers/ServiceWorkerUpdateJob.cpp index 614fe4de5..69877dfe4 100644 --- a/dom/workers/ServiceWorkerUpdateJob.cpp +++ b/dom/workers/ServiceWorkerUpdateJob.cpp @@ -408,8 +408,6 @@ ServiceWorkerUpdateJob::ComparisonResult(nsresult aStatus, return; } - Telemetry::Accumulate(Telemetry::SERVICE_WORKER_UPDATED, 1); - // Begin step 7 of the Update algorithm to evaluate the new script. RefPtr<ServiceWorkerInfo> sw = diff --git a/dom/workers/ServiceWorkerWindowClient.cpp b/dom/workers/ServiceWorkerWindowClient.cpp index 2ce0603cf..bae747214 100644 --- a/dom/workers/ServiceWorkerWindowClient.cpp +++ b/dom/workers/ServiceWorkerWindowClient.cpp @@ -183,7 +183,7 @@ ServiceWorkerWindowClient::Focus(ErrorResult& aRv) const if (promiseProxy) { RefPtr<ClientFocusRunnable> r = new ClientFocusRunnable(mWindowId, promiseProxy); - MOZ_ALWAYS_SUCCEEDS(workerPrivate->DispatchToMainThread(r.forget())); + MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r)); } else { promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR); } @@ -549,7 +549,7 @@ ServiceWorkerWindowClient::Navigate(const nsAString& aUrl, ErrorResult& aRv) if (promiseProxy) { RefPtr<ClientNavigateRunnable> r = new ClientNavigateRunnable(mWindowId, aUrl, scope, promiseProxy); - MOZ_ALWAYS_SUCCEEDS(workerPrivate->DispatchToMainThread(r.forget())); + MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r)); } else { promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR); } diff --git a/dom/workers/SharedWorker.cpp b/dom/workers/SharedWorker.cpp index b0eed2def..99bb50339 100644 --- a/dom/workers/SharedWorker.cpp +++ b/dom/workers/SharedWorker.cpp @@ -12,7 +12,6 @@ #include "mozilla/Preferences.h" #include "mozilla/dom/MessagePort.h" #include "mozilla/dom/SharedWorkerBinding.h" -#include "mozilla/Telemetry.h" #include "nsContentUtils.h" #include "nsIClassInfoImpl.h" #include "nsIDOMEvent.h" @@ -73,8 +72,6 @@ SharedWorker::Constructor(const GlobalObject& aGlobal, JSContext* aCx, return nullptr; } - Telemetry::Accumulate(Telemetry::SHARED_WORKER_COUNT, 1); - return sharedWorker.forget(); } diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index 612090027..6bc5c4f96 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -404,7 +404,7 @@ private: RefPtr<MainThreadReleaseRunnable> runnable = new MainThreadReleaseRunnable(doomed, loadGroupToCancel); - if (NS_FAILED(mWorkerPrivate->DispatchToMainThread(runnable.forget()))) { + if (NS_FAILED(NS_DispatchToMainThread(runnable))) { NS_WARNING("Failed to dispatch, going to leak!"); } @@ -4078,7 +4078,7 @@ WorkerDebugger::PostMessageToDebugger(const nsAString& aMessage) RefPtr<PostDebuggerMessageRunnable> runnable = new PostDebuggerMessageRunnable(this, aMessage); - if (NS_FAILED(mWorkerPrivate->DispatchToMainThread(runnable.forget()))) { + if (NS_FAILED(NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL))) { NS_WARNING("Failed to post message to debugger on main thread!"); } } @@ -4103,7 +4103,7 @@ WorkerDebugger::ReportErrorToDebugger(const nsAString& aFilename, RefPtr<ReportDebuggerErrorRunnable> runnable = new ReportDebuggerErrorRunnable(this, aFilename, aLineno, aMessage); - if (NS_FAILED(mWorkerPrivate->DispatchToMainThread(runnable.forget()))) { + if (NS_FAILED(NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL))) { NS_WARNING("Failed to report error to debugger on main thread!"); } } @@ -4862,7 +4862,7 @@ WorkerPrivate::MaybeDispatchLoadFailedRunnable() return; } - MOZ_ALWAYS_SUCCEEDS(DispatchToMainThread(runnable.forget())); + MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable.forget())); } nsIEventTarget* @@ -5083,7 +5083,7 @@ WorkerPrivate::ScheduleDeletion(WorkerRanOrNot aRanOrNot) else { RefPtr<TopLevelWorkerFinishedRunnable> runnable = new TopLevelWorkerFinishedRunnable(this); - if (NS_FAILED(DispatchToMainThread(runnable.forget()))) { + if (NS_FAILED(NS_DispatchToMainThread(runnable))) { NS_WARNING("Failed to dispatch runnable!"); } } diff --git a/dom/workers/WorkerRunnable.cpp b/dom/workers/WorkerRunnable.cpp index 6bbe40f66..60d69d4e4 100644 --- a/dom/workers/WorkerRunnable.cpp +++ b/dom/workers/WorkerRunnable.cpp @@ -15,7 +15,6 @@ #include "mozilla/DebugOnly.h" #include "mozilla/ErrorResult.h" #include "mozilla/dom/ScriptSettings.h" -#include "mozilla/Telemetry.h" #include "js/RootingAPI.h" #include "js/Value.h" @@ -118,7 +117,10 @@ WorkerRunnable::DispatchInternal() return NS_SUCCEEDED(parent->Dispatch(runnable.forget())); } - return NS_SUCCEEDED(mWorkerPrivate->DispatchToMainThread(runnable.forget())); + nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); + MOZ_ASSERT(mainThread); + + return NS_SUCCEEDED(mainThread->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL)); } void @@ -554,7 +556,10 @@ WorkerControlRunnable::DispatchInternal() return NS_SUCCEEDED(parent->DispatchControlRunnable(runnable.forget())); } - return NS_SUCCEEDED(mWorkerPrivate->DispatchToMainThread(runnable.forget())); + nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); + MOZ_ASSERT(mainThread); + + return NS_SUCCEEDED(mainThread->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL)); } NS_IMPL_ISUPPORTS_INHERITED0(WorkerControlRunnable, WorkerRunnable) @@ -572,8 +577,6 @@ WorkerMainThreadRunnable::Dispatch(Status aFailStatus, ErrorResult& aRv) { mWorkerPrivate->AssertIsOnWorkerThread(); - TimeStamp startTime = TimeStamp::NowLoRes(); - AutoSyncLoopHolder syncLoop(mWorkerPrivate, aFailStatus); mSyncLoopTarget = syncLoop.GetEventTarget(); @@ -583,18 +586,16 @@ WorkerMainThreadRunnable::Dispatch(Status aFailStatus, ErrorResult& aRv) return; } - DebugOnly<nsresult> rv = mWorkerPrivate->DispatchToMainThread(this); + RefPtr<WorkerMainThreadRunnable> runnable(this); + + DebugOnly<nsresult> rv = + NS_DispatchToMainThread(runnable.forget(), NS_DISPATCH_NORMAL); MOZ_ASSERT(NS_SUCCEEDED(rv), "Should only fail after xpcom-shutdown-threads and we're gone by then"); if (!syncLoop.Run()) { aRv.ThrowUncatchableException(); } - - Telemetry::Accumulate(Telemetry::SYNC_WORKER_OPERATION, mTelemetryKey, - static_cast<uint32_t>((TimeStamp::NowLoRes() - startTime) - .ToMilliseconds())); - Unused << startTime; // Shut the compiler up. } NS_IMETHODIMP @@ -678,7 +679,7 @@ WorkerProxyToMainThreadRunnable::Dispatch() return false; } - if (NS_WARN_IF(NS_FAILED(mWorkerPrivate->DispatchToMainThread(this)))) { + if (NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(this)))) { ReleaseWorker(); RunBackOnWorkerThread(); return false; diff --git a/dom/workers/WorkerScope.cpp b/dom/workers/WorkerScope.cpp index 54252e53b..ace1a09fc 100644 --- a/dom/workers/WorkerScope.cpp +++ b/dom/workers/WorkerScope.cpp @@ -717,7 +717,7 @@ ServiceWorkerGlobalScope::SkipWaiting(ErrorResult& aRv) new WorkerScopeSkipWaitingRunnable(promiseProxy, NS_ConvertUTF16toUTF8(mScope)); - MOZ_ALWAYS_SUCCEEDS(mWorkerPrivate->DispatchToMainThread(runnable.forget())); + MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable)); return promise.forget(); } diff --git a/dom/worklet/WorkletGlobalScope.cpp b/dom/worklet/WorkletGlobalScope.cpp index 4caeae81a..8c05a0abe 100644 --- a/dom/worklet/WorkletGlobalScope.cpp +++ b/dom/worklet/WorkletGlobalScope.cpp @@ -22,8 +22,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(WorkletGlobalScope) NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(WorkletGlobalScope) - - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsole) tmp->TraverseHostObjectURIs(cb); diff --git a/dom/xbl/nsXBLBinding.cpp b/dom/xbl/nsXBLBinding.cpp index d9a2aacc5..b8174f6c2 100644 --- a/dom/xbl/nsXBLBinding.cpp +++ b/dom/xbl/nsXBLBinding.cpp @@ -1049,7 +1049,8 @@ nsXBLBinding::DoInitJSClass(JSContext *cx, // to create and define it. JS::Rooted<JSObject*> proto(cx); JS::Rooted<JS::PropertyDescriptor> desc(cx); - if (!JS_GetOwnUCPropertyDescriptor(cx, holder, aClassName.get(), &desc)) { + if (!JS_GetOwnUCPropertyDescriptor(cx, holder, aClassName.get(), + aClassName.Length(), &desc)) { return NS_ERROR_OUT_OF_MEMORY; } *aNew = !desc.object(); diff --git a/dom/xbl/nsXBLDocumentInfo.cpp b/dom/xbl/nsXBLDocumentInfo.cpp index 283775dc6..73b08d7e1 100644 --- a/dom/xbl/nsXBLDocumentInfo.cpp +++ b/dom/xbl/nsXBLDocumentInfo.cpp @@ -52,7 +52,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXBLDocumentInfo) if (tmp->mDocument && nsCCUncollectableMarker::InGeneration(cb, tmp->mDocument->GetMarkedCCGeneration())) { - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS return NS_SUCCESS_INTERRUPTED_TRAVERSE; } NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument) @@ -62,7 +61,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXBLDocumentInfo) iter.UserData()->Traverse(cb); } } - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsXBLDocumentInfo) if (tmp->mBindingTable) { diff --git a/dom/xbl/nsXBLProtoImpl.cpp b/dom/xbl/nsXBLProtoImpl.cpp index 4db9cabf0..5efcb71e0 100644 --- a/dom/xbl/nsXBLProtoImpl.cpp +++ b/dom/xbl/nsXBLProtoImpl.cpp @@ -100,11 +100,15 @@ nsXBLProtoImpl::InstallImplementation(nsXBLPrototypeBinding* aPrototypeBinding, // end up with a different content prototype, but we'll already have a property // holder called |foo| in the XBL scope. Check for that to avoid wasteful and // weird property holder duplication. - const char16_t* className = aPrototypeBinding->ClassName().get(); + const nsString& className = aPrototypeBinding->ClassName(); + const char16_t* classNameChars = className.get(); + const size_t classNameLen = className.Length(); + JS::Rooted<JSObject*> propertyHolder(cx); JS::Rooted<JS::PropertyDescriptor> existingHolder(cx); if (scopeObject != globalObject && - !JS_GetOwnUCPropertyDescriptor(cx, scopeObject, className, &existingHolder)) { + !JS_GetOwnUCPropertyDescriptor(cx, scopeObject, classNameChars, + classNameLen, &existingHolder)) { return NS_ERROR_FAILURE; } bool propertyHolderIsNew = !existingHolder.object() || !existingHolder.value().isObject(); @@ -119,8 +123,8 @@ nsXBLProtoImpl::InstallImplementation(nsXBLPrototypeBinding* aPrototypeBinding, // Define it as a property on the scopeObject, using the same name used on // the content side. - bool ok = JS_DefineUCProperty(cx, scopeObject, className, -1, propertyHolder, - JSPROP_PERMANENT | JSPROP_READONLY, + bool ok = JS_DefineUCProperty(cx, scopeObject, classNameChars, classNameLen, + propertyHolder, JSPROP_PERMANENT | JSPROP_READONLY, JS_STUBGETTER, JS_STUBSETTER); NS_ENSURE_TRUE(ok, NS_ERROR_UNEXPECTED); } else { diff --git a/dom/xhr/XMLHttpRequestMainThread.cpp b/dom/xhr/XMLHttpRequestMainThread.cpp index 4fd34a993..613008ad5 100644 --- a/dom/xhr/XMLHttpRequestMainThread.cpp +++ b/dom/xhr/XMLHttpRequestMainThread.cpp @@ -757,15 +757,6 @@ XMLHttpRequestMainThread::SetResponseType(XMLHttpRequestResponseType aResponseTy return; } - // We want to get rid of this moz-only types. Bug 1335365. - if (aResponseType == XMLHttpRequestResponseType::Moz_blob) { - Telemetry::Accumulate(Telemetry::MOZ_BLOB_IN_XHR, 1); - } else if (aResponseType == XMLHttpRequestResponseType::Moz_chunked_text) { - Telemetry::Accumulate(Telemetry::MOZ_CHUNKED_TEXT_IN_XHR, 1); - } else if (aResponseType == XMLHttpRequestResponseType::Moz_chunked_arraybuffer) { - Telemetry::Accumulate(Telemetry::MOZ_CHUNKED_ARRAYBUFFER_IN_XHR, 1); - } - // Set the responseType attribute's value to the given value. mResponseType = aResponseType; } @@ -1521,8 +1512,6 @@ XMLHttpRequestMainThread::Open(const nsACString& aMethod, GetOwner()->GetExtantDoc()->WarnOnceAbout(nsIDocument::eSyncXMLHttpRequest); } - Telemetry::Accumulate(Telemetry::XMLHTTPREQUEST_ASYNC_OR_SYNC, aAsync ? 0 : 1); - // Step 1 nsCOMPtr<nsIDocument> responsibleDocument = GetDocumentIfCurrent(); if (!responsibleDocument) { diff --git a/dom/xhr/XMLHttpRequestWorker.cpp b/dom/xhr/XMLHttpRequestWorker.cpp index c9e892f26..2af61bd7d 100644 --- a/dom/xhr/XMLHttpRequestWorker.cpp +++ b/dom/xhr/XMLHttpRequestWorker.cpp @@ -1588,8 +1588,6 @@ XMLHttpRequestWorker::Construct(const GlobalObject& aGlobal, WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx); MOZ_ASSERT(workerPrivate); - Telemetry::Accumulate(Telemetry::XHR_IN_WORKER, 1); - RefPtr<XMLHttpRequestWorker> xhr = new XMLHttpRequestWorker(workerPrivate); if (workerPrivate->XHRParamsAllowed()) { diff --git a/dom/xslt/xpath/XPathResult.cpp b/dom/xslt/xpath/XPathResult.cpp index 33315c942..07121347e 100644 --- a/dom/xslt/xpath/XPathResult.cpp +++ b/dom/xslt/xpath/XPathResult.cpp @@ -63,7 +63,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(XPathResult) NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument) NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(XPathResult) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mResultNodes) diff --git a/dom/xslt/xpath/txUnaryExpr.cpp b/dom/xslt/xpath/txUnaryExpr.cpp index 95682b5b2..ae20fda46 100644 --- a/dom/xslt/xpath/txUnaryExpr.cpp +++ b/dom/xslt/xpath/txUnaryExpr.cpp @@ -23,16 +23,7 @@ UnaryExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult) NS_ENSURE_SUCCESS(rv, rv); double value = exprRes->numberValue(); -#ifdef HPUX - /* - * Negation of a zero doesn't produce a negative - * zero on HPUX. Perform the operation by multiplying with - * -1. - */ - return aContext->recycler()->getNumberResult(-1 * value, aResult); -#else return aContext->recycler()->getNumberResult(-value, aResult); -#endif } TX_IMPL_EXPR_STUBS_1(UnaryExpr, NODESET_RESULT, expr) diff --git a/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp b/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp index 726441757..c9bcc31ff 100644 --- a/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp +++ b/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp @@ -462,10 +462,6 @@ txCompileObserver::startLoad(nsIURI* aUri, txStylesheetCompiler* aCompiler, nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel)); if (httpChannel) { - httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"), - NS_LITERAL_CSTRING("*/*"), - false); - nsCOMPtr<nsIURI> referrerURI; aReferrerPrincipal->GetURI(getter_AddRefs(referrerURI)); if (referrerURI) { diff --git a/dom/xul/nsXULElement.cpp b/dom/xul/nsXULElement.cpp index 14fa898ab..e351a46eb 100644 --- a/dom/xul/nsXULElement.cpp +++ b/dom/xul/nsXULElement.cpp @@ -2173,7 +2173,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXULPrototypeNode) } ImplCycleCollectionTraverse(cb, elem->mChildren, "mChildren"); } - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsXULPrototypeNode) if (tmp->mType == nsXULPrototypeNode::eType_Script) { diff --git a/dom/xul/nsXULPrototypeCache.cpp b/dom/xul/nsXULPrototypeCache.cpp index 84a201d59..2c3454860 100644 --- a/dom/xul/nsXULPrototypeCache.cpp +++ b/dom/xul/nsXULPrototypeCache.cpp @@ -45,12 +45,6 @@ UpdategDisableXULCache() // Get the value of "nglayout.debug.disable_xul_cache" preference gDisableXULCache = Preferences::GetBool(kDisableXULCachePref, gDisableXULCache); - - // Sets the flag if the XUL cache is disabled - if (gDisableXULCache) { - Telemetry::Accumulate(Telemetry::XUL_CACHE_DISABLED, true); - } - } static void |