diff options
Diffstat (limited to 'dom')
464 files changed, 4891 insertions, 13755 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..70b5534ba 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,13 @@ 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(); + nsIFrame* originalTargetFrame = targetFrame; 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 +351,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 +368,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 +423,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 = originalTargetFrame->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 +500,7 @@ DOMIntersectionObserver::QueueIntersectionObserverEntry(Element* aTarget, rootBounds.forget(), boundingClientRect.forget(), intersectionRect.forget(), + aIntersectionRect.isSome(), aTarget, aIntersectionRatio); mQueuedEntries.AppendElement(entry.forget()); } @@ -480,7 +513,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..0054f4800 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); } @@ -1246,7 +1283,7 @@ Element::ToggleAttribute(const nsAString& aName, if (aForce.WasPassed() && !aForce.Value()) { return false; } - nsCOMPtr<nsIAtom> nameAtom = NS_Atomize(nameToUse); + nsCOMPtr<nsIAtom> nameAtom = NS_AtomizeMainThread(nameToUse); if (!nameAtom) { aError.Throw(NS_ERROR_OUT_OF_MEMORY); return false; @@ -1279,7 +1316,7 @@ Element::SetAttribute(const nsAString& aName, nsAutoString nameToUse; const nsAttrName* name = InternalGetAttrNameFromQName(aName, &nameToUse); if (!name) { - nsCOMPtr<nsIAtom> nameAtom = NS_Atomize(nameToUse); + nsCOMPtr<nsIAtom> nameAtom = NS_AtomizeMainThread(nameToUse); if (!nameAtom) { aError.Throw(NS_ERROR_OUT_OF_MEMORY); return; @@ -1361,7 +1398,7 @@ Element::GetAttributeNS(const nsAString& aNamespaceURI, return; } - nsCOMPtr<nsIAtom> name = NS_Atomize(aLocalName); + nsCOMPtr<nsIAtom> name = NS_AtomizeMainThread(aLocalName); bool hasAttr = GetAttr(nsid, name, aReturn); if (!hasAttr) { SetDOMStringToNull(aReturn); @@ -1393,7 +1430,7 @@ Element::RemoveAttributeNS(const nsAString& aNamespaceURI, const nsAString& aLocalName, ErrorResult& aError) { - nsCOMPtr<nsIAtom> name = NS_Atomize(aLocalName); + nsCOMPtr<nsIAtom> name = NS_AtomizeMainThread(aLocalName); int32_t nsid = nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI, nsContentUtils::IsChromeDoc(OwnerDoc())); @@ -1481,7 +1518,7 @@ Element::HasAttributeNS(const nsAString& aNamespaceURI, return false; } - nsCOMPtr<nsIAtom> name = NS_Atomize(aLocalName); + nsCOMPtr<nsIAtom> name = NS_AtomizeMainThread(aLocalName); return HasAttr(nsid, name); } @@ -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/moz.build b/dom/base/moz.build index 77eb01ba6..ebb76d617 100755 --- a/dom/base/moz.build +++ b/dom/base/moz.build @@ -410,17 +410,12 @@ EXTRA_COMPONENTS += [ 'contentAreaDropListener.manifest', 'messageWakeupService.js', 'messageWakeupService.manifest', + 'SiteSpecificUserAgent.js', + 'SiteSpecificUserAgent.manifest', 'SlowScriptDebug.js', 'SlowScriptDebug.manifest', ] -# Firefox for Android provides an alternate version of this component -if not CONFIG['MOZ_FENNEC']: - EXTRA_COMPONENTS += [ - 'SiteSpecificUserAgent.js', - 'SiteSpecificUserAgent.manifest', - ] - EXTRA_JS_MODULES += [ 'DOMRequestHelper.jsm', 'IndexedDBHelper.jsm', @@ -471,7 +466,7 @@ include('/ipc/chromium/chromium-config.mozbuild') FINAL_LIBRARY = 'xul' -if CONFIG['MOZ_PHOENIX'] or CONFIG['MOZ_FENNEC'] or CONFIG['MOZ_XULRUNNER']: +if CONFIG['MOZ_PHOENIX'] or CONFIG['MOZ_XULRUNNER']: DEFINES['HAVE_SIDEBAR'] = True if CONFIG['MOZ_X11']: 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/nsAttrValue.cpp b/dom/base/nsAttrValue.cpp index 8eb1aaf97..ebddcb7ed 100644 --- a/dom/base/nsAttrValue.cpp +++ b/dom/base/nsAttrValue.cpp @@ -742,7 +742,7 @@ nsAttrValue::GetAsAtom() const { switch (Type()) { case eString: - return NS_Atomize(GetStringValue()); + return NS_AtomizeMainThread(GetStringValue()); case eAtom: { @@ -754,7 +754,7 @@ nsAttrValue::GetAsAtom() const { nsAutoString val; ToString(val); - return NS_Atomize(val); + return NS_AtomizeMainThread(val); } } } @@ -1267,7 +1267,7 @@ nsAttrValue::ParseAtomArray(const nsAString& aValue) ++iter; } while (iter != end && !nsContentUtils::IsHTMLWhitespace(*iter)); - nsCOMPtr<nsIAtom> classAtom = NS_Atomize(Substring(start, iter)); + nsCOMPtr<nsIAtom> classAtom = NS_AtomizeMainThread(Substring(start, iter)); if (!classAtom) { Reset(); return; @@ -1308,7 +1308,7 @@ nsAttrValue::ParseAtomArray(const nsAString& aValue) ++iter; } while (iter != end && !nsContentUtils::IsHTMLWhitespace(*iter)); - classAtom = NS_Atomize(Substring(start, iter)); + classAtom = NS_AtomizeMainThread(Substring(start, iter)); if (!array->AppendElement(classAtom)) { Reset(); @@ -1757,7 +1757,7 @@ nsAttrValue::SetMiscAtomOrString(const nsAString* aValue) "Empty string?"); MiscContainer* cont = GetMiscContainer(); if (len <= NS_ATTRVALUE_MAX_STRINGLENGTH_ATOM) { - nsCOMPtr<nsIAtom> atom = NS_Atomize(*aValue); + nsCOMPtr<nsIAtom> atom = NS_AtomizeMainThread(*aValue); if (atom) { cont->mStringBits = reinterpret_cast<uintptr_t>(atom.forget().take()) | eAtomBase; 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/nsContentPolicy.cpp b/dom/base/nsContentPolicy.cpp index 5511b9086..534466103 100644 --- a/dom/base/nsContentPolicy.cpp +++ b/dom/base/nsContentPolicy.cpp @@ -22,6 +22,7 @@ #include "nsIDOMWindow.h" #include "nsITabChild.h" #include "nsIContent.h" +#include "nsIImageLoadingContent.h" #include "nsILoadContext.h" #include "nsCOMArray.h" #include "nsContentUtils.h" @@ -145,6 +146,16 @@ nsContentPolicy::CheckPolicy(CPMethod policyMethod, decision); if (NS_SUCCEEDED(rv) && NS_CP_REJECTED(*decision)) { + // If we are blocking an image, we have to let the + // ImageLoadingContent know that we blocked the load. + if (externalType == nsIContentPolicy::TYPE_IMAGE || + externalType == nsIContentPolicy::TYPE_IMAGESET) { + nsCOMPtr<nsIImageLoadingContent> img = + do_QueryInterface(requestingContext); + if (img) { + img->SetBlockedRequest(*decision); + } + } /* policy says no, no point continuing to check */ return NS_OK; } @@ -193,6 +204,16 @@ nsContentPolicy::CheckPolicy(CPMethod policyMethod, decision); if (NS_SUCCEEDED(rv) && NS_CP_REJECTED(*decision)) { + // If we are blocking an image, we have to let the + // ImageLoadingContent know that we blocked the load. + if (externalType == nsIContentPolicy::TYPE_IMAGE || + externalType == nsIContentPolicy::TYPE_IMAGESET) { + nsCOMPtr<nsIImageLoadingContent> img = + do_QueryInterface(requestingContext); + if (img) { + img->SetBlockedRequest(*decision); + } + } /* policy says no, no point continuing to check */ return NS_OK; } diff --git a/dom/base/nsContentSink.cpp b/dom/base/nsContentSink.cpp index 85b3d07bf..490f0ec17 100644 --- a/dom/base/nsContentSink.cpp +++ b/dom/base/nsContentSink.cpp @@ -304,7 +304,8 @@ nsContentSink::ProcessHeaderData(nsIAtom* aHeader, const nsAString& aValue, mDocument->SetHeaderData(aHeader, aValue); - if (aHeader == nsGkAtoms::setcookie) { + if (aHeader == nsGkAtoms::setcookie && + Preferences::GetBool("dom.meta-set-cookie.enabled", true)) { // Don't allow setting cookies in cookie-averse documents. if (mDocument->IsCookieAverse()) { return NS_OK; diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 34c7d23b8..800f40fa1 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -2947,11 +2947,11 @@ nsContentUtils::SplitQName(const nsIContent* aNamespaceResolver, if (*aNamespace == kNameSpaceID_Unknown) return NS_ERROR_FAILURE; - *aLocalName = NS_Atomize(Substring(colon + 1, end)).take(); + *aLocalName = NS_AtomizeMainThread(Substring(colon + 1, end)).take(); } else { *aNamespace = kNameSpaceID_None; - *aLocalName = NS_Atomize(aQName).take(); + *aLocalName = NS_AtomizeMainThread(aQName).take(); } NS_ENSURE_TRUE(aLocalName, NS_ERROR_OUT_OF_MEMORY); return NS_OK; @@ -2976,7 +2976,8 @@ nsContentUtils::GetNodeInfoFromQName(const nsAString& aNamespaceURI, const char16_t* end; qName.EndReading(end); - nsCOMPtr<nsIAtom> prefix = NS_Atomize(Substring(qName.get(), colon)); + nsCOMPtr<nsIAtom> prefix = + NS_AtomizeMainThread(Substring(qName.get(), colon)); rv = aNodeInfoManager->GetNodeInfo(Substring(colon + 1, end), prefix, nsID, aNodeType, aNodeInfo); @@ -3036,7 +3037,7 @@ nsContentUtils::SplitExpatName(const char16_t *aExpatName, nsIAtom **aPrefix, nameStart = (uriEnd + 1); if (nameEnd) { const char16_t *prefixStart = nameEnd + 1; - *aPrefix = NS_Atomize(Substring(prefixStart, pos)).take(); + *aPrefix = NS_AtomizeMainThread(Substring(prefixStart, pos)).take(); } else { nameEnd = pos; @@ -3049,7 +3050,7 @@ nsContentUtils::SplitExpatName(const char16_t *aExpatName, nsIAtom **aPrefix, nameEnd = pos; *aPrefix = nullptr; } - *aLocalName = NS_Atomize(Substring(nameStart, nameEnd)).take(); + *aLocalName = NS_AtomizeMainThread(Substring(nameStart, nameEnd)).take(); } // static @@ -3887,7 +3888,8 @@ nsContentUtils::GetEventMessageAndAtom(const nsAString& aName, } *aEventMessage = eUnidentifiedEvent; - nsCOMPtr<nsIAtom> atom = NS_Atomize(NS_LITERAL_STRING("on") + aName); + nsCOMPtr<nsIAtom> atom = + NS_AtomizeMainThread(NS_LITERAL_STRING("on") + aName); sUserDefinedEvents->AppendObject(atom); mapping.mAtom = atom; mapping.mMessage = eUnidentifiedEvent; @@ -3920,7 +3922,7 @@ nsContentUtils::GetEventMessageAndAtomForListener(const nsAString& aName, if (mapping.mMaybeSpecialSVGorSMILEvent) { // Try the atom version so that we should get the right message for // SVG/SMIL. - atom = NS_Atomize(NS_LITERAL_STRING("on") + aName); + atom = NS_AtomizeMainThread(NS_LITERAL_STRING("on") + aName); msg = GetEventMessage(atom); } else { atom = mapping.mAtom; @@ -7597,6 +7599,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 +7631,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 +7986,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)) { @@ -8443,12 +8478,9 @@ nsContentUtils::InternalContentPolicyTypeToExternalOrWorker(nsContentPolicyType bool nsContentUtils::IsPreloadType(nsContentPolicyType aType) { - if (aType == nsIContentPolicy::TYPE_INTERNAL_SCRIPT_PRELOAD || - aType == nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD || - aType == nsIContentPolicy::TYPE_INTERNAL_STYLESHEET_PRELOAD) { - return true; - } - return false; + return (aType == nsIContentPolicy::TYPE_INTERNAL_SCRIPT_PRELOAD || + aType == nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD || + aType == nsIContentPolicy::TYPE_INTERNAL_STYLESHEET_PRELOAD); } nsresult @@ -9787,3 +9819,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..606d67de9 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -9,13 +9,13 @@ #ifndef nsContentUtils_h___ #define nsContentUtils_h___ -#if defined(XP_WIN) +#ifdef XP_WIN #include <float.h> #endif -#if defined(SOLARIS) +#ifdef XP_SOLARIS #include <ieeefp.h> -#endif +#endif #include "js/TypeDecls.h" #include "js/Value.h" @@ -975,11 +975,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 +2736,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/nsDeprecatedOperationList.h b/dom/base/nsDeprecatedOperationList.h index 8fb381d9d..ea4b05289 100644 --- a/dom/base/nsDeprecatedOperationList.h +++ b/dom/base/nsDeprecatedOperationList.h @@ -44,7 +44,6 @@ DEPRECATED_OPERATION(PannerNodeDoppler) DEPRECATED_OPERATION(NavigatorGetUserMedia) DEPRECATED_OPERATION(WebrtcDeprecatedPrefix) DEPRECATED_OPERATION(RTCPeerConnectionGetStreams) -DEPRECATED_OPERATION(AppCache) DEPRECATED_OPERATION(PrefixedImageSmoothingEnabled) DEPRECATED_OPERATION(PrefixedFullscreenAPI) DEPRECATED_OPERATION(LenientSetter) diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index 8acfd901a..6b8e11db0 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) { @@ -9286,19 +9222,23 @@ already_AddRefed<nsIURI> nsDocument::ResolvePreloadImage(nsIURI *aBaseURI, const nsAString& aSrcAttr, const nsAString& aSrcsetAttr, - const nsAString& aSizesAttr) + const nsAString& aSizesAttr, + bool *aIsImgSet) { nsString sourceURL; + bool isImgSet; if (mPreloadPictureDepth == 1 && !mPreloadPictureFoundSource.IsVoid()) { // We're in a <picture> element and found a URI from a source previous to // this image, use it. sourceURL = mPreloadPictureFoundSource; + isImgSet = true; } else { // Otherwise try to use this <img> as a source HTMLImageElement::SelectSourceForTagWithAttrs(this, false, aSrcAttr, aSrcsetAttr, aSizesAttr, NullString(), NullString(), sourceURL); + isImgSet = !aSrcsetAttr.IsEmpty(); } // Empty sources are not loaded by <img> (i.e. not resolved to the baseURI) @@ -9316,6 +9256,8 @@ nsDocument::ResolvePreloadImage(nsIURI *aBaseURI, return nullptr; } + *aIsImgSet = isImgSet; + // We don't clear mPreloadPictureFoundSource because subsequent <img> tags in // this this <picture> share the same <sources> (though this is not valid per // spec) @@ -9324,16 +9266,12 @@ nsDocument::ResolvePreloadImage(nsIURI *aBaseURI, void nsDocument::MaybePreLoadImage(nsIURI* uri, const nsAString &aCrossOriginAttr, - ReferrerPolicy aReferrerPolicy) + ReferrerPolicy aReferrerPolicy, bool aIsImgSet) { // Early exit if the img is already present in the img-cache // which indicates that the "real" load has already started and // that we shouldn't preload it. - int16_t blockingStatus; - if (nsContentUtils::IsImageInCache(uri, static_cast<nsIDocument *>(this)) || - !nsContentUtils::CanLoadImage(uri, static_cast<nsIDocument *>(this), - this, NodePrincipal(), &blockingStatus, - nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD)) { + if (nsContentUtils::IsImageInCache(uri, static_cast<nsIDocument *>(this))) { return; } @@ -9352,6 +9290,10 @@ nsDocument::MaybePreLoadImage(nsIURI* uri, const nsAString &aCrossOriginAttr, MOZ_CRASH("Unknown CORS mode!"); } + nsContentPolicyType policyType = + aIsImgSet ? nsIContentPolicy::TYPE_IMAGESET : + nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD; + // Image not in cache - trigger preload RefPtr<imgRequestProxy> request; nsresult rv = @@ -9365,7 +9307,7 @@ nsDocument::MaybePreLoadImage(nsIURI* uri, const nsAString &aCrossOriginAttr, loadFlags, NS_LITERAL_STRING("img"), getter_AddRefs(request), - nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD); + policyType); // Pin image-reference to avoid evicting it from the img-cache before // the "real" load occurs. Unpinned in DispatchContentLoadedEvents and @@ -12007,7 +11949,8 @@ nsIDocument::DocAddSizeOfExcludingThis(nsWindowSizes* aWindowSizes) const &aWindowSizes->mLayoutPresShellSize, &aWindowSizes->mLayoutStyleSetsSize, &aWindowSizes->mLayoutTextRunsSize, - &aWindowSizes->mLayoutPresContextSize); + &aWindowSizes->mLayoutPresContextSize, + &aWindowSizes->mLayoutFramePropertiesSize); } aWindowSizes->mPropertyTablesSize += @@ -12356,134 +12299,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 +12327,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..2b29b98fa 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( @@ -950,11 +948,13 @@ public: ResolvePreloadImage(nsIURI *aBaseURI, const nsAString& aSrcAttr, const nsAString& aSrcsetAttr, - const nsAString& aSizesAttr) override; + const nsAString& aSizesAttr, + bool *aIsImgSet) override; virtual void MaybePreLoadImage(nsIURI* uri, const nsAString &aCrossOriginAttr, - ReferrerPolicy aReferrerPolicy) override; + ReferrerPolicy aReferrerPolicy, + bool aIsImgSet) override; virtual void ForgetImagePreload(nsIURI* aURI) override; virtual void MaybePreconnect(nsIURI* uri, @@ -1341,8 +1341,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 +1449,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/nsDocumentEncoder.cpp b/dom/base/nsDocumentEncoder.cpp index 84b128b15..34eb6ed38 100644 --- a/dom/base/nsDocumentEncoder.cpp +++ b/dom/base/nsDocumentEncoder.cpp @@ -82,7 +82,9 @@ protected: nsAString& aStr, bool aDontSerializeRoot, uint32_t aMaxLength = 0); - nsresult SerializeNodeEnd(nsINode* aNode, nsAString& aStr); + nsresult SerializeNodeEnd(nsINode* aOriginalNode, + nsAString& aStr, + nsINode* aFixupNode = nullptr); // This serializes the content of aNode. nsresult SerializeToStringIterative(nsINode* aNode, nsAString& aStr); @@ -405,14 +407,37 @@ nsDocumentEncoder::SerializeNodeStart(nsINode* aNode, } nsresult -nsDocumentEncoder::SerializeNodeEnd(nsINode* aNode, - nsAString& aStr) +nsDocumentEncoder::SerializeNodeEnd(nsINode* aOriginalNode, + nsAString& aStr, + nsINode* aFixupNode) { - if (!IsVisibleNode(aNode)) + if (!IsVisibleNode(aOriginalNode)) return NS_OK; - if (aNode->IsElement()) { - mSerializer->AppendElementEnd(aNode->AsElement(), aStr); + nsINode* node = nullptr; + nsCOMPtr<nsINode> fixedNodeKungfuDeathGrip; + + // Caller didn't do fixup, so we'll do it ourselves + if (!aFixupNode) { + aFixupNode = aOriginalNode; + if (mNodeFixup) { + bool dummy; + nsCOMPtr<nsIDOMNode> domNodeIn = do_QueryInterface(aOriginalNode); + nsCOMPtr<nsIDOMNode> domNodeOut; + mNodeFixup->FixupNode(domNodeIn, &dummy, getter_AddRefs(domNodeOut)); + fixedNodeKungfuDeathGrip = do_QueryInterface(domNodeOut); + node = fixedNodeKungfuDeathGrip; + } + } + + // Fall back to original node if needed. + if (!node) + node = aOriginalNode; + + if (node->IsElement()) { + mSerializer->AppendElementEnd(node->AsElement(), + aOriginalNode->AsElement(), + aStr); } return NS_OK; } @@ -481,7 +506,7 @@ nsDocumentEncoder::SerializeToStringRecursive(nsINode* aNode, } if (!aDontSerializeRoot) { - rv = SerializeNodeEnd(maybeFixedNode, aStr); + rv = SerializeNodeEnd(aNode, aStr, maybeFixedNode); NS_ENSURE_SUCCESS(rv, rv); } 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..1288b3435 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 @@ -1031,11 +1026,6 @@ public: return false; } - virtual bool watch(JSContext *cx, JS::Handle<JSObject*> proxy, - JS::Handle<jsid> id, JS::Handle<JSObject*> callable) const override; - virtual bool unwatch(JSContext *cx, JS::Handle<JSObject*> proxy, - JS::Handle<jsid> id) const override; - static void ObjectMoved(JSObject *obj, const JSObject *old); static const nsOuterWindowProxy singleton; @@ -1403,20 +1393,6 @@ nsOuterWindowProxy::AppendIndexedPropertyNames(JSContext *cx, JSObject *proxy, return true; } -bool -nsOuterWindowProxy::watch(JSContext *cx, JS::Handle<JSObject*> proxy, - JS::Handle<jsid> id, JS::Handle<JSObject*> callable) const -{ - return js::WatchGuts(cx, proxy, id, callable); -} - -bool -nsOuterWindowProxy::unwatch(JSContext *cx, JS::Handle<JSObject*> proxy, - JS::Handle<jsid> id) const -{ - return js::UnwatchGuts(cx, proxy, id); -} - void nsOuterWindowProxy::ObjectMoved(JSObject *obj, const JSObject *old) { @@ -1522,7 +1498,6 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow) mIsPopupSpam(false), mBlockScriptedClosingFlag(false), mWasOffline(false), - mHasHadSlowScript(false), mNotifyIdleObserversIdleOnThaw(false), mNotifyIdleObserversActiveOnThaw(false), mCreatingInnerWindow(false), @@ -1533,7 +1508,6 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow) mShowFocusRingForContent(false), mFocusByKeyOccurred(false), mHasGamepad(false), - mHasVREvents(false), #ifdef MOZ_GAMEPAD mHasSeenGamepadInput(false), #endif @@ -1759,9 +1733,6 @@ nsGlobalWindow::~nsGlobalWindow() DropOuterWindowDocs(); } else { - Telemetry::Accumulate(Telemetry::INNERWINDOWS_WITH_MUTATION_LISTENERS, - mMutationBits ? 1 : 0); - if (mListenerManager) { mListenerManager->Disconnect(); mListenerManager = nullptr; @@ -1971,12 +1942,9 @@ nsGlobalWindow::CleanUp() if (IsInnerWindow()) { DisableGamepadUpdates(); mHasGamepad = false; - DisableVRUpdates(); - mHasVREvents = false; DisableIdleCallbackRequests(); } else { MOZ_ASSERT(!mHasGamepad); - MOZ_ASSERT(!mHasVREvents); } if (mCleanMessageManager) { @@ -2027,7 +1995,7 @@ nsGlobalWindow::ClearControllers() } void -nsGlobalWindow::FreeInnerObjects() +nsGlobalWindow::FreeInnerObjects(bool aForDocumentOpen) { NS_ASSERTION(IsInnerWindow(), "Don't free inner objects on an outer window"); @@ -2086,8 +2054,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 +2090,6 @@ nsGlobalWindow::FreeInnerObjects() mHasGamepad = false; mGamepads.Clear(); #endif - DisableVRUpdates(); - mHasVREvents = false; - mVRDisplays.Clear(); } //***************************************************************************** @@ -2277,7 +2244,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 +2265,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 +2319,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) @@ -2521,8 +2485,7 @@ nsGlobalWindow::WouldReuseInnerWindow(nsIDocument* aNewDocument) } bool equal; - if (NS_SUCCEEDED(mDoc->NodePrincipal()->Equals(aNewDocument->NodePrincipal(), - &equal)) && + if (NS_SUCCEEDED(mDoc->NodePrincipal()->EqualsConsideringDomain(aNewDocument->NodePrincipal(), &equal)) && equal) { // The origin is the same. return true; @@ -2695,7 +2658,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 +2967,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 +3060,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 +3085,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); } } @@ -3240,6 +3205,12 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument, newInnerWindow->mLocalStorage = nullptr; newInnerWindow->mSessionStorage = nullptr; + newInnerWindow->mPerformance = nullptr; + + // This must be called after nulling the internal objects because + // we might recreate them here by calling the getter methods, and + // store them into the JS slots. If we null them after, the slot + // values and the objects will be out of sync. newInnerWindow->ClearDocumentDependentSlots(cx); } } else { @@ -3380,18 +3351,21 @@ nsGlobalWindow::InnerSetNewDocument(JSContext* aCx, nsIDocument* aDocument) } mDoc = aDocument; - ClearDocumentDependentSlots(aCx); mFocusedNode = nullptr; mLocalStorage = nullptr; mSessionStorage = nullptr; + mPerformance = nullptr; + + // This must be called after nulling the internal objects because we might + // recreate them here by calling the getter methods, and store them into the JS + // slots. If we null them after, the slot values and the objects will be + // out of sync. + ClearDocumentDependentSlots(aCx); #ifdef DEBUG mLastOpenedURI = aDocument->GetDocumentURI(); #endif - Telemetry::Accumulate(Telemetry::INNERWINDOWS_WITH_MUTATION_LISTENERS, - mMutationBits ? 1 : 0); - // Clear our mutation bitfield. mMutationBits = 0; } @@ -6848,8 +6822,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 +10485,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 +11531,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 +11560,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 +12167,6 @@ nsGlobalWindow::Suspend() ac->RemoveWindowListener(mEnabledSensors[i], this); } DisableGamepadUpdates(); - DisableVRUpdates(); mozilla::dom::workers::SuspendWorkersForWindow(AsInner()); @@ -12288,7 +12230,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 +13386,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 +13978,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 +14122,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/nsHTMLContentSerializer.cpp b/dom/base/nsHTMLContentSerializer.cpp index ab8b4f2b2..c135c4cf8 100644 --- a/dom/base/nsHTMLContentSerializer.cpp +++ b/dom/base/nsHTMLContentSerializer.cpp @@ -301,6 +301,7 @@ nsHTMLContentSerializer::AppendElementStart(Element* aElement, NS_IMETHODIMP nsHTMLContentSerializer::AppendElementEnd(Element* aElement, + Element* aOriginalElement /* unused */, nsAString& aStr) { NS_ENSURE_ARG(aElement); diff --git a/dom/base/nsHTMLContentSerializer.h b/dom/base/nsHTMLContentSerializer.h index 6f3500e01..8e23d54ca 100644 --- a/dom/base/nsHTMLContentSerializer.h +++ b/dom/base/nsHTMLContentSerializer.h @@ -31,6 +31,7 @@ class nsHTMLContentSerializer final : public nsXHTMLContentSerializer { nsAString& aStr) override; NS_IMETHOD AppendElementEnd(mozilla::dom::Element* aElement, + mozilla::dom::Element* aOriginalElement, nsAString& aStr) override; NS_IMETHOD AppendDocumentStart(nsIDocument *aDocument, diff --git a/dom/base/nsIContentSerializer.h b/dom/base/nsIContentSerializer.h index f023cbc90..35014bd2c 100644 --- a/dom/base/nsIContentSerializer.h +++ b/dom/base/nsIContentSerializer.h @@ -55,6 +55,7 @@ class nsIContentSerializer : public nsISupports { nsAString& aStr) = 0; NS_IMETHOD AppendElementEnd(mozilla::dom::Element* aElement, + mozilla::dom::Element* aOriginalElement, nsAString& aStr) = 0; NS_IMETHOD Flush(nsAString& aStr) = 0; diff --git a/dom/base/nsIDocument.h b/dom/base/nsIDocument.h index 7a73fae71..d76a12d71 100644 --- a/dom/base/nsIDocument.h +++ b/dom/base/nsIDocument.h @@ -2260,21 +2260,27 @@ public: * nesting and possible sources, which are used to inform URL selection * responsive <picture> or <img srcset> images. Unset attributes are expected * to be marked void. + * If this image is for <picture> or <img srcset>, aIsImgSet will be set to + * true, false otherwise. */ virtual already_AddRefed<nsIURI> ResolvePreloadImage(nsIURI *aBaseURI, const nsAString& aSrcAttr, const nsAString& aSrcsetAttr, - const nsAString& aSizesAttr) = 0; + const nsAString& aSizesAttr, + bool *aIsImgSet) = 0; /** * Called by nsParser to preload images. Can be removed and code moved * to nsPreloadURIs::PreloadURIs() in file nsParser.cpp whenever the * parser-module is linked with gklayout-module. aCrossOriginAttr should * be a void string if the attr is not present. + * aIsImgSet is the value got from calling ResolvePreloadImage, it is true + * when this image is for loading <picture> or <img srcset> images. */ virtual void MaybePreLoadImage(nsIURI* uri, const nsAString& aCrossOriginAttr, - ReferrerPolicyEnum aReferrerPolicy) = 0; + ReferrerPolicyEnum aReferrerPolicy, + bool aIsImgSet) = 0; /** * Called by images to forget an image preload when they start doing @@ -3439,13 +3445,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/nsIImageLoadingContent.idl b/dom/base/nsIImageLoadingContent.idl index fea261a34..eacc4ac3a 100644 --- a/dom/base/nsIImageLoadingContent.idl +++ b/dom/base/nsIImageLoadingContent.idl @@ -104,6 +104,15 @@ interface nsIImageLoadingContent : imgINotificationObserver imgIRequest getRequest(in long aRequestType); /** + * Call this function when the request was blocked by any of the + * security policies enforced. + * + * @param aContentDecision the decision returned from nsIContentPolicy + * (any of the types REJECT_*) + */ + void setBlockedRequest(in int16_t aContentDecision); + + /** * @return true if the current request's size is available. */ [noscript, notxpcom] boolean currentRequestHasSize(); 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/nsImageLoadingContent.cpp b/dom/base/nsImageLoadingContent.cpp index 0c6c37b44..4aad55941 100644 --- a/dom/base/nsImageLoadingContent.cpp +++ b/dom/base/nsImageLoadingContent.cpp @@ -44,6 +44,7 @@ #include "mozAutoDocUpdate.h" #include "mozilla/AsyncEventDispatcher.h" +#include "mozilla/AutoRestore.h" #include "mozilla/EventStates.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/ImageTracker.h" @@ -94,7 +95,8 @@ nsImageLoadingContent::nsImageLoadingContent() mNewRequestsWillNeedAnimationReset(false), mStateChangerDepth(0), mCurrentRequestRegistered(false), - mPendingRequestRegistered(false) + mPendingRequestRegistered(false), + mIsStartingImageLoad(false) { if (!nsContentUtils::GetImgLoaderForChannel(nullptr, nullptr)) { mLoadingEnabled = false; @@ -785,6 +787,11 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI, nsIDocument* aDocument, nsLoadFlags aLoadFlags) { + MOZ_ASSERT(!mIsStartingImageLoad, "some evil code is reentering LoadImage."); + if (mIsStartingImageLoad) { + return NS_OK; + } + // Pending load/error events need to be canceled in some situations. This // is not documented in the spec, but can cause site compat problems if not // done. See bug 1309461 and https://github.com/whatwg/html/issues/1872. @@ -814,6 +821,21 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI, } } + AutoRestore<bool> guard(mIsStartingImageLoad); + mIsStartingImageLoad = true; + + // Data documents, or documents from DOMParser shouldn't perform image loading. + if (aDocument->IsLoadedAsData()) { + // This is the only codepath on which we can reach SetBlockedRequest while + // our pending request exists. Just clear it out here if we do have one. + ClearPendingRequest(NS_BINDING_ABORTED, + Some(OnNonvisible::DISCARD_IMAGES)); + SetBlockedRequest(nsIContentPolicy::REJECT_REQUEST); + FireEvent(NS_LITERAL_STRING("error")); + FireEvent(NS_LITERAL_STRING("loadend")); + return NS_OK; + } + // URI equality check. // // We skip the equality check if our current image was blocked, since in that @@ -844,23 +866,8 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI, "Principal mismatch?"); #endif - // Are we blocked? - int16_t cpDecision = nsIContentPolicy::REJECT_REQUEST; nsContentPolicyType policyType = PolicyTypeForLoad(aImageLoadType); - nsContentUtils::CanLoadImage(aNewURI, - static_cast<nsIImageLoadingContent*>(this), - aDocument, - aDocument->NodePrincipal(), - &cpDecision, - policyType); - if (!NS_CP_ACCEPTED(cpDecision)) { - FireEvent(NS_LITERAL_STRING("error")); - FireEvent(NS_LITERAL_STRING("loadend")); - SetBlockedRequest(aNewURI, cpDecision); - return NS_OK; - } - nsLoadFlags loadFlags = aLoadFlags; int32_t corsmode = GetCORSMode(); if (corsmode == CORS_ANONYMOUS) { @@ -878,7 +885,6 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI, referrerPolicy = imgReferrerPolicy; } - // Not blocked. Do the load. RefPtr<imgRequestProxy>& req = PrepareNextRequest(aImageLoadType); nsCOMPtr<nsIContent> content = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this)); @@ -932,7 +938,6 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI, FireEvent(NS_LITERAL_STRING("error")); FireEvent(NS_LITERAL_STRING("loadend")); - return NS_OK; } return NS_OK; @@ -1212,46 +1217,42 @@ nsImageLoadingContent::PrepareNextRequest(ImageLoadType aImageLoadType) mMostRecentRequestChange = now; } - // If we don't have a usable current request, get rid of any half-baked - // request that might be sitting there and make this one current. - if (!HaveSize(mCurrentRequest)) - return PrepareCurrentRequest(aImageLoadType); - // Otherwise, make it pending. - return PreparePendingRequest(aImageLoadType); + // We only want to cancel the existing current request if size is not + // available. bz says the web depends on this behavior. + // Otherwise, we get rid of any half-baked request that might be sitting there + // and make this one current. + // TODO: Bug 583491 + // Investigate/Cleanup NS_ERROR_IMAGE_SRC_CHANGED use in nsImageFrame.cpp + return HaveSize(mCurrentRequest) ? + PreparePendingRequest(aImageLoadType) : + PrepareCurrentRequest(aImageLoadType); } -void -nsImageLoadingContent::SetBlockedRequest(nsIURI* aURI, int16_t aContentDecision) +nsresult +nsImageLoadingContent::SetBlockedRequest(int16_t aContentDecision) { + // If this is not calling from LoadImage, for example, from ServiceWorker, + // bail out. + if (!mIsStartingImageLoad) { + return NS_OK; + } + // Sanity MOZ_ASSERT(!NS_CP_ACCEPTED(aContentDecision), "Blocked but not?"); - // We do some slightly illogical stuff here to maintain consistency with - // old behavior that people probably depend on. Even in the case where the - // new image is blocked, the old one should really be canceled with the - // reason "image source changed". However, apparently there's some abuse - // over in nsImageFrame where the displaying of the "broken" icon for the - // next image depends on the cancel reason of the previous image. ugh. - // XXX(seth): So shouldn't we fix nsImageFrame?! - ClearPendingRequest(NS_ERROR_IMAGE_BLOCKED, - Some(OnNonvisible::DISCARD_IMAGES)); - - // For the blocked case, we only want to cancel the existing current request - // if size is not available. bz says the web depends on this behavior. - if (!HaveSize(mCurrentRequest)) { + // We should never have a pending request after we got blocked. + MOZ_ASSERT(!mPendingRequest, "mPendingRequest should be null."); + if (HaveSize(mCurrentRequest)) { + // PreparePendingRequest set mPendingRequestFlags, now since we've decided + // to block it, we reset it back to 0. + mPendingRequestFlags = 0; + } else { mImageBlockingStatus = aContentDecision; - uint32_t keepFlags = mCurrentRequestFlags & REQUEST_IS_IMAGESET; - ClearCurrentRequest(NS_ERROR_IMAGE_BLOCKED, - Some(OnNonvisible::DISCARD_IMAGES)); - - // We still want to remember what URI we were and if it was an imageset, - // despite not having an actual request. These are both cleared as part of - // ClearCurrentRequest() before a new request is started. - mCurrentURI = aURI; - mCurrentRequestFlags = keepFlags; } + + return NS_OK; } RefPtr<imgRequestProxy>& @@ -1262,7 +1263,7 @@ nsImageLoadingContent::PrepareCurrentRequest(ImageLoadType aImageLoadType) mImageBlockingStatus = nsIContentPolicy::ACCEPT; // Get rid of anything that was there previously. - ClearCurrentRequest(NS_ERROR_IMAGE_SRC_CHANGED, + ClearCurrentRequest(NS_BINDING_ABORTED, Some(OnNonvisible::DISCARD_IMAGES)); if (mNewRequestsWillNeedAnimationReset) { @@ -1281,7 +1282,7 @@ RefPtr<imgRequestProxy>& nsImageLoadingContent::PreparePendingRequest(ImageLoadType aImageLoadType) { // Get rid of anything that was there previously. - ClearPendingRequest(NS_ERROR_IMAGE_SRC_CHANGED, + ClearPendingRequest(NS_BINDING_ABORTED, Some(OnNonvisible::DISCARD_IMAGES)); if (mNewRequestsWillNeedAnimationReset) { diff --git a/dom/base/nsImageLoadingContent.h b/dom/base/nsImageLoadingContent.h index 5f7daff72..cfb2a6207 100644 --- a/dom/base/nsImageLoadingContent.h +++ b/dom/base/nsImageLoadingContent.h @@ -303,17 +303,10 @@ protected: RefPtr<imgRequestProxy>& PrepareNextRequest(ImageLoadType aImageLoadType); /** - * Called when we would normally call PrepareNextRequest(), but the request was - * blocked. - */ - void SetBlockedRequest(nsIURI* aURI, int16_t aContentDecision); - - /** * Returns a COMPtr reference to the current/pending image requests, cleaning * up and canceling anything that was there before. Note that if you just want * to get rid of one of the requests, you should call - * Clear*Request(NS_BINDING_ABORTED) instead, since it passes a more appropriate - * aReason than Prepare*Request() does (NS_ERROR_IMAGE_SRC_CHANGED). + * Clear*Request(NS_BINDING_ABORTED) instead. * * @param aImageLoadType The ImageLoadType for this request */ @@ -459,6 +452,14 @@ private: // registered with the refresh driver. bool mCurrentRequestRegistered; bool mPendingRequestRegistered; + + // This member is used in SetBlockedRequest, if it's true, then this call is + // triggered from LoadImage. + // If this is false, it means this call is from other places like + // ServiceWorker, then we will ignore call to SetBlockedRequest for now. + // + // Also we use this variable to check if some evil code is reentering LoadImage. + bool mIsStartingImageLoad; }; #endif // nsImageLoadingContent_h__ 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..1f751ea71 100644 --- a/dom/base/nsNodeInfoManager.cpp +++ b/dom/base/nsNodeInfoManager.cpp @@ -112,7 +112,8 @@ nsNodeInfoManager::nsNodeInfoManager() mNonDocumentNodeInfos(0), mTextNodeInfo(nullptr), mCommentNodeInfo(nullptr), - mDocumentNodeInfo(nullptr) + mDocumentNodeInfo(nullptr), + mRecentlyUsedNodeInfos{} { nsLayoutStatics::AddRef(); @@ -232,11 +233,19 @@ nsNodeInfoManager::GetNodeInfo(nsIAtom *aName, nsIAtom *aPrefix, NodeInfo::NodeInfoInner tmpKey(aName, aPrefix, aNamespaceID, aNodeType, aExtraName); + uint32_t index = + GetNodeInfoInnerHashValue(&tmpKey) % RECENTLY_USED_NODEINFOS_SIZE; + NodeInfo* ni = mRecentlyUsedNodeInfos[index]; + if (ni && NodeInfoInnerKeyCompare(&(ni->mInner), &tmpKey)) { + RefPtr<NodeInfo> nodeInfo = ni; + return nodeInfo.forget(); + } + void *node = PL_HashTableLookup(mNodeInfoHash, &tmpKey); if (node) { RefPtr<NodeInfo> nodeInfo = static_cast<NodeInfo*>(node); - + mRecentlyUsedNodeInfos[index] = nodeInfo; return nodeInfo.forget(); } @@ -254,6 +263,7 @@ nsNodeInfoManager::GetNodeInfo(nsIAtom *aName, nsIAtom *aPrefix, NS_IF_ADDREF(mDocument); } + mRecentlyUsedNodeInfos[index] = newNodeInfo; return newNodeInfo.forget(); } @@ -272,16 +282,26 @@ nsNodeInfoManager::GetNodeInfo(const nsAString& aName, nsIAtom *aPrefix, NodeInfo::NodeInfoInner tmpKey(aName, aPrefix, aNamespaceID, aNodeType); + uint32_t index = + GetNodeInfoInnerHashValue(&tmpKey) % RECENTLY_USED_NODEINFOS_SIZE; + NodeInfo* ni = mRecentlyUsedNodeInfos[index]; + if (ni && NodeInfoInnerKeyCompare(&(ni->mInner), &tmpKey)) { + RefPtr<NodeInfo> nodeInfo = ni; + nodeInfo.forget(aNodeInfo); + return NS_OK; + } + void *node = PL_HashTableLookup(mNodeInfoHash, &tmpKey); if (node) { RefPtr<NodeInfo> nodeInfo = static_cast<NodeInfo*>(node); + mRecentlyUsedNodeInfos[index] = nodeInfo; nodeInfo.forget(aNodeInfo); return NS_OK; } - nsCOMPtr<nsIAtom> nameAtom = NS_Atomize(aName); + nsCOMPtr<nsIAtom> nameAtom = NS_AtomizeMainThread(aName); NS_ENSURE_TRUE(nameAtom, NS_ERROR_OUT_OF_MEMORY); RefPtr<NodeInfo> newNodeInfo = @@ -297,6 +317,7 @@ nsNodeInfoManager::GetNodeInfo(const nsAString& aName, nsIAtom *aPrefix, NS_IF_ADDREF(mDocument); } + mRecentlyUsedNodeInfos[index] = newNodeInfo; newNodeInfo.forget(aNodeInfo); return NS_OK; @@ -392,9 +413,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; } @@ -424,6 +442,12 @@ nsNodeInfoManager::RemoveNodeInfo(NodeInfo *aNodeInfo) } } + uint32_t index = + GetNodeInfoInnerHashValue(&aNodeInfo->mInner) % RECENTLY_USED_NODEINFOS_SIZE; + if (mRecentlyUsedNodeInfos[index] == aNodeInfo) { + mRecentlyUsedNodeInfos[index] = nullptr; + } + #ifdef DEBUG bool ret = #endif diff --git a/dom/base/nsNodeInfoManager.h b/dom/base/nsNodeInfoManager.h index 6ece66577..759dd391e 100644 --- a/dom/base/nsNodeInfoManager.h +++ b/dom/base/nsNodeInfoManager.h @@ -32,6 +32,8 @@ class NodeInfo; } // namespace dom } // namespace mozilla +#define RECENTLY_USED_NODEINFOS_SIZE 31 + class nsNodeInfoManager final { private: @@ -137,6 +139,7 @@ private: mozilla::dom::NodeInfo * MOZ_NON_OWNING_REF mCommentNodeInfo; // WEAK to avoid circular ownership mozilla::dom::NodeInfo * MOZ_NON_OWNING_REF mDocumentNodeInfo; // WEAK to avoid circular ownership RefPtr<nsBindingManager> mBindingManager; + mozilla::dom::NodeInfo* mRecentlyUsedNodeInfos[RECENTLY_USED_NODEINFOS_SIZE]; }; #endif /* nsNodeInfoManager_h___ */ 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..4978744e8 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" @@ -716,11 +715,13 @@ nsObjectLoadingContent::UnbindFromTree(bool aDeep, bool aNullParent) /// would keep the docshell around, but trash the frameloader UnloadObject(); } - nsIDocument* doc = thisContent->GetComposedDoc(); - if (doc && doc->IsActive()) { - nsCOMPtr<nsIRunnable> ev = new nsSimplePluginEvent(doc, - NS_LITERAL_STRING("PluginRemoved")); - NS_DispatchToCurrentThread(ev); + if (mType == eType_Plugin) { + nsIDocument* doc = thisContent->GetComposedDoc(); + if (doc && doc->IsActive()) { + nsCOMPtr<nsIRunnable> ev = new nsSimplePluginEvent(doc, + NS_LITERAL_STRING("PluginRemoved")); + NS_DispatchToCurrentThread(ev); + } } } @@ -1149,7 +1150,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 +1565,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 +1584,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; } @@ -3634,6 +3628,14 @@ nsObjectLoadingContent::HasGoodFallback() { } } + // RULE "nosrc": + // Use fallback content if the object has not specified a src URI. + if (rulesList[i].EqualsLiteral("nosrc")) { + if (!mOriginalURI) { + return true; + } + } + // RULE "adobelink": // Don't use fallback content when it has a link to adobe's website. if (rulesList[i].EqualsLiteral("adobelink")) { @@ -3800,8 +3802,6 @@ nsObjectLoadingContent::LegacyCall(JSContext* aCx, aRv.Throw(NS_ERROR_FAILURE); return; } - - Telemetry::Accumulate(Telemetry::PLUGIN_CALLED_DIRECTLY, true); } void diff --git a/dom/base/nsPlainTextSerializer.cpp b/dom/base/nsPlainTextSerializer.cpp index ef6bdcac7..8097c4ec8 100644 --- a/dom/base/nsPlainTextSerializer.cpp +++ b/dom/base/nsPlainTextSerializer.cpp @@ -390,6 +390,7 @@ nsPlainTextSerializer::AppendElementStart(Element* aElement, NS_IMETHODIMP nsPlainTextSerializer::AppendElementEnd(Element* aElement, + Element* aOriginalElement /* unused */, nsAString& aStr) { NS_ENSURE_ARG(aElement); diff --git a/dom/base/nsPlainTextSerializer.h b/dom/base/nsPlainTextSerializer.h index 95cf5590c..5055c75a0 100644 --- a/dom/base/nsPlainTextSerializer.h +++ b/dom/base/nsPlainTextSerializer.h @@ -61,6 +61,7 @@ public: mozilla::dom::Element* aOriginalElement, nsAString& aStr) override; NS_IMETHOD AppendElementEnd(mozilla::dom::Element* aElement, + mozilla::dom::Element* aOriginalElement, nsAString& aStr) override; NS_IMETHOD Flush(nsAString& aStr) override; 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 61d122386..3ac00142d 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/nsWindowMemoryReporter.cpp b/dom/base/nsWindowMemoryReporter.cpp index acec4acfb..8f4bf6b11 100644 --- a/dom/base/nsWindowMemoryReporter.cpp +++ b/dom/base/nsWindowMemoryReporter.cpp @@ -400,6 +400,12 @@ CollectWindowReports(nsGlobalWindow *aWindow, aWindowTotalSizes->mLayoutPresContextSize += windowSizes.mLayoutPresContextSize; + REPORT_SIZE("/layout/frame-properties", windowSizes.mLayoutFramePropertiesSize, + "Memory used for frame properties attached to frames " + "within a window."); + aWindowTotalSizes->mLayoutFramePropertiesSize += + windowSizes.mLayoutFramePropertiesSize; + // There are many different kinds of frames, but it is very likely // that only a few matter. Implement a cutoff so we don't bloat // about:memory with many uninteresting entries. @@ -563,6 +569,9 @@ nsWindowMemoryReporter::CollectReports(nsIHandleReportCallback* aHandleReport, REPORT("window-objects/layout/pres-contexts", windowTotalSizes.mLayoutPresContextSize, "This is the sum of all windows' 'layout/pres-contexts' numbers."); + REPORT("window-objects/layout/frame-properties", windowTotalSizes.mLayoutFramePropertiesSize, + "This is the sum of all windows' 'layout/frame-properties' numbers."); + size_t frameTotal = 0; #define FRAME_ID(classname) \ frameTotal += windowTotalSizes.mArenaStats.FRAME_ID_STAT_FIELD(classname); diff --git a/dom/base/nsWindowMemoryReporter.h b/dom/base/nsWindowMemoryReporter.h index b9e986959..5d40dc9f5 100644 --- a/dom/base/nsWindowMemoryReporter.h +++ b/dom/base/nsWindowMemoryReporter.h @@ -33,6 +33,7 @@ class nsWindowSizes { macro(Style, mLayoutStyleSetsSize) \ macro(Other, mLayoutTextRunsSize) \ macro(Other, mLayoutPresContextSize) \ + macro(Other, mLayoutFramePropertiesSize) \ macro(Other, mPropertyTablesSize) \ public: 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/base/nsXHTMLContentSerializer.cpp b/dom/base/nsXHTMLContentSerializer.cpp index 111ed46c7..0a39ef663 100755 --- a/dom/base/nsXHTMLContentSerializer.cpp +++ b/dom/base/nsXHTMLContentSerializer.cpp @@ -514,6 +514,7 @@ nsXHTMLContentSerializer::CheckElementStart(nsIContent * aContent, bool nsXHTMLContentSerializer::CheckElementEnd(mozilla::dom::Element* aElement, + mozilla::dom::Element* aOriginalElement, bool& aForceFormat, nsAString& aStr) { @@ -532,7 +533,7 @@ nsXHTMLContentSerializer::CheckElementEnd(mozilla::dom::Element* aElement, } bool dummyFormat; - return nsXMLContentSerializer::CheckElementEnd(aElement, dummyFormat, aStr); + return nsXMLContentSerializer::CheckElementEnd(aElement, aOriginalElement, dummyFormat, aStr); } bool diff --git a/dom/base/nsXHTMLContentSerializer.h b/dom/base/nsXHTMLContentSerializer.h index 7473ba074..79ecf28f1 100644 --- a/dom/base/nsXHTMLContentSerializer.h +++ b/dom/base/nsXHTMLContentSerializer.h @@ -53,6 +53,7 @@ class nsXHTMLContentSerializer : public nsXMLContentSerializer { nsAString& aStr) override; virtual bool CheckElementEnd(mozilla::dom::Element* aContent, + mozilla::dom::Element* aOriginalElement, bool& aForceFormat, nsAString& aStr) override; diff --git a/dom/base/nsXMLContentSerializer.cpp b/dom/base/nsXMLContentSerializer.cpp index 54fadaa94..f12bb8fdc 100644 --- a/dom/base/nsXMLContentSerializer.cpp +++ b/dom/base/nsXMLContentSerializer.cpp @@ -1028,6 +1028,7 @@ nsXMLContentSerializer::AppendEndOfElementStart(Element* aElement, NS_IMETHODIMP nsXMLContentSerializer::AppendElementEnd(Element* aElement, + Element* aOriginalElement, nsAString& aStr) { NS_ENSURE_ARG(aElement); @@ -1035,7 +1036,7 @@ nsXMLContentSerializer::AppendElementEnd(Element* aElement, nsIContent* content = aElement; bool forceFormat = false, outputElementEnd; - outputElementEnd = CheckElementEnd(aElement, forceFormat, aStr); + outputElementEnd = CheckElementEnd(aElement, aOriginalElement, forceFormat, aStr); nsIAtom *name = content->NodeInfo()->NameAtom(); @@ -1161,16 +1162,14 @@ nsXMLContentSerializer::CheckElementStart(nsIContent * aContent, bool nsXMLContentSerializer::CheckElementEnd(Element* aElement, + Element* aOriginalElement, bool& aForceFormat, nsAString& aStr) { // We don't output a separate end tag for empty element aForceFormat = false; - // XXXbz this is a bit messed up, but by now we don't have our fixed-up - // version of aElement anymore. Let's hope fixup never changes the localName - // or namespace... - return ElementNeedsSeparateEndTag(aElement, aElement); + return ElementNeedsSeparateEndTag(aElement, aOriginalElement); } bool diff --git a/dom/base/nsXMLContentSerializer.h b/dom/base/nsXMLContentSerializer.h index 941acb179..2f76b0892 100644 --- a/dom/base/nsXMLContentSerializer.h +++ b/dom/base/nsXMLContentSerializer.h @@ -59,6 +59,7 @@ class nsXMLContentSerializer : public nsIContentSerializer { nsAString& aStr) override; NS_IMETHOD AppendElementEnd(mozilla::dom::Element* aElement, + mozilla::dom::Element* aOriginalElement, nsAString& aStr) override; NS_IMETHOD Flush(nsAString& aStr) override { return NS_OK; } @@ -263,6 +264,7 @@ class nsXMLContentSerializer : public nsIContentSerializer { * @return boolean true if the element can be output */ virtual bool CheckElementEnd(mozilla::dom::Element* aElement, + mozilla::dom::Element* aOriginalElement, bool& aForceFormat, nsAString& aStr); diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp index 7056658a7..6e0db29b1 100644 --- a/dom/bindings/BindingUtils.cpp +++ b/dom/bindings/BindingUtils.cpp @@ -119,7 +119,7 @@ ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs, MSG_METHOD_THIS_DOES_NOT_IMPLEMENT_INTERFACE; MOZ_RELEASE_ASSERT(GetErrorArgCount(errorNumber) <= 2); JS_ReportErrorNumberUC(aCx, GetErrorMessage, nullptr, - static_cast<const unsigned>(errorNumber), + static_cast<unsigned>(errorNumber), funcNameStr.get(), ifaceName.get()); return false; } @@ -226,7 +226,7 @@ TErrorResult<CleanupPolicy>::SetPendingExceptionWithMessage(JSContext* aCx) args[argCount] = nullptr; JS_ReportErrorNumberUCArray(aCx, dom::GetErrorMessage, nullptr, - static_cast<const unsigned>(message->mErrorNumber), + static_cast<unsigned>(message->mErrorNumber), argCount > 0 ? args : nullptr); ClearMessage(); @@ -1184,14 +1184,6 @@ GetInterfaceImpl(JSContext* aCx, nsIInterfaceRequestor* aRequestor, } bool -UnforgeableValueOf(JSContext* cx, unsigned argc, JS::Value* vp) -{ - JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - args.rval().set(args.thisv()); - return true; -} - -bool ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp) { return ThrowErrorMessage(cx, MSG_ILLEGAL_CONSTRUCTOR); @@ -1976,8 +1968,6 @@ const js::ObjectOps sInterfaceObjectClassObjectOps = { nullptr, /* setProperty */ nullptr, /* getOwnPropertyDescriptor */ nullptr, /* deleteProperty */ - nullptr, /* watch */ - nullptr, /* unwatch */ nullptr, /* getElements */ nullptr, /* enumerate */ InterfaceObjectToString, /* funToString */ @@ -2558,7 +2548,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 +2565,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..5cab835b3 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() { @@ -2045,9 +2045,6 @@ GetInterface(JSContext* aCx, T* aThis, nsIJSID* aIID, } bool -UnforgeableValueOf(JSContext* cx, unsigned argc, JS::Value* vp); - -bool ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp); bool @@ -2127,11 +2124,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 +2174,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 +2316,26 @@ public: } }; -template<typename T> -static void -TraceMozMapValue(T* aValue, void* aClosure) +template<typename K, typename V> +void TraceRecord(JSTracer* trc, Record<K, V>& record) { - 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) -{ - 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 +2413,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..924241aa0 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 @@ -2388,11 +2390,10 @@ class MethodDefiner(PropertyDefiner): # Synthesize our valueOf method self.regular.append({ "name": 'valueOf', - "nativeName": "UnforgeableValueOf", + "selfHostedName": "Object_valueOf", "methodInfo": False, "length": 0, - "flags": "JSPROP_ENUMERATE", # readonly/permanent added - # automatically. + "flags": "0", # readonly/permanent added automatically. "condition": MemberCondition() }) @@ -3454,19 +3455,15 @@ def InitUnforgeablePropertiesOnHolder(descriptor, properties, failureCode, "nsContentUtils::ThreadsafeIsCallerChrome()")) if descriptor.interface.getExtendedAttribute("Unforgeable"): - # We do our undefined toJSON and toPrimitive here, not as a regular - # property because we don't have a concept of value props anywhere in - # IDL. + # We do our undefined toPrimitive here, not as a regular property + # because we don't have a concept of value props anywhere in IDL. unforgeables.append(CGGeneric(fill( """ JS::RootedId toPrimitive(aCx, SYMBOL_TO_JSID(JS::GetWellKnownSymbol(aCx, JS::SymbolCode::toPrimitive))); if (!JS_DefinePropertyById(aCx, ${holderName}, toPrimitive, JS::UndefinedHandleValue, - JSPROP_READONLY | JSPROP_PERMANENT) || - !JS_DefineProperty(aCx, ${holderName}, "toJSON", - JS::UndefinedHandleValue, - JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT)) { + JSPROP_READONLY | JSPROP_PERMANENT)) { $*{failureCode} } """, @@ -4290,6 +4287,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 +4355,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 +4367,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 +4572,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 +4738,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 +4785,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 +4983,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 +5008,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 +5031,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 +5213,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 +5594,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 +5757,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 +5769,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 +5793,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 +5837,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 +6326,7 @@ def getMaybeWrapValueFuncForType(type): sequenceWrapLevel = 0 -mozMapWrapLevel = 0 +recordWrapLevel = 0 def getWrapTemplateForType(type, descriptorProvider, result, successCode, @@ -6361,7 +6431,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 +6504,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 +6524,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 +6547,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 +6569,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 +6854,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 +6950,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 +7061,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 +7223,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 +7284,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 +8193,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 +9491,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 +9752,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 +10128,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() @@ -13081,9 +13169,9 @@ class CGDictionary(CGThing): # continues to match the list in test_Object.prototype_props.html if (member.identifier.name in ["constructor", "toSource", "toString", "toLocaleString", "valueOf", - "watch", "unwatch", "hasOwnProperty", "isPrototypeOf", - "propertyIsEnumerable", "__defineGetter__", "__defineSetter__", - "__lookupGetter__", "__lookupSetter__", "__proto__"]): + "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable", + "__defineGetter__", "__defineSetter__", "__lookupGetter__", + "__lookupSetter__", "__proto__"]): raise TypeError("'%s' member of %s dictionary shadows " "a property of Object.prototype, and Xrays to " "Object can't handle that.\n" @@ -13172,8 +13260,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 +13671,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 +14177,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 +14227,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 +14295,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 +14306,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 +15083,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/DOMJSProxyHandler.cpp b/dom/bindings/DOMJSProxyHandler.cpp index 23f0abd88..49281c1c2 100644 --- a/dom/bindings/DOMJSProxyHandler.cpp +++ b/dom/bindings/DOMJSProxyHandler.cpp @@ -275,19 +275,6 @@ DOMProxyHandler::delete_(JSContext* cx, JS::Handle<JSObject*> proxy, } bool -BaseDOMProxyHandler::watch(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id, - JS::Handle<JSObject*> callable) const -{ - return js::WatchGuts(cx, proxy, id, callable); -} - -bool -BaseDOMProxyHandler::unwatch(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id) const -{ - return js::UnwatchGuts(cx, proxy, id); -} - -bool BaseDOMProxyHandler::ownPropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy, JS::AutoIdVector& props) const diff --git a/dom/bindings/DOMJSProxyHandler.h b/dom/bindings/DOMJSProxyHandler.h index 1781649cc..e3e151b7a 100644 --- a/dom/bindings/DOMJSProxyHandler.h +++ b/dom/bindings/DOMJSProxyHandler.h @@ -72,11 +72,6 @@ public: virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy, JS::AutoIdVector &props) const override; - bool watch(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id, - JS::Handle<JSObject*> callable) const override; - bool unwatch(JSContext* cx, JS::Handle<JSObject*> proxy, - JS::Handle<jsid> id) const override; - protected: // Hook for subclasses to implement shared ownPropertyKeys()/keys() // functionality. The "flags" argument is either JSITER_OWNONLY (for keys()) diff --git a/dom/bindings/ErrorResult.h b/dom/bindings/ErrorResult.h index 7c3fc9e2f..da7ec30e7 100644 --- a/dom/bindings/ErrorResult.h +++ b/dom/bindings/ErrorResult.h @@ -75,7 +75,7 @@ template<typename... Ts> inline bool ThrowErrorMessage(JSContext* aCx, const ErrNum aErrorNumber, Ts&&... aArgs) { - binding_detail::ThrowErrorMessage(aCx, static_cast<const unsigned>(aErrorNumber), + binding_detail::ThrowErrorMessage(aCx, static_cast<unsigned>(aErrorNumber), mozilla::Forward<Ts>(aArgs)...); return false; } 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..ed8a4d37e 100644 --- a/dom/bindings/moz.build +++ b/dom/bindings/moz.build @@ -6,6 +6,12 @@ TEST_DIRS += ['test'] +XPIDL_SOURCES += [ + 'nsIScriptError.idl' +] + +XPIDL_MODULE = 'dom_bindings' + EXPORTS.ipc += [ 'ErrorIPCUtils.h', ] @@ -32,10 +38,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', @@ -91,6 +97,8 @@ UNIFIED_SOURCES += [ 'DOMJSProxyHandler.cpp', 'Exceptions.cpp', 'IterableIterator.cpp', + 'nsScriptError.cpp', + 'nsScriptErrorWithStack.cpp', 'SimpleGlobalObject.cpp', 'ToJSValue.cpp', 'WebIDLGlobalNameHash.cpp', @@ -139,7 +147,7 @@ FINAL_LIBRARY = 'xul' SPHINX_TREES['webidl'] = 'docs' SPHINX_PYTHON_PACKAGE_DIRS += ['mozwebidlcodegen'] -if CONFIG['MOZ_PHOENIX'] or CONFIG['MOZ_FENNEC'] or CONFIG['MOZ_XULRUNNER']: +if CONFIG['MOZ_PHOENIX'] or CONFIG['MOZ_XULRUNNER']: # This is needed for Window.webidl DEFINES['HAVE_SIDEBAR'] = True diff --git a/dom/bindings/nsIScriptError.idl b/dom/bindings/nsIScriptError.idl new file mode 100644 index 000000000..8436361a8 --- /dev/null +++ b/dom/bindings/nsIScriptError.idl @@ -0,0 +1,135 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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/. */ + +/* + * nsIConsoleMessage subclass for representing JavaScript errors and warnings. + */ + + +#include "nsISupports.idl" +#include "nsIArray.idl" +#include "nsIConsoleMessage.idl" + +%{C++ +#include "nsStringGlue.h" // for nsDependentCString +%} + +[scriptable, uuid(e8933fc9-c302-4e12-a55b-4f88611d9c6c)] +interface nsIScriptErrorNote : nsISupports +{ + readonly attribute AString errorMessage; + readonly attribute AString sourceName; + readonly attribute uint32_t lineNumber; + readonly attribute uint32_t columnNumber; + + AUTF8String toString(); +}; + +[scriptable, uuid(63eb4d3e-7d99-4150-b4f3-11314f9d82a9)] +interface nsIScriptError : nsIConsoleMessage +{ + /** pseudo-flag for default case */ + const unsigned long errorFlag = 0x0; + + /** message is warning */ + const unsigned long warningFlag = 0x1; + + /** exception was thrown for this case - exception-aware hosts can ignore */ + const unsigned long exceptionFlag = 0x2; + + // XXX check how strict is implemented these days. + /** error or warning is due to strict option */ + const unsigned long strictFlag = 0x4; + + /** just a log message */ + const unsigned long infoFlag = 0x8; + + /** + * The error message without any context/line number information. + * + * @note nsIConsoleMessage.message will return the error formatted + * with file/line information. + */ + readonly attribute AString errorMessage; + + readonly attribute AString sourceName; + readonly attribute AString sourceLine; + readonly attribute uint32_t lineNumber; + readonly attribute uint32_t columnNumber; + readonly attribute uint32_t flags; + + /** + * Categories I know about - + * XUL javascript + * content javascript (both of these from nsDocShell, currently) + * system javascript (errors in JS components and other system JS) + */ + readonly attribute string category; + + /* Get the window id this was initialized with. Zero will be + returned if init() was used instead of initWithWindowID(). */ + readonly attribute unsigned long long outerWindowID; + + /* Get the inner window id this was initialized with. Zero will be + returned if init() was used instead of initWithWindowID(). */ + readonly attribute unsigned long long innerWindowID; + + readonly attribute boolean isFromPrivateWindow; + + attribute jsval stack; + + /** + * The name of a template string, as found in js.msg, associated with the + * error message. + */ + attribute AString errorMessageName; + + readonly attribute nsIArray notes; + + void init(in AString message, + in AString sourceName, + in AString sourceLine, + in uint32_t lineNumber, + in uint32_t columnNumber, + in uint32_t flags, + in string category); + + /* This should be called instead of nsIScriptError.init to + initialize with a window id. The window id should be for the + inner window associated with this error. */ + void initWithWindowID(in AString message, + in AString sourceName, + in AString sourceLine, + in uint32_t lineNumber, + in uint32_t columnNumber, + in uint32_t flags, + in ACString category, + in unsigned long long innerWindowID); +%{C++ + // This overload allows passing a literal string for category. + template<uint32_t N> + nsresult InitWithWindowID(const nsAString& message, + const nsAString& sourceName, + const nsAString& sourceLine, + uint32_t lineNumber, + uint32_t columnNumber, + uint32_t flags, + const char (&c)[N], + uint64_t aInnerWindowID) + { + nsDependentCString category(c, N - 1); + return InitWithWindowID(message, sourceName, sourceLine, lineNumber, + columnNumber, flags, category, aInnerWindowID); + } +%} + +}; + +%{ C++ +#define NS_SCRIPTERROR_CID \ +{ 0x1950539a, 0x90f0, 0x4d22, { 0xb5, 0xaf, 0x71, 0x32, 0x9c, 0x68, 0xfa, 0x35 }} + +#define NS_SCRIPTERROR_CONTRACTID "@mozilla.org/scripterror;1" +%} diff --git a/dom/bindings/nsScriptError.cpp b/dom/bindings/nsScriptError.cpp new file mode 100644 index 000000000..9248d1a31 --- /dev/null +++ b/dom/bindings/nsScriptError.cpp @@ -0,0 +1,438 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim: set ts=8 sts=4 et sw=4 tw=99: */ +/* 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/. */ + +/* + * nsIScriptError implementation. + */ + +#include "nsScriptError.h" +#include "jsprf.h" +#include "MainThreadUtils.h" +#include "mozilla/Assertions.h" +#include "nsGlobalWindow.h" +#include "nsNetUtil.h" +#include "nsPIDOMWindow.h" +#include "nsILoadContext.h" +#include "nsIDocShell.h" +#include "nsIMutableArray.h" +#include "nsIScriptError.h" +#include "nsISensitiveInfoHiddenURI.h" + +static_assert(nsIScriptError::errorFlag == JSREPORT_ERROR && + nsIScriptError::warningFlag == JSREPORT_WARNING && + nsIScriptError::exceptionFlag == JSREPORT_EXCEPTION && + nsIScriptError::strictFlag == JSREPORT_STRICT && + nsIScriptError::infoFlag == JSREPORT_USER_1, + "flags should be consistent"); + +nsScriptErrorBase::nsScriptErrorBase() + : mMessage(), + mMessageName(), + mSourceName(), + mLineNumber(0), + mSourceLine(), + mColumnNumber(0), + mFlags(0), + mCategory(), + mOuterWindowID(0), + mInnerWindowID(0), + mTimeStamp(0), + mInitializedOnMainThread(false), + mIsFromPrivateWindow(false) +{ +} + +nsScriptErrorBase::~nsScriptErrorBase() {} + +void +nsScriptErrorBase::AddNote(nsIScriptErrorNote* note) +{ + mNotes.AppendObject(note); +} + +void +nsScriptErrorBase::InitializeOnMainThread() +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(!mInitializedOnMainThread); + + if (mInnerWindowID) { + nsGlobalWindow* window = + nsGlobalWindow::GetInnerWindowWithId(mInnerWindowID); + if (window) { + nsPIDOMWindowOuter* outer = window->GetOuterWindow(); + if (outer) + mOuterWindowID = outer->WindowID(); + + nsIDocShell* docShell = window->GetDocShell(); + nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell); + + if (loadContext) { + // Never mark exceptions from chrome windows as having come from + // private windows, since we always want them to be reported. + nsIPrincipal* winPrincipal = window->GetPrincipal(); + mIsFromPrivateWindow = loadContext->UsePrivateBrowsing() && + !nsContentUtils::IsSystemPrincipal(winPrincipal); + } + } + } + + mInitializedOnMainThread = true; +} + +// nsIConsoleMessage methods +NS_IMETHODIMP +nsScriptErrorBase::GetMessageMoz(char16_t** result) { + nsresult rv; + + nsAutoCString message; + rv = ToString(message); + if (NS_FAILED(rv)) + return rv; + + *result = UTF8ToNewUnicode(message); + if (!*result) + return NS_ERROR_OUT_OF_MEMORY; + + return NS_OK; +} + + +NS_IMETHODIMP +nsScriptErrorBase::GetLogLevel(uint32_t* aLogLevel) +{ + if (mFlags & (uint32_t)nsIScriptError::infoFlag) { + *aLogLevel = nsIConsoleMessage::info; + } else if (mFlags & (uint32_t)nsIScriptError::warningFlag) { + *aLogLevel = nsIConsoleMessage::warn; + } else { + *aLogLevel = nsIConsoleMessage::error; + } + return NS_OK; +} + +// nsIScriptError methods +NS_IMETHODIMP +nsScriptErrorBase::GetErrorMessage(nsAString& aResult) { + aResult.Assign(mMessage); + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::GetSourceName(nsAString& aResult) { + aResult.Assign(mSourceName); + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::GetSourceLine(nsAString& aResult) { + aResult.Assign(mSourceLine); + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::GetLineNumber(uint32_t* result) { + *result = mLineNumber; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::GetColumnNumber(uint32_t* result) { + *result = mColumnNumber; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::GetFlags(uint32_t* result) { + *result = mFlags; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::GetCategory(char** result) { + *result = ToNewCString(mCategory); + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::GetStack(JS::MutableHandleValue aStack) { + aStack.setUndefined(); + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::SetStack(JS::HandleValue aStack) { + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::GetErrorMessageName(nsAString& aErrorMessageName) { + aErrorMessageName = mMessageName; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::SetErrorMessageName(const nsAString& aErrorMessageName) { + mMessageName = aErrorMessageName; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::Init(const nsAString& message, + const nsAString& sourceName, + const nsAString& sourceLine, + uint32_t lineNumber, + uint32_t columnNumber, + uint32_t flags, + const char* category) +{ + return InitWithWindowID(message, sourceName, sourceLine, lineNumber, + columnNumber, flags, + category ? nsDependentCString(category) + : EmptyCString(), + 0); +} + +static void +AssignSourceNameHelper(nsString& aSourceNameDest, const nsAString& aSourceNameSrc) +{ + if (aSourceNameSrc.IsEmpty()) + return; + + aSourceNameDest.Assign(aSourceNameSrc); + + nsCOMPtr<nsIURI> uri; + nsAutoCString pass; + if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), aSourceNameSrc)) && + NS_SUCCEEDED(uri->GetPassword(pass)) && + !pass.IsEmpty()) + { + nsCOMPtr<nsISensitiveInfoHiddenURI> safeUri = do_QueryInterface(uri); + + nsAutoCString loc; + if (safeUri && NS_SUCCEEDED(safeUri->GetSensitiveInfoHiddenSpec(loc))) + aSourceNameDest.Assign(NS_ConvertUTF8toUTF16(loc)); + } +} + +NS_IMETHODIMP +nsScriptErrorBase::InitWithWindowID(const nsAString& message, + const nsAString& sourceName, + const nsAString& sourceLine, + uint32_t lineNumber, + uint32_t columnNumber, + uint32_t flags, + const nsACString& category, + uint64_t aInnerWindowID) +{ + mMessage.Assign(message); + AssignSourceNameHelper(mSourceName, sourceName); + mLineNumber = lineNumber; + mSourceLine.Assign(sourceLine); + mColumnNumber = columnNumber; + mFlags = flags; + mCategory = category; + mTimeStamp = JS_Now() / 1000; + mInnerWindowID = aInnerWindowID; + + if (aInnerWindowID && NS_IsMainThread()) { + InitializeOnMainThread(); + } + + return NS_OK; +} + +static nsresult +ToStringHelper(const char* aSeverity, const nsString& aMessage, + const nsString& aSourceName, const nsString* aSourceLine, + uint32_t aLineNumber, uint32_t aColumnNumber, + nsACString& /*UTF8*/ aResult) +{ + static const char format0[] = + "[%s: \"%s\" {file: \"%s\" line: %d column: %d source: \"%s\"}]"; + static const char format1[] = + "[%s: \"%s\" {file: \"%s\" line: %d}]"; + static const char format2[] = + "[%s: \"%s\"]"; + + char* temp; + char* tempMessage = nullptr; + char* tempSourceName = nullptr; + char* tempSourceLine = nullptr; + + if (!aMessage.IsEmpty()) + tempMessage = ToNewUTF8String(aMessage); + if (!aSourceName.IsEmpty()) + // Use at most 512 characters from mSourceName. + tempSourceName = ToNewUTF8String(StringHead(aSourceName, 512)); + if (aSourceLine && !aSourceLine->IsEmpty()) + // Use at most 512 characters from mSourceLine. + tempSourceLine = ToNewUTF8String(StringHead(*aSourceLine, 512)); + + if (nullptr != tempSourceName && nullptr != tempSourceLine) { + temp = JS_smprintf(format0, + aSeverity, + tempMessage, + tempSourceName, + aLineNumber, + aColumnNumber, + tempSourceLine); + } else if (!aSourceName.IsEmpty()) { + temp = JS_smprintf(format1, + aSeverity, + tempMessage, + tempSourceName, + aLineNumber); + } else { + temp = JS_smprintf(format2, + aSeverity, + tempMessage); + } + + if (nullptr != tempMessage) + free(tempMessage); + if (nullptr != tempSourceName) + free(tempSourceName); + if (nullptr != tempSourceLine) + free(tempSourceLine); + + if (!temp) + return NS_ERROR_OUT_OF_MEMORY; + + aResult.Assign(temp); + JS_smprintf_free(temp); + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::ToString(nsACString& /*UTF8*/ aResult) +{ + static const char error[] = "JavaScript Error"; + static const char warning[] = "JavaScript Warning"; + + const char* severity = !(mFlags & JSREPORT_WARNING) ? error : warning; + + return ToStringHelper(severity, mMessage, mSourceName, &mSourceLine, + mLineNumber, mColumnNumber, aResult); +} + +NS_IMETHODIMP +nsScriptErrorBase::GetOuterWindowID(uint64_t* aOuterWindowID) +{ + NS_WARNING_ASSERTION(NS_IsMainThread() || mInitializedOnMainThread, + "This can't be safely determined off the main thread, " + "returning an inaccurate value!"); + + if (!mInitializedOnMainThread && NS_IsMainThread()) { + InitializeOnMainThread(); + } + + *aOuterWindowID = mOuterWindowID; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::GetInnerWindowID(uint64_t* aInnerWindowID) +{ + *aInnerWindowID = mInnerWindowID; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::GetTimeStamp(int64_t* aTimeStamp) +{ + *aTimeStamp = mTimeStamp; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::GetIsFromPrivateWindow(bool* aIsFromPrivateWindow) +{ + NS_WARNING_ASSERTION(NS_IsMainThread() || mInitializedOnMainThread, + "This can't be safely determined off the main thread, " + "returning an inaccurate value!"); + + if (!mInitializedOnMainThread && NS_IsMainThread()) { + InitializeOnMainThread(); + } + + *aIsFromPrivateWindow = mIsFromPrivateWindow; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::GetNotes(nsIArray** aNotes) +{ + nsresult rv = NS_OK; + nsCOMPtr<nsIMutableArray> array = + do_CreateInstance(NS_ARRAY_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + uint32_t len = mNotes.Length(); + for (uint32_t i = 0; i < len; i++) + array->AppendElement(mNotes[i], false); + array.forget(aNotes); + + return NS_OK; +} + +NS_IMPL_ISUPPORTS(nsScriptError, nsIConsoleMessage, nsIScriptError) + +nsScriptErrorNote::nsScriptErrorNote() + : mMessage(), + mSourceName(), + mLineNumber(0), + mColumnNumber(0) +{ +} + +nsScriptErrorNote::~nsScriptErrorNote() {} + +void +nsScriptErrorNote::Init(const nsAString& message, + const nsAString& sourceName, + uint32_t lineNumber, + uint32_t columnNumber) +{ + mMessage.Assign(message); + AssignSourceNameHelper(mSourceName, sourceName); + mLineNumber = lineNumber; + mColumnNumber = columnNumber; +} + +// nsIScriptErrorNote methods +NS_IMETHODIMP +nsScriptErrorNote::GetErrorMessage(nsAString& aResult) { + aResult.Assign(mMessage); + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorNote::GetSourceName(nsAString& aResult) { + aResult.Assign(mSourceName); + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorNote::GetLineNumber(uint32_t* result) { + *result = mLineNumber; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorNote::GetColumnNumber(uint32_t* result) { + *result = mColumnNumber; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorNote::ToString(nsACString& /*UTF8*/ aResult) +{ + return ToStringHelper("JavaScript Note", mMessage, mSourceName, nullptr, + mLineNumber, mColumnNumber, aResult); +} + +NS_IMPL_ISUPPORTS(nsScriptErrorNote, nsIScriptErrorNote) diff --git a/dom/bindings/nsScriptError.h b/dom/bindings/nsScriptError.h new file mode 100644 index 000000000..b8049d0a0 --- /dev/null +++ b/dom/bindings/nsScriptError.h @@ -0,0 +1,109 @@ +/* -*- 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_nsScriptError_h +#define mozilla_dom_nsScriptError_h + +#include "mozilla/Atomics.h" + +#include <stdint.h> + +#include "jsapi.h" +#include "js/RootingAPI.h" + +#include "nsIScriptError.h" +#include "nsString.h" + +class nsScriptErrorNote final : public nsIScriptErrorNote { + public: + nsScriptErrorNote(); + + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSISCRIPTERRORNOTE + + void Init(const nsAString& message, const nsAString& sourceName, + uint32_t lineNumber, uint32_t columnNumber); + + private: + virtual ~nsScriptErrorNote(); + + nsString mMessage; + nsString mSourceName; + nsString mSourceLine; + uint32_t mLineNumber; + uint32_t mColumnNumber; +}; + +// Definition of nsScriptError.. +class nsScriptErrorBase : public nsIScriptError { +public: + nsScriptErrorBase(); + + NS_DECL_NSICONSOLEMESSAGE + NS_DECL_NSISCRIPTERROR + + void AddNote(nsIScriptErrorNote* note); + +protected: + virtual ~nsScriptErrorBase(); + + void + InitializeOnMainThread(); + + nsCOMArray<nsIScriptErrorNote> mNotes; + nsString mMessage; + nsString mMessageName; + nsString mSourceName; + uint32_t mLineNumber; + nsString mSourceLine; + uint32_t mColumnNumber; + uint32_t mFlags; + nsCString mCategory; + // mOuterWindowID is set on the main thread from InitializeOnMainThread(). + uint64_t mOuterWindowID; + uint64_t mInnerWindowID; + int64_t mTimeStamp; + // mInitializedOnMainThread and mIsFromPrivateWindow are set on the main + // thread from InitializeOnMainThread(). + mozilla::Atomic<bool> mInitializedOnMainThread; + bool mIsFromPrivateWindow; +}; + +class nsScriptError final : public nsScriptErrorBase { +public: + nsScriptError() {} + NS_DECL_THREADSAFE_ISUPPORTS + +private: + virtual ~nsScriptError() {} +}; + +class nsScriptErrorWithStack : public nsScriptErrorBase { +public: + explicit nsScriptErrorWithStack(JS::HandleObject); + + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsScriptErrorWithStack) + + NS_IMETHOD Init(const nsAString& message, + const nsAString& sourceName, + const nsAString& sourceLine, + uint32_t lineNumber, + uint32_t columnNumber, + uint32_t flags, + const char* category) override; + + NS_IMETHOD GetStack(JS::MutableHandleValue) override; + NS_IMETHOD ToString(nsACString& aResult) override; + +private: + virtual ~nsScriptErrorWithStack(); + // Complete stackframe where the error happened. + // Must be SavedFrame object. + JS::Heap<JSObject*> mStack; +}; + +#endif /* mozilla_dom_nsScriptError_h */ diff --git a/dom/bindings/nsScriptErrorWithStack.cpp b/dom/bindings/nsScriptErrorWithStack.cpp new file mode 100644 index 000000000..74c00999f --- /dev/null +++ b/dom/bindings/nsScriptErrorWithStack.cpp @@ -0,0 +1,120 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim: set ts=8 sts=4 et sw=4 tw=99: */ +/* 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/. */ + +/* + * nsScriptErrorWithStack implementation. + * a main-thread-only, cycle-collected subclass of nsScriptErrorBase + * that can store a SavedFrame stack trace object. + */ + +#include "nsScriptError.h" +#include "MainThreadUtils.h" +#include "mozilla/Assertions.h" +#include "mozilla/dom/ScriptSettings.h" +#include "nsGlobalWindow.h" +#include "nsCycleCollectionParticipant.h" + +using namespace mozilla::dom; + +namespace { + +static nsCString +FormatStackString(JSContext* cx, HandleObject aStack) { + JS::RootedString formattedStack(cx); + + if (!JS::BuildStackString(cx, aStack, &formattedStack)) { + return nsCString(); + } + + nsAutoJSString stackJSString; + if (!stackJSString.init(cx, formattedStack)) { + return nsCString(); + } + + return NS_ConvertUTF16toUTF8(stackJSString.get()); +} + +} + + +NS_IMPL_CYCLE_COLLECTION_CLASS(nsScriptErrorWithStack) + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsScriptErrorWithStack) + tmp->mStack = nullptr; +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsScriptErrorWithStack) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsScriptErrorWithStack) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mStack) +NS_IMPL_CYCLE_COLLECTION_TRACE_END + +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsScriptErrorWithStack) +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsScriptErrorWithStack) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsScriptErrorWithStack) + NS_INTERFACE_MAP_ENTRY(nsISupports) + NS_INTERFACE_MAP_ENTRY(nsIConsoleMessage) + NS_INTERFACE_MAP_ENTRY(nsIScriptError) +NS_INTERFACE_MAP_END + +nsScriptErrorWithStack::nsScriptErrorWithStack(JS::HandleObject aStack) + : mStack(aStack) +{ + MOZ_ASSERT(NS_IsMainThread(), "You can't use this class on workers."); + mozilla::HoldJSObjects(this); +} + +nsScriptErrorWithStack::~nsScriptErrorWithStack() { + mozilla::DropJSObjects(this); +} + +NS_IMETHODIMP +nsScriptErrorWithStack::Init(const nsAString& message, + const nsAString& sourceName, + const nsAString& sourceLine, + uint32_t lineNumber, + uint32_t columnNumber, + uint32_t flags, + const char* category) +{ + MOZ_CRASH("nsScriptErrorWithStack requires to be initialized with a document, by using InitWithWindowID"); +} + +NS_IMETHODIMP +nsScriptErrorWithStack::GetStack(JS::MutableHandleValue aStack) { + aStack.setObjectOrNull(mStack); + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorWithStack::ToString(nsACString& /*UTF8*/ aResult) +{ + MOZ_ASSERT(NS_IsMainThread()); + + nsCString message; + nsresult rv = nsScriptErrorBase::ToString(message); + NS_ENSURE_SUCCESS(rv, rv); + + if (!mStack) { + aResult.Assign(message); + return NS_OK; + } + + AutoJSAPI jsapi; + if (!jsapi.Init(mStack)) { + return NS_ERROR_FAILURE; + } + + JSContext* cx = jsapi.cx(); + RootedObject stack(cx, mStack); + nsCString stackString = FormatStackString(cx, stack); + nsCString combined = message + NS_LITERAL_CSTRING("\n") + stackString; + aResult.Assign(combined); + + return NS_OK; +} 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/bindings/test/test_Object.prototype_props.html b/dom/bindings/test/test_Object.prototype_props.html index 03147eb03..3ab27c5e4 100644 --- a/dom/bindings/test/test_Object.prototype_props.html +++ b/dom/bindings/test/test_Object.prototype_props.html @@ -11,9 +11,9 @@ test(function() { // Codegen.py's CGDictionary.getMemberDefinition method. var expected = [ "constructor", "toSource", "toString", "toLocaleString", "valueOf", - "watch", "unwatch", "hasOwnProperty", "isPrototypeOf", - "propertyIsEnumerable", "__defineGetter__", "__defineSetter__", - "__lookupGetter__", "__lookupSetter__", "__proto__" + "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable", + "__defineGetter__", "__defineSetter__", "__lookupGetter__", + "__lookupSetter__", "__proto__" ]; assert_array_equals(props.sort(), expected.sort()); }, "Own properties of Object.prototype"); diff --git a/dom/browser-element/BrowserElementChildPreload.js b/dom/browser-element/BrowserElementChildPreload.js index 780dfa80e..5adff2cac 100644 --- a/dom/browser-element/BrowserElementChildPreload.js +++ b/dom/browser-element/BrowserElementChildPreload.js @@ -1010,11 +1010,7 @@ BrowserElementChild.prototype = { self._takeScreenshot(maxWidth, maxHeight, mimeType, domRequestID); }; - let maxDelayMS = 2000; - try { - maxDelayMS = Services.prefs.getIntPref('dom.browserElement.maxScreenshotDelayMS'); - } - catch(e) {} + let maxDelayMS = Services.prefs.getIntPref('dom.browserElement.maxScreenshotDelayMS', 2000); // Try to wait for the event loop to go idle before we take the screenshot, // but once we've waited maxDelayMS milliseconds, go ahead and take it @@ -1720,10 +1716,7 @@ BrowserElementChild.prototype = { // certerror? If yes, maybe we should add a property to the // event to to indicate whether there is a custom page. That would // let the embedder have more control over the desired behavior. - let errorPage = null; - try { - errorPage = Services.prefs.getCharPref(CERTIFICATE_ERROR_PAGE_PREF); - } catch (e) {} + let errorPage = Services.prefs.getCharPref(CERTIFICATE_ERROR_PAGE_PREF, ""); if (errorPage == 'certerror') { sendAsyncMsg('error', { type: 'certerror' }); 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..111519c71 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(); } @@ -4209,6 +4219,12 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor : public nsBidiPresUtils::BidiProcess if (state->gradientStyles[style]) { // Gradient pattern = GetGradientFor(style); } else if (state->patternStyles[style]) { // Pattern + if (mCtx->mCanvasElement) { + CanvasUtils::DoDrawImageSecurityCheck( + mCtx->mCanvasElement, state->patternStyles[style]->mPrincipal, + state->patternStyles[style]->mForceWriteOnly, + state->patternStyles[style]->mCORSUsed); + } pattern = GetPatternFor(style); } else { MOZ_ASSERT(false, "Should never reach here."); @@ -4944,6 +4960,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 +4972,10 @@ CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage, return; } + if (imageBitmap.IsWriteOnly()) { + SetWriteOnly(); + } + imgSize = gfx::IntSize(imageBitmap.Width(), imageBitmap.Height()); } else { @@ -5666,9 +5690,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 +6335,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/WebGLBuffer.cpp b/dom/canvas/WebGLBuffer.cpp index f202c9950..02a8f649f 100644 --- a/dom/canvas/WebGLBuffer.cpp +++ b/dom/canvas/WebGLBuffer.cpp @@ -115,7 +115,7 @@ WebGLBuffer::BufferData(GLenum target, size_t size, const void* data, GLenum usa const ScopedLazyBind lazyBind(gl, target, this); mContext->InvalidateBufferFetching(); -#ifdef XP_MACOSX +#if defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK) // bug 790879 if (gl->WorkAroundDriverBugs() && size > INT32_MAX) @@ -134,6 +134,7 @@ WebGLBuffer::BufferData(GLenum target, size_t size, const void* data, GLenum usa if (error) { MOZ_ASSERT(error == LOCAL_GL_OUT_OF_MEMORY); mContext->ErrorOutOfMemory("%s: Error from driver: 0x%04x", funcName, error); + mByteLength = 0; return; } } else { 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..0510e6898 100644 --- a/dom/canvas/WebGLContext.h +++ b/dom/canvas/WebGLContext.h @@ -20,6 +20,7 @@ #include "mozilla/gfx/2D.h" #include "mozilla/LinkedList.h" #include "mozilla/UniquePtr.h" +#include "mozilla/WeakPtr.h" #include "nsCycleCollectionNoteChild.h" #include "nsICanvasRenderingContextInternal.h" #include "nsLayoutUtils.h" @@ -275,8 +276,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*) { @@ -298,6 +300,7 @@ class WebGLContext , public WebGLContextUnchecked , public WebGLRectangleObject , public nsWrapperCache + , public SupportsWeakPtr<WebGLContext> { friend class ScopedDrawHelper; friend class ScopedDrawWithTransformFeedback; @@ -341,6 +344,7 @@ public: NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(WebGLContext, nsIDOMWebGLRenderingContext) + MOZ_DECLARE_WEAKREFERENCE_TYPENAME(WebGLContext) virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override = 0; @@ -656,9 +660,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/WebGLContextBuffers.cpp b/dom/canvas/WebGLContextBuffers.cpp index af506c01c..f53f9d7d7 100644 --- a/dom/canvas/WebGLContextBuffers.cpp +++ b/dom/canvas/WebGLContextBuffers.cpp @@ -9,6 +9,8 @@ #include "WebGLBuffer.h" #include "WebGLVertexArray.h" +#include "mozilla/CheckedInt.h" + namespace mozilla { WebGLRefPtr<WebGLBuffer>* @@ -345,6 +347,16 @@ WebGLContext::BufferData(GLenum target, WebGLsizeiptr size, GLenum usage) //// + const auto checkedSize = CheckedInt<size_t>(size); + if (!checkedSize.isValid()) + return ErrorOutOfMemory("%s: Size too large for platform.", funcName); + +#if defined(XP_MACOSX) + if (gl->WorkAroundDriverBugs() && size > 1200000000) { + return ErrorOutOfMemory("Allocations larger than 1200000000 fail on MacOS."); + } +#endif + const UniqueBuffer zeroBuffer(calloc(size, 1)); if (!zeroBuffer) return ErrorOutOfMemory("%s: Failed to allocate zeros.", funcName); diff --git a/dom/canvas/WebGLExtensionDebugShaders.cpp b/dom/canvas/WebGLExtensionDebugShaders.cpp index 75880465e..8399aeb95 100644 --- a/dom/canvas/WebGLExtensionDebugShaders.cpp +++ b/dom/canvas/WebGLExtensionDebugShaders.cpp @@ -29,15 +29,10 @@ WebGLExtensionDebugShaders::GetTranslatedShaderSource(const WebGLShader& shader, { retval.SetIsVoid(true); - if (mIsLost) { - mContext->ErrorInvalidOperation("%s: Extension is lost.", - "getTranslatedShaderSource"); + if (mIsLost || !mContext) { return; } - if (mContext->IsContextLost()) - return; - if (!mContext->ValidateObject("getShaderTranslatedSource: shader", shader)) return; diff --git a/dom/canvas/WebGLExtensionDisjointTimerQuery.cpp b/dom/canvas/WebGLExtensionDisjointTimerQuery.cpp index e2e34f14e..da76eeb2d 100644 --- a/dom/canvas/WebGLExtensionDisjointTimerQuery.cpp +++ b/dom/canvas/WebGLExtensionDisjointTimerQuery.cpp @@ -40,8 +40,10 @@ void WebGLExtensionDisjointTimerQuery::DeleteQueryEXT(WebGLQuery* query) const { const char funcName[] = "deleteQueryEXT"; - if (mIsLost) - return; + + if (mIsLost || !mContext) { + return; + } mContext->DeleteQuery(query, funcName); } @@ -50,8 +52,10 @@ bool WebGLExtensionDisjointTimerQuery::IsQueryEXT(const WebGLQuery* query) const { const char funcName[] = "isQueryEXT"; - if (mIsLost) - return false; + + if (mIsLost || !mContext) { + return false; + } return mContext->IsQuery(query, funcName); } @@ -60,8 +64,10 @@ void WebGLExtensionDisjointTimerQuery::BeginQueryEXT(GLenum target, WebGLQuery& query) const { const char funcName[] = "beginQueryEXT"; - if (mIsLost) - return; + + if (mIsLost || !mContext) { + return; + } mContext->BeginQuery(target, query, funcName); } @@ -70,8 +76,10 @@ void WebGLExtensionDisjointTimerQuery::EndQueryEXT(GLenum target) const { const char funcName[] = "endQueryEXT"; - if (mIsLost) - return; + + if (mIsLost || !mContext) { + return; + } mContext->EndQuery(target, funcName); } @@ -80,8 +88,10 @@ void WebGLExtensionDisjointTimerQuery::QueryCounterEXT(WebGLQuery& query, GLenum target) const { const char funcName[] = "queryCounterEXT"; - if (mIsLost) - return; + + if (mIsLost || !mContext) { + return; + } if (!mContext->ValidateObject(funcName, query)) return; @@ -95,8 +105,10 @@ WebGLExtensionDisjointTimerQuery::GetQueryEXT(JSContext* cx, GLenum target, GLen { const char funcName[] = "getQueryEXT"; retval.setNull(); - if (mIsLost) - return; + + if (mIsLost || !mContext) { + return; + } mContext->GetQuery(cx, target, pname, retval, funcName); } @@ -108,8 +120,10 @@ WebGLExtensionDisjointTimerQuery::GetQueryObjectEXT(JSContext* cx, { const char funcName[] = "getQueryObjectEXT"; retval.setNull(); - if (mIsLost) - return; + + if (mIsLost || !mContext) { + return; + } mContext->GetQueryParameter(cx, query, pname, retval, funcName); } diff --git a/dom/canvas/WebGLExtensionDrawBuffers.cpp b/dom/canvas/WebGLExtensionDrawBuffers.cpp index 27aa76cc7..6f386621f 100644 --- a/dom/canvas/WebGLExtensionDrawBuffers.cpp +++ b/dom/canvas/WebGLExtensionDrawBuffers.cpp @@ -36,7 +36,9 @@ void WebGLExtensionDrawBuffers::DrawBuffersWEBGL(const dom::Sequence<GLenum>& buffers) { if (mIsLost) { - mContext->ErrorInvalidOperation("drawBuffersWEBGL: Extension is lost."); + if (mContext) { + mContext->ErrorInvalidOperation("drawBuffersWEBGL: Extension is lost."); + } return; } diff --git a/dom/canvas/WebGLExtensionInstancedArrays.cpp b/dom/canvas/WebGLExtensionInstancedArrays.cpp index 10d0533fe..22b3ec12c 100644 --- a/dom/canvas/WebGLExtensionInstancedArrays.cpp +++ b/dom/canvas/WebGLExtensionInstancedArrays.cpp @@ -28,8 +28,10 @@ WebGLExtensionInstancedArrays::DrawArraysInstancedANGLE(GLenum mode, GLsizei primcount) { if (mIsLost) { - mContext->ErrorInvalidOperation("%s: Extension is lost.", - "drawArraysInstancedANGLE"); + if (mContext) { + mContext->ErrorInvalidOperation("%s: Extension is lost.", + "drawArraysInstancedANGLE"); + } return; } @@ -44,8 +46,10 @@ WebGLExtensionInstancedArrays::DrawElementsInstancedANGLE(GLenum mode, GLsizei primcount) { if (mIsLost) { - mContext->ErrorInvalidOperation("%s: Extension is lost.", - "drawElementsInstancedANGLE"); + if (mContext) { + mContext->ErrorInvalidOperation("%s: Extension is lost.", + "drawElementsInstancedANGLE"); + } return; } @@ -57,8 +61,10 @@ WebGLExtensionInstancedArrays::VertexAttribDivisorANGLE(GLuint index, GLuint divisor) { if (mIsLost) { - mContext->ErrorInvalidOperation("%s: Extension is lost.", - "vertexAttribDivisorANGLE"); + if (mContext) { + mContext->ErrorInvalidOperation("%s: Extension is lost.", + "vertexAttribDivisorANGLE"); + } return; } diff --git a/dom/canvas/WebGLExtensionLoseContext.cpp b/dom/canvas/WebGLExtensionLoseContext.cpp index 020731e63..41f1633d8 100644 --- a/dom/canvas/WebGLExtensionLoseContext.cpp +++ b/dom/canvas/WebGLExtensionLoseContext.cpp @@ -22,12 +22,14 @@ WebGLExtensionLoseContext::~WebGLExtensionLoseContext() void WebGLExtensionLoseContext::LoseContext() { + if (!mContext) return; mContext->LoseContext(); } void WebGLExtensionLoseContext::RestoreContext() { + if (!mContext) return; mContext->RestoreContext(); } diff --git a/dom/canvas/WebGLExtensionVertexArray.cpp b/dom/canvas/WebGLExtensionVertexArray.cpp index 0984582f5..39aa96801 100644 --- a/dom/canvas/WebGLExtensionVertexArray.cpp +++ b/dom/canvas/WebGLExtensionVertexArray.cpp @@ -25,7 +25,7 @@ WebGLExtensionVertexArray::~WebGLExtensionVertexArray() already_AddRefed<WebGLVertexArray> WebGLExtensionVertexArray::CreateVertexArrayOES() { - if (mIsLost) + if (mIsLost || !mContext) return nullptr; return mContext->CreateVertexArray(); @@ -34,7 +34,7 @@ WebGLExtensionVertexArray::CreateVertexArrayOES() void WebGLExtensionVertexArray::DeleteVertexArrayOES(WebGLVertexArray* array) { - if (mIsLost) + if (mIsLost || !mContext) return; mContext->DeleteVertexArray(array); @@ -43,7 +43,7 @@ WebGLExtensionVertexArray::DeleteVertexArrayOES(WebGLVertexArray* array) bool WebGLExtensionVertexArray::IsVertexArrayOES(const WebGLVertexArray* array) { - if (mIsLost) + if (mIsLost || !mContext) return false; return mContext->IsVertexArray(array); @@ -52,7 +52,7 @@ WebGLExtensionVertexArray::IsVertexArrayOES(const WebGLVertexArray* array) void WebGLExtensionVertexArray::BindVertexArrayOES(WebGLVertexArray* array) { - if (mIsLost) + if (mIsLost || !mContext) return; mContext->BindVertexArray(array); diff --git a/dom/canvas/WebGLObjectModel.h b/dom/canvas/WebGLObjectModel.h index b18b790c0..6371c7b03 100644 --- a/dom/canvas/WebGLObjectModel.h +++ b/dom/canvas/WebGLObjectModel.h @@ -6,8 +6,8 @@ #ifndef WEBGLOBJECTMODEL_H_ #define WEBGLOBJECTMODEL_H_ +#include "mozilla/WeakPtr.h" #include "nsCycleCollectionNoteChild.h" - #include "WebGLTypes.h" namespace mozilla { @@ -24,7 +24,7 @@ class WebGLContext; class WebGLContextBoundObject { public: - WebGLContext* const mContext; + const WeakPtr<WebGLContext> mContext; private: const uint32_t mContextGeneration; diff --git a/dom/canvas/WebGLRenderbuffer.cpp b/dom/canvas/WebGLRenderbuffer.cpp index ec076fdbb..32397dd1a 100644 --- a/dom/canvas/WebGLRenderbuffer.cpp +++ b/dom/canvas/WebGLRenderbuffer.cpp @@ -215,6 +215,16 @@ WebGLRenderbuffer::RenderbufferStorage(const char* funcName, uint32_t samples, if (error) { const char* errorName = mContext->ErrorName(error); mContext->GenerateWarning("%s generated error %s", funcName, errorName); + if (error == LOCAL_GL_OUT_OF_MEMORY) { + // Truncate. + mSamples = 0; + mFormat = nullptr; + mWidth = 0; + mHeight = 0; + mImageDataStatus = WebGLImageDataStatus::NoImageData; + + InvalidateStatusOfAttachedFBs(); + } return; } diff --git a/dom/canvas/WebGLShader.cpp b/dom/canvas/WebGLShader.cpp index 37380f1e0..69ca03fc4 100644 --- a/dom/canvas/WebGLShader.cpp +++ b/dom/canvas/WebGLShader.cpp @@ -168,16 +168,6 @@ WebGLShader::ShaderSource(const nsAString& source) // 7-bit ASCII range, so we can skip the NS_IsAscii() check. const NS_LossyConvertUTF16toASCII sourceCString(cleanSource); - if (mContext->gl->WorkAroundDriverBugs()) { - const size_t maxSourceLength = 0x3ffff; - if (sourceCString.Length() > maxSourceLength) { - mContext->ErrorInvalidValue("shaderSource: Source has more than %d" - " characters. (Driver workaround)", - maxSourceLength); - return; - } - } - if (PR_GetEnv("MOZ_WEBGL_DUMP_SHADERS")) { printf_stderr("////////////////////////////////////////\n"); printf_stderr("// MOZ_WEBGL_DUMP_SHADERS:\n"); diff --git a/dom/canvas/WebGLTexture.cpp b/dom/canvas/WebGLTexture.cpp index 767ff610a..65bb71153 100644 --- a/dom/canvas/WebGLTexture.cpp +++ b/dom/canvas/WebGLTexture.cpp @@ -51,8 +51,6 @@ WebGLTexture::ImageInfo::Clear() WebGLTexture::ImageInfo& WebGLTexture::ImageInfo::operator =(const ImageInfo& a) { - MOZ_ASSERT(a.IsDefined()); - Mutable(mFormat) = a.mFormat; Mutable(mWidth) = a.mWidth; Mutable(mHeight) = a.mHeight; @@ -1216,6 +1214,12 @@ WebGLTexture::TexParameter(TexTarget texTarget, GLenum pname, const FloatOrInt& mContext->gl->fTexParameterf(texTarget.get(), pname, clamped.f); } +void WebGLTexture::Truncate() { + for (auto& cur : mImageInfoArr) { + SetImageInfo(&cur, ImageInfo()); + } +} + //////////////////////////////////////////////////////////////////////////////// NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLTexture) diff --git a/dom/canvas/WebGLTexture.h b/dom/canvas/WebGLTexture.h index 66e781f23..8d3024590 100644 --- a/dom/canvas/WebGLTexture.h +++ b/dom/canvas/WebGLTexture.h @@ -386,6 +386,7 @@ public: bool* const out_initFailed); bool IsMipmapCubeComplete() const; + void Truncate(); bool IsCubeMap() const { return (mTarget == LOCAL_GL_TEXTURE_CUBE_MAP); } diff --git a/dom/canvas/WebGLTextureUpload.cpp b/dom/canvas/WebGLTextureUpload.cpp index 612d5889d..ae60d2a2b 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) { @@ -1160,6 +1178,7 @@ WebGLTexture::TexStorage(const char* funcName, TexTarget target, GLsizei levels, if (error == LOCAL_GL_OUT_OF_MEMORY) { mContext->ErrorOutOfMemory("%s: Ran out of memory during texture allocation.", funcName); + Truncate(); return; } if (error) { @@ -1292,6 +1311,7 @@ WebGLTexture::TexImage(const char* funcName, TexImageTarget target, GLint level, if (glError == LOCAL_GL_OUT_OF_MEMORY) { mContext->ErrorOutOfMemory("%s: Driver ran out of memory during upload.", funcName); + Truncate(); return; } @@ -1380,6 +1400,7 @@ WebGLTexture::TexSubImage(const char* funcName, TexImageTarget target, GLint lev if (glError == LOCAL_GL_OUT_OF_MEMORY) { mContext->ErrorOutOfMemory("%s: Driver ran out of memory during upload.", funcName); + Truncate(); return; } @@ -1496,6 +1517,7 @@ WebGLTexture::CompressedTexImage(const char* funcName, TexImageTarget target, GL blob->mAvailBytes, blob->mPtr); if (error == LOCAL_GL_OUT_OF_MEMORY) { mContext->ErrorOutOfMemory("%s: Ran out of memory during upload.", funcName); + Truncate(); return; } if (error) { @@ -1646,6 +1668,7 @@ WebGLTexture::CompressedTexSubImage(const char* funcName, TexImageTarget target, blob->mAvailBytes, blob->mPtr); if (error == LOCAL_GL_OUT_OF_MEMORY) { mContext->ErrorOutOfMemory("%s: Ran out of memory during upload.", funcName); + Truncate(); return; } if (error) { @@ -1974,7 +1997,7 @@ WebGLTexture::ValidateCopyTexImageForFeedback(const char* funcName, uint32_t lev static bool DoCopyTexOrSubImage(WebGLContext* webgl, const char* funcName, bool isSubImage, - const WebGLTexture* tex, TexImageTarget target, GLint level, + WebGLTexture* tex, TexImageTarget target, GLint level, GLint xWithinSrc, GLint yWithinSrc, uint32_t srcTotalWidth, uint32_t srcTotalHeight, const webgl::FormatUsageInfo* srcUsage, @@ -2051,6 +2074,7 @@ DoCopyTexOrSubImage(WebGLContext* webgl, const char* funcName, bool isSubImage, if (error == LOCAL_GL_OUT_OF_MEMORY) { webgl->ErrorOutOfMemory("%s: Ran out of memory during texture copy.", funcName); + tex->Truncate(); return false; } 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..35e80fea4 100644 --- a/dom/events/DataTransfer.cpp +++ b/dom/events/DataTransfer.cpp @@ -39,6 +39,7 @@ #include "mozilla/dom/OSFileSystem.h" #include "mozilla/dom/Promise.h" #include "nsNetUtil.h" +#include "nsReadableUtils.h" namespace mozilla { namespace dom { @@ -57,7 +58,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) @@ -645,6 +645,13 @@ DataTransfer::PrincipalMaySetData(const nsAString& aType, NS_WARNING("Disallowing adding x-moz-file or x-moz-file-promize types to DataTransfer"); return false; } + + // Disallow content from creating x-moz-place flavors, so that it cannot + // create fake Places smart queries exposing user data. + if (StringBeginsWith(aType, NS_LITERAL_STRING("text/x-moz-place"))) { + NS_WARNING("Disallowing adding moz-place types to DataTransfer"); + return false; + } } return true; } 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/grid/GridLines.cpp b/dom/grid/GridLines.cpp index fac645c64..898885346 100644 --- a/dom/grid/GridLines.cpp +++ b/dom/grid/GridLines.cpp @@ -90,7 +90,9 @@ GridLines::SetLineInfo(const ComputedGridTrackInfo* aTrackInfo, for (uint32_t i = aTrackInfo->mStartFragmentTrack; i < aTrackInfo->mEndFragmentTrack + 1; i++) { - uint32_t line1Index = i + 1; + // Since line indexes are 1-based, calculate a 1-based value + // for this track to simplify some calculations. + const uint32_t line1Index = i + 1; startOfNextTrack = (i < aTrackInfo->mEndFragmentTrack) ? aTrackInfo->mPositions[i] : @@ -127,7 +129,8 @@ GridLines::SetLineInfo(const ComputedGridTrackInfo* aTrackInfo, } } - if (i >= aTrackInfo->mRepeatFirstTrack && + if (i >= (aTrackInfo->mRepeatFirstTrack + + aTrackInfo->mNumLeadingImplicitTracks) && repeatIndex < numRepeatTracks) { numAddedLines += AppendRemovedAutoFits(aTrackInfo, aLineInfo, @@ -139,23 +142,30 @@ GridLines::SetLineInfo(const ComputedGridTrackInfo* aTrackInfo, RefPtr<GridLine> line = new GridLine(this); mLines.AppendElement(line); + MOZ_ASSERT(line1Index > 0, "line1Index must be positive."); + bool isBeforeFirstExplicit = + (line1Index <= aTrackInfo->mNumLeadingImplicitTracks); + // Calculate an actionable line number for this line, that could be used + // in a css grid property to align a grid item or area at that line. + // For implicit lines that appear before line 1, report a number of 0. + // We can't report negative indexes, because those have a different + // meaning in the css grid spec (negative indexes are negative-1-based + // from the end of the grid decreasing towards the front). + uint32_t lineNumber = isBeforeFirstExplicit ? 0 : + (line1Index - aTrackInfo->mNumLeadingImplicitTracks + numAddedLines); + GridDeclaration lineType = + (isBeforeFirstExplicit || + line1Index > (aTrackInfo->mNumLeadingImplicitTracks + + aTrackInfo->mNumExplicitTracks + 1)) + ? GridDeclaration::Implicit + : GridDeclaration::Explicit; line->SetLineValues( lineNames, nsPresContext::AppUnitsToDoubleCSSPixels(lastTrackEdge), nsPresContext::AppUnitsToDoubleCSSPixels(startOfNextTrack - lastTrackEdge), - line1Index + numAddedLines, - ( - // Implicit if there are no explicit tracks, or if the index - // is before the first explicit track, or after - // a track beyond the last explicit track. - (aTrackInfo->mNumExplicitTracks == 0) || - (i < aTrackInfo->mNumLeadingImplicitTracks) || - (i > aTrackInfo->mNumLeadingImplicitTracks + - aTrackInfo->mNumExplicitTracks) ? - GridDeclaration::Implicit : - GridDeclaration::Explicit - ) + lineNumber, + lineType ); if (i < aTrackInfo->mEndFragmentTrack) { @@ -215,11 +225,13 @@ GridLines::AppendRemovedAutoFits(const ComputedGridTrackInfo* aTrackInfo, RefPtr<GridLine> line = new GridLine(this); mLines.AppendElement(line); + uint32_t lineNumber = aTrackInfo->mRepeatFirstTrack + + aRepeatIndex + 1; line->SetLineValues( aLineNames, nsPresContext::AppUnitsToDoubleCSSPixels(aLastTrackEdge), nsPresContext::AppUnitsToDoubleCSSPixels(0), - aTrackInfo->mRepeatFirstTrack + aRepeatIndex + 1, + lineNumber, GridDeclaration::Explicit ); diff --git a/dom/grid/test/chrome.ini b/dom/grid/test/chrome.ini index 2241cf9eb..169fa9b89 100644 --- a/dom/grid/test/chrome.ini +++ b/dom/grid/test/chrome.ini @@ -2,6 +2,7 @@ [chrome/test_grid_fragmentation.html] [chrome/test_grid_implicit.html] [chrome/test_grid_lines.html] +[chrome/test_grid_line_numbers.html] [chrome/test_grid_object.html] [chrome/test_grid_repeats.html] [chrome/test_grid_tracks.html] diff --git a/dom/grid/test/chrome/test_grid_implicit.html b/dom/grid/test/chrome/test_grid_implicit.html index c7782e0e5..1f7142658 100644 --- a/dom/grid/test/chrome/test_grid_implicit.html +++ b/dom/grid/test/chrome/test_grid_implicit.html @@ -33,6 +33,11 @@ body { grid-template-rows: [areaA-end areaB-start areaC-end] 50px [areaA-start areaB-end areaC-start]; } +.template4 { + grid-template-columns: 100px 50px 100px; + grid-template-rows: 50px; +} + .box { background-color: #444; color: #fff; @@ -50,6 +55,9 @@ body { .d { grid-area: areaD; } +.e { + grid-column: -7 / 5; +} </style> <script> @@ -78,9 +86,12 @@ function runTests() { is(grid.cols.lines[4].type, "implicit", "Grid column line 5 is implicit."); is(grid.cols.lines[5].type, "implicit", "Grid column line 6 is implicit."); - is(grid.rows.lines[0].type, "implicit", "Grid row line 1 is implicit."); - is(grid.rows.lines[1].type, "explicit", "Grid row line 2 is explicit."); - is(grid.rows.lines[3].type, "explicit", "Grid row line 4 is explicit."); + is(grid.rows.lines[0].type, "implicit", "Grid row line 0 is implicit."); + is(grid.rows.lines[0].number, 0, "Grid row line 0 has correct number."); + is(grid.rows.lines[1].type, "explicit", "Grid row line 1 is explicit."); + is(grid.rows.lines[1].number, 1, "Grid row line 1 has correct number."); + is(grid.rows.lines[3].type, "explicit", "Grid row line 3 is explicit."); + is(grid.rows.lines[3].number, 3, "Grid row line 3 has correct number."); // test that row line 1 gets the name forced on it by placement of item B todo_isnot(grid.rows.lines[0].names.indexOf("got-this-name-implicitly"), -1, @@ -221,6 +232,48 @@ function runTests() { } } + // test the fourth grid wrapper + wrapper = document.getElementById("wrapper4"); + grid = wrapper.getGridFragments()[0]; + + // test column and row line counts + is(grid.cols.lines.length, 8, + "Grid.cols.lines property expands properly with implicit columns on both sides." + ); + is(grid.rows.lines.length, 2, + "Grid.rows.lines property is as expected" + ); + + if (grid.cols.lines.length == 8) { + // check that all the lines get correct implict/explicit type and number + let expectedType = [ + "implicit", + "implicit", + "implicit", + "explicit", + "explicit", + "explicit", + "explicit", + "implicit", + ]; + let expectedNumber = [ + 0, + 0, + 0, + 1, + 2, + 3, + 4, + 5, + ]; + + for (let i = 0; i < grid.cols.lines.length; i++) { + let line = grid.cols.lines[i]; + is(line.type, expectedType[i], "Line index " + i + " has expected type."); + is(line.number, expectedNumber[i], "Line index " + i + " has expected number."); + } + } + SimpleTest.finish(); } </script> @@ -246,5 +299,9 @@ function runTests() { <div id="boxC" class="box c">C</div> </div> + <div id="wrapper4" class="wrapper template4"> + <div id="boxE" class="box e">E</div> + </div> + </body> </html> diff --git a/dom/grid/test/chrome/test_grid_line_numbers.html b/dom/grid/test/chrome/test_grid_line_numbers.html new file mode 100644 index 000000000..c8e5226b6 --- /dev/null +++ b/dom/grid/test/chrome/test_grid_line_numbers.html @@ -0,0 +1,101 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"> +<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> +<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" /> +<style> +body { + margin: 40px; +} +.wrapper { + display: grid; + grid-gap: 0px; + background-color: #f00; +} +.wrapper > div { + background-color: #444; + color: #fff; +} +.repeatColumns { + width: 600px; + grid-auto-columns: 50px; + grid-template-columns: repeat(auto-fit, 100px); +} +.repeatRows { + height: 600px; + grid-auto-rows: 50px; + grid-template-rows: repeat(auto-fit, 100px); +} +</style> + +<script> +'use strict'; + +SimpleTest.waitForExplicitFinish(); + +function testLines(elementName, lines, expectedValues) { + is(lines.count, expectedValues.count, elementName + " has expected number of lines."); + for (let i = 0; i < lines.length; i++) { + is(lines[i].number, expectedValues[i].number, elementName + " line index " + i + " has expected number."); + } +} + +function runTests() { + let grid; + let lines; + let expectedValues; + + grid = document.getElementById("gridWithColumns").getGridFragments()[0]; + lines = grid.cols.lines; + expectedValues = [ + { "number": 0 }, + { "number": 0 }, + { "number": 1 }, + { "number": 2 }, + { "number": 3 }, + { "number": 4 }, + { "number": 5 }, + { "number": 6 }, + { "number": 7 }, + { "number": 8 }, + ]; + testLines("gridWithColumns", lines, expectedValues); + + grid = document.getElementById("gridWithRows").getGridFragments()[0]; + lines = grid.rows.lines; + expectedValues = [ + { "number": 0 }, + { "number": 0 }, + { "number": 1 }, + { "number": 2 }, + { "number": 3 }, + { "number": 4 }, + { "number": 5 }, + { "number": 6 }, + { "number": 7 }, + { "number": 8 }, + ]; + testLines("gridWithRows", lines, expectedValues); + + SimpleTest.finish(); +} +</script> +</head> +<body onLoad="runTests();"> + +<div id="gridWithColumns" class="wrapper repeatColumns"> +<div style="grid-column: -9">A</div> +<div style="grid-column: 4">B</div> +<div style="grid-column: 7">C</div> +</div> + +<div id="gridWithRows" class="wrapper repeatRows"> +<div style="grid-row: span 3 / 2">A</div> +<div style="grid-row: 4">B</div> +<div style="grid-row: 5">C</div> +<div style="grid-row: span 2 / 8">D</div> +</div> + +</body> +</html> diff --git a/dom/html/HTMLCanvasElement.cpp b/dom/html/HTMLCanvasElement.cpp index 88b41bce0..4b5deab18 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) {} @@ -554,17 +552,23 @@ HTMLCanvasElement::CopyInnerTo(Element* aDest) HTMLCanvasElement* dest = static_cast<HTMLCanvasElement*>(aDest); dest->mOriginalCanvas = this; - nsCOMPtr<nsISupports> cxt; - dest->GetContext(NS_LITERAL_STRING("2d"), getter_AddRefs(cxt)); - RefPtr<CanvasRenderingContext2D> context2d = - static_cast<CanvasRenderingContext2D*>(cxt.get()); - if (context2d && !mPrintCallback) { - CanvasImageSource source; - source.SetAsHTMLCanvasElement() = this; - ErrorResult err; - context2d->DrawImage(source, - 0.0, 0.0, err); - rv = err.StealNSResult(); + // We make sure that the canvas is not zero sized since that would cause + // the DrawImage call below to return an error, which would cause printing + // to fail. + nsIntSize size = GetWidthHeight(); + if (size.height > 0 && size.width > 0) { + nsCOMPtr<nsISupports> cxt; + dest->GetContext(NS_LITERAL_STRING("2d"), getter_AddRefs(cxt)); + RefPtr<CanvasRenderingContext2D> context2d = + static_cast<CanvasRenderingContext2D*>(cxt.get()); + if (context2d && !mPrintCallback) { + CanvasImageSource source; + source.SetAsHTMLCanvasElement() = this; + ErrorResult err; + context2d->DrawImage(source, + 0.0, 0.0, err); + rv = err.StealNSResult(); + } } } return rv; @@ -1002,7 +1006,7 @@ HTMLCanvasElement::GetSize() } bool -HTMLCanvasElement::IsWriteOnly() +HTMLCanvasElement::IsWriteOnly() const { return mWriteOnly; } @@ -1111,7 +1115,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 +1445,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..451d989c3 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; } @@ -655,7 +659,7 @@ ImageDocument::CreateSyntheticDocument() NS_ENSURE_SUCCESS(rv, rv); // Add the image element - Element* body = GetBodyElement(); + RefPtr<Element> body = GetBodyElement(); if (!body) { NS_WARNING("no body on image document!"); return NS_ERROR_FAILURE; @@ -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/PluginDocument.cpp b/dom/html/PluginDocument.cpp index 1c923ecc6..f6be8a915 100644 --- a/dom/html/PluginDocument.cpp +++ b/dom/html/PluginDocument.cpp @@ -206,7 +206,7 @@ PluginDocument::CreateSyntheticPluginDocument() NS_ENSURE_SUCCESS(rv, rv); // then attach our plugin - Element* body = GetBodyElement(); + RefPtr<Element> body = GetBodyElement(); if (!body) { NS_WARNING("no body on plugin document!"); return NS_ERROR_FAILURE; 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/VideoDocument.cpp b/dom/html/VideoDocument.cpp index 1bd898564..76b2e326f 100644 --- a/dom/html/VideoDocument.cpp +++ b/dom/html/VideoDocument.cpp @@ -90,7 +90,7 @@ VideoDocument::CreateSyntheticVideoDocument(nsIChannel* aChannel, nsresult rv = MediaDocument::CreateSyntheticDocument(); NS_ENSURE_SUCCESS(rv, rv); - Element* body = GetBodyElement(); + RefPtr<Element> body = GetBodyElement(); if (!body) { NS_WARNING("no body on video document!"); return NS_ERROR_FAILURE; 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/html/test/mochitest.ini b/dom/html/test/mochitest.ini index 0c0ba847c..1059bc5d0 100644 --- a/dom/html/test/mochitest.ini +++ b/dom/html/test/mochitest.ini @@ -553,7 +553,6 @@ skip-if = true # Disabled for timeouts. [test_viewport.html] [test_documentAll.html] [test_document-element-inserted.html] -[test_document.watch.html] [test_bug445004.html] skip-if = true || toolkit == 'android' # Disabled permanently (bug 559932). [test_bug446483.html] diff --git a/dom/html/test/test_document.watch.html b/dom/html/test/test_document.watch.html deleted file mode 100644 index 54509823b..000000000 --- a/dom/html/test/test_document.watch.html +++ /dev/null @@ -1,129 +0,0 @@ -<!DOCTYPE html> -<html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=903332 ---> -<head> - <meta charset="utf-8"> - <title>Test for Bug 903332</title> - <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> - <script type="application/javascript"> - - /** Test for Bug 903332 **/ - - var watch1Called; - function watch1(prop, oldValue, newValue) - { - is(watch1Called, false, "watch1Called not reset properly?"); - watch1Called = true; - - is(prop, "cookie", "wrong property name passed to watch1"); - return newValue; - } - - var watch2Called; - function watch2(prop, oldValue, newValue) - { - is(watch2Called, false, "watch2Called not reset properly?"); - watch2Called = true; - - is(prop, "cookie", "wrong property name passed to watch2"); - return newValue; - } - - // Just in case subsequent tests depend on a particular value... - var originalValue = document.cookie; - ok(true, "originalValue: " + originalValue); - - var originalPrefix = originalValue.length > 0 ? originalValue + "; " : ""; - - try - { - // trial set (no watch) to verify things work - document.cookie = "first=set"; - is(document.cookie, originalPrefix + "first=set", - "first value correct"); - - // add a watch - document.watch("cookie", watch1); - - // set, check for watch invoked - watch1Called = false; - document.cookie = "second=set"; - is(watch1Called, true, "watch1 function should be called"); - is(document.cookie, originalPrefix + "first=set; second=set", - "second value correct"); - - // and a second time, just in case - watch1Called = false; - document.cookie = "third=set"; - is(watch1Called, true, "watch1 function should be called"); - is(document.cookie, originalPrefix + "first=set; second=set; third=set", - "third value correct"); - - // overwrite the current watch with a new one - document.watch("cookie", watch2); - - // set, check for watch invoked - watch1Called = false; - watch2Called = false; - document.cookie = "fourth=set"; - is(watch1Called, false, "watch1 invoked erroneously"); - is(watch2Called, true, "watch2 function should be called"); - is(document.cookie, originalPrefix + "first=set; second=set; third=set; fourth=set", - "fourth value correct"); - - // and a second time, just in case - watch1Called = false; - watch2Called = false; - document.cookie = "fifth=set"; - is(watch1Called, false, "watch1 invoked erroneously"); - is(watch2Called, true, "watch2 function should be called"); - is(document.cookie, originalPrefix + "first=set; second=set; third=set; fourth=set; fifth=set", - "fifth value correct"); - - // remove the watch - document.unwatch("cookie"); - - // check for non-invocation now - watch1Called = false; - watch2Called = false; - document.cookie = "sixth=set"; - is(watch1Called, false, "watch1 shouldn't be called"); - is(watch2Called, false, "watch2 shouldn't be called"); - is(document.cookie, originalPrefix + "first=set; second=set; third=set; fourth=set; fifth=set; sixth=set", - "sixth value correct"); - } - finally - { - // reset - document.unwatch("cookie"); // harmless, should be no-op except if bugs - - var d = new Date(); - d.setTime(0); - var suffix = "=; expires=" + d.toGMTString(); - - document.cookie = "first" + suffix; - document.cookie = "second" + suffix; - document.cookie = "third" + suffix; - document.cookie = "fourth" + suffix; - document.cookie = "fifth" + suffix; - document.cookie = "sixth" + suffix; - } - - is(document.cookie, originalValue, - "document.cookie isn't what it was initially! expect bustage further " + - "down the line"); - </script> -</head> -<body> -<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=903332">Mozilla Bug 903332</a> -<p id="display"></p> -<div id="content" style="display: none"> - -</div> -<pre id="test"> -</pre> -</body> -</html> diff --git a/dom/indexedDB/ActorsChild.cpp b/dom/indexedDB/ActorsChild.cpp index 3e8f97348..30dc9b6da 100644 --- a/dom/indexedDB/ActorsChild.cpp +++ b/dom/indexedDB/ActorsChild.cpp @@ -2385,9 +2385,14 @@ BackgroundVersionChangeTransactionChild::RecvComplete(const nsresult& aResult) database->Close(); } + RefPtr<IDBOpenDBRequest> request = mOpenDBRequest; + MOZ_ASSERT(request); + mTransaction->FireCompleteOrAbortEvents(aResult); - mOpenDBRequest->SetTransaction(nullptr); + request->SetTransaction(nullptr); + request = nullptr; + mOpenDBRequest = nullptr; NoteComplete(); @@ -3456,6 +3461,8 @@ BackgroundCursorChild::RecvResponse(const CursorResponse& aResponse) RefPtr<IDBCursor> cursor; mStrongCursor.swap(cursor); + + RefPtr<IDBTransaction> transaction = mTransaction; switch (aResponse.type()) { case CursorResponse::Tnsresult: @@ -3486,7 +3493,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..74afef452 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(); @@ -4442,24 +4427,11 @@ CreateStorageConnection(nsIFile* aDBFile, nsresult rv; bool exists; - if (IndexedDatabaseManager::InLowDiskSpaceMode()) { - rv = aDBFile->Exists(&exists); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - if (!exists) { - NS_WARNING("Refusing to create database because disk space is low!"); - return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR; - } - } - nsCOMPtr<nsIFileURL> dbFileUrl; rv = GetDatabaseFileURL(aDBFile, aPersistenceType, aGroup, aOrigin, - aTelemetryId, getter_AddRefs(dbFileUrl)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; @@ -4895,7 +4867,6 @@ GetStorageConnection(nsIFile* aDatabaseFile, PersistenceType aPersistenceType, const nsACString& aGroup, const nsACString& aOrigin, - uint32_t aTelemetryId, mozIStorageConnection** aConnection) { MOZ_ASSERT(!NS_IsMainThread()); @@ -4923,7 +4894,6 @@ GetStorageConnection(nsIFile* aDatabaseFile, aPersistenceType, aGroup, aOrigin, - aTelemetryId, getter_AddRefs(dbFileUrl)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; @@ -4960,7 +4930,6 @@ GetStorageConnection(const nsAString& aDatabaseFilePath, PersistenceType aPersistenceType, const nsACString& aGroup, const nsACString& aOrigin, - uint32_t aTelemetryId, mozIStorageConnection** aConnection) { MOZ_ASSERT(!NS_IsMainThread()); @@ -4979,7 +4948,6 @@ GetStorageConnection(const nsAString& aDatabaseFilePath, aPersistenceType, aGroup, aOrigin, - aTelemetryId, aConnection); } @@ -6301,7 +6269,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 +6285,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 +6343,6 @@ public: return mId; } - uint32_t - TelemetryId() const - { - return mTelemetryId; - } - PersistenceType Type() const { @@ -7678,8 +7638,6 @@ class OpenDatabaseOp final // cycles. VersionChangeOp* mVersionChangeOp; - uint32_t mTelemetryId; - public: OpenDatabaseOp(Factory* aFactory, already_AddRefed<ContentParent> aContentParent, @@ -10307,13 +10265,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 +10360,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 +12139,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 +14007,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 +14023,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 +17262,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 +17334,6 @@ FileManager::InitDirectory(nsIFile* aDirectory, aPersistenceType, aGroup, aOrigin, - aTelemetryId, getter_AddRefs(connection)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; @@ -17653,11 +17517,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 +17525,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 +17800,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 +18893,6 @@ DatabaseMaintenance::PerformMaintenanceOnDatabase() mPersistenceType, mGroup, mOrigin, - TelemetryIdForFile(databaseFile), getter_AddRefs(connection)); if (NS_WARN_IF(NS_FAILED(rv))) { return; @@ -19240,23 +19091,6 @@ DatabaseMaintenance::DetermineMaintenanceAction( return NS_OK; } - bool lowDiskSpace = IndexedDatabaseManager::InLowDiskSpaceMode(); - - if (QuotaManager::IsRunningXPCShellTests()) { - // If we're running XPCShell then we want to test both the low disk space - // and normal disk space code paths so pick semi-randomly based on the - // current time. - lowDiskSpace = ((PR_Now() / PR_USEC_PER_MSEC) % 2) == 0; - } - - // If we're low on disk space then the best we can hope for is that an - // incremental vacuum might free some space. That is a journaled operation so - // it may not be possible even then. - if (lowDiskSpace) { - *aMaintenanceAction = MaintenanceAction::IncrementalVacuum; - return NS_OK; - } - // This method shouldn't make any permanent changes to the database, so make // sure everything gets rolled back when we leave. mozStorageTransaction transaction(aConnection, @@ -21172,16 +21006,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 +21492,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 +21600,6 @@ OpenDatabaseOp::DoDatabaseWork() return rv; } - mTelemetryId = TelemetryIdForFile(dbFile); - #ifdef DEBUG nsString databaseFilePath; rv = dbFile->GetPath(databaseFilePath); @@ -21809,7 +21630,6 @@ OpenDatabaseOp::DoDatabaseWork() persistenceType, mGroup, mOrigin, - mTelemetryId, getter_AddRefs(connection)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; @@ -22692,7 +22512,6 @@ OpenDatabaseOp::EnsureDatabaseActor() mOptionalContentParentId, mGroup, mOrigin, - mTelemetryId, mMetadata, mFileManager, mDirectoryLock.forget(), @@ -23869,32 +23688,38 @@ TransactionDatabaseOperationBase::SendPreprocessInfoOrResults( MOZ_ASSERT(mTransaction); if (NS_WARN_IF(IsActorDestroyed())) { - // Don't send any notifications if the actor was destroyed already. + // Normally we wouldn't need to send any notifications if the actor was + // already destroyed, but this can be a VersionChangeOp which needs to + // notify its parent operation (OpenDatabaseOp) about the failure. + // So SendFailureResult needs to be called even when the actor was + // destroyed. Normal operations redundantly check if the actor was + // destroyed in SendSuccessResult and SendFailureResult, therefore it's + // ok to call it in all cases here. if (NS_SUCCEEDED(mResultCode)) { IDB_REPORT_INTERNAL_ERR(); mResultCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } - } else { - if (mTransaction->IsInvalidated() || mTransaction->IsAborted()) { - // Aborted transactions always see their requests fail with ABORT_ERR, - // even if the request succeeded or failed with another error. - mResultCode = NS_ERROR_DOM_INDEXEDDB_ABORT_ERR; - } else if (NS_SUCCEEDED(mResultCode)) { - if (aSendPreprocessInfo) { - // This should not release the IPDL reference. - mResultCode = SendPreprocessInfo(); - } else { - // This may release the IPDL reference. - mResultCode = SendSuccessResult(); - } + } else if (mTransaction->IsInvalidated() || mTransaction->IsAborted()) { + // Aborted transactions always see their requests fail with ABORT_ERR, + // even if the request succeeded or failed with another error. + mResultCode = NS_ERROR_DOM_INDEXEDDB_ABORT_ERR; + } + + if (NS_SUCCEEDED(mResultCode)) { + if (aSendPreprocessInfo) { + // This should not release the IPDL reference. + mResultCode = SendPreprocessInfo(); + } else { + // This may release the IPDL reference. + mResultCode = SendSuccessResult(); } + } - if (NS_FAILED(mResultCode)) { - // This should definitely release the IPDL reference. - if (!SendFailureResult(mResultCode)) { - // Abort the transaction. - mTransaction->Abort(mResultCode, /* aForce */ false); - } + if (NS_FAILED(mResultCode)) { + // This should definitely release the IPDL reference. + if (!SendFailureResult(mResultCode)) { + // Abort the transaction. + mTransaction->Abort(mResultCode, /* aForce */ false); } } @@ -24379,11 +24204,6 @@ CreateFileOp::DoDatabaseWork() "CreateFileOp::DoDatabaseWork", js::ProfileEntry::Category::STORAGE); - if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) { - NS_WARNING("Refusing to create file because disk space is low!"); - return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR; - } - if (NS_WARN_IF(QuotaManager::IsShuttingDown()) || !OperationMayProceed()) { IDB_REPORT_INTERNAL_ERR(); return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; @@ -24524,10 +24344,6 @@ CreateObjectStoreOp::DoDatabaseWork(DatabaseConnection* aConnection) "CreateObjectStoreOp::DoDatabaseWork", js::ProfileEntry::Category::STORAGE); - if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) { - return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR; - } - #ifdef DEBUG { // Make sure that we're not creating an object store with the same name as @@ -24851,10 +24667,6 @@ RenameObjectStoreOp::DoDatabaseWork(DatabaseConnection* aConnection) "RenameObjectStoreOp::DoDatabaseWork", js::ProfileEntry::Category::STORAGE); - if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) { - return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR; - } - #ifdef DEBUG { // Make sure that we're not renaming an object store with the same name as @@ -24944,7 +24756,6 @@ CreateIndexOp::InsertDataFromObjectStore(DatabaseConnection* aConnection) { MOZ_ASSERT(aConnection); aConnection->AssertIsOnConnectionThread(); - MOZ_ASSERT(!IndexedDatabaseManager::InLowDiskSpaceMode()); MOZ_ASSERT(mMaybeUniqueIndexTable); PROFILER_LABEL("IndexedDB", @@ -24995,7 +24806,6 @@ CreateIndexOp::InsertDataFromObjectStoreInternal( { MOZ_ASSERT(aConnection); aConnection->AssertIsOnConnectionThread(); - MOZ_ASSERT(!IndexedDatabaseManager::InLowDiskSpaceMode()); MOZ_ASSERT(mMaybeUniqueIndexTable); DebugOnly<void*> storageConnection = aConnection->GetStorageConnection(); @@ -25072,10 +24882,6 @@ CreateIndexOp::DoDatabaseWork(DatabaseConnection* aConnection) "CreateIndexOp::DoDatabaseWork", js::ProfileEntry::Category::STORAGE); - if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) { - return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR; - } - #ifdef DEBUG { // Make sure that we're not creating an index with the same name and object @@ -25952,10 +25758,6 @@ RenameIndexOp::DoDatabaseWork(DatabaseConnection* aConnection) "RenameIndexOp::DoDatabaseWork", js::ProfileEntry::Category::STORAGE); - if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) { - return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR; - } - #ifdef DEBUG { // Make sure that we're not renaming an index with the same name as another @@ -26440,10 +26242,6 @@ ObjectStoreAddOrPutRequestOp::DoDatabaseWork(DatabaseConnection* aConnection) "ObjectStoreAddOrPutRequestOp::DoDatabaseWork", js::ProfileEntry::Category::STORAGE); - if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) { - return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR; - } - DatabaseConnection::AutoSavepoint autoSave; nsresult rv = autoSave.Start(Transaction()); if (NS_WARN_IF(NS_FAILED(rv))) { 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..be0295dc7 100644 --- a/dom/indexedDB/IDBCursor.cpp +++ b/dom/indexedDB/IDBCursor.cpp @@ -430,7 +430,7 @@ IDBCursor::Continue(JSContext* aCx, } Key key; - aRv = key.SetFromJSVal(aCx, aKey); + aRv = key.SetFromJSVal(aCx, aKey, /* aCallGetters */ true); if (aRv.Failed()) { return; } @@ -536,7 +536,7 @@ IDBCursor::ContinuePrimaryKey(JSContext* aCx, } Key key; - aRv = key.SetFromJSVal(aCx, aKey); + aRv = key.SetFromJSVal(aCx, aKey, /* aCallGetters */ true); if (aRv.Failed()) { return; } @@ -558,7 +558,7 @@ IDBCursor::ContinuePrimaryKey(JSContext* aCx, } Key primaryKey; - aRv = primaryKey.SetFromJSVal(aCx, aPrimaryKey); + aRv = primaryKey.SetFromJSVal(aCx, aPrimaryKey, /* aCallGetters */ true); if (aRv.Failed()) { return; } @@ -718,7 +718,7 @@ IDBCursor::Update(JSContext* aCx, JS::Handle<JS::Value> aValue, const KeyPath& keyPath = objectStore->GetKeyPath(); Key key; - aRv = keyPath.ExtractKey(aCx, aValue, key); + aRv = keyPath.ExtractKey(aCx, aValue, key, /* aCallGetters */ false); if (aRv.Failed()) { return nullptr; } @@ -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/IDBDatabase.cpp b/dom/indexedDB/IDBDatabase.cpp index 5592e7f93..6ef352801 100644 --- a/dom/indexedDB/IDBDatabase.cpp +++ b/dom/indexedDB/IDBDatabase.cpp @@ -1257,6 +1257,9 @@ IDBDatabase::LastRelease() AssertIsOnOwningThread(); CloseInternal(); + + // Make sure that file actors created after the database was closed are expired. + ExpireFileActors(/* aExpireAll */ true); if (mBackgroundActor) { mBackgroundActor->SendDeleteMeInternal(); diff --git a/dom/indexedDB/IDBFactory.cpp b/dom/indexedDB/IDBFactory.cpp index 663828978..66471fe24 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(); @@ -500,13 +482,13 @@ IDBFactory::Cmp(JSContext* aCx, JS::Handle<JS::Value> aFirst, JS::Handle<JS::Value> aSecond, ErrorResult& aRv) { Key first, second; - nsresult rv = first.SetFromJSVal(aCx, aFirst); + nsresult rv = first.SetFromJSVal(aCx, aFirst, /* aCallGetters */ true); if (NS_FAILED(rv)) { aRv.Throw(rv); return 0; } - rv = second.SetFromJSVal(aCx, aSecond); + rv = second.SetFromJSVal(aCx, aSecond, /* aCallGetters */ true); if (NS_FAILED(rv)) { aRv.Throw(rv); return 0; @@ -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..168fb4a5a 100644 --- a/dom/indexedDB/IDBKeyRange.cpp +++ b/dom/indexedDB/IDBKeyRange.cpp @@ -24,7 +24,7 @@ GetKeyFromJSVal(JSContext* aCx, JS::Handle<JS::Value> aVal, Key& aKey) { - nsresult rv = aKey.SetFromJSVal(aCx, aVal); + nsresult rv = aKey.SetFromJSVal(aCx, aVal, /* aCallGetters */ true); if (NS_FAILED(rv)) { MOZ_ASSERT(NS_ERROR_GET_MODULE(rv) == NS_ERROR_MODULE_DOM_INDEXEDDB); return rv; @@ -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..cbac30894 100644 --- a/dom/indexedDB/IDBObjectStore.cpp +++ b/dom/indexedDB/IDBObjectStore.cpp @@ -1084,7 +1084,7 @@ IDBObjectStore::AppendIndexUpdateInfo( if (!aMultiEntry) { Key key; - rv = aKeyPath.ExtractKey(aCx, aVal, key); + rv = aKeyPath.ExtractKey(aCx, aVal, key, /* aCallGetters */ false); // If an index's keyPath doesn't match an object, we ignore that object. if (rv == NS_ERROR_DOM_INDEXEDDB_DATA_ERR || key.IsUnset()) { @@ -1114,7 +1114,7 @@ IDBObjectStore::AppendIndexUpdateInfo( } bool isArray; - if (!JS_IsArrayObject(aCx, val, &isArray)) { + if (NS_WARN_IF(!JS_IsArrayObject(aCx, val, &isArray))) { IDB_REPORT_INTERNAL_ERR(); return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } @@ -1127,14 +1127,31 @@ IDBObjectStore::AppendIndexUpdateInfo( } for (uint32_t arrayIndex = 0; arrayIndex < arrayLength; arrayIndex++) { - JS::Rooted<JS::Value> arrayItem(aCx); - if (NS_WARN_IF(!JS_GetElement(aCx, array, arrayIndex, &arrayItem))) { + JS::RootedId indexId(aCx);
+ if (NS_WARN_IF(!JS_IndexToId(aCx, arrayIndex, &indexId))) {
+ IDB_REPORT_INTERNAL_ERR();
+ return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+ }
+
+ bool hasOwnProperty;
+ if (NS_WARN_IF(
+ !JS_HasOwnPropertyById(aCx, array, indexId, &hasOwnProperty))) {
+ IDB_REPORT_INTERNAL_ERR();
+ return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+ }
+
+ if (!hasOwnProperty) {
+ continue;
+ }
+
+ JS::RootedValue arrayItem(aCx);
+ if (NS_WARN_IF(!JS_GetPropertyById(aCx, array, indexId, &arrayItem))) { IDB_REPORT_INTERNAL_ERR(); return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } Key value; - if (NS_FAILED(value.SetFromJSVal(aCx, arrayItem)) || + if (NS_FAILED(value.SetFromJSVal(aCx, arrayItem, /* aCallGetters */ false)) || value.IsUnset()) { // Not a value we can do anything with, ignore it. continue; @@ -1153,7 +1170,7 @@ IDBObjectStore::AppendIndexUpdateInfo( } else { Key value; - if (NS_FAILED(value.SetFromJSVal(aCx, val)) || + if (NS_FAILED(value.SetFromJSVal(aCx, val, /* aCallGetters */ false)) || value.IsUnset()) { // Not a value we can do anything with, ignore it. return NS_OK; @@ -1324,12 +1341,12 @@ IDBObjectStore::GetAddInfo(JSContext* aCx, if (!HasValidKeyPath()) { // Out-of-line keys must be passed in. - rv = aKey.SetFromJSVal(aCx, aKeyVal); + rv = aKey.SetFromJSVal(aCx, aKeyVal, /* aCallGetters */ true); if (NS_FAILED(rv)) { return rv; } } else if (!isAutoIncrement) { - rv = GetKeyPath().ExtractKey(aCx, aValue, aKey); + rv = GetKeyPath().ExtractKey(aCx, aValue, aKey, /* aCallGetters */ false); if (NS_FAILED(rv)) { return rv; } @@ -1368,7 +1385,8 @@ IDBObjectStore::GetAddInfo(JSContext* aCx, aValue, aKey, &GetAddInfoCallback, - &data); + &data, + /* aCallGetters */ false); } else { rv = GetAddInfoCallback(aCx, &data); } @@ -1758,7 +1776,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/IndexedDatabaseManager.cpp b/dom/indexedDB/IndexedDatabaseManager.cpp index 62ba51c08..213de5cc9 100644 --- a/dom/indexedDB/IndexedDatabaseManager.cpp +++ b/dom/indexedDB/IndexedDatabaseManager.cpp @@ -8,11 +8,9 @@ #include "chrome/common/ipc_channel.h" // for IPC::Channel::kMaximumMessageSize #include "nsIConsoleService.h" -#include "nsIDiskSpaceWatcher.h" #include "nsIDOMWindow.h" #include "nsIEventTarget.h" #include "nsIFile.h" -#include "nsIObserverService.h" #include "nsIScriptError.h" #include "nsIScriptGlobalObject.h" @@ -64,11 +62,6 @@ #define IDB_STR "indexedDB" -// The two possible values for the data argument when receiving the disk space -// observer notification. -#define LOW_DISK_SPACE_DATA_FULL "full" -#define LOW_DISK_SPACE_DATA_FREE "free" - namespace mozilla { namespace dom { namespace indexedDB { @@ -313,8 +306,6 @@ Atomic<IndexedDatabaseManager::LoggingMode> IndexedDatabaseManager::sLoggingMode( IndexedDatabaseManager::Logging_Disabled); -mozilla::Atomic<bool> IndexedDatabaseManager::sLowDiskSpaceMode(false); - // static IndexedDatabaseManager* IndexedDatabaseManager::GetOrCreate() @@ -329,24 +320,6 @@ IndexedDatabaseManager::GetOrCreate() if (!gDBManager) { sIsMainProcess = XRE_IsParentProcess(); - if (sIsMainProcess && Preferences::GetBool("disk_space_watcher.enabled", false)) { - // See if we're starting up in low disk space conditions. - nsCOMPtr<nsIDiskSpaceWatcher> watcher = - do_GetService(DISKSPACEWATCHER_CONTRACTID); - if (watcher) { - bool isDiskFull; - if (NS_SUCCEEDED(watcher->GetIsDiskFull(&isDiskFull))) { - sLowDiskSpaceMode = isDiskFull; - } - else { - NS_WARNING("GetIsDiskFull failed!"); - } - } - else { - NS_WARNING("No disk space watcher component available!"); - } - } - RefPtr<IndexedDatabaseManager> instance(new IndexedDatabaseManager()); nsresult rv = instance->Init(); @@ -380,13 +353,6 @@ IndexedDatabaseManager::Init() // During Init() we can't yet call IsMainProcess(), just check sIsMainProcess // directly. if (sIsMainProcess) { - nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); - NS_ENSURE_STATE(obs); - - nsresult rv = - obs->AddObserver(this, DISKSPACEWATCHER_OBSERVER_TOPIC, false); - NS_ENSURE_SUCCESS(rv, rv); - mDeleteTimer = do_CreateInstance(NS_TIMER_CONTRACTID); NS_ENSURE_STATE(mDeleteTimer); @@ -680,16 +646,6 @@ IndexedDatabaseManager::IsMainProcess() return sIsMainProcess; } -//static -bool -IndexedDatabaseManager::InLowDiskSpaceMode() -{ - NS_ASSERTION(gDBManager, - "InLowDiskSpaceMode() called before indexedDB has been " - "initialized!"); - return sLowDiskSpaceMode; -} - // static IndexedDatabaseManager::LoggingMode IndexedDatabaseManager::GetLoggingMode() @@ -1087,36 +1043,7 @@ IndexedDatabaseManager::GetLocale() NS_IMPL_ADDREF(IndexedDatabaseManager) NS_IMPL_RELEASE_WITH_DESTROY(IndexedDatabaseManager, Destroy()) -NS_IMPL_QUERY_INTERFACE(IndexedDatabaseManager, nsIObserver, nsITimerCallback) - -NS_IMETHODIMP -IndexedDatabaseManager::Observe(nsISupports* aSubject, const char* aTopic, - const char16_t* aData) -{ - NS_ASSERTION(IsMainProcess(), "Wrong process!"); - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - - if (!strcmp(aTopic, DISKSPACEWATCHER_OBSERVER_TOPIC)) { - NS_ASSERTION(aData, "No data?!"); - - const nsDependentString data(aData); - - if (data.EqualsLiteral(LOW_DISK_SPACE_DATA_FULL)) { - sLowDiskSpaceMode = true; - } - else if (data.EqualsLiteral(LOW_DISK_SPACE_DATA_FREE)) { - sLowDiskSpaceMode = false; - } - else { - NS_NOTREACHED("Unknown data value!"); - } - - return NS_OK; - } - - NS_NOTREACHED("Unknown topic!"); - return NS_ERROR_UNEXPECTED; -} +NS_IMPL_QUERY_INTERFACE(IndexedDatabaseManager, nsITimerCallback) NS_IMETHODIMP IndexedDatabaseManager::Notify(nsITimer* aTimer) diff --git a/dom/indexedDB/IndexedDatabaseManager.h b/dom/indexedDB/IndexedDatabaseManager.h index d63c548ec..fb4376426 100644 --- a/dom/indexedDB/IndexedDatabaseManager.h +++ b/dom/indexedDB/IndexedDatabaseManager.h @@ -7,8 +7,6 @@ #ifndef mozilla_dom_indexeddatabasemanager_h__ #define mozilla_dom_indexeddatabasemanager_h__ -#include "nsIObserver.h" - #include "js/TypeDecls.h" #include "mozilla/Atomics.h" #include "mozilla/dom/quota/PersistenceType.h" @@ -43,8 +41,7 @@ class FileManagerInfo; } // namespace indexedDB class IndexedDatabaseManager final - : public nsIObserver - , public nsITimerCallback + : public nsITimerCallback { typedef mozilla::dom::quota::PersistenceType PersistenceType; typedef mozilla::dom::quota::QuotaManager QuotaManager; @@ -62,7 +59,6 @@ public: }; NS_DECL_ISUPPORTS - NS_DECL_NSIOBSERVER NS_DECL_NSITIMERCALLBACK // Returns a non-owning reference. @@ -87,16 +83,6 @@ public: #endif static bool - InLowDiskSpaceMode() -#ifdef DEBUG - ; -#else - { - return !!sLowDiskSpaceMode; - } -#endif - - static bool InTestingMode(); static bool @@ -244,7 +230,6 @@ private: static bool sFullSynchronousMode; static LazyLogModule sLoggingModule; static Atomic<LoggingMode> sLoggingMode; - static mozilla::Atomic<bool> sLowDiskSpaceMode; }; } // namespace dom diff --git a/dom/indexedDB/Key.cpp b/dom/indexedDB/Key.cpp index 0f693b2c6..575734af2 100644 --- a/dom/indexedDB/Key.cpp +++ b/dom/indexedDB/Key.cpp @@ -201,8 +201,11 @@ Key::ToLocaleBasedKey(Key& aTarget, const nsCString& aLocale) const } nsresult -Key::EncodeJSValInternal(JSContext* aCx, JS::Handle<JS::Value> aVal, - uint8_t aTypeOffset, uint16_t aRecursionDepth) +Key::EncodeJSValInternal(JSContext* aCx, + JS::Handle<JS::Value> aVal, + uint8_t aTypeOffset, + uint16_t aRecursionDepth, + bool aCallGetters) { static_assert(eMaxType * kMaxArrayCollapse < 256, "Unable to encode jsvals."); @@ -257,13 +260,18 @@ Key::EncodeJSValInternal(JSContext* aCx, JS::Handle<JS::Value> aVal, for (uint32_t index = 0; index < length; index++) { JS::Rooted<JS::Value> val(aCx); - if (!JS_GetElement(aCx, obj, index, &val)) { + bool ok = aCallGetters ? JS_GetElement(aCx, obj, index, &val) + : JS_GetOwnElement(aCx, obj, index, &val); + if (!ok) { IDB_REPORT_INTERNAL_ERR(); return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } - nsresult rv = EncodeJSValInternal(aCx, val, aTypeOffset, - aRecursionDepth + 1); + nsresult rv = EncodeJSValInternal(aCx, + val, + aTypeOffset, + aRecursionDepth + 1, + aCallGetters); if (NS_FAILED(rv)) { return rv; } @@ -406,9 +414,10 @@ Key::DecodeJSValInternal(const unsigned char*& aPos, const unsigned char* aEnd, nsresult Key::EncodeJSVal(JSContext* aCx, JS::Handle<JS::Value> aVal, - uint8_t aTypeOffset) + uint8_t aTypeOffset, + bool aCallGetters) { - return EncodeJSValInternal(aCx, aVal, aTypeOffset, 0); + return EncodeJSValInternal(aCx, aVal, aTypeOffset, 0, aCallGetters); } void @@ -741,7 +750,8 @@ Key::SetFromValueArray(mozIStorageValueArray* aValues, nsresult Key::SetFromJSVal(JSContext* aCx, - JS::Handle<JS::Value> aVal) + JS::Handle<JS::Value> aVal, + bool aCallGetters) { mBuffer.Truncate(); @@ -750,7 +760,7 @@ Key::SetFromJSVal(JSContext* aCx, return NS_OK; } - nsresult rv = EncodeJSVal(aCx, aVal, 0); + nsresult rv = EncodeJSVal(aCx, aVal, 0, aCallGetters); if (NS_FAILED(rv)) { Unset(); return rv; @@ -793,9 +803,15 @@ Key::ToJSVal(JSContext* aCx, } nsresult -Key::AppendItem(JSContext* aCx, bool aFirstOfArray, JS::Handle<JS::Value> aVal) +Key::AppendItem(JSContext* aCx, + bool aFirstOfArray, + JS::Handle<JS::Value> aVal, + bool aCallGetters) { - nsresult rv = EncodeJSVal(aCx, aVal, aFirstOfArray ? eMaxType : 0); + nsresult rv = EncodeJSVal(aCx, + aVal, + aFirstOfArray ? eMaxType : 0, + aCallGetters); if (NS_FAILED(rv)) { Unset(); return rv; diff --git a/dom/indexedDB/Key.h b/dom/indexedDB/Key.h index 9d70ce6ad..a4fb65b48 100644 --- a/dom/indexedDB/Key.h +++ b/dom/indexedDB/Key.h @@ -203,7 +203,7 @@ public: } nsresult - SetFromJSVal(JSContext* aCx, JS::Handle<JS::Value> aVal); + SetFromJSVal(JSContext* aCx, JS::Handle<JS::Value> aVal, bool aCallGetters); nsresult ToJSVal(JSContext* aCx, JS::MutableHandle<JS::Value> aVal) const; @@ -212,7 +212,10 @@ public: ToJSVal(JSContext* aCx, JS::Heap<JS::Value>& aVal) const; nsresult - AppendItem(JSContext* aCx, bool aFirstOfArray, JS::Handle<JS::Value> aVal); + AppendItem(JSContext* aCx, + bool aFirstOfArray, + JS::Handle<JS::Value> aVal, + bool aCallGetters); nsresult ToLocaleBasedKey(Key& aTarget, const nsCString& aLocale) const; @@ -283,7 +286,10 @@ private: // Encoding functions. These append the encoded value to the end of mBuffer nsresult - EncodeJSVal(JSContext* aCx, JS::Handle<JS::Value> aVal, uint8_t aTypeOffset); + EncodeJSVal(JSContext* aCx, + JS::Handle<JS::Value> aVal, + uint8_t aTypeOffset, + bool aCallGetters); void EncodeString(const nsAString& aString, uint8_t aTypeOffset); @@ -331,7 +337,8 @@ private: EncodeJSValInternal(JSContext* aCx, JS::Handle<JS::Value> aVal, uint8_t aTypeOffset, - uint16_t aRecursionDepth); + uint16_t aRecursionDepth, + bool aCallGetters); static nsresult DecodeJSValInternal(const unsigned char*& aPos, diff --git a/dom/indexedDB/KeyPath.cpp b/dom/indexedDB/KeyPath.cpp index dc8d10668..0221c9450 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; @@ -311,11 +372,13 @@ KeyPath::AppendStringWithValidation(const nsAString& aString) } nsresult -KeyPath::ExtractKey(JSContext* aCx, const JS::Value& aValue, Key& aKey) const +KeyPath::ExtractKey(JSContext* aCx, + const JS::Value& aValue, + Key& aKey, + bool aCallGetters) const { uint32_t len = mStrings.Length(); JS::Rooted<JS::Value> value(aCx); - aKey.Unset(); for (uint32_t i = 0; i < len; ++i) { @@ -327,7 +390,10 @@ KeyPath::ExtractKey(JSContext* aCx, const JS::Value& aValue, Key& aKey) const return rv; } - if (NS_FAILED(aKey.AppendItem(aCx, IsArray() && i == 0, value))) { + if (NS_FAILED(aKey.AppendItem(aCx, + IsArray() && i == 0, + value, + aCallGetters))) { NS_ASSERTION(aKey.IsUnset(), "Encoding error should unset"); return NS_ERROR_DOM_INDEXEDDB_DATA_ERR; } @@ -376,9 +442,12 @@ KeyPath::ExtractKeyAsJSVal(JSContext* aCx, const JS::Value& aValue, } nsresult -KeyPath::ExtractOrCreateKey(JSContext* aCx, const JS::Value& aValue, - Key& aKey, ExtractOrCreateKeyCallback aCallback, - void* aClosure) const +KeyPath::ExtractOrCreateKey(JSContext* aCx, + const JS::Value& aValue, + Key& aKey, + ExtractOrCreateKeyCallback aCallback, + void* aClosure, + bool aCallGetters) const { NS_ASSERTION(IsString(), "This doesn't make sense!"); @@ -394,7 +463,7 @@ KeyPath::ExtractOrCreateKey(JSContext* aCx, const JS::Value& aValue, return rv; } - if (NS_FAILED(aKey.AppendItem(aCx, false, value))) { + if (NS_FAILED(aKey.AppendItem(aCx, false, value, aCallGetters))) { NS_ASSERTION(aKey.IsUnset(), "Should be unset"); return value.isUndefined() ? NS_OK : NS_ERROR_DOM_INDEXEDDB_DATA_ERR; } diff --git a/dom/indexedDB/KeyPath.h b/dom/indexedDB/KeyPath.h index c133cdc4a..e6e5f57d4 100644 --- a/dom/indexedDB/KeyPath.h +++ b/dom/indexedDB/KeyPath.h @@ -72,7 +72,10 @@ public: Parse(const Nullable<OwningStringOrStringSequence>& aValue, KeyPath* aKeyPath); nsresult - ExtractKey(JSContext* aCx, const JS::Value& aValue, Key& aKey) const; + ExtractKey(JSContext* aCx, + const JS::Value& aValue, + Key& aKey, + bool aCallGetters) const; nsresult ExtractKeyAsJSVal(JSContext* aCx, const JS::Value& aValue, @@ -82,9 +85,12 @@ public: (*ExtractOrCreateKeyCallback)(JSContext* aCx, void* aClosure); nsresult - ExtractOrCreateKey(JSContext* aCx, const JS::Value& aValue, Key& aKey, + ExtractOrCreateKey(JSContext* aCx, + const JS::Value& aValue, + Key& aKey, ExtractOrCreateKeyCallback aCallback, - void* aClosure) const; + void* aClosure, + bool aCallGetters) const; inline bool IsValid() const { return mType != NONEXISTENT; diff --git a/dom/indexedDB/test/helpers.js b/dom/indexedDB/test/helpers.js index e6e27f3f3..ffe66ebcd 100644 --- a/dom/indexedDB/test/helpers.js +++ b/dom/indexedDB/test/helpers.js @@ -217,10 +217,6 @@ if (!window.runTest) { function finishTest() { - SpecialPowers.notifyObserversInParentProcess(null, - "disk-space-watcher", - "free"); - SimpleTest.executeSoon(function() { testGenerator.close(); testHarnessGenerator.close(); diff --git a/dom/indexedDB/test/mochitest.ini b/dom/indexedDB/test/mochitest.ini index 4ab55a9dc..ca65ea8b6 100644 --- a/dom/indexedDB/test/mochitest.ini +++ b/dom/indexedDB/test/mochitest.ini @@ -66,7 +66,6 @@ support-files = unit/test_locale_aware_indexes.js unit/test_locale_aware_index_getAll.js unit/test_locale_aware_index_getAllObjects.js - unit/test_lowDiskSpace.js unit/test_maximal_serialized_object_size.js unit/test_multientry.js unit/test_names_sorted.js @@ -214,7 +213,6 @@ skip-if = true [test_key_requirements.html] [test_keys.html] [test_leaving_page.html] -[test_lowDiskSpace.html] [test_maximal_serialized_object_size.html] [test_message_manager_ipc.html] # This test is only supposed to run in the main process. diff --git a/dom/indexedDB/test/test_globalObjects_other.xul b/dom/indexedDB/test/test_globalObjects_other.xul index eb180a9b4..b527d66bd 100644 --- a/dom/indexedDB/test/test_globalObjects_other.xul +++ b/dom/indexedDB/test/test_globalObjects_other.xul @@ -31,14 +31,8 @@ Cu.import("resource://gre/modules/Services.jsm"); for (var stage of [ "install", "startup", "shutdown", "uninstall" ]) { for (var symbol of [ "IDBKeyRange", "indexedDB" ]) { - let pref; - try { - pref = Services.prefs.getBoolPref("indexeddbtest.bootstrap." + stage + - "." + symbol); - } - catch(ex) { - pref = false; - } + let pref = Services.prefs.getBoolPref("indexeddbtest.bootstrap." + stage + + "." + symbol, false); ok(pref, "Symbol '" + symbol + "' present during '" + stage + "'"); } } diff --git a/dom/indexedDB/test/test_lowDiskSpace.html b/dom/indexedDB/test/test_lowDiskSpace.html deleted file mode 100644 index cffd46549..000000000 --- a/dom/indexedDB/test/test_lowDiskSpace.html +++ /dev/null @@ -1,19 +0,0 @@ -<!-- - Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ ---> -<html> -<head> - <title>Indexed Database Low Disk Space Test</title> - - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> - - <script type="text/javascript;version=1.7" src="unit/test_lowDiskSpace.js"></script> - <script type="text/javascript;version=1.7" src="helpers.js"></script> - -</head> - -<body onload="runTest();"></body> - -</html> diff --git a/dom/indexedDB/test/unit/test_lowDiskSpace.js b/dom/indexedDB/test/unit/test_lowDiskSpace.js deleted file mode 100644 index eaea5797d..000000000 --- a/dom/indexedDB/test/unit/test_lowDiskSpace.js +++ /dev/null @@ -1,754 +0,0 @@ -/** - * Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ - */ -"use strict"; - -var disableWorkerTest = "This test uses SpecialPowers"; - -var self = this; - -var testGenerator = testSteps(); - -function testSteps() -{ - const dbName = self.window ? window.location.pathname : "test_lowDiskSpace"; - const dbVersion = 1; - - const objectStoreName = "foo"; - const objectStoreOptions = { keyPath: "foo" }; - - const indexName = "bar"; - const indexOptions = { unique: true }; - - const dbData = [ - { foo: 0, bar: 0 }, - { foo: 1, bar: 10 }, - { foo: 2, bar: 20 }, - { foo: 3, bar: 30 }, - { foo: 4, bar: 40 }, - { foo: 5, bar: 50 }, - { foo: 6, bar: 60 }, - { foo: 7, bar: 70 }, - { foo: 8, bar: 80 }, - { foo: 9, bar: 90 } - ]; - - let lowDiskMode = false; - function setLowDiskMode(val) { - let data = val ? "full" : "free"; - - if (val == lowDiskMode) { - info("Low disk mode is: " + data); - } - else { - info("Changing low disk mode to: " + data); - SpecialPowers.notifyObserversInParentProcess(null, "disk-space-watcher", - data); - lowDiskMode = val; - } - } - - { // Make sure opening works from the beginning. - info("Test 1"); - - setLowDiskMode(false); - - let request = indexedDB.open(dbName, dbVersion); - request.onerror = errorHandler; - request.onsuccess = grabEventAndContinueHandler; - let event = yield undefined; - - is(event.type, "success", "Opened database without setting low disk mode"); - - let db = event.target.result; - db.close(); - } - - { // Make sure delete works in low disk mode. - info("Test 2"); - - setLowDiskMode(true); - - let request = indexedDB.deleteDatabase(dbName); - request.onerror = errorHandler; - request.onsuccess = grabEventAndContinueHandler; - let event = yield undefined; - - is(event.type, "success", "Deleted database after setting low disk mode"); - } - - { // Make sure creating a db in low disk mode fails. - info("Test 3"); - - setLowDiskMode(true); - - let request = indexedDB.open(dbName, dbVersion); - request.onerror = expectedErrorHandler("QuotaExceededError"); - request.onupgradeneeded = unexpectedSuccessHandler; - request.onsuccess = unexpectedSuccessHandler; - let event = yield undefined; - - is(event.type, "error", "Didn't create new database in low disk mode"); - } - - { // Make sure opening an already-existing db in low disk mode succeeds. - info("Test 4"); - - setLowDiskMode(false); - - let request = indexedDB.open(dbName, dbVersion); - request.onerror = errorHandler; - request.onupgradeneeded = grabEventAndContinueHandler; - request.onsuccess = unexpectedSuccessHandler; - let event = yield undefined; - - is(event.type, "upgradeneeded", "Upgrading database"); - - let db = event.target.result; - db.onerror = errorHandler; - - request.onupgradeneeded = unexpectedSuccessHandler; - request.onsuccess = grabEventAndContinueHandler; - event = yield undefined; - - is(event.type, "success", "Created database"); - ok(event.target.result === db, "Got the same database"); - - db.close(); - - setLowDiskMode(true); - - request = indexedDB.open(dbName); - request.onerror = errorHandler; - request.onupgradeneeded = unexpectedSuccessHandler; - request.onsuccess = grabEventAndContinueHandler; - event = yield undefined; - - is(event.type, "success", "Opened existing database in low disk mode"); - - db = event.target.result; - db.close(); - } - - { // Make sure upgrading an already-existing db in low disk mode succeeds. - info("Test 5"); - - setLowDiskMode(true); - - let request = indexedDB.open(dbName, dbVersion + 1); - request.onerror = errorHandler; - request.onupgradeneeded = grabEventAndContinueHandler; - request.onsuccess = unexpectedSuccessHandler; - - let event = yield undefined; - - is(event.type, "upgradeneeded", "Upgrading database"); - - let db = event.target.result; - db.onerror = errorHandler; - - request.onupgradeneeded = unexpectedSuccessHandler; - request.onsuccess = grabEventAndContinueHandler; - event = yield undefined; - - is(event.type, "success", "Created database"); - ok(event.target.result === db, "Got the same database"); - - db.close(); - } - - { // Make sure creating objectStores in low disk mode fails. - info("Test 6"); - - setLowDiskMode(true); - - let request = indexedDB.open(dbName, dbVersion + 2); - request.onerror = errorHandler; - request.onupgradeneeded = grabEventAndContinueHandler; - request.onsuccess = unexpectedSuccessHandler; - - let event = yield undefined; - - is(event.type, "upgradeneeded", "Upgrading database"); - - let db = event.target.result; - db.onerror = errorHandler; - - let txn = event.target.transaction; - txn.onerror = expectedErrorHandler("AbortError"); - txn.onabort = grabEventAndContinueHandler; - - let objectStore = db.createObjectStore(objectStoreName, objectStoreOptions); - - request.onupgradeneeded = unexpectedSuccessHandler; - event = yield undefined; - - is(event.type, "abort", "Got correct event type"); - is(event.target.error.name, "QuotaExceededError", "Got correct error type"); - - request.onerror = expectedErrorHandler("AbortError"); - event = yield undefined; - } - - { // Make sure creating indexes in low disk mode fails. - info("Test 7"); - - setLowDiskMode(false); - - let request = indexedDB.open(dbName, dbVersion + 2); - request.onerror = errorHandler; - request.onupgradeneeded = grabEventAndContinueHandler; - request.onsuccess = unexpectedSuccessHandler; - - let event = yield undefined; - - is(event.type, "upgradeneeded", "Upgrading database"); - - let db = event.target.result; - db.onerror = errorHandler; - - let objectStore = db.createObjectStore(objectStoreName, objectStoreOptions); - - request.onupgradeneeded = unexpectedSuccessHandler; - request.onsuccess = grabEventAndContinueHandler; - event = yield undefined; - - is(event.type, "success", "Upgraded database"); - ok(event.target.result === db, "Got the same database"); - - db.close(); - - setLowDiskMode(true); - - request = indexedDB.open(dbName, dbVersion + 3); - request.onerror = errorHandler; - request.onupgradeneeded = grabEventAndContinueHandler; - request.onsuccess = unexpectedSuccessHandler; - event = yield undefined; - - is(event.type, "upgradeneeded", "Upgrading database"); - - db = event.target.result; - db.onerror = errorHandler; - let txn = event.target.transaction; - txn.onerror = expectedErrorHandler("AbortError"); - txn.onabort = grabEventAndContinueHandler; - - objectStore = event.target.transaction.objectStore(objectStoreName); - let index = objectStore.createIndex(indexName, indexName, indexOptions); - - request.onupgradeneeded = unexpectedSuccessHandler; - event = yield undefined; - - is(event.type, "abort", "Got correct event type"); - is(event.target.error.name, "QuotaExceededError", "Got correct error type"); - - request.onerror = expectedErrorHandler("AbortError"); - event = yield undefined; - } - - { // Make sure deleting indexes in low disk mode succeeds. - info("Test 8"); - - setLowDiskMode(false); - - let request = indexedDB.open(dbName, dbVersion + 3); - request.onerror = errorHandler; - request.onupgradeneeded = grabEventAndContinueHandler; - request.onsuccess = unexpectedSuccessHandler; - - let event = yield undefined; - - is(event.type, "upgradeneeded", "Upgrading database"); - - let db = event.target.result; - db.onerror = errorHandler; - - let objectStore = event.target.transaction.objectStore(objectStoreName); - let index = objectStore.createIndex(indexName, indexName, indexOptions); - - request.onupgradeneeded = unexpectedSuccessHandler; - request.onsuccess = grabEventAndContinueHandler; - event = yield undefined; - - is(event.type, "success", "Upgraded database"); - ok(event.target.result === db, "Got the same database"); - - db.close(); - - setLowDiskMode(true); - - request = indexedDB.open(dbName, dbVersion + 4); - request.onerror = errorHandler; - request.onupgradeneeded = grabEventAndContinueHandler; - request.onsuccess = unexpectedSuccessHandler; - event = yield undefined; - - is(event.type, "upgradeneeded", "Upgrading database"); - - db = event.target.result; - db.onerror = errorHandler; - - objectStore = event.target.transaction.objectStore(objectStoreName); - objectStore.deleteIndex(indexName); - - request.onupgradeneeded = unexpectedSuccessHandler; - request.onsuccess = grabEventAndContinueHandler; - event = yield undefined; - - is(event.type, "success", "Upgraded database"); - ok(event.target.result === db, "Got the same database"); - - db.close(); - } - - { // Make sure deleting objectStores in low disk mode succeeds. - info("Test 9"); - - setLowDiskMode(true); - - let request = indexedDB.open(dbName, dbVersion + 5); - request.onerror = errorHandler; - request.onupgradeneeded = grabEventAndContinueHandler; - request.onsuccess = unexpectedSuccessHandler; - - let event = yield undefined; - - is(event.type, "upgradeneeded", "Upgrading database"); - - let db = event.target.result; - db.onerror = errorHandler; - - db.deleteObjectStore(objectStoreName); - - request.onupgradeneeded = unexpectedSuccessHandler; - request.onsuccess = grabEventAndContinueHandler; - event = yield undefined; - - is(event.type, "success", "Upgraded database"); - ok(event.target.result === db, "Got the same database"); - - db.close(); - - // Reset everything. - indexedDB.deleteDatabase(dbName); - } - - - { // Add data that the rest of the tests will use. - info("Adding test data"); - - setLowDiskMode(false); - - let request = indexedDB.open(dbName, dbVersion); - request.onerror = errorHandler; - request.onupgradeneeded = grabEventAndContinueHandler; - request.onsuccess = unexpectedSuccessHandler; - let event = yield undefined; - - is(event.type, "upgradeneeded", "Upgrading database"); - - let db = event.target.result; - db.onerror = errorHandler; - - let objectStore = db.createObjectStore(objectStoreName, objectStoreOptions); - let index = objectStore.createIndex(indexName, indexName, indexOptions); - - for (let data of dbData) { - objectStore.add(data); - } - - request.onupgradeneeded = unexpectedSuccessHandler; - request.onsuccess = grabEventAndContinueHandler; - event = yield undefined; - - is(event.type, "success", "Upgraded database"); - ok(event.target.result === db, "Got the same database"); - - db.close(); - } - - { // Make sure read operations in readonly transactions succeed in low disk - // mode. - info("Test 10"); - - setLowDiskMode(true); - - let request = indexedDB.open(dbName, dbVersion); - request.onerror = errorHandler; - request.onupgradeneeded = unexpectedSuccessHandler; - request.onsuccess = grabEventAndContinueHandler; - let event = yield undefined; - - let db = event.target.result; - db.onerror = errorHandler; - - let transaction = db.transaction(objectStoreName); - let objectStore = transaction.objectStore(objectStoreName); - let index = objectStore.index(indexName); - - let data = dbData[0]; - - let requestCounter = new RequestCounter(); - - objectStore.get(data.foo).onsuccess = requestCounter.handler(); - objectStore.mozGetAll().onsuccess = requestCounter.handler(); - objectStore.count().onsuccess = requestCounter.handler(); - index.get(data.bar).onsuccess = requestCounter.handler(); - index.mozGetAll().onsuccess = requestCounter.handler(); - index.getKey(data.bar).onsuccess = requestCounter.handler(); - index.mozGetAllKeys().onsuccess = requestCounter.handler(); - index.count().onsuccess = requestCounter.handler(); - - let objectStoreDataCount = 0; - - request = objectStore.openCursor(); - request.onsuccess = function(event) { - let cursor = event.target.result; - if (cursor) { - objectStoreDataCount++; - objectStoreDataCount % 2 ? cursor.continue() : cursor.advance(1); - } - else { - is(objectStoreDataCount, dbData.length, "Saw all data"); - requestCounter.decr(); - } - }; - requestCounter.incr(); - - let indexDataCount = 0; - - request = index.openCursor(); - request.onsuccess = function(event) { - let cursor = event.target.result; - if (cursor) { - indexDataCount++; - indexDataCount % 2 ? cursor.continue() : cursor.advance(1); - } - else { - is(indexDataCount, dbData.length, "Saw all data"); - requestCounter.decr(); - } - }; - requestCounter.incr(); - - let indexKeyDataCount = 0; - - request = index.openCursor(); - request.onsuccess = function(event) { - let cursor = event.target.result; - if (cursor) { - indexKeyDataCount++; - indexKeyDataCount % 2 ? cursor.continue() : cursor.advance(1); - } - else { - is(indexKeyDataCount, dbData.length, "Saw all data"); - requestCounter.decr(); - } - }; - requestCounter.incr(); - - // Wait for all requests. - yield undefined; - - transaction.oncomplete = grabEventAndContinueHandler; - event = yield undefined; - - is(event.type, "complete", "Transaction succeeded"); - - db.close(); - } - - { // Make sure read operations in readwrite transactions succeed in low disk - // mode. - info("Test 11"); - - setLowDiskMode(true); - - let request = indexedDB.open(dbName, dbVersion); - request.onerror = errorHandler; - request.onupgradeneeded = unexpectedSuccessHandler; - request.onsuccess = grabEventAndContinueHandler; - let event = yield undefined; - - let db = event.target.result; - db.onerror = errorHandler; - - let transaction = db.transaction(objectStoreName, "readwrite"); - let objectStore = transaction.objectStore(objectStoreName); - let index = objectStore.index(indexName); - - let data = dbData[0]; - - let requestCounter = new RequestCounter(); - - objectStore.get(data.foo).onsuccess = requestCounter.handler(); - objectStore.mozGetAll().onsuccess = requestCounter.handler(); - objectStore.count().onsuccess = requestCounter.handler(); - index.get(data.bar).onsuccess = requestCounter.handler(); - index.mozGetAll().onsuccess = requestCounter.handler(); - index.getKey(data.bar).onsuccess = requestCounter.handler(); - index.mozGetAllKeys().onsuccess = requestCounter.handler(); - index.count().onsuccess = requestCounter.handler(); - - let objectStoreDataCount = 0; - - request = objectStore.openCursor(); - request.onsuccess = function(event) { - let cursor = event.target.result; - if (cursor) { - objectStoreDataCount++; - objectStoreDataCount % 2 ? cursor.continue() : cursor.advance(1); - } - else { - is(objectStoreDataCount, dbData.length, "Saw all data"); - requestCounter.decr(); - } - }; - requestCounter.incr(); - - let indexDataCount = 0; - - request = index.openCursor(); - request.onsuccess = function(event) { - let cursor = event.target.result; - if (cursor) { - indexDataCount++; - indexDataCount % 2 ? cursor.continue() : cursor.advance(1); - } - else { - is(indexDataCount, dbData.length, "Saw all data"); - requestCounter.decr(); - } - }; - requestCounter.incr(); - - let indexKeyDataCount = 0; - - request = index.openCursor(); - request.onsuccess = function(event) { - let cursor = event.target.result; - if (cursor) { - indexKeyDataCount++; - indexKeyDataCount % 2 ? cursor.continue() : cursor.advance(1); - } - else { - is(indexKeyDataCount, dbData.length, "Saw all data"); - requestCounter.decr(); - } - }; - requestCounter.incr(); - - // Wait for all requests. - yield undefined; - - transaction.oncomplete = grabEventAndContinueHandler; - event = yield undefined; - - is(event.type, "complete", "Transaction succeeded"); - - db.close(); - } - - { // Make sure write operations in readwrite transactions fail in low disk - // mode. - info("Test 12"); - - setLowDiskMode(true); - - let request = indexedDB.open(dbName, dbVersion); - request.onerror = errorHandler; - request.onupgradeneeded = unexpectedSuccessHandler; - request.onsuccess = grabEventAndContinueHandler; - let event = yield undefined; - - let db = event.target.result; - db.onerror = errorHandler; - - let transaction = db.transaction(objectStoreName, "readwrite"); - let objectStore = transaction.objectStore(objectStoreName); - let index = objectStore.index(indexName); - - let data = dbData[0]; - let newData = { foo: 999, bar: 999 }; - - let requestCounter = new RequestCounter(); - - objectStore.add(newData).onerror = requestCounter.errorHandler(); - objectStore.put(newData).onerror = requestCounter.errorHandler(); - - objectStore.get(data.foo).onsuccess = requestCounter.handler(); - objectStore.mozGetAll().onsuccess = requestCounter.handler(); - objectStore.count().onsuccess = requestCounter.handler(); - index.get(data.bar).onsuccess = requestCounter.handler(); - index.mozGetAll().onsuccess = requestCounter.handler(); - index.getKey(data.bar).onsuccess = requestCounter.handler(); - index.mozGetAllKeys().onsuccess = requestCounter.handler(); - index.count().onsuccess = requestCounter.handler(); - - let objectStoreDataCount = 0; - - request = objectStore.openCursor(); - request.onsuccess = function(event) { - let cursor = event.target.result; - if (cursor) { - objectStoreDataCount++; - cursor.update(cursor.value).onerror = requestCounter.errorHandler(); - objectStoreDataCount % 2 ? cursor.continue() : cursor.advance(1); - } - else { - is(objectStoreDataCount, dbData.length, "Saw all data"); - requestCounter.decr(); - } - }; - requestCounter.incr(); - - let indexDataCount = 0; - - request = index.openCursor(); - request.onsuccess = function(event) { - let cursor = event.target.result; - if (cursor) { - indexDataCount++; - cursor.update(cursor.value).onerror = requestCounter.errorHandler(); - indexDataCount % 2 ? cursor.continue() : cursor.advance(1); - } - else { - is(indexDataCount, dbData.length, "Saw all data"); - requestCounter.decr(); - } - }; - requestCounter.incr(); - - let indexKeyDataCount = 0; - - request = index.openCursor(); - request.onsuccess = function(event) { - let cursor = event.target.result; - if (cursor) { - indexKeyDataCount++; - cursor.update(cursor.value).onerror = requestCounter.errorHandler(); - indexKeyDataCount % 2 ? cursor.continue() : cursor.advance(1); - } - else { - is(indexKeyDataCount, dbData.length, "Saw all data"); - requestCounter.decr(); - } - }; - requestCounter.incr(); - - // Wait for all requests. - yield undefined; - - transaction.oncomplete = grabEventAndContinueHandler; - event = yield undefined; - - is(event.type, "complete", "Transaction succeeded"); - - db.close(); - } - - { // Make sure deleting operations in readwrite transactions succeed in low - // disk mode. - info("Test 13"); - - setLowDiskMode(true); - - let request = indexedDB.open(dbName, dbVersion); - request.onerror = errorHandler; - request.onupgradeneeded = unexpectedSuccessHandler; - request.onsuccess = grabEventAndContinueHandler; - let event = yield undefined; - - let db = event.target.result; - db.onerror = errorHandler; - - let transaction = db.transaction(objectStoreName, "readwrite"); - let objectStore = transaction.objectStore(objectStoreName); - let index = objectStore.index(indexName); - - let dataIndex = 0; - let data = dbData[dataIndex++]; - - let requestCounter = new RequestCounter(); - - objectStore.delete(data.foo).onsuccess = requestCounter.handler(); - - objectStore.openCursor().onsuccess = function(event) { - let cursor = event.target.result; - if (cursor) { - cursor.delete().onsuccess = requestCounter.handler(); - } - requestCounter.decr(); - }; - requestCounter.incr(); - - index.openCursor(null, "prev").onsuccess = function(event) { - let cursor = event.target.result; - if (cursor) { - cursor.delete().onsuccess = requestCounter.handler(); - } - requestCounter.decr(); - }; - requestCounter.incr(); - - yield undefined; - - objectStore.count().onsuccess = grabEventAndContinueHandler; - event = yield undefined; - - is(event.target.result, dbData.length - 3, "Actually deleted something"); - - objectStore.clear(); - objectStore.count().onsuccess = grabEventAndContinueHandler; - event = yield undefined; - - is(event.target.result, 0, "Actually cleared"); - - transaction.oncomplete = grabEventAndContinueHandler; - event = yield undefined; - - is(event.type, "complete", "Transaction succeeded"); - - db.close(); - } - - finishTest(); - yield undefined; -} - -function RequestCounter(expectedType) { - this._counter = 0; -} -RequestCounter.prototype = { - incr: function() { - this._counter++; - }, - - decr: function() { - if (!--this._counter) { - continueToNextStepSync(); - } - }, - - handler: function(type, preventDefault) { - this.incr(); - return function(event) { - is(event.type, type || "success", "Correct type"); - this.decr(); - }.bind(this); - }, - - errorHandler: function(eventType, errorName) { - this.incr(); - return function(event) { - is(event.type, eventType || "error", "Correct type"); - is(event.target.error.name, errorName || "QuotaExceededError", - "Correct error name"); - event.preventDefault(); - event.stopPropagation(); - this.decr(); - }.bind(this); - } -}; diff --git a/dom/indexedDB/test/unit/xpcshell-head-parent-process.js b/dom/indexedDB/test/unit/xpcshell-head-parent-process.js index def791f52..fe69b1f7b 100644 --- a/dom/indexedDB/test/unit/xpcshell-head-parent-process.js +++ b/dom/indexedDB/test/unit/xpcshell-head-parent-process.js @@ -66,9 +66,6 @@ function finishTest() resetWasm(); resetExperimental(); resetTesting(); - - SpecialPowers.notifyObserversInParentProcess(null, "disk-space-watcher", - "free"); } SpecialPowers.removeFiles(); diff --git a/dom/indexedDB/test/unit/xpcshell-parent-process.ini b/dom/indexedDB/test/unit/xpcshell-parent-process.ini index 04df5f552..2def60c34 100644 --- a/dom/indexedDB/test/unit/xpcshell-parent-process.ini +++ b/dom/indexedDB/test/unit/xpcshell-parent-process.ini @@ -46,7 +46,6 @@ skip-if = toolkit == 'android' [test_invalidate.js] # disabled for the moment. skip-if = true -[test_lowDiskSpace.js] [test_maximal_serialized_object_size.js] [test_metadata2Restore.js] [test_metadataRestore.js] 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..97e3a4880 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" @@ -230,11 +229,6 @@ static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID); -#if defined(XP_WIN) -// e10s forced enable pref, defined in nsAppRunner.cpp -extern const char* kForceEnableE10sPref; -#endif - using base::ChildPrivileges; using base::KillProcess; @@ -1276,12 +1270,6 @@ ContentParent::Init() if (nsIPresShell::IsAccessibilityActive()) { #if !defined(XP_WIN) Unused << SendActivateA11y(0); -#else - // On Windows we currently only enable a11y in the content process - // for testing purposes. - if (Preferences::GetBool(kForceEnableE10sPref, false)) { - Unused << SendActivateA11y(a11y::AccessibleWrap::GetContentProcessIdFor(ChildID())); - } #endif } #endif @@ -1718,9 +1706,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 +2061,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 +2186,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)); } @@ -2583,12 +2562,6 @@ ContentParent::Observe(nsISupports* aSubject, // accessibility gets initiated in chrome process. #if !defined(XP_WIN) Unused << SendActivateA11y(0); -#else - // On Windows we currently only enable a11y in the content process - // for testing purposes. - if (Preferences::GetBool(kForceEnableE10sPref, false)) { - Unused << SendActivateA11y(a11y::AccessibleWrap::GetContentProcessIdFor(ChildID())); - } #endif } else { // If possible, shut down accessibility in content process when @@ -3373,17 +3346,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 +4735,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/dom/dom.properties b/dom/locales/en-US/chrome/dom/dom.properties index ec0356c04..0472979d7 100644 --- a/dom/locales/en-US/chrome/dom/dom.properties +++ b/dom/locales/en-US/chrome/dom/dom.properties @@ -195,8 +195,6 @@ IgnoringWillChangeOverBudgetWarning=Will-change memory consumption is too high. HittingMaxWorkersPerDomain2=A Worker could not be started immediately because other documents in the same origin are already using the maximum number of workers. The Worker is now queued and will be started after some of the other workers have completed. # LOCALIZATION NOTE: Do not translate "setVelocity", "PannerNode", "AudioListener", "speedOfSound" and "dopplerFactor" PannerNodeDopplerWarning=Use of setVelocity on the PannerNode and AudioListener, and speedOfSound and dopplerFactor on the AudioListener are deprecated and those members will be removed. For more help https://developer.mozilla.org/en-US/docs/Web/API/AudioListener#Deprecated_features -# LOCALIZATION NOTE: Do not translate "Application Cache API", "AppCache" and "ServiceWorker". -AppCacheWarning=The Application Cache API (AppCache) is deprecated and will be removed at a future date. Please consider using ServiceWorker for offline support. # LOCALIZATION NOTE: Do not translate "Worker". EmptyWorkerSourceWarning=Attempting to create a Worker from an empty source. This is probably unintentional. WebrtcDeprecatedPrefixWarning=WebRTC interfaces with the “moz” prefix (mozRTCPeerConnection, mozRTCSessionDescription, mozRTCIceCandidate) have been deprecated. 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/AudioConverter.cpp b/dom/media/AudioConverter.cpp index 25b981f43..002e79108 100644 --- a/dom/media/AudioConverter.cpp +++ b/dom/media/AudioConverter.cpp @@ -5,8 +5,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "AudioConverter.h" -#include <string.h> #include <speex/speex_resampler.h> +#include <string.h> #include <cmath> /* @@ -140,24 +140,28 @@ static inline int16_t clipTo15(int32_t aX) size_t AudioConverter::DownmixAudio(void* aOut, const void* aIn, size_t aFrames) const { - MOZ_ASSERT(mIn.Format() == AudioConfig::FORMAT_S16 || - mIn.Format() == AudioConfig::FORMAT_FLT); - MOZ_ASSERT(mIn.Channels() >= mOut.Channels()); - MOZ_ASSERT(mIn.Layout() == AudioConfig::ChannelLayout(mIn.Channels()), - "Can only downmix input data in SMPTE layout"); - MOZ_ASSERT(mOut.Layout() == AudioConfig::ChannelLayout(2) || - mOut.Layout() == AudioConfig::ChannelLayout(1)); + MOZ_DIAGNOSTIC_ASSERT(mIn.Format() == AudioConfig::FORMAT_S16 || + mIn.Format() == AudioConfig::FORMAT_FLT); + MOZ_DIAGNOSTIC_ASSERT(mIn.Channels() >= mOut.Channels()); + MOZ_DIAGNOSTIC_ASSERT( + mIn.Layout() == AudioConfig::ChannelLayout(mIn.Channels()), + "Can only downmix input data in SMPTE layout"); + MOZ_DIAGNOSTIC_ASSERT(mOut.Layout() == AudioConfig::ChannelLayout(2) || + mOut.Layout() == AudioConfig::ChannelLayout(1), + "Can only downmix to stereo or mono"); - uint32_t channels = mIn.Channels(); + uint32_t inChannels = mIn.Channels(); + uint32_t outChannels = mOut.Channels(); - if (channels == 1 && mOut.Channels() == 1) { + if (inChannels == outChannels) { + // Number of channels is equal; no processing needed, just move data. if (aOut != aIn) { memmove(aOut, aIn, FramesOutToBytes(aFrames)); } return aFrames; } - if (channels > 2) { + if (inChannels > 2) { if (mIn.Format() == AudioConfig::FORMAT_FLT) { // Downmix matrix. Per-row normalization 1 for rows 3,4 and 2 for rows 5-8. static const float dmatrix[6][8][2]= { @@ -174,12 +178,18 @@ AudioConverter::DownmixAudio(void* aOut, const void* aIn, size_t aFrames) const for (uint32_t i = 0; i < aFrames; i++) { float sampL = 0.0; float sampR = 0.0; - for (uint32_t j = 0; j < channels; j++) { - sampL += in[i*mIn.Channels()+j]*dmatrix[mIn.Channels()-3][j][0]; - sampR += in[i*mIn.Channels()+j]*dmatrix[mIn.Channels()-3][j][1]; + for (uint32_t j = 0; j < inChannels; j++) { + sampL += in[i * inChannels + j] * dmatrix[inChannels - 3][j][0]; + sampR += in[i * inChannels + j] * dmatrix[inChannels - 3][j][1]; + } + if (outChannels == 2) { + // Stereo + *out++ = sampL; + *out++ = sampR; + } else { + // Mono + *out++ = (sampL + sampR) * 0.5; } - *out++ = sampL; - *out++ = sampR; } } else if (mIn.Format() == AudioConfig::FORMAT_S16) { // Downmix matrix. Per-row normalization 1 for rows 3,4 and 2 for rows 5-8. @@ -198,45 +208,51 @@ AudioConverter::DownmixAudio(void* aOut, const void* aIn, size_t aFrames) const for (uint32_t i = 0; i < aFrames; i++) { int32_t sampL = 0; int32_t sampR = 0; - for (uint32_t j = 0; j < channels; j++) { - sampL+=in[i*channels+j]*dmatrix[channels-3][j][0]; - sampR+=in[i*channels+j]*dmatrix[channels-3][j][1]; + for (uint32_t j = 0; j < inChannels; j++) { + sampL += in[i * inChannels + j] * dmatrix[inChannels - 3][j][0]; + sampR += in[i * inChannels + j] * dmatrix[inChannels - 3][j][1]; + } + sampL = clipTo15((sampL + 8192) >> 14); + sampR = clipTo15((sampR + 8192) >> 14); + if (outChannels == 2) { + // Stereo + *out++ = sampL; + *out++ = sampR; + } else { + // Mono + *out++ = (sampL + sampR) * 0.5; } - *out++ = clipTo15((sampL + 8192)>>14); - *out++ = clipTo15((sampR + 8192)>>14); } } else { MOZ_DIAGNOSTIC_ASSERT(false, "Unsupported data type"); } - // If we are to continue downmixing to mono, start working on the output - // buffer. - aIn = aOut; - channels = 2; + return aFrames; } - if (mOut.Channels() == 1) { - if (mIn.Format() == AudioConfig::FORMAT_FLT) { - const float* in = static_cast<const float*>(aIn); - float* out = static_cast<float*>(aOut); - for (size_t fIdx = 0; fIdx < aFrames; ++fIdx) { - float sample = 0.0; - // The sample of the buffer would be interleaved. - sample = (in[fIdx*channels] + in[fIdx*channels + 1]) * 0.5; - *out++ = sample; - } - } else if (mIn.Format() == AudioConfig::FORMAT_S16) { - const int16_t* in = static_cast<const int16_t*>(aIn); - int16_t* out = static_cast<int16_t*>(aOut); - for (size_t fIdx = 0; fIdx < aFrames; ++fIdx) { - int32_t sample = 0.0; - // The sample of the buffer would be interleaved. - sample = (in[fIdx*channels] + in[fIdx*channels + 1]) * 0.5; - *out++ = sample; - } - } else { - MOZ_DIAGNOSTIC_ASSERT(false, "Unsupported data type"); + // If we get here, we're doing a stereo -> mono conversion. + MOZ_DIAGNOSTIC_ASSERT(inChannels == 2 && outChannels == 1); + + if (mIn.Format() == AudioConfig::FORMAT_FLT) { + const float* in = static_cast<const float*>(aIn); + float* out = static_cast<float*>(aOut); + for (size_t fIdx = 0; fIdx < aFrames; ++fIdx) { + float sample = 0.0; + // The sample of the buffer would be interleaved. + sample = (in[fIdx * inChannels] + in[fIdx * inChannels + 1]) * 0.5; + *out++ = sample; } + } else if (mIn.Format() == AudioConfig::FORMAT_S16) { + const int16_t* in = static_cast<const int16_t*>(aIn); + int16_t* out = static_cast<int16_t*>(aOut); + for (size_t fIdx = 0; fIdx < aFrames; ++fIdx) { + int32_t sample = 0.0; + // The sample of the buffer would be interleaved. + sample = (in[fIdx * inChannels] + in[fIdx * inChannels + 1]) * 0.5; + *out++ = sample; + } + } else { + MOZ_DIAGNOSTIC_ASSERT(false, "Unsupported data type"); } return aFrames; } 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/AudioStream.h b/dom/media/AudioStream.h index acc38b93d..199314d4b 100644 --- a/dom/media/AudioStream.h +++ b/dom/media/AudioStream.h @@ -17,6 +17,10 @@ #include "mozilla/UniquePtr.h" #include "CubebUtils.h" #include "soundtouch/SoundTouchFactory.h" +#ifdef XP_SOLARIS +#include "soundtouch/SoundTouch.h" +#endif + namespace mozilla { 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/MediaResource.cpp b/dom/media/MediaResource.cpp index d36783be7..84a8d67fd 100644 --- a/dom/media/MediaResource.cpp +++ b/dom/media/MediaResource.cpp @@ -1525,7 +1525,7 @@ void BaseMediaResource::SetLoadInBackground(bool aLoadInBackground) { NS_WARNING("Null owner in MediaResource::SetLoadInBackground()"); return; } - dom::HTMLMediaElement* element = owner->GetMediaElement(); + RefPtr<dom::HTMLMediaElement> element = owner->GetMediaElement(); if (!element) { NS_WARNING("Null element in MediaResource::SetLoadInBackground()"); return; 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..b293c251b 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) { @@ -168,7 +172,8 @@ bool MP4Decoder::IsH264(const nsACString& aMimeType) { return aMimeType.EqualsLiteral("video/mp4") || - aMimeType.EqualsLiteral("video/avc"); + aMimeType.EqualsLiteral("video/avc") || + aMimeType.EqualsLiteral("video/webm; codecs=avc1"); } /* static */ 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/ContainerParser.cpp b/dom/media/mediasource/ContainerParser.cpp index 4ae37d7e9..b4dcfde8a 100644 --- a/dom/media/mediasource/ContainerParser.cpp +++ b/dom/media/mediasource/ContainerParser.cpp @@ -697,6 +697,9 @@ ContainerParser::CreateForMIMEType(const nsACString& aType) if (aType.LowerCaseEqualsLiteral("video/webm") || aType.LowerCaseEqualsLiteral("audio/webm")) { return new WebMContainerParser(aType); } + if (aType.LowerCaseEqualsLiteral("video/x-matroska") || aType.LowerCaseEqualsLiteral("audio/x-matroska")) { + return new WebMContainerParser(aType); + } #ifdef MOZ_FMP4 if (aType.LowerCaseEqualsLiteral("video/mp4") || aType.LowerCaseEqualsLiteral("audio/mp4")) { diff --git a/dom/media/mediasource/MediaSource.cpp b/dom/media/mediasource/MediaSource.cpp index af541bbbb..1c276cdc1 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. @@ -112,14 +110,16 @@ MediaSource::IsTypeSupported(const nsAString& aType, DecoderDoctorDiagnostics* a } return NS_OK; } - if (mimeType.EqualsASCII("video/webm")) { + if (mimeType.EqualsASCII("video/webm") || + mimeType.EqualsASCII("video/x-matroska")) { if (!(Preferences::GetBool("media.mediasource.webm.enabled", false) || IsWebMForced(aDiagnostics))) { return NS_ERROR_DOM_NOT_SUPPORTED_ERR; } return NS_OK; } - if (mimeType.EqualsASCII("audio/webm")) { + if (mimeType.EqualsASCII("audio/webm") || + mimeType.EqualsASCII("audio/x-matroska")) { if (!(Preferences::GetBool("media.mediasource.webm.enabled", false) || Preferences::GetBool("media.mediasource.webm.audio.enabled", true))) { return NS_ERROR_DOM_NOT_SUPPORTED_ERR; diff --git a/dom/media/mediasource/TrackBuffersManager.cpp b/dom/media/mediasource/TrackBuffersManager.cpp index ac6d82411..21fb158b5 100644 --- a/dom/media/mediasource/TrackBuffersManager.cpp +++ b/dom/media/mediasource/TrackBuffersManager.cpp @@ -814,6 +814,8 @@ TrackBuffersManager::CreateDemuxerforMIMEType() ShutdownDemuxers(); if (mType.LowerCaseEqualsLiteral("video/webm") || + mType.LowerCaseEqualsLiteral("video/x-matroska") || + mType.LowerCaseEqualsLiteral("audio/x-matroska") || mType.LowerCaseEqualsLiteral("audio/webm")) { mInputDemuxer = new WebMDemuxer(mCurrentInputBuffer, true /* IsMediaSource*/ ); return; 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..cbe9ffdb7 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" @@ -38,7 +42,10 @@ WebMDecoder::CanHandleMediaType(const nsACString& aMIMETypeExcludingCodecs, const bool isWebMAudio = aMIMETypeExcludingCodecs.EqualsASCII("audio/webm"); const bool isWebMVideo = aMIMETypeExcludingCodecs.EqualsASCII("video/webm"); - if (!isWebMAudio && !isWebMVideo) { + const bool isMatroskaAudio = aMIMETypeExcludingCodecs.EqualsASCII("audio/x-matroska") ; + const bool isMatroskaVideo = aMIMETypeExcludingCodecs.EqualsASCII("video/x-matroska") ; + + if (!isWebMAudio && !isWebMVideo && !isMatroskaAudio && !isMatroskaVideo) { return false; } @@ -59,12 +66,26 @@ WebMDecoder::CanHandleMediaType(const nsACString& aMIMETypeExcludingCodecs, } // Note: Only accept VP8/VP9 in a video content type, not in an audio // content type. - if (isWebMVideo && + if ((isWebMVideo || isMatroskaVideo) && (codec.EqualsLiteral("vp8") || codec.EqualsLiteral("vp8.0") || codec.EqualsLiteral("vp9") || codec.EqualsLiteral("vp9.0"))) { continue; } +#ifdef MOZ_AV1 + if (MediaPrefs::AV1Enabled() && IsAV1CodecString(codec)) { + continue; + } +#endif + + if (IsH264CodecString(codec)) { + continue; + } + + if (IsAACCodecString(codec)) { + continue; + } + // Some unsupported codec. return false; } diff --git a/dom/media/webm/WebMDemuxer.cpp b/dom/media/webm/WebMDemuxer.cpp index 20ed71581..84b4b506e 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,23 @@ 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; + case NESTEGG_CODEC_AVC1: { + mInfo.mVideo.mMimeType = "video/webm; codecs=avc1"; + + unsigned char* data = 0; + size_t length = 0; + r = nestegg_track_codec_data(context, track, 0, &data, &length); + if (r == -1) { + return NS_ERROR_FAILURE; + } + + mInfo.mVideo.mExtraData = new MediaByteBuffer(length); + mInfo.mVideo.mExtraData->AppendElements(data, length); + break; + } default: NS_WARNING("Unknown WebM video codec"); return NS_ERROR_FAILURE; @@ -404,6 +422,8 @@ WebMDemuxer::ReadMetadata() mInfo.mAudio.mMimeType = "audio/opus"; OpusDataDecoder::AppendCodecDelay(mInfo.mAudio.mCodecSpecificConfig, media::TimeUnit::FromNanoseconds(params.codec_delay).ToMicroseconds()); + } else if (mAudioCodec == NESTEGG_CODEC_AAC) { + mInfo.mAudio.mMimeType = "audio/mp4a-latm"; } mSeekPreroll = params.seek_preroll; mInfo.mAudio.mRate = params.rate; @@ -549,7 +569,7 @@ WebMDemuxer::GetTrackCrypto(TrackInfo::TrackType aType, size_t aTrackNumber) { return crypto; } -bool +nsresult WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSamples) { if (mIsMediaSource) { @@ -557,17 +577,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 +599,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 +618,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 +639,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 +655,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 +665,49 @@ 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 + case NESTEGG_CODEC_AVC1: + isKeyframe = nestegg_packet_has_keyframe(holder->Packet()); + break; + 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 +717,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; @@ -719,13 +768,19 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl if (aType == TrackInfo::kVideoTrack) { sample->mTrackInfo = mSharedVideoTrackInfo; } + + if (mVideoCodec == NESTEGG_CODEC_AVC1) { + sample->mExtraData = mInfo.mVideo.mExtraData; + } + 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 +789,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 +1006,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 +1026,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 +1046,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 +1063,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 +1098,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 +1181,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 +1194,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/network/UDPSocketChild.cpp b/dom/network/UDPSocketChild.cpp index 6e374ce31..d205e7e8a 100644 --- a/dom/network/UDPSocketChild.cpp +++ b/dom/network/UDPSocketChild.cpp @@ -172,19 +172,28 @@ UDPSocketChild::Bind(nsIUDPSocketInternal* aSocket, NS_ENSURE_ARG(aSocket); - mSocket = aSocket; - AddIPDLReference(); + if (NS_IsMainThread()) { + if (!gNeckoChild->SendPUDPSocketConstructor( + this, IPC::Principal(aPrincipal), mFilterName)) { + return NS_ERROR_FAILURE; + } + } else { + if (!mBackgroundManager) { + return NS_ERROR_NOT_AVAILABLE; + } - if (mBackgroundManager) { // If we want to support a passed-in principal here we'd need to // convert it to a PrincipalInfo MOZ_ASSERT(!aPrincipal); - mBackgroundManager->SendPUDPSocketConstructor(this, void_t(), mFilterName); - } else { - gNeckoChild->SendPUDPSocketConstructor(this, IPC::Principal(aPrincipal), - mFilterName); + if (!mBackgroundManager->SendPUDPSocketConstructor( + this, void_t(), mFilterName)) { + return NS_ERROR_FAILURE; + } } + mSocket = aSocket; + AddIPDLReference(); + SendBind(UDPAddressInfo(nsCString(aHost), aPort), aAddressReuse, aLoopback, recvBufferSize, sendBufferSize); return NS_OK; 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/npapi.h b/dom/plugins/base/npapi.h index 12ac635c7..e554aaabc 100644 --- a/dom/plugins/base/npapi.h +++ b/dom/plugins/base/npapi.h @@ -327,9 +327,12 @@ typedef enum { #define NP_ABI_GCC3_MASK 0x10000000 /* * gcc 3.x generated vtables on UNIX and OSX are incompatible with - * previous compilers. + * previous compilers. Flash plugin binaries for Solaris were compiled + * with Sun Studio, so this has to be false to make things work. This may + * become a problem in the future when/if new plugins are compiled with + * GCC, however. */ -#if (defined(XP_UNIX) && defined(__GNUC__) && (__GNUC__ >= 3)) +#if (defined(XP_UNIX) && defined(__GNUC__) && (__GNUC__ >= 3) && !defined(XP_SOLARIS)) #define _NP_ABI_MIXIN_FOR_GCC3 NP_ABI_GCC3_MASK #else #define _NP_ABI_MIXIN_FOR_GCC3 0 diff --git a/dom/plugins/base/nptypes.h b/dom/plugins/base/nptypes.h index 12a5fb78e..d0cef6540 100644 --- a/dom/plugins/base/nptypes.h +++ b/dom/plugins/base/nptypes.h @@ -22,18 +22,19 @@ 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) +#elif defined(__sun) /* - * AIX and SunOS ship a inttypes.h header that defines [u]int32_t, + * SunOS ships an 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 + #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/nsJSNPRuntime.cpp b/dom/plugins/base/nsJSNPRuntime.cpp index 05e0ec4ba..1d42c18d6 100644 --- a/dom/plugins/base/nsJSNPRuntime.cpp +++ b/dom/plugins/base/nsJSNPRuntime.cpp @@ -248,7 +248,6 @@ const static js::ObjectOps sNPObjectJSWrapperObjectOps = { nullptr, // setProperty nullptr, // getOwnPropertyDescriptor nullptr, // deleteProperty - nullptr, nullptr, // watch/unwatch nullptr, // getElements NPObjWrapper_Enumerate, nullptr, 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/nsPluginStreamListenerPeer.cpp b/dom/plugins/base/nsPluginStreamListenerPeer.cpp index 665e11ec1..0476315d5 100644 --- a/dom/plugins/base/nsPluginStreamListenerPeer.cpp +++ b/dom/plugins/base/nsPluginStreamListenerPeer.cpp @@ -1381,7 +1381,7 @@ nsPluginStreamListenerPeer::AsyncOnChannelRedirect(nsIChannel *oldChannel, nsICh return NS_ERROR_FAILURE; } - // Don't allow cross-origin 307 POST redirects. + // Don't allow cross-origin 307/308 POST redirects. nsCOMPtr<nsIHttpChannel> oldHttpChannel(do_QueryInterface(oldChannel)); if (oldHttpChannel) { uint32_t responseStatus; @@ -1389,7 +1389,7 @@ nsPluginStreamListenerPeer::AsyncOnChannelRedirect(nsIChannel *oldChannel, nsICh if (NS_FAILED(rv)) { return rv; } - if (responseStatus == 307) { + if (responseStatus == 307 || responseStatus == 308) { nsAutoCString method; rv = oldHttpChannel->GetRequestMethod(method); if (NS_FAILED(rv)) { diff --git a/dom/plugins/base/nsPluginsDirUnix.cpp b/dom/plugins/base/nsPluginsDirUnix.cpp index 6d112b4fe..de3b7a2d1 100644 --- a/dom/plugins/base/nsPluginsDirUnix.cpp +++ b/dom/plugins/base/nsPluginsDirUnix.cpp @@ -19,16 +19,8 @@ #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/" +#ifdef XP_SOLARIS +#define DEFAULT_X11_PATH "/usr/openwin/lib" #elif defined(LINUX) #define DEFAULT_X11_PATH "/usr/X11R6/lib/" #elif defined(__APPLE__) @@ -102,7 +94,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) +#ifdef XP_SOLARIS #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 @@ -278,9 +270,7 @@ nsresult nsPluginFile::LoadPlugin(PRLibrary **outLibrary) // at runtime. Explicitly opening Xt/Xext into the global // namespace before attempting to load the plug-in seems to // work fine. - - -#if defined(SOLARIS) || defined(HPUX) +#if defined(XP_SOLARIS) // Acrobat/libXm: Lazy resolving might cause crash later (bug 211587) *outLibrary = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW); pLibrary = *outLibrary; @@ -288,7 +278,7 @@ nsresult nsPluginFile::LoadPlugin(PRLibrary **outLibrary) // Some dlopen() doesn't recover from a failed PR_LD_NOW (bug 223744) *outLibrary = PR_LoadLibraryWithFlags(libSpec, 0); pLibrary = *outLibrary; -#endif +#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/PluginMessageUtils.cpp b/dom/plugins/ipc/PluginMessageUtils.cpp index 47653fe6e..5b1d1667f 100644 --- a/dom/plugins/ipc/PluginMessageUtils.cpp +++ b/dom/plugins/ipc/PluginMessageUtils.cpp @@ -82,7 +82,7 @@ MediateRace(const MessageChannel::MessageInfo& parent, } } -#if defined(OS_LINUX) +#if defined(OS_LINUX) || defined(OS_SOLARIS) static string ReplaceAll(const string& haystack, const string& needle, const string& with) { @@ -101,7 +101,7 @@ ReplaceAll(const string& haystack, const string& needle, const string& with) string MungePluginDsoPath(const string& path) { -#if defined(OS_LINUX) +#if defined(OS_LINUX) || defined(OS_SOLARIS) // https://bugzilla.mozilla.org/show_bug.cgi?id=519601 return ReplaceAll(path, "netscape", "netsc@pe"); #else @@ -112,7 +112,7 @@ MungePluginDsoPath(const string& path) string UnmungePluginDsoPath(const string& munged) { -#if defined(OS_LINUX) +#if defined(OS_LINUX) || defined(OS_SOLARIS) return ReplaceAll(munged, "netsc@pe", "netscape"); #else return munged; diff --git a/dom/plugins/ipc/PluginModuleChild.cpp b/dom/plugins/ipc/PluginModuleChild.cpp index cbf6e509f..f943dfc42 100644 --- a/dom/plugins/ipc/PluginModuleChild.cpp +++ b/dom/plugins/ipc/PluginModuleChild.cpp @@ -286,7 +286,7 @@ PluginModuleChild::InitForChrome(const std::string& aPluginFilename, // TODO: use PluginPRLibrary here -#if defined(OS_LINUX) || defined(OS_BSD) +#if defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS) mShutdownFunc = (NP_PLUGINSHUTDOWN) PR_FindFunctionSymbol(mLibrary, "NP_Shutdown"); @@ -1821,7 +1821,7 @@ PluginModuleChild::AnswerNP_GetEntryPoints(NPError* _retval) AssertPluginThread(); MOZ_ASSERT(mIsChrome); -#if defined(OS_LINUX) || defined(OS_BSD) +#if defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS) return true; #elif defined(OS_WIN) || defined(OS_MACOSX) *_retval = mGetEntryPointsFunc(&mFunctions); @@ -1866,7 +1866,7 @@ PluginModuleChild::DoNP_Initialize(const PluginSettings& aSettings) #endif NPError result; -#if defined(OS_LINUX) || defined(OS_BSD) +#if defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS) result = mInitializeFunc(&sBrowserFuncs, &mFunctions); #elif defined(OS_WIN) || defined(OS_MACOSX) result = mInitializeFunc(&sBrowserFuncs); diff --git a/dom/plugins/ipc/PluginModuleChild.h b/dom/plugins/ipc/PluginModuleChild.h index 681743582..5e4fa7d20 100644 --- a/dom/plugins/ipc/PluginModuleChild.h +++ b/dom/plugins/ipc/PluginModuleChild.h @@ -258,7 +258,7 @@ private: // we get this from the plugin NP_PLUGINSHUTDOWN mShutdownFunc; -#if defined(OS_LINUX) || defined(OS_BSD) +#if defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS) NP_PLUGINUNIXINIT mInitializeFunc; #elif defined(OS_WIN) || defined(OS_MACOSX) NP_PLUGININIT mInitializeFunc; 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/PresentationDataChannelSessionTransport.js b/dom/presentation/PresentationDataChannelSessionTransport.js index 461e4f2cb..9af6213cb 100644 --- a/dom/presentation/PresentationDataChannelSessionTransport.js +++ b/dom/presentation/PresentationDataChannelSessionTransport.js @@ -109,13 +109,7 @@ PresentationTransportBuilder.prototype = { // TODO bug 1228235 we should have a way to let device providers customize // the time-out duration. - let timeout; - try { - timeout = Services.prefs.getIntPref("presentation.receiver.loading.timeout"); - } catch (e) { - // This happens if the pref doesn't exist, so we have a default value. - timeout = 10000; - } + let timeout = Services.prefs.getIntPref("presentation.receiver.loading.timeout", 10000); // The timer is to check if the negotiation finishes on time. this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); 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/PushServiceAndroidGCM.jsm b/dom/push/PushServiceAndroidGCM.jsm deleted file mode 100644 index ed07be339..000000000 --- a/dom/push/PushServiceAndroidGCM.jsm +++ /dev/null @@ -1,275 +0,0 @@ -/* jshint moz: true, esnext: true */ -/* 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/. */ - -"use strict"; - -const Cc = Components.classes; -const Ci = Components.interfaces; -const Cu = Components.utils; -const Cr = Components.results; - -const {PushDB} = Cu.import("resource://gre/modules/PushDB.jsm"); -const {PushRecord} = Cu.import("resource://gre/modules/PushRecord.jsm"); -const {PushCrypto} = Cu.import("resource://gre/modules/PushCrypto.jsm"); -Cu.import("resource://gre/modules/Messaging.jsm"); /*global: Messaging */ -Cu.import("resource://gre/modules/Services.jsm"); /*global: Services */ -Cu.import("resource://gre/modules/Preferences.jsm"); /*global: Preferences */ -Cu.import("resource://gre/modules/Promise.jsm"); /*global: Promise */ -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); /*global: XPCOMUtils */ - -const Log = Cu.import("resource://gre/modules/AndroidLog.jsm", {}).AndroidLog.bind("Push"); - -this.EXPORTED_SYMBOLS = ["PushServiceAndroidGCM"]; - -XPCOMUtils.defineLazyGetter(this, "console", () => { - let {ConsoleAPI} = Cu.import("resource://gre/modules/Console.jsm", {}); - return new ConsoleAPI({ - dump: Log.i, - maxLogLevelPref: "dom.push.loglevel", - prefix: "PushServiceAndroidGCM", - }); -}); - -const kPUSHANDROIDGCMDB_DB_NAME = "pushAndroidGCM"; -const kPUSHANDROIDGCMDB_DB_VERSION = 5; // Change this if the IndexedDB format changes -const kPUSHANDROIDGCMDB_STORE_NAME = "pushAndroidGCM"; - -const FXA_PUSH_SCOPE = "chrome://fxa-push"; - -const prefs = new Preferences("dom.push."); - -/** - * The implementation of WebPush push backed by Android's GCM - * delivery. - */ -this.PushServiceAndroidGCM = { - _mainPushService: null, - _serverURI: null, - - newPushDB: function() { - return new PushDB(kPUSHANDROIDGCMDB_DB_NAME, - kPUSHANDROIDGCMDB_DB_VERSION, - kPUSHANDROIDGCMDB_STORE_NAME, - "channelID", - PushRecordAndroidGCM); - }, - - validServerURI: function(serverURI) { - if (!serverURI) { - return false; - } - - if (serverURI.scheme == "https") { - return true; - } - if (serverURI.scheme == "http") { - // Allow insecure server URLs for development and testing. - return !!prefs.get("testing.allowInsecureServerURL"); - } - console.info("Unsupported Android GCM dom.push.serverURL scheme", serverURI.scheme); - return false; - }, - - observe: function(subject, topic, data) { - switch (topic) { - case "nsPref:changed": - if (data == "dom.push.debug") { - // Reconfigure. - let debug = !!prefs.get("debug"); - console.info("Debug parameter changed; updating configuration with new debug", debug); - this._configure(this._serverURI, debug); - } - break; - case "PushServiceAndroidGCM:ReceivedPushMessage": - this._onPushMessageReceived(data); - break; - default: - break; - } - }, - - _onPushMessageReceived(data) { - // TODO: Use Messaging.jsm for this. - if (this._mainPushService == null) { - // Shouldn't ever happen, but let's be careful. - console.error("No main PushService! Dropping message."); - return; - } - if (!data) { - console.error("No data from Java! Dropping message."); - return; - } - data = JSON.parse(data); - console.debug("ReceivedPushMessage with data", data); - - let { headers, message } = this._messageAndHeaders(data); - - console.debug("Delivering message to main PushService:", message, headers); - this._mainPushService.receivedPushMessage( - data.channelID, "", headers, message, (record) => { - // Always update the stored record. - return record; - }); - }, - - _messageAndHeaders(data) { - // Default is no data (and no encryption). - let message = null; - let headers = null; - - if (data.message && data.enc && (data.enckey || data.cryptokey)) { - headers = { - encryption_key: data.enckey, - crypto_key: data.cryptokey, - encryption: data.enc, - encoding: data.con, - }; - // Ciphertext is (urlsafe) Base 64 encoded. - message = ChromeUtils.base64URLDecode(data.message, { - // The Push server may append padding. - padding: "ignore", - }); - } - return { headers, message }; - }, - - _configure: function(serverURL, debug) { - return Messaging.sendRequestForResult({ - type: "PushServiceAndroidGCM:Configure", - endpoint: serverURL.spec, - debug: debug, - }); - }, - - init: function(options, mainPushService, serverURL) { - console.debug("init()"); - this._mainPushService = mainPushService; - this._serverURI = serverURL; - - prefs.observe("debug", this); - Services.obs.addObserver(this, "PushServiceAndroidGCM:ReceivedPushMessage", false); - - return this._configure(serverURL, !!prefs.get("debug")).then(() => { - Messaging.sendRequestForResult({ - type: "PushServiceAndroidGCM:Initialized" - }); - }); - }, - - uninit: function() { - console.debug("uninit()"); - Messaging.sendRequestForResult({ - type: "PushServiceAndroidGCM:Uninitialized" - }); - - this._mainPushService = null; - Services.obs.removeObserver(this, "PushServiceAndroidGCM:ReceivedPushMessage"); - prefs.ignore("debug", this); - }, - - onAlarmFired: function() { - // No action required. - }, - - connect: function(records) { - console.debug("connect:", records); - // It's possible for the registration or subscriptions backing the - // PushService to not be registered with the underlying AndroidPushService. - // Expire those that are unrecognized. - return Messaging.sendRequestForResult({ - type: "PushServiceAndroidGCM:DumpSubscriptions", - }) - .then(subscriptions => { - console.debug("connect:", subscriptions); - // subscriptions maps chid => subscription data. - return Promise.all(records.map(record => { - if (subscriptions.hasOwnProperty(record.keyID)) { - console.debug("connect:", "hasOwnProperty", record.keyID); - return Promise.resolve(); - } - console.debug("connect:", "!hasOwnProperty", record.keyID); - // Subscription is known to PushService.jsm but not to AndroidPushService. Drop it. - return this._mainPushService.dropRegistrationAndNotifyApp(record.keyID) - .catch(error => { - console.error("connect: Error dropping registration", record.keyID, error); - }); - })); - }); - }, - - isConnected: function() { - return this._mainPushService != null; - }, - - disconnect: function() { - console.debug("disconnect"); - }, - - register: function(record) { - console.debug("register:", record); - let ctime = Date.now(); - let appServerKey = record.appServerKey ? - ChromeUtils.base64URLEncode(record.appServerKey, { - // The Push server requires padding. - pad: true, - }) : null; - let message = { - type: "PushServiceAndroidGCM:SubscribeChannel", - appServerKey: appServerKey, - } - if (record.scope == FXA_PUSH_SCOPE) { - message.service = "fxa"; - } - // Caller handles errors. - return Messaging.sendRequestForResult(message) - .then(data => { - console.debug("Got data:", data); - return PushCrypto.generateKeys() - .then(exportedKeys => - new PushRecordAndroidGCM({ - // Straight from autopush. - channelID: data.channelID, - pushEndpoint: data.endpoint, - // Common to all PushRecord implementations. - scope: record.scope, - originAttributes: record.originAttributes, - ctime: ctime, - systemRecord: record.systemRecord, - // Cryptography! - p256dhPublicKey: exportedKeys[0], - p256dhPrivateKey: exportedKeys[1], - authenticationSecret: PushCrypto.generateAuthenticationSecret(), - appServerKey: record.appServerKey, - }) - ); - }); - }, - - unregister: function(record) { - console.debug("unregister: ", record); - return Messaging.sendRequestForResult({ - type: "PushServiceAndroidGCM:UnsubscribeChannel", - channelID: record.keyID, - }); - }, - - reportDeliveryError: function(messageID, reason) { - console.warn("reportDeliveryError: Ignoring message delivery error", - messageID, reason); - }, -}; - -function PushRecordAndroidGCM(record) { - PushRecord.call(this, record); - this.channelID = record.channelID; -} - -PushRecordAndroidGCM.prototype = Object.create(PushRecord.prototype, { - keyID: { - get() { - return this.channelID; - }, - }, -}); 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/push/moz.build b/dom/push/moz.build index 35683120f..7eee8896f 100644 --- a/dom/push/moz.build +++ b/dom/push/moz.build @@ -14,20 +14,10 @@ EXTRA_JS_MODULES += [ 'PushDB.jsm', 'PushRecord.jsm', 'PushService.jsm', + 'PushServiceHttp2.jsm', + 'PushServiceWebSocket.jsm', ] -if not CONFIG['MOZ_FENNEC']: - # Everything but Fennec. - EXTRA_JS_MODULES += [ - 'PushServiceHttp2.jsm', - 'PushServiceWebSocket.jsm', - ] -else: - # Fennec only. - EXTRA_JS_MODULES += [ - 'PushServiceAndroidGCM.jsm', - ] - MOCHITEST_MANIFESTS += [ 'test/mochitest.ini', ] diff --git a/dom/security/nsCSPContext.cpp b/dom/security/nsCSPContext.cpp index 65be02809..56a119e1a 100644 --- a/dom/security/nsCSPContext.cpp +++ b/dom/security/nsCSPContext.cpp @@ -513,8 +513,19 @@ nsCSPContext::GetAllowsInline(nsContentPolicyType aContentType, for (uint32_t i = 0; i < mPolicies.Length(); i++) { bool allowed = mPolicies[i]->allows(aContentType, CSP_UNSAFE_INLINE, EmptyString(), aParserCreated) || - mPolicies[i]->allows(aContentType, CSP_NONCE, aNonce, aParserCreated) || - mPolicies[i]->allows(aContentType, CSP_HASH, aContent, aParserCreated); + mPolicies[i]->allows(aContentType, CSP_NONCE, aNonce, aParserCreated); + + // If the inlined script or style is allowed by either unsafe-inline or the + // nonce, go ahead and shortcut this loop. + if (allowed) { + continue; + } + + // Check if the csp-hash matches against the hash of the script. + // If we don't have any content to check, block the script. + if (!aContent.IsEmpty()) { + allowed = mPolicies[i]->allows(aContentType, CSP_HASH, aContent, aParserCreated); + } if (!allowed) { // policy is violoated: deny the load unless policy is report only and diff --git a/dom/security/nsCSPUtils.cpp b/dom/security/nsCSPUtils.cpp index 71c8e3433..d07ad7945 100644 --- a/dom/security/nsCSPUtils.cpp +++ b/dom/security/nsCSPUtils.cpp @@ -641,13 +641,22 @@ nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected // just a specific scheme, the parser should generate a nsCSPSchemeSource. NS_ASSERTION((!mHost.IsEmpty()), "host can not be the empty string"); + // Before we can check if the host matches, we have to + // extract the host part from aUri. + nsAutoCString uriHost; + nsresult rv = aUri->GetAsciiHost(uriHost); + NS_ENSURE_SUCCESS(rv, false); + + nsString decodedUriHost; + CSP_PercentDecodeStr(NS_ConvertUTF8toUTF16(uriHost), decodedUriHost); + // 2) host matching: Enforce a single * if (mHost.EqualsASCII("*")) { // The single ASTERISK character (*) does not match a URI's scheme of a type // designating a globally unique identifier (such as blob:, data:, or filesystem:) - // At the moment firefox does not support filesystem; but for future compatibility + // At the moment UXP does not support "filesystem:" but for future compatibility // we support it in CSP according to the spec, see: 4.2.2 Matching Source Expressions - // Note, that whitelisting any of these schemes would call nsCSPSchemeSrc::permits(). + // Note: whitelisting any of these schemes would call nsCSPSchemeSrc::permits(). bool isBlobScheme = (NS_SUCCEEDED(aUri->SchemeIs("blob", &isBlobScheme)) && isBlobScheme); bool isDataScheme = @@ -658,20 +667,15 @@ nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected if (isBlobScheme || isDataScheme || isFileScheme) { return false; } - return true; - } - - // Before we can check if the host matches, we have to - // extract the host part from aUri. - nsAutoCString uriHost; - nsresult rv = aUri->GetAsciiHost(uriHost); - NS_ENSURE_SUCCESS(rv, false); - - nsString decodedUriHost; - CSP_PercentDecodeStr(NS_ConvertUTF8toUTF16(uriHost), decodedUriHost); + // If no scheme is present there also won't be a port and folder to check + // which means we can return early. + if (mScheme.IsEmpty()) { + return true; + } + } // 4.5) host matching: Check if the allowed host starts with a wilcard. - if (mHost.First() == '*') { + else if (mHost.First() == '*') { NS_ASSERTION(mHost[1] == '.', "Second character needs to be '.' whenever host starts with '*'"); // Eliminate leading "*", but keeping the FULL STOP (.) thereafter before checking diff --git a/dom/security/nsContentSecurityManager.cpp b/dom/security/nsContentSecurityManager.cpp index 570730312..5c6701992 100644 --- a/dom/security/nsContentSecurityManager.cpp +++ b/dom/security/nsContentSecurityManager.cpp @@ -10,6 +10,7 @@ #include "nsIStreamListener.h" #include "nsCDefaultURIFixup.h" #include "nsIURIFixup.h" +#include "nsIImageLoadingContent.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/TabChild.h" @@ -92,6 +93,78 @@ nsContentSecurityManager::AllowTopLevelNavigationToDataURI(nsIChannel* aChannel) return false; } +/* static */ nsresult +nsContentSecurityManager::CheckFTPSubresourceLoad(nsIChannel* aChannel) +{ + // We dissallow using FTP resources as a subresource almost everywhere. + // The only valid way to use FTP resources is loading it as + // a top level document. + + // Override blocking if the pref is set to allow. + if (!mozilla::net::nsIOService::BlockFTPSubresources()) { + return NS_OK; + } + + nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo(); + if (!loadInfo) { + return NS_OK; + } + + nsContentPolicyType type = loadInfo->GetExternalContentPolicyType(); + + // Allow save-as download of FTP files on HTTP pages. + if (type == nsIContentPolicy::TYPE_SAVEAS_DOWNLOAD) { + return NS_OK; + } + + // Allow direct document requests + 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; + } + + // Allow if it's not the FTP protocol + bool isFtpURI = (NS_SUCCEEDED(uri->SchemeIs("ftp", &isFtpURI)) && isFtpURI); + if (!isFtpURI) { + return NS_OK; + } + + // Allow loading FTP subresources in top-level FTP documents. + nsIPrincipal* triggeringPrincipal = loadInfo->TriggeringPrincipal(); + nsCOMPtr<nsIURI> tURI; + triggeringPrincipal->GetURI(getter_AddRefs(tURI)); + bool isTrigFtpURI = (NS_SUCCEEDED(tURI->SchemeIs("ftp", &isTrigFtpURI)) && isTrigFtpURI); + if (isTrigFtpURI) { + return NS_OK; + } + + // If we get here, the request is blocked and should be reported. + 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 +647,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 +668,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; @@ -722,6 +802,8 @@ nsContentSecurityManager::CheckChannel(nsIChannel* aChannel) // within nsCorsListenerProxy rv = DoCheckLoadURIChecks(uri, loadInfo); NS_ENSURE_SUCCESS(rv, rv); + // TODO: Bug 1371237 + // consider calling SetBlockedRequest in nsContentSecurityManager::CheckChannel } return NS_OK; 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..ee9a22e96 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]; @@ -206,11 +205,6 @@ DOMStorageCache::ProcessUsageDelta(const DOMStorage* aStorage, int64_t aDelta) bool DOMStorageCache::ProcessUsageDelta(uint32_t aGetDataSetIndex, const int64_t aDelta) { - // Check if we are in a low disk space situation - if (aDelta > 0 && mManager && mManager->IsLowDiskSpace()) { - return false; - } - // Check limit per this origin Data& data = mData[aGetDataSetIndex]; uint64_t newOriginUsage = data.mOriginQuotaUsage + aDelta; @@ -298,49 +292,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 +320,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 +338,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 +360,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 +377,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 +402,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 +451,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 +490,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 +561,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 +581,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/storage/DOMStorageIPC.cpp b/dom/storage/DOMStorageIPC.cpp index a8cd745f1..9d87a5788 100644 --- a/dom/storage/DOMStorageIPC.cpp +++ b/dom/storage/DOMStorageIPC.cpp @@ -11,7 +11,6 @@ #include "mozilla/dom/ContentChild.h" #include "mozilla/dom/ContentParent.h" #include "mozilla/Unused.h" -#include "nsIDiskSpaceWatcher.h" #include "nsThreadUtils.h" namespace mozilla { @@ -321,22 +320,6 @@ private: mozilla::Unused << mParent->SendOriginsHavingData(scopes); } - // We need to check if the device is in a low disk space situation, so - // we can forbid in that case any write in localStorage. - nsCOMPtr<nsIDiskSpaceWatcher> diskSpaceWatcher = - do_GetService("@mozilla.org/toolkit/disk-space-watcher;1"); - if (!diskSpaceWatcher) { - return NS_OK; - } - - bool lowDiskSpace = false; - diskSpaceWatcher->GetIsDiskFull(&lowDiskSpace); - - if (lowDiskSpace) { - mozilla::Unused << mParent->SendObserve( - nsDependentCString("low-disk-space"), EmptyString(), EmptyCString()); - } - return NS_OK; } diff --git a/dom/storage/DOMStorageManager.cpp b/dom/storage/DOMStorageManager.cpp index 156e846ba..8f50fcfb4 100644 --- a/dom/storage/DOMStorageManager.cpp +++ b/dom/storage/DOMStorageManager.cpp @@ -103,7 +103,6 @@ NS_IMPL_ISUPPORTS(DOMStorageManager, DOMStorageManager::DOMStorageManager(DOMStorage::StorageType aType) : mCaches(8) , mType(aType) - , mLowDiskSpace(false) { DOMStorageObserver* observer = DOMStorageObserver::Self(); NS_ASSERTION(observer, "No DOMStorageObserver, cannot observe private data delete notifications!"); @@ -566,22 +565,6 @@ DOMStorageManager::Observe(const char* aTopic, return NS_OK; } - if (!strcmp(aTopic, "low-disk-space")) { - if (mType == LocalStorage) { - mLowDiskSpace = true; - } - - return NS_OK; - } - - if (!strcmp(aTopic, "no-low-disk-space")) { - if (mType == LocalStorage) { - mLowDiskSpace = false; - } - - return NS_OK; - } - #ifdef DOM_STORAGE_TESTS if (!strcmp(aTopic, "test-reload")) { if (mType != LocalStorage) { diff --git a/dom/storage/DOMStorageManager.h b/dom/storage/DOMStorageManager.h index 666e16a6f..0bfd21975 100644 --- a/dom/storage/DOMStorageManager.h +++ b/dom/storage/DOMStorageManager.h @@ -102,12 +102,6 @@ private: const DOMStorage::StorageType mType; - // If mLowDiskSpace is true it indicates a low device storage situation and - // so no localStorage writes are allowed. sessionStorage writes are still - // allowed. - bool mLowDiskSpace; - bool IsLowDiskSpace() const { return mLowDiskSpace; }; - void ClearCaches(uint32_t aUnloadFlags, const OriginAttributesPattern& aPattern, const nsACString& aKeyPrefix); diff --git a/dom/storage/DOMStorageObserver.cpp b/dom/storage/DOMStorageObserver.cpp index a2b3f1da8..fbbab8e54 100644 --- a/dom/storage/DOMStorageObserver.cpp +++ b/dom/storage/DOMStorageObserver.cpp @@ -70,9 +70,6 @@ DOMStorageObserver::Init() obs->AddObserver(sSelf, "profile-before-change", true); obs->AddObserver(sSelf, "xpcom-shutdown", true); - // Observe low device storage notifications. - obs->AddObserver(sSelf, "disk-space-watcher", true); - #ifdef DOM_STORAGE_TESTS // Testing obs->AddObserver(sSelf, "domstorage-test-flush-force", true); @@ -313,16 +310,6 @@ DOMStorageObserver::Observe(nsISupports* aSubject, return NS_OK; } - if (!strcmp(aTopic, "disk-space-watcher")) { - if (NS_LITERAL_STRING("full").Equals(aData)) { - Notify("low-disk-space"); - } else if (NS_LITERAL_STRING("free").Equals(aData)) { - Notify("no-low-disk-space"); - } - - return NS_OK; - } - #ifdef DOM_STORAGE_TESTS if (!strcmp(aTopic, "domstorage-test-flush-force")) { DOMStorageDBBridge* db = DOMStorageCache::GetDatabase(); 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/crashtests/880544-1.svg b/dom/svg/crashtests/880544-1.svg deleted file mode 100644 index 9052d2396..000000000 --- a/dom/svg/crashtests/880544-1.svg +++ /dev/null @@ -1,15 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg">
- <script>//<![CDATA[
-
-function add_watch()
-{
- document.getElementById("p").transform.baseVal.watch("0", function(){});
-}
-
-window.addEventListener("load", add_watch, false);
-
- //]]></script>
-
- <path id="p" transform="scale(1)" />
-
-</svg>
diff --git a/dom/svg/crashtests/880544-2.svg b/dom/svg/crashtests/880544-2.svg deleted file mode 100644 index 7570c7cbf..000000000 --- a/dom/svg/crashtests/880544-2.svg +++ /dev/null @@ -1,15 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg">
- <script>//<![CDATA[
-
-function add_watch()
-{
- document.getElementById("e").x.baseVal.watch("0", function(){});
-}
-
-window.addEventListener("load", add_watch, false);
-
- //]]></script>
-
- <text id="e" x="10">foo</text>
-
-</svg>
diff --git a/dom/svg/crashtests/880544-3.svg b/dom/svg/crashtests/880544-3.svg deleted file mode 100644 index 5791b8ec6..000000000 --- a/dom/svg/crashtests/880544-3.svg +++ /dev/null @@ -1,15 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg">
- <script>//<![CDATA[
-
-function add_watch()
-{
- document.getElementById("e").rotate.baseVal.watch("0", function(){});
-}
-
-window.addEventListener("load", add_watch, false);
-
- //]]></script>
-
- <text id="e" rotate="10">foo</text>
-
-</svg>
diff --git a/dom/svg/crashtests/880544-4.svg b/dom/svg/crashtests/880544-4.svg deleted file mode 100644 index 7bdb80f47..000000000 --- a/dom/svg/crashtests/880544-4.svg +++ /dev/null @@ -1,15 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg">
- <script>//<![CDATA[
-
-function add_watch()
-{
- document.getElementById("e").pathSegList.watch("0", function(){});
-}
-
-window.addEventListener("load", add_watch, false);
-
- //]]></script>
-
- <path id="e" d="M0,0"/>
-
-</svg>
diff --git a/dom/svg/crashtests/880544-5.svg b/dom/svg/crashtests/880544-5.svg deleted file mode 100644 index ef7f468f8..000000000 --- a/dom/svg/crashtests/880544-5.svg +++ /dev/null @@ -1,15 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg">
- <script>//<![CDATA[
-
-function add_watch()
-{
- document.getElementById("e").points.watch("0", function(){});
-}
-
-window.addEventListener("load", add_watch, false);
-
- //]]></script>
-
- <polygon id="e" points="0,0"/>
-
-</svg>
diff --git a/dom/svg/crashtests/crashtests.list b/dom/svg/crashtests/crashtests.list index 147838bbe..b2e920152 100644 --- a/dom/svg/crashtests/crashtests.list +++ b/dom/svg/crashtests/crashtests.list @@ -66,11 +66,6 @@ load 837450-1.svg load 842463-1.html load 847138-1.svg load 864509.svg -load 880544-1.svg -load 880544-2.svg -load 880544-3.svg -load 880544-4.svg -load 880544-5.svg load 898915-1.svg load 1035248-1.svg load 1035248-2.svg 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/tests/mochitest/ajax/offline/mochitest.ini b/dom/tests/mochitest/ajax/offline/mochitest.ini index 961b143b6..45909e94e 100644 --- a/dom/tests/mochitest/ajax/offline/mochitest.ini +++ b/dom/tests/mochitest/ajax/offline/mochitest.ini @@ -79,8 +79,6 @@ support-files = [test_fallback.html] [test_foreign.html] [test_identicalManifest.html] -[test_lowDeviceStorage.html] -[test_lowDeviceStorageDuringUpdate.html] [test_missingFile.html] [test_missingManifest.html] [test_noManifest.html] diff --git a/dom/tests/mochitest/ajax/offline/test_lowDeviceStorage.html b/dom/tests/mochitest/ajax/offline/test_lowDeviceStorage.html deleted file mode 100644 index d03ef5a12..000000000 --- a/dom/tests/mochitest/ajax/offline/test_lowDeviceStorage.html +++ /dev/null @@ -1,91 +0,0 @@ -<html xmlns="http://www.w3.org/1999/xhtml"> -<head> -<title>Low device storage</title> - -<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> -<script type="text/javascript" src="/tests/dom/tests/mochitest/ajax/offline/offlineTests.js"></script> -<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> - -<script type="text/javascript"> - -/** - * This test checks that an offline cache update scheduled *after* a low device - * storage situation appears is canceled. It basically does: - * - * 1. Notifies to the offline cache update service about a fake - * low device storage situation. - * 2. Schedules an update and observes for its notifications. - * 3. We are supposed to receive an error event notifying about the cancelation - * of the update because of the low storage situation. - * 4. Notifies to the offline cache update service that we've recovered from - * the low storage situation. - */ - -var updateService = SpecialPowers.Cc['@mozilla.org/offlinecacheupdate-service;1'] - .getService(Ci.nsIOfflineCacheUpdateService); - -var obs = SpecialPowers.Cc["@mozilla.org/observer-service;1"] - .getService(SpecialPowers.Ci.nsIObserverService); - -var errorReceived = false; - -var systemPrincipal = SpecialPowers.Services.scriptSecurityManager.getSystemPrincipal(); - -function finish() { - obs.notifyObservers(updateService, "disk-space-watcher", "free"); - - OfflineTest.teardownAndFinish(); -} - -if (OfflineTest.setup()) { - obs.notifyObservers(updateService, "disk-space-watcher", "full"); - - var updateObserver = { - updateStateChanged: function (aUpdate, aState) { - switch(aState) { - case Ci.nsIOfflineCacheUpdateObserver.STATE_ERROR: - errorReceived = true; - OfflineTest.ok(true, "Expected error. Update canceled"); - break; - case Ci.nsIOfflineCacheUpdateObserver.STATE_FINISHED: - aUpdate.removeObserver(this); - OfflineTest.ok(errorReceived, - "Finished after receiving the expected error"); - finish(); - break; - case Ci.nsIOfflineCacheUpdateObserver.STATE_NOUPDATE: - aUpdate.removeObserver(this); - OfflineTest.ok(false, "No update"); - finish(); - break; - case Ci.nsIOfflineCacheUpdateObserver.STATE_DOWNLOADING: - case Ci.nsIOfflineCacheUpdateObserver.STATE_ITEMSTARTED: - case Ci.nsIOfflineCacheUpdateObserver.STATE_ITEMPROGRESS: - aUpdate.removeObserver(this); - OfflineTest.ok(false, "The update was supposed to be canceled"); - finish(); - break; - } - }, - applicationCacheAvailable: function() {} - }; - - var manifest = "http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/simpleManifest.cacheManifest"; - var ioService = Cc["@mozilla.org/network/io-service;1"] - .getService(Ci.nsIIOService); - var manifestURI = ioService.newURI(manifest, null, null); - var documentURI = ioService.newURI(document.documentURI, null, null); - var update = updateService.scheduleUpdate(manifestURI, documentURI, systemPrincipal, window); - update.addObserver(updateObserver, false); -} - -SimpleTest.waitForExplicitFinish(); - -</script> - -</head> - -<body> - -</body> -</html> diff --git a/dom/tests/mochitest/ajax/offline/test_lowDeviceStorageDuringUpdate.html b/dom/tests/mochitest/ajax/offline/test_lowDeviceStorageDuringUpdate.html deleted file mode 100644 index 88a0b4eae..000000000 --- a/dom/tests/mochitest/ajax/offline/test_lowDeviceStorageDuringUpdate.html +++ /dev/null @@ -1,58 +0,0 @@ -<html xmlns="http://www.w3.org/1999/xhtml" manifest="http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/simpleManifest.cacheManifest"> -<head> -<title>Low device storage during update</title> - -<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> -<script type="text/javascript" src="/tests/dom/tests/mochitest/ajax/offline/offlineTests.js"></script> -<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> - -<script type="text/javascript"> - -/** - * This test checks that an offline cache update is canceled when a low device - * storage condition is detected during the update. - */ - -var updateService = Cc['@mozilla.org/offlinecacheupdate-service;1'] - .getService(Ci.nsIOfflineCacheUpdateService); - -var obs = SpecialPowers.Cc["@mozilla.org/observer-service;1"] - .getService(SpecialPowers.Ci.nsIObserverService); - -function finish() { - obs.notifyObservers(updateService, "disk-space-watcher", "free"); - - OfflineTest.teardownAndFinish(); -} - -function onError() { - OfflineTest.ok(true, "Expected error: Update canceled"); - finish(); -} - -function onUnexpectedEvent() { - OfflineTest.ok(false, "The update was supposed to be canceled"); - finish(); -} - -function onChecking() { - obs.notifyObservers(updateService, "disk-space-watcher", "full"); -} - -if (OfflineTest.setup()) { - applicationCache.onerror = OfflineTest.priv(onError); - applicationCache.onprogress = OfflineTest.priv(onUnexpectedEvent); - applicationCache.oncached = OfflineTest.priv(onUnexpectedEvent); - applicationCache.onchecking = OfflineTest.priv(onChecking); -} - -SimpleTest.waitForExplicitFinish(); - -</script> - -</head> - -<body> - -</body> -</html> diff --git a/dom/tests/mochitest/bugs/iframe_bug38959-1.html b/dom/tests/mochitest/bugs/iframe_bug38959-1.html deleted file mode 100644 index d4c16c47a..000000000 --- a/dom/tests/mochitest/bugs/iframe_bug38959-1.html +++ /dev/null @@ -1,14 +0,0 @@ -<html> -<head> - <title>Iframe test for bug 38959</title> -</head> -<body"> -<script> - -x = false; -window.opener.postMessage(1, "http://mochi.test:8888"); -window.close(); - -</script> -</body> -</html> diff --git a/dom/tests/mochitest/bugs/iframe_bug38959-2.html b/dom/tests/mochitest/bugs/iframe_bug38959-2.html deleted file mode 100644 index 36cd0c156..000000000 --- a/dom/tests/mochitest/bugs/iframe_bug38959-2.html +++ /dev/null @@ -1,14 +0,0 @@ -<html> -<head> - <title>Iframe test for bug 38959</title> -</head> -<body"> -<script> - -x = true; -window.opener.postMessage(2, "http://mochi.test:8888"); -window.close(); - -</script> -</body> -</html> diff --git a/dom/tests/mochitest/bugs/mochitest.ini b/dom/tests/mochitest/bugs/mochitest.ini index e0c71f857..309aab6e0 100644 --- a/dom/tests/mochitest/bugs/mochitest.ini +++ b/dom/tests/mochitest/bugs/mochitest.ini @@ -23,8 +23,6 @@ support-files = grandchild_bug260264.html iframe_bug304459-1.html iframe_bug304459-2.html - iframe_bug38959-1.html - iframe_bug38959-2.html iframe_bug430276-2.html iframe_bug430276.html iframe_bug440572.html @@ -64,7 +62,6 @@ skip-if = toolkit == 'android' #TIMED_OUT [test_bug377539.html] [test_bug384122.html] [test_bug389366.html] -[test_bug38959.html] [test_bug393974.html] [test_bug394769.html] [test_bug396843.html] diff --git a/dom/tests/mochitest/bugs/test_bug38959.html b/dom/tests/mochitest/bugs/test_bug38959.html deleted file mode 100644 index a8d07d1a6..000000000 --- a/dom/tests/mochitest/bugs/test_bug38959.html +++ /dev/null @@ -1,57 +0,0 @@ -<!DOCTYPE HTML> -<html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=38959 ---> -<head> - <title>Test for Bug 38959</title> - <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> -</head> -<body> -<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=38959">Mozilla Bug 38959</a> -<p id="display"></p> -<div id="content" style="display: none"> - <iframe id="frame"></iframe> -</div> -<pre id="test"> -<script type="application/javascript"> - -/** Test for Bug 38959 **/ - -var newValue; - -function watcher(id, ol, ne) -{ - newValue = ne; - return ne; -} - -function openWindow(url, crossOrigin) -{ - newValue = true; - var w = window.open(url); - w.watch("x", watcher); -} - -function receiveMessage(evt) -{ - ok(newValue, "Watchpoints only allowed same-origin."); - if (evt.data == 1) { - openWindow("/tests/dom/tests/mochitest/bugs/iframe_bug38959-2.html"); - } - else { - SimpleTest.finish(); - } -} - -SimpleTest.waitForExplicitFinish(); - -window.addEventListener("message", receiveMessage, false); - -openWindow("http://example.org/tests/dom/tests/mochitest/bugs/iframe_bug38959-1.html"); - -</script> -</pre> -</body> -</html> diff --git a/dom/tests/mochitest/localstorage/mochitest.ini b/dom/tests/mochitest/localstorage/mochitest.ini index 5242bf9b1..30b90664a 100644 --- a/dom/tests/mochitest/localstorage/mochitest.ini +++ b/dom/tests/mochitest/localstorage/mochitest.ini @@ -47,6 +47,5 @@ skip-if = toolkit == 'android' #TIMED_OUT skip-if = toolkit == 'android' #TIMED_OUT [test_localStorageReplace.html] skip-if = toolkit == 'android' -[test_lowDeviceStorage.html] [test_storageConstructor.html] [test_localStorageSessionPrefOverride.html] diff --git a/dom/tests/mochitest/localstorage/test_localStorageQuotaPrivateBrowsing_perwindowpb.html b/dom/tests/mochitest/localstorage/test_localStorageQuotaPrivateBrowsing_perwindowpb.html index 24d3e4ba3..4dcc361c1 100644 --- a/dom/tests/mochitest/localstorage/test_localStorageQuotaPrivateBrowsing_perwindowpb.html +++ b/dom/tests/mochitest/localstorage/test_localStorageQuotaPrivateBrowsing_perwindowpb.html @@ -14,13 +14,7 @@ const Ci = Components.interfaces; const CONTENT_PAGE = "http://mochi.test:8888/chrome/dom/tests/mochitest/localstorage/page_blank.html"; const slavePath = "/chrome/dom/tests/mochitest/localstorage/"; var currentTest = 1; -var quota; - -try { - quota = Services.prefs.getIntPref("dom.storage.default_quota"); -} catch (ex) { - quota = 5 * 1024; -} +var quota = Services.prefs.getIntPref("dom.storage.default_quota", 5 * 1024); Services.prefs.setIntPref("browser.startup.page", 0); Services.prefs.setIntPref("dom.storage.default_quota", 1); diff --git a/dom/tests/mochitest/localstorage/test_lowDeviceStorage.html b/dom/tests/mochitest/localstorage/test_lowDeviceStorage.html deleted file mode 100644 index 046587150..000000000 --- a/dom/tests/mochitest/localstorage/test_lowDeviceStorage.html +++ /dev/null @@ -1,76 +0,0 @@ -<html xmlns="http://www.w3.org/1999/xhtml"> -<head> -<title>Test localStorage usage while in a low device storage situation</title> - -<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> -<script type="text/javascript" src="localStorageCommon.js"></script> -<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> - -<script type="text/javascript"> - -/* -This test does the following: -- Stores an item in localStorage. -- Checks the stored value. -- Emulates a low device storage situation. -- Gets the stored item again. -- Removes the stored item. -- Fails storing a new value. -- Emulates recovering from a low device storage situation. -- Stores a new value. -- Checks the stored value. -*/ - -function lowDeviceStorage(lowStorage) { - var data = lowStorage ? "full" : "free"; - os().notifyObservers(null, "disk-space-watcher", data); -} - -function startTest() { - // Add a test item. - localStorage.setItem("item", "value"); - is(localStorage.getItem("item"), "value", "getItem()"); - - // Emulates a low device storage situation. - lowDeviceStorage(true); - - // Checks that we can still access to the stored item. - is(localStorage.getItem("item"), "value", - "getItem() during a device storage situation"); - - // Removes the stored item. - localStorage.removeItem("item"); - is(localStorage.getItem("item"), null, - "getItem() after removing the item"); - - // Fails storing a new item. - try { - localStorage.setItem("newItem", "value"); - ok(false, "Storing a new item is expected to fail"); - } catch(e) { - ok(true, "Got an expected exception " + e); - } finally { - is(localStorage.getItem("newItem"), null, - "setItem while device storage is low"); - } - - // Emulates recovering from a low device storage situation. - lowDeviceStorage(false); - - // Add a test item after recovering from the low device storage situation. - localStorage.setItem("newItem", "value"); - is(localStorage.getItem("newItem"), "value", - "getItem() with available storage"); - - SimpleTest.finish(); -} - -SimpleTest.waitForExplicitFinish(); - -</script> - -</head> - -<body onload="startTest();"> -</body> -</html> 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..0fe10eff9 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', @@ -753,7 +746,7 @@ if CONFIG['MOZ_BUILD_APP'] in ['xulrunner'] or CONFIG['MOZ_PHOENIX'] or CONFIG[' 'BrowserFeedWriter.webidl', ] -if CONFIG['MOZ_PHOENIX'] or CONFIG['MOZ_FENNEC'] or CONFIG['MOZ_XULRUNNER']: +if CONFIG['MOZ_PHOENIX'] or CONFIG['MOZ_XULRUNNER']: WEBIDL_FILES += [ 'External.webidl', ] diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp index e1910536f..19c4ded2a 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" @@ -989,7 +988,7 @@ Wrap(JSContext *cx, JS::HandleObject existing, JS::HandleObject obj) } if (existing) { - js::Wrapper::Renew(cx, existing, obj, wrapper); + js::Wrapper::Renew(existing, obj, wrapper); } return js::Wrapper::New(cx, obj, wrapper); } @@ -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..27eb570e9 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -87,6 +87,7 @@ #include "nsProxyRelease.h" #include "nsQueryObject.h" #include "nsSandboxFlags.h" +#include "nsScriptError.h" #include "nsUTF8Utils.h" #include "prthread.h" #include "xpcpublic.h" @@ -281,27 +282,34 @@ struct WindowAction }; void -LogErrorToConsole(const nsAString& aMessage, - const nsAString& aFilename, - const nsAString& aLine, - uint32_t aLineNumber, - uint32_t aColumnNumber, - uint32_t aFlags, - uint64_t aInnerWindowId) +LogErrorToConsole(const WorkerErrorReport& aReport, uint64_t aInnerWindowId) { AssertIsOnMainThread(); - nsCOMPtr<nsIScriptError> scriptError = - do_CreateInstance(NS_SCRIPTERROR_CONTRACTID); + RefPtr<nsScriptErrorBase> scriptError = new nsScriptError(); NS_WARNING_ASSERTION(scriptError, "Failed to create script error!"); if (scriptError) { - if (NS_FAILED(scriptError->InitWithWindowID(aMessage, aFilename, aLine, - aLineNumber, aColumnNumber, - aFlags, "Web Worker", + nsAutoCString category("Web Worker"); + if (NS_FAILED(scriptError->InitWithWindowID(aReport.mMessage, + aReport.mFilename, + aReport.mLine, + aReport.mLineNumber, + aReport.mColumnNumber, + aReport.mFlags, + category, aInnerWindowId))) { NS_WARNING("Failed to init script error!"); scriptError = nullptr; + + for (size_t i = 0, len = aReport.mNotes.Length(); i < len; i++) { + const WorkerErrorNote& note = aReport.mNotes.ElementAt(i); + + nsScriptErrorNote* noteObject = new nsScriptErrorNote(); + noteObject->Init(note.mMessage, note.mFilename, + note.mLineNumber, note.mColumnNumber); + scriptError->AddNote(noteObject); + } } } @@ -316,23 +324,23 @@ LogErrorToConsole(const nsAString& aMessage, } NS_WARNING("LogMessage failed!"); } else if (NS_SUCCEEDED(consoleService->LogStringMessage( - aMessage.BeginReading()))) { + aReport.mMessage.BeginReading()))) { return; } NS_WARNING("LogStringMessage failed!"); } - NS_ConvertUTF16toUTF8 msg(aMessage); - NS_ConvertUTF16toUTF8 filename(aFilename); + NS_ConvertUTF16toUTF8 msg(aReport.mMessage); + NS_ConvertUTF16toUTF8 filename(aReport.mFilename); static const char kErrorString[] = "JS error in Web Worker: %s [%s:%u]"; #ifdef ANDROID __android_log_print(ANDROID_LOG_INFO, "Gecko", kErrorString, msg.get(), - filename.get(), aLineNumber); + filename.get(), aReport.mLineNumber); #endif - fprintf(stderr, kErrorString, msg.get(), filename.get(), aLineNumber); + fprintf(stderr, kErrorString, msg.get(), filename.get(), aReport.mLineNumber); fflush(stderr); } @@ -404,7 +412,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!"); } @@ -536,10 +544,7 @@ private: } if (aWorkerPrivate->IsSharedWorker()) { - aWorkerPrivate->BroadcastErrorToSharedWorkers(aCx, EmptyString(), - EmptyString(), - EmptyString(), 0, 0, - JSREPORT_ERROR, + aWorkerPrivate->BroadcastErrorToSharedWorkers(aCx, nullptr, /* isErrorEvent */ false); return true; } @@ -1060,15 +1065,7 @@ private: class ReportErrorRunnable final : public WorkerRunnable { - nsString mMessage; - nsString mFilename; - nsString mLine; - uint32_t mLineNumber; - uint32_t mColumnNumber; - uint32_t mFlags; - uint32_t mErrorNumber; - JSExnType mExnType; - bool mMutedError; + WorkerErrorReport mReport; public: // aWorkerPrivate is the worker thread we're on (or the main thread, if null) @@ -1077,11 +1074,7 @@ public: static void ReportError(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aFireAtScope, WorkerPrivate* aTarget, - const nsString& aMessage, const nsString& aFilename, - const nsString& aLine, uint32_t aLineNumber, - uint32_t aColumnNumber, uint32_t aFlags, - uint32_t aErrorNumber, JSExnType aExnType, - bool aMutedError, uint64_t aInnerWindowId, + const WorkerErrorReport& aReport, uint64_t aInnerWindowId, JS::Handle<JS::Value> aException = JS::NullHandleValue) { if (aWorkerPrivate) { @@ -1092,16 +1085,16 @@ public: // We should not fire error events for warnings but instead make sure that // they show up in the error console. - if (!JSREPORT_IS_WARNING(aFlags)) { + if (!JSREPORT_IS_WARNING(aReport.mFlags)) { // First fire an ErrorEvent at the worker. RootedDictionary<ErrorEventInit> init(aCx); - if (aMutedError) { + if (aReport.mMutedError) { init.mMessage.AssignLiteral("Script error."); } else { - init.mMessage = aMessage; - init.mFilename = aFilename; - init.mLineno = aLineNumber; + init.mMessage = aReport.mMessage; + init.mFilename = aReport.mFilename; + init.mLineno = aReport.mLineNumber; init.mError = aException; } @@ -1128,7 +1121,8 @@ public: // into an error event on our parent worker! // https://bugzilla.mozilla.org/show_bug.cgi?id=1271441 tracks making this // better. - if (aFireAtScope && (aTarget || aErrorNumber != JSMSG_OVER_RECURSED)) { + if (aFireAtScope && + (aTarget || aReport.mErrorNumber != JSMSG_OVER_RECURSED)) { JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx)); NS_ASSERTION(global, "This should never be null!"); @@ -1145,8 +1139,8 @@ public: MOZ_ASSERT_IF(globalScope, globalScope->GetWrapperPreserveColor() == global); if (globalScope || IsDebuggerSandbox(global)) { - aWorkerPrivate->ReportErrorToDebugger(aFilename, aLineNumber, - aMessage); + aWorkerPrivate->ReportErrorToDebugger(aReport.mFilename, aReport.mLineNumber, + aReport.mMessage); return; } @@ -1193,28 +1187,20 @@ public: // Now fire a runnable to do the same on the parent's thread if we can. if (aWorkerPrivate) { RefPtr<ReportErrorRunnable> runnable = - new ReportErrorRunnable(aWorkerPrivate, aMessage, aFilename, aLine, - aLineNumber, aColumnNumber, aFlags, - aErrorNumber, aExnType, aMutedError); + new ReportErrorRunnable(aWorkerPrivate, aReport); runnable->Dispatch(); return; } // Otherwise log an error to the error console. - LogErrorToConsole(aMessage, aFilename, aLine, aLineNumber, aColumnNumber, - aFlags, aInnerWindowId); + LogErrorToConsole(aReport, aInnerWindowId); } private: - ReportErrorRunnable(WorkerPrivate* aWorkerPrivate, const nsString& aMessage, - const nsString& aFilename, const nsString& aLine, - uint32_t aLineNumber, uint32_t aColumnNumber, - uint32_t aFlags, uint32_t aErrorNumber, - JSExnType aExnType, bool aMutedError) + ReportErrorRunnable(WorkerPrivate* aWorkerPrivate, + const WorkerErrorReport& aReport) : WorkerRunnable(aWorkerPrivate, ParentThreadUnchangedBusyCount), - mMessage(aMessage), mFilename(aFilename), mLine(aLine), - mLineNumber(aLineNumber), mColumnNumber(aColumnNumber), mFlags(aFlags), - mErrorNumber(aErrorNumber), mExnType(aExnType), mMutedError(aMutedError) + mReport(aReport) { } virtual void @@ -1251,9 +1237,7 @@ private: } if (aWorkerPrivate->IsSharedWorker()) { - aWorkerPrivate->BroadcastErrorToSharedWorkers(aCx, mMessage, mFilename, - mLine, mLineNumber, - mColumnNumber, mFlags, + aWorkerPrivate->BroadcastErrorToSharedWorkers(aCx, &mReport, /* isErrorEvent */ true); return true; } @@ -1267,9 +1251,10 @@ private: swm->HandleError(aCx, aWorkerPrivate->GetPrincipal(), aWorkerPrivate->WorkerName(), aWorkerPrivate->ScriptURL(), - mMessage, - mFilename, mLine, mLineNumber, - mColumnNumber, mFlags, mExnType); + mReport.mMessage, + mReport.mFilename, mReport.mLine, mReport.mLineNumber, + mReport.mColumnNumber, mReport.mFlags, + mReport.mExnType); } return true; } @@ -1289,9 +1274,8 @@ private: return true; } - ReportError(aCx, parent, fireAtScope, aWorkerPrivate, mMessage, - mFilename, mLine, mLineNumber, mColumnNumber, mFlags, - mErrorNumber, mExnType, mMutedError, innerWindowId); + ReportError(aCx, parent, fireAtScope, aWorkerPrivate, mReport, + innerWindowId); return true; } }; @@ -3314,21 +3298,16 @@ template <class Derived> void WorkerPrivateParent<Derived>::BroadcastErrorToSharedWorkers( JSContext* aCx, - const nsAString& aMessage, - const nsAString& aFilename, - const nsAString& aLine, - uint32_t aLineNumber, - uint32_t aColumnNumber, - uint32_t aFlags, + const WorkerErrorReport* aReport, bool aIsErrorEvent) { AssertIsOnMainThread(); - if (JSREPORT_IS_WARNING(aFlags)) { + if (aIsErrorEvent && JSREPORT_IS_WARNING(aReport->mFlags)) { // Don't fire any events anywhere. Just log to console. // XXXbz should we log to all the consoles of all the relevant windows? - LogErrorToConsole(aMessage, aFilename, aLine, aLineNumber, aColumnNumber, - aFlags, 0); + MOZ_ASSERT(aReport); + LogErrorToConsole(*aReport, 0); return; } @@ -3357,10 +3336,10 @@ WorkerPrivateParent<Derived>::BroadcastErrorToSharedWorkers( RootedDictionary<ErrorEventInit> errorInit(aCx); errorInit.mBubbles = false; errorInit.mCancelable = true; - errorInit.mMessage = aMessage; - errorInit.mFilename = aFilename; - errorInit.mLineno = aLineNumber; - errorInit.mColno = aColumnNumber; + errorInit.mMessage = aReport->mMessage; + errorInit.mFilename = aReport->mFilename; + errorInit.mLineno = aReport->mLineNumber; + errorInit.mColno = aReport->mColumnNumber; event = ErrorEvent::Constructor(sharedWorker, NS_LITERAL_STRING("error"), errorInit); @@ -3426,9 +3405,9 @@ WorkerPrivateParent<Derived>::BroadcastErrorToSharedWorkers( MOZ_ASSERT(NS_IsMainThread()); RootedDictionary<ErrorEventInit> init(aCx); - init.mLineno = aLineNumber; - init.mFilename = aFilename; - init.mMessage = aMessage; + init.mLineno = aReport->mLineNumber; + init.mFilename = aReport->mFilename; + init.mMessage = aReport->mMessage; init.mCancelable = true; init.mBubbles = true; @@ -3446,8 +3425,8 @@ WorkerPrivateParent<Derived>::BroadcastErrorToSharedWorkers( // Finally log a warning in the console if no window tried to prevent it. if (shouldLogErrorToConsole) { - LogErrorToConsole(aMessage, aFilename, aLine, aLineNumber, aColumnNumber, - aFlags, 0); + MOZ_ASSERT(aReport); + LogErrorToConsole(*aReport, 0); } } @@ -4078,7 +4057,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 +4082,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!"); } } @@ -4120,7 +4099,10 @@ WorkerDebugger::ReportErrorToDebuggerOnMainThread(const nsAString& aFilename, listeners[index]->OnError(aFilename, aLineno, aMessage); } - LogErrorToConsole(aMessage, aFilename, nsString(), aLineno, 0, 0, 0); + WorkerErrorReport report; + report.mMessage = aMessage; + report.mFilename = aFilename; + LogErrorToConsole(report, 0); } WorkerPrivate::WorkerPrivate(WorkerPrivate* aParent, @@ -4862,7 +4844,7 @@ WorkerPrivate::MaybeDispatchLoadFailedRunnable() return; } - MOZ_ALWAYS_SUCCEEDS(DispatchToMainThread(runnable.forget())); + MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable.forget())); } nsIEventTarget* @@ -5083,7 +5065,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!"); } } @@ -5926,6 +5908,47 @@ WorkerPrivate::NotifyInternal(JSContext* aCx, Status aStatus) } void +WorkerErrorBase::AssignErrorBase(JSErrorBase* aReport) +{ + mFilename = NS_ConvertUTF8toUTF16(aReport->filename); + mLineNumber = aReport->lineno; + mColumnNumber = aReport->column; + mErrorNumber = aReport->errorNumber; +} + +void +WorkerErrorNote::AssignErrorNote(JSErrorNotes::Note* aNote) +{ + WorkerErrorBase::AssignErrorBase(aNote); + xpc::ErrorNote::ErrorNoteToMessageString(aNote, mMessage); +} + +void +WorkerErrorReport::AssignErrorReport(JSErrorReport* aReport) +{ + WorkerErrorBase::AssignErrorBase(aReport); + xpc::ErrorReport::ErrorReportToMessageString(aReport, mMessage); + + mLine.Assign(aReport->linebuf(), aReport->linebufLength()); + mFlags = aReport->flags; + MOZ_ASSERT(aReport->exnType >= JSEXN_FIRST && aReport->exnType < JSEXN_LIMIT); + mExnType = JSExnType(aReport->exnType); + mMutedError = aReport->isMuted; + + if (aReport->notes) { + if (!mNotes.SetLength(aReport->notes->length(), fallible)) { + return; + } + + size_t i = 0; + for (auto&& note : *aReport->notes) { + mNotes.ElementAt(i).AssignErrorNote(note.get()); + i++; + } + } +} + +void WorkerPrivate::ReportError(JSContext* aCx, JS::ConstUTF8CharsZ aToStringResult, JSErrorReport* aReport) { @@ -5947,32 +5970,17 @@ WorkerPrivate::ReportError(JSContext* aCx, JS::ConstUTF8CharsZ aToStringResult, } JS_ClearPendingException(aCx); - nsString message, filename, line; - uint32_t lineNumber, columnNumber, flags, errorNumber; - JSExnType exnType = JSEXN_ERR; - bool mutedError = aReport && aReport->isMuted; - + WorkerErrorReport report; if (aReport) { - // We want the same behavior here as xpc::ErrorReport::init here. - xpc::ErrorReport::ErrorReportToMessageString(aReport, message); - - filename = NS_ConvertUTF8toUTF16(aReport->filename); - line.Assign(aReport->linebuf(), aReport->linebufLength()); - lineNumber = aReport->lineno; - columnNumber = aReport->tokenOffset(); - flags = aReport->flags; - errorNumber = aReport->errorNumber; - MOZ_ASSERT(aReport->exnType >= JSEXN_FIRST && aReport->exnType < JSEXN_LIMIT); - exnType = JSExnType(aReport->exnType); + report.AssignErrorReport(aReport); } else { - lineNumber = columnNumber = errorNumber = 0; - flags = nsIScriptError::errorFlag | nsIScriptError::exceptionFlag; + report.mFlags = nsIScriptError::errorFlag | nsIScriptError::exceptionFlag; } - if (message.IsEmpty() && aToStringResult) { + if (report.mMessage.IsEmpty() && aToStringResult) { nsDependentCString toStringResult(aToStringResult.c_str()); - if (!AppendUTF8toUTF16(toStringResult, message, mozilla::fallible)) { + if (!AppendUTF8toUTF16(toStringResult, report.mMessage, mozilla::fallible)) { // Try again, with only a 1 KB string. Do this infallibly this time. // If the user doesn't have 1 KB to spare we're done anyways. uint32_t index = std::min(uint32_t(1024), toStringResult.Length()); @@ -5982,7 +5990,7 @@ WorkerPrivate::ReportError(JSContext* aCx, JS::ConstUTF8CharsZ aToStringResult, nsDependentCString truncatedToStringResult(aToStringResult.c_str(), index); - AppendUTF8toUTF16(truncatedToStringResult, message); + AppendUTF8toUTF16(truncatedToStringResult, report.mMessage); } } @@ -5991,13 +5999,11 @@ WorkerPrivate::ReportError(JSContext* aCx, JS::ConstUTF8CharsZ aToStringResult, // Don't want to run the scope's error handler if this is a recursive error or // if we ran out of memory. bool fireAtScope = mErrorHandlerRecursionCount == 1 && - errorNumber != JSMSG_OUT_OF_MEMORY && + report.mErrorNumber != JSMSG_OUT_OF_MEMORY && JS::CurrentGlobalOrNull(aCx); - ReportErrorRunnable::ReportError(aCx, this, fireAtScope, nullptr, message, - filename, line, lineNumber, - columnNumber, flags, errorNumber, exnType, - mutedError, 0, exn); + ReportErrorRunnable::ReportError(aCx, this, fireAtScope, nullptr, report, 0, + exn); mErrorHandlerRecursionCount--; } diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h index 20a530205..885abccd5 100644 --- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h @@ -140,6 +140,45 @@ public: } }; +class WorkerErrorBase { +public: + nsString mMessage; + nsString mFilename; + uint32_t mLineNumber; + uint32_t mColumnNumber; + uint32_t mErrorNumber; + + WorkerErrorBase() + : mLineNumber(0), + mColumnNumber(0), + mErrorNumber(0) + { } + + void AssignErrorBase(JSErrorBase* aReport); +}; + +class WorkerErrorNote : public WorkerErrorBase { +public: + void AssignErrorNote(JSErrorNotes::Note* aNote); +}; + +class WorkerErrorReport : public WorkerErrorBase { +public: + nsString mLine; + uint32_t mFlags; + JSExnType mExnType; + bool mMutedError; + nsTArray<WorkerErrorNote> mNotes; + + WorkerErrorReport() + : mFlags(0), + mExnType(JSEXN_ERR), + mMutedError(false) + { } + + void AssignErrorReport(JSErrorReport* aReport); +}; + template <class Derived> class WorkerPrivateParent : public DOMEventTargetHelper { @@ -401,12 +440,7 @@ public: void BroadcastErrorToSharedWorkers(JSContext* aCx, - const nsAString& aMessage, - const nsAString& aFilename, - const nsAString& aLine, - uint32_t aLineNumber, - uint32_t aColumnNumber, - uint32_t aFlags, + const WorkerErrorReport* aReport, bool aIsErrorEvent); void 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/workers/moz.build b/dom/workers/moz.build index 4f4b52e4a..9fea84193 100644 --- a/dom/workers/moz.build +++ b/dom/workers/moz.build @@ -94,6 +94,7 @@ LOCAL_INCLUDES += [ '../base', '../system', '/dom/base', + '/dom/bindings', '/xpcom/build', '/xpcom/threads', ] diff --git a/dom/workers/test/test_sharedWorker.html b/dom/workers/test/test_sharedWorker.html index 3d3d4e2c6..c00c4e586 100644 --- a/dom/workers/test/test_sharedWorker.html +++ b/dom/workers/test/test_sharedWorker.html @@ -23,7 +23,7 @@ const errorFilename = href.substring(0, href.lastIndexOf("/") + 1) + filename; const errorLine = 91; - const errorColumn = 0; + const errorColumn = 11; var worker = new SharedWorker(filename); 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/base/txURIUtils.cpp b/dom/xslt/base/txURIUtils.cpp index 3f3556f80..bce2f8d0f 100644 --- a/dom/xslt/base/txURIUtils.cpp +++ b/dom/xslt/base/txURIUtils.cpp @@ -45,6 +45,10 @@ void URIUtils::resolveHref(const nsAString& href, const nsAString& base, void URIUtils::ResetWithSource(nsIDocument *aNewDoc, nsINode *aSourceNode) { + if (!aSourceNode) { + return; + } + nsCOMPtr<nsIDocument> sourceDoc = aSourceNode->OwnerDoc(); nsIPrincipal* sourcePrincipal = sourceDoc->NodePrincipal(); 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 |