diff options
author | janekptacijarabaci <janekptacijarabaci@seznam.cz> | 2018-03-27 15:57:18 +0200 |
---|---|---|
committer | janekptacijarabaci <janekptacijarabaci@seznam.cz> | 2018-03-27 15:57:18 +0200 |
commit | d990d8ab2cade6c928e8bbe56ae038d020cef599 (patch) | |
tree | c7561ae0f303cb0d4a7a7507178531b4852e4dea /dom | |
parent | 0c36b27511c1fbca594f0426c493ef601fda3e4c (diff) | |
parent | 8d5ec757ece850fb7ad5c712868f305636e41177 (diff) | |
download | UXP-d990d8ab2cade6c928e8bbe56ae038d020cef599.tar UXP-d990d8ab2cade6c928e8bbe56ae038d020cef599.tar.gz UXP-d990d8ab2cade6c928e8bbe56ae038d020cef599.tar.lz UXP-d990d8ab2cade6c928e8bbe56ae038d020cef599.tar.xz UXP-d990d8ab2cade6c928e8bbe56ae038d020cef599.zip |
Merge branch 'master' of https://github.com/MoonchildProductions/UXP into js_array_values_1
Diffstat (limited to 'dom')
171 files changed, 2416 insertions, 784 deletions
diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index 886acc670..9ced64c0d 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -165,10 +165,9 @@ nsIContent::DoGetID() const } const nsAttrValue* -nsIContent::DoGetClasses() const +Element::DoGetClasses() const { MOZ_ASSERT(HasFlag(NODE_MAY_HAVE_CLASS), "Unexpected call"); - MOZ_ASSERT(IsElement(), "Only elements can have classes"); if (IsSVGElement()) { const nsAttrValue* animClass = @@ -178,7 +177,7 @@ nsIContent::DoGetClasses() const } } - return AsElement()->GetParsedAttr(nsGkAtoms::_class); + return GetParsedAttr(nsGkAtoms::_class); } NS_IMETHODIMP diff --git a/dom/base/Element.h b/dom/base/Element.h index 5d878df60..cf1d197e2 100644 --- a/dom/base/Element.h +++ b/dom/base/Element.h @@ -544,6 +544,18 @@ public: virtual uint32_t GetAttrCount() const override; virtual bool IsNodeOfType(uint32_t aFlags) const override; + /** + * Get the class list of this element (this corresponds to the value of the + * class attribute). This may be null if there are no classes, but that's not + * guaranteed (e.g. we could have class=""). + */ + const nsAttrValue* GetClasses() const { + if (HasFlag(NODE_MAY_HAVE_CLASS)) { + return DoGetClasses(); + } + return nullptr; + } + #ifdef DEBUG virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override { @@ -1372,6 +1384,12 @@ protected: private: /** + * Hook for implementing GetClasses. This is guaranteed to only be + * called if the NODE_MAY_HAVE_CLASS flag is set. + */ + const nsAttrValue* DoGetClasses() const; + + /** * Get this element's client area rect in app units. * @return the frame's client area */ diff --git a/dom/base/File.cpp b/dom/base/File.cpp index 46b37b976..8602a3064 100644..100755 --- a/dom/base/File.cpp +++ b/dom/base/File.cpp @@ -29,6 +29,7 @@ #include "nsStringStream.h" #include "nsJSUtils.h" #include "nsPrintfCString.h" +#include "mozilla/TimerClamping.h" #include "mozilla/SHA1.h" #include "mozilla/CheckedInt.h" #include "mozilla/Preferences.h" @@ -727,7 +728,7 @@ BlobImplBase::GetLastModified(ErrorResult& aRv) mLastModificationDate = PR_Now(); } - return mLastModificationDate / PR_USEC_PER_MSEC; + return TimerClamping::ReduceUsTimeValue(mLastModificationDate) / PR_USEC_PER_MSEC; } void diff --git a/dom/base/FragmentOrElement.cpp b/dom/base/FragmentOrElement.cpp index 293177ce7..79f6cff51 100644 --- a/dom/base/FragmentOrElement.cpp +++ b/dom/base/FragmentOrElement.cpp @@ -574,6 +574,9 @@ FragmentOrElement::nsDOMSlots::Traverse(nsCycleCollectionTraversalCallback &cb, NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mChildrenList"); cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIDOMNodeList*, mChildrenList)); + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mLabelsList"); + cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIDOMNodeList*, mLabelsList)); + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mClassList"); cb.NoteXPCOMChild(mClassList.get()); @@ -602,6 +605,7 @@ FragmentOrElement::nsDOMSlots::Unlink(bool aIsXUL) mShadowRoot = nullptr; mContainingShadow = nullptr; mChildrenList = nullptr; + mLabelsList = nullptr; mCustomElementData = nullptr; mClassList = nullptr; } @@ -1827,7 +1831,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(FragmentOrElement) } nsAutoString classes; - const nsAttrValue* classAttrValue = tmp->GetClasses(); + const nsAttrValue* classAttrValue = tmp->IsElement() ? + tmp->AsElement()->GetClasses() : nullptr; if (classAttrValue) { classes.AppendLiteral(" class='"); nsAutoString classString; diff --git a/dom/base/FragmentOrElement.h b/dom/base/FragmentOrElement.h index 3cb5575fe..1cd8033bb 100644 --- a/dom/base/FragmentOrElement.h +++ b/dom/base/FragmentOrElement.h @@ -24,6 +24,7 @@ class ContentUnbinder; class nsContentList; +class nsLabelsNodeList; class nsDOMAttributeMap; class nsDOMTokenList; class nsIControllers; @@ -313,6 +314,11 @@ public: */ RefPtr<nsDOMTokenList> mClassList; + /* + * An object implementing the .labels property for this element. + */ + RefPtr<nsLabelsNodeList> mLabelsList; + /** * ShadowRoot bound to the element. */ diff --git a/dom/base/MultipartBlobImpl.cpp b/dom/base/MultipartBlobImpl.cpp index ba26d07f9..03bb62add 100644..100755 --- a/dom/base/MultipartBlobImpl.cpp +++ b/dom/base/MultipartBlobImpl.cpp @@ -17,6 +17,7 @@ #include "nsContentUtils.h" #include "nsIScriptError.h" #include "nsIXPConnect.h" +#include "mozilla/TimerClamping.h" #include <algorithm> using namespace mozilla; @@ -270,8 +271,7 @@ MultipartBlobImpl::SetLengthAndModifiedDate(ErrorResult& aRv) // var x = new Date(); var f = new File(...); // x.getTime() < f.dateModified.getTime() // could fail. - mLastModificationDate = - lastModifiedSet ? lastModified * PR_USEC_PER_MSEC : JS_Now(); + mLastModificationDate = TimerClamping::ReduceUsTimeValue(lastModifiedSet ? lastModified * PR_USEC_PER_MSEC : JS_Now()); } } diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp index 290af152b..5c315517c 100644 --- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp @@ -97,8 +97,10 @@ #endif #include "mozilla/dom/ContentChild.h" +#ifdef MOZ_EME #include "mozilla/EMEUtils.h" #include "mozilla/DetailedPromise.h" +#endif namespace mozilla { namespace dom { @@ -214,7 +216,9 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServiceWorkerContainer) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow) +#ifdef MOZ_EME NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaKeySystemAccessManager) +#endif NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPresentation) #ifdef MOZ_GAMEPAD NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGamepadServiceTest) @@ -288,10 +292,12 @@ Navigator::Invalidate() mServiceWorkerContainer = nullptr; +#ifdef MOZ_EME if (mMediaKeySystemAccessManager) { mMediaKeySystemAccessManager->Shutdown(); mMediaKeySystemAccessManager = nullptr; } +#endif #ifdef MOZ_GAMEPAD if (mGamepadServiceTest) { @@ -1854,16 +1860,6 @@ Navigator::GetUserAgent(nsPIDOMWindowInner* aWindow, nsIURI* aURI, { MOZ_ASSERT(NS_IsMainThread()); - if (!aIsCallerChrome) { - const nsAdoptingString& override = - mozilla::Preferences::GetString("general.useragent.override"); - - if (override) { - aUserAgent = override; - return NS_OK; - } - } - nsresult rv; nsCOMPtr<nsIHttpProtocolHandler> service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv)); @@ -1894,6 +1890,7 @@ Navigator::GetUserAgent(nsPIDOMWindowInner* aWindow, nsIURI* aURI, return siteSpecificUA->GetUserAgentForURIAndWindow(aURI, aWindow, aUserAgent); } +#ifdef MOZ_EME static nsCString ToCString(const nsString& aString) { @@ -2019,6 +2016,7 @@ Navigator::RequestMediaKeySystemAccess(const nsAString& aKeySystem, mMediaKeySystemAccessManager->Request(promise, aKeySystem, aConfigs); return promise.forget(); } +#endif Presentation* Navigator::GetPresentation(ErrorResult& aRv) diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h index 4b4ae6759..d47a80bc1 100644 --- a/dom/base/Navigator.h +++ b/dom/base/Navigator.h @@ -18,7 +18,9 @@ #include "nsString.h" #include "nsTArray.h" #include "nsWeakPtr.h" +#ifdef MOZ_EME #include "mozilla/dom/MediaKeySystemAccessManager.h" +#endif class nsPluginArray; class nsMimeTypeArray; @@ -258,12 +260,14 @@ public: // any, else null. static already_AddRefed<nsPIDOMWindowInner> GetWindowFromGlobal(JSObject* aGlobal); +#ifdef MOZ_EME already_AddRefed<Promise> RequestMediaKeySystemAccess(const nsAString& aKeySystem, const Sequence<MediaKeySystemConfiguration>& aConfig, ErrorResult& aRv); private: RefPtr<MediaKeySystemAccessManager> mMediaKeySystemAccessManager; +#endif public: void NotifyVRDisplaysUpdated(); diff --git a/dom/base/TimerClamping.cpp b/dom/base/TimerClamping.cpp new file mode 100755 index 000000000..70639686b --- /dev/null +++ b/dom/base/TimerClamping.cpp @@ -0,0 +1,35 @@ +/* -*- 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 "TimerClamping.h" + +namespace mozilla { + +/* static */ +double +TimerClamping::ReduceSTimeValue(double aTime) +{ + static const double maxResolutionS = .002; + return floor(aTime / maxResolutionS) * maxResolutionS; +} + +/* static */ +double +TimerClamping::ReduceMsTimeValue(double aTime) +{ + static const double maxResolutionMs = 2; + return floor(aTime / maxResolutionMs) * maxResolutionMs; +} + +/* static */ +double +TimerClamping::ReduceUsTimeValue(double aTime) +{ + static const double maxResolutionUs = 2000; + return floor(aTime / maxResolutionUs) * maxResolutionUs; +} + +}
\ No newline at end of file diff --git a/dom/base/TimerClamping.h b/dom/base/TimerClamping.h new file mode 100755 index 000000000..2ffd6add5 --- /dev/null +++ b/dom/base/TimerClamping.h @@ -0,0 +1,22 @@ +/* -*- 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 TimerClamping_h___ +#define TimerClamping_h___ + +namespace mozilla { + +class TimerClamping +{ +public: + static double ReduceSTimeValue(double aTime); + static double ReduceMsTimeValue(double aTime); + static double ReduceUsTimeValue(double aTime); +}; + +} + +#endif /* TimerClamping_h___ */
\ No newline at end of file diff --git a/dom/base/moz.build b/dom/base/moz.build index 0bc9902e4..0fb345d22 100644..100755 --- a/dom/base/moz.build +++ b/dom/base/moz.build @@ -143,6 +143,7 @@ EXPORTS.mozilla += [ 'CORSMode.h', 'FeedWriterEnabled.h', 'TextInputProcessor.h', + 'TimerClamping.h', 'UseCounter.h', ] @@ -363,6 +364,7 @@ UNIFIED_SOURCES += [ 'TextInputProcessor.cpp', 'ThirdPartyUtil.cpp', 'Timeout.cpp', + 'TimerClamping.cpp', 'TreeWalker.cpp', 'WebKitCSSMatrix.cpp', 'WebSocket.cpp', @@ -411,7 +413,7 @@ EXTRA_COMPONENTS += [ ] # Firefox for Android provides an alternate version of this component -if CONFIG['MOZ_BUILD_APP'] != 'mobile/android': +if not CONFIG['MOZ_FENNEC']: EXTRA_COMPONENTS += [ 'SiteSpecificUserAgent.js', 'SiteSpecificUserAgent.manifest', @@ -472,7 +474,7 @@ include('/ipc/chromium/chromium-config.mozbuild') FINAL_LIBRARY = 'xul' -if CONFIG['MOZ_BUILD_APP'] in ['mobile/android', 'xulrunner'] or CONFIG['MOZ_PHOENIX']: +if CONFIG['MOZ_PHOENIX'] or CONFIG['MOZ_FENNEC'] or CONFIG['MOZ_XULRUNNER']: DEFINES['HAVE_SIDEBAR'] = True if CONFIG['MOZ_X11']: diff --git a/dom/base/nsContentList.cpp b/dom/base/nsContentList.cpp index 09e949009..43e65777d 100644 --- a/dom/base/nsContentList.cpp +++ b/dom/base/nsContentList.cpp @@ -254,19 +254,6 @@ const nsCacheableFuncStringContentList::ContentListType nsCacheableFuncStringHTMLCollection::sType = nsCacheableFuncStringContentList::eHTMLCollection; #endif -JSObject* -nsCacheableFuncStringNodeList::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto) -{ - return NodeListBinding::Wrap(cx, this, aGivenProto); -} - - -JSObject* -nsCacheableFuncStringHTMLCollection::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto) -{ - return HTMLCollectionBinding::Wrap(cx, this, aGivenProto); -} - // Hashtable for storing nsCacheableFuncStringContentList static PLDHashTable* gFuncStringContentListHashTable; @@ -379,6 +366,7 @@ NS_GetFuncStringHTMLCollection(nsINode* aRootNode, aString); } +//----------------------------------------------------- // nsContentList implementation nsContentList::nsContentList(nsINode* aRootNode, @@ -660,7 +648,7 @@ nsContentList::AttributeChanged(nsIDocument *aDocument, Element* aElement, const nsAttrValue* aOldValue) { NS_PRECONDITION(aElement, "Must have a content node to work with"); - + if (!mFunc || !mFuncMayDependOnAttr || mState == LIST_DIRTY || !MayContainRelevantNodes(aElement->GetParentNode()) || !nsContentUtils::IsInSameAnonymousTree(mRootNode, aElement)) { @@ -806,7 +794,7 @@ nsContentList::ContentInserted(nsIDocument *aDocument, ASSERT_IN_SYNC; } - + void nsContentList::ContentRemoved(nsIDocument *aDocument, nsIContent* aContainer, @@ -1075,3 +1063,128 @@ nsContentList::AssertInSync() NS_ASSERTION(cnt == mElements.Length(), "Too few elements"); } #endif + +//----------------------------------------------------- +// nsCacheableFuncStringNodeList + +JSObject* +nsCacheableFuncStringNodeList::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto) +{ + return NodeListBinding::Wrap(cx, this, aGivenProto); +} + +//----------------------------------------------------- +// nsCacheableFuncStringHTMLCollection + +JSObject* +nsCacheableFuncStringHTMLCollection::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto) +{ + return HTMLCollectionBinding::Wrap(cx, this, aGivenProto); +} + +//----------------------------------------------------- +// nsLabelsNodeList + +JSObject* +nsLabelsNodeList::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto) +{ + return NodeListBinding::Wrap(cx, this, aGivenProto); +} + +void +nsLabelsNodeList::AttributeChanged(nsIDocument* aDocument, Element* aElement, + int32_t aNameSpaceID, nsIAtom* aAttribute, + int32_t aModType, + const nsAttrValue* aOldValue) +{ + MOZ_ASSERT(aElement, "Must have a content node to work with"); + if (mState == LIST_DIRTY || + !nsContentUtils::IsInSameAnonymousTree(mRootNode, aElement)) { + return; + } + + // We need to handle input type changes to or from "hidden". + if (aElement->IsHTMLElement(nsGkAtoms::input) && + aAttribute == nsGkAtoms::type && aNameSpaceID == kNameSpaceID_None) { + SetDirty(); + return; + } +} + +void +nsLabelsNodeList::ContentAppended(nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aFirstNewContent, + int32_t aNewIndexInContainer) +{ + // If a labelable element is moved to outside or inside of + // nested associated labels, we're gonna have to modify + // the content list. + if (mState != LIST_DIRTY || + nsContentUtils::IsInSameAnonymousTree(mRootNode, aContainer)) { + SetDirty(); + return; + } +} + +void +nsLabelsNodeList::ContentInserted(nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + int32_t aIndexInContainer) +{ + // If a labelable element is moved to outside or inside of + // nested associated labels, we're gonna have to modify + // the content list. + if (mState != LIST_DIRTY || + nsContentUtils::IsInSameAnonymousTree(mRootNode, aChild)) { + SetDirty(); + return; + } +} + +void +nsLabelsNodeList::ContentRemoved(nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + int32_t aIndexInContainer, + nsIContent* aPreviousSibling) +{ + // If a labelable element is removed, we're gonna have to clean + // the content list. + if (mState != LIST_DIRTY || + nsContentUtils::IsInSameAnonymousTree(mRootNode, aChild)) { + SetDirty(); + return; + } +} + +void +nsLabelsNodeList::MaybeResetRoot(nsINode* aRootNode) +{ + MOZ_ASSERT(aRootNode, "Must have root"); + if (mRootNode == aRootNode) { + return; + } + + if (mRootNode) { + mRootNode->RemoveMutationObserver(this); + } + mRootNode = aRootNode; + mRootNode->AddMutationObserver(this); + SetDirty(); +} + +void +nsLabelsNodeList::PopulateSelf(uint32_t aNeededLength) +{ + MOZ_ASSERT(mRootNode, "Must have root"); + + // Start searching at the root. + nsINode* cur = mRootNode; + if (mElements.IsEmpty() && cur->IsElement() && Match(cur->AsElement())) { + mElements.AppendElement(cur->AsElement()); + } + + nsContentList::PopulateSelf(aNeededLength); +} diff --git a/dom/base/nsContentList.h b/dom/base/nsContentList.h index 3878074b2..83d27da95 100644 --- a/dom/base/nsContentList.h +++ b/dom/base/nsContentList.h @@ -371,9 +371,9 @@ protected: * traversed the whole document (or both). * * @param aNeededLength the length the list should have when we are - * done (unless it exhausts the document) + * done (unless it exhausts the document) */ - void PopulateSelf(uint32_t aNeededLength); + virtual void PopulateSelf(uint32_t aNeededLength); /** * @param aContainer a content node which must be a descendant of @@ -584,4 +584,40 @@ public: #endif }; +class nsLabelsNodeList final : public nsContentList +{ +public: + nsLabelsNodeList(nsINode* aRootNode, + nsContentListMatchFunc aFunc, + nsContentListDestroyFunc aDestroyFunc, + void* aData) + : nsContentList(aRootNode, aFunc, aDestroyFunc, aData) + { + } + + NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED + NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED + NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED + NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED + + virtual JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override; + + /** + * Reset root, mutation observer, and clear content list + * if the root has been changed. + * + * @param aRootNode The node under which to limit our search. + */ + void MaybeResetRoot(nsINode* aRootNode); + +private: + /** + * Start searching at the last one if we already have nodes, otherwise + * start searching at the root. + * + * @param aNeededLength The list of length should have when we are + * done (unless it exhausts the document). + */ + void PopulateSelf(uint32_t aNeededLength) override; +}; #endif // nsContentList_h___ diff --git a/dom/base/nsContentListDeclarations.h b/dom/base/nsContentListDeclarations.h index db3a09036..a5e0e3691 100644 --- a/dom/base/nsContentListDeclarations.h +++ b/dom/base/nsContentListDeclarations.h @@ -18,6 +18,12 @@ class nsINode; class nsString; class nsAString; +namespace mozilla { +namespace dom { +class Element; +} // namespace dom +} // namespace mozilla + // Magic namespace id that means "match all namespaces". This is // negative so it won't collide with actual namespace constants. #define kNameSpaceID_Wildcard INT32_MIN @@ -26,7 +32,7 @@ class nsAString; // arbitrary matching algorithm. aContent is the content that may // match the list, while aNamespaceID, aAtom, and aData are whatever // was passed to the list's constructor. -typedef bool (*nsContentListMatchFunc)(nsIContent* aContent, +typedef bool (*nsContentListMatchFunc)(mozilla::dom::Element* aElement, int32_t aNamespaceID, nsIAtom* aAtom, void* aData); diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 1cc352685..02c6bf1de 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -6287,11 +6287,11 @@ struct ClassMatchingInfo { // static bool -nsContentUtils::MatchClassNames(nsIContent* aContent, int32_t aNamespaceID, +nsContentUtils::MatchClassNames(Element* aElement, int32_t aNamespaceID, nsIAtom* aAtom, void* aData) { // We can't match if there are no class names - const nsAttrValue* classAttr = aContent->GetClasses(); + const nsAttrValue* classAttr = aElement->GetClasses(); if (!classAttr) { return false; } diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index f688eeecf..0a293d73e 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -2753,7 +2753,8 @@ private: static void DropFragmentParsers(); - static bool MatchClassNames(nsIContent* aContent, int32_t aNamespaceID, + static bool MatchClassNames(mozilla::dom::Element* aElement, + int32_t aNamespaceID, nsIAtom* aAtom, void* aData); static void DestroyClassNameArray(void* aData); static void* AllocClassMatchingInfo(nsINode* aRootNode, diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index 8e6920a0e..eaea49b02 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -61,6 +61,7 @@ #include "nsGenericHTMLElement.h" #include "mozilla/dom/CDATASection.h" #include "mozilla/dom/ProcessingInstruction.h" +#include "nsDSURIContentListener.h" #include "nsDOMString.h" #include "nsNodeUtils.h" #include "nsLayoutUtils.h" // for GetFrameForPoint @@ -2456,6 +2457,15 @@ nsDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel, NS_ENSURE_SUCCESS(rv, rv); } + // XFO needs to be checked after CSP because it is ignored if + // the CSP defines frame-ancestors. + if (!nsDSURIContentListener::CheckFrameOptions(aChannel, docShell, NodePrincipal())) { + MOZ_LOG(gCspPRLog, LogLevel::Debug, + ("XFO doesn't like frame's ancestry, not loading.")); + // stop! ERROR page! + aChannel->Cancel(NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION); + } + return NS_OK; } @@ -4330,6 +4340,7 @@ nsDocument::SetScopeObject(nsIGlobalObject* aGlobal) } } +#ifdef MOZ_EME static void CheckIfContainsEMEContent(nsISupports* aSupports, void* aContainsEME) { @@ -4353,6 +4364,7 @@ nsDocument::ContainsEMEContent() static_cast<void*>(&containsEME)); return containsEME; } +#endif // MOZ_EME static void CheckIfContainsMSEContent(nsISupports* aSupports, void* aContainsMSE) @@ -8380,11 +8392,13 @@ nsDocument::CanSavePresentation(nsIRequest *aNewRequest) } #endif // MOZ_WEBRTC +#ifdef MOZ_EME // Don't save presentations for documents containing EME content, so that // CDMs reliably shutdown upon user navigation. if (ContainsEMEContent()) { return false; } +#endif // Don't save presentations for documents containing MSE content, to // reduce memory usage. diff --git a/dom/base/nsDocument.h b/dom/base/nsDocument.h index 17d936055..3725b3c18 100644 --- a/dom/base/nsDocument.h +++ b/dom/base/nsDocument.h @@ -1267,7 +1267,9 @@ public: js::ExpandoAndGeneration mExpandoAndGeneration; +#ifdef MOZ_EME bool ContainsEMEContent(); +#endif bool ContainsMSEContent(); @@ -1491,7 +1493,6 @@ private: void PostUnblockOnloadEvent(); void DoUnblockOnload(); - nsresult CheckFrameOptions(); nsresult InitCSP(nsIChannel* aChannel); /** diff --git a/dom/base/nsDocumentEncoder.cpp b/dom/base/nsDocumentEncoder.cpp index 0a3570962..84b128b15 100644 --- a/dom/base/nsDocumentEncoder.cpp +++ b/dom/base/nsDocumentEncoder.cpp @@ -481,7 +481,7 @@ nsDocumentEncoder::SerializeToStringRecursive(nsINode* aNode, } if (!aDontSerializeRoot) { - rv = SerializeNodeEnd(node, aStr); + rv = SerializeNodeEnd(maybeFixedNode, aStr); NS_ENSURE_SUCCESS(rv, rv); } diff --git a/dom/base/nsGkAtomList.h b/dom/base/nsGkAtomList.h index 0b76b2bea..e4ae7ede8 100644 --- a/dom/base/nsGkAtomList.h +++ b/dom/base/nsGkAtomList.h @@ -526,6 +526,7 @@ GK_ATOM(keytext, "keytext") GK_ATOM(keyup, "keyup") GK_ATOM(kind, "kind") GK_ATOM(label, "label") +GK_ATOM(labels, "labels") GK_ATOM(lang, "lang") GK_ATOM(language, "language") GK_ATOM(last, "last") @@ -950,6 +951,7 @@ GK_ATOM(onupdateready, "onupdateready") GK_ATOM(onupgradeneeded, "onupgradeneeded") GK_ATOM(onussdreceived, "onussdreceived") GK_ATOM(onversionchange, "onversionchange") +GK_ATOM(onvisibilitychange, "onvisibilitychange") GK_ATOM(onvoicechange, "onvoicechange") GK_ATOM(onvoiceschanged, "onvoiceschanged") GK_ATOM(onvrdisplayconnect, "onvrdisplayconnect") @@ -1449,6 +1451,7 @@ GK_ATOM(font_style, "font-style") GK_ATOM(font_variant, "font-variant") GK_ATOM(foreignObject, "foreignObject") GK_ATOM(fractalNoise, "fractalNoise") +GK_ATOM(fr, "fr") GK_ATOM(fx, "fx") GK_ATOM(fy, "fy") GK_ATOM(G, "G") diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 8ff4b84ce..f784031f6 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -6187,7 +6187,7 @@ nsGlobalWindow::GetScrollMaxY(ErrorResult& aError) FORWARD_TO_OUTER_OR_THROW(GetScrollBoundaryOuter, (eSideBottom), aError, 0); } -CSSIntPoint +CSSPoint nsGlobalWindow::GetScrollXY(bool aDoFlush) { MOZ_ASSERT(IsOuterWindow()); @@ -6211,30 +6211,30 @@ nsGlobalWindow::GetScrollXY(bool aDoFlush) return GetScrollXY(true); } - return sf->GetScrollPositionCSSPixels(); + return CSSPoint::FromAppUnits(scrollPos); } -int32_t +double nsGlobalWindow::GetScrollXOuter() { MOZ_RELEASE_ASSERT(IsOuterWindow()); return GetScrollXY(false).x; } -int32_t +double nsGlobalWindow::GetScrollX(ErrorResult& aError) { FORWARD_TO_OUTER_OR_THROW(GetScrollXOuter, (), aError, 0); } -int32_t +double nsGlobalWindow::GetScrollYOuter() { MOZ_RELEASE_ASSERT(IsOuterWindow()); return GetScrollXY(false).y; } -int32_t +double nsGlobalWindow::GetScrollY(ErrorResult& aError) { FORWARD_TO_OUTER_OR_THROW(GetScrollYOuter, (), aError, 0); diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h index eab91c2e4..dbceeab74 100644 --- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -1050,15 +1050,15 @@ public: void SetInnerHeight(JSContext* aCx, JS::Handle<JS::Value> aValue, mozilla::dom::CallerType aCallerType, mozilla::ErrorResult& aError); - int32_t GetScrollXOuter(); - int32_t GetScrollX(mozilla::ErrorResult& aError); - int32_t GetPageXOffset(mozilla::ErrorResult& aError) + double GetScrollXOuter(); + double GetScrollX(mozilla::ErrorResult& aError); + double GetPageXOffset(mozilla::ErrorResult& aError) { return GetScrollX(aError); } - int32_t GetScrollYOuter(); - int32_t GetScrollY(mozilla::ErrorResult& aError); - int32_t GetPageYOffset(mozilla::ErrorResult& aError) + double GetScrollYOuter(); + double GetScrollY(mozilla::ErrorResult& aError); + double GetPageYOffset(mozilla::ErrorResult& aError) { return GetScrollY(aError); } @@ -1579,7 +1579,7 @@ public: // If aDoFlush is true, we'll flush our own layout; otherwise we'll try to // just flush our parent and only flush ourselves if we think we need to. // Outer windows only. - mozilla::CSSIntPoint GetScrollXY(bool aDoFlush); + mozilla::CSSPoint GetScrollXY(bool aDoFlush); int32_t GetScrollBoundaryOuter(mozilla::Side aSide); diff --git a/dom/base/nsIContent.h b/dom/base/nsIContent.h index f05c47a61..405090865 100644 --- a/dom/base/nsIContent.h +++ b/dom/base/nsIContent.h @@ -862,18 +862,6 @@ public: } /** - * Get the class list of this content node (this corresponds to the - * value of the class attribute). This may be null if there are no - * classes, but that's not guaranteed. - */ - const nsAttrValue* GetClasses() const { - if (HasFlag(NODE_MAY_HAVE_CLASS)) { - return DoGetClasses(); - } - return nullptr; - } - - /** * Walk aRuleWalker over the content style rules (presentational * hint rules) for this content node. */ @@ -990,13 +978,6 @@ protected: */ nsIAtom* DoGetID() const; -private: - /** - * Hook for implementing GetClasses. This is guaranteed to only be - * called if the NODE_MAY_HAVE_CLASS flag is set. - */ - const nsAttrValue* DoGetClasses() const; - public: #ifdef DEBUG /** diff --git a/dom/base/nsPluginArray.cpp b/dom/base/nsPluginArray.cpp index b9c946ca3..5b9378ae0 100644 --- a/dom/base/nsPluginArray.cpp +++ b/dom/base/nsPluginArray.cpp @@ -372,9 +372,21 @@ nsPluginArray::EnsurePlugins() nsCString permString; nsresult rv = pluginHost->GetPermissionStringForTag(pluginTag, 0, permString); if (rv == NS_OK) { - nsIPrincipal* principal = mWindow->GetExtantDoc()->NodePrincipal(); - nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager(); - permMgr->TestPermissionFromPrincipal(principal, permString.get(), &permission); + nsCOMPtr<nsIDocument> currentDoc = mWindow->GetExtantDoc(); + + // The top-level content document gets the final say on whether or not + // a plugin is going to be hidden or not, regardless of the origin + // that a subframe is hosted at. This is to avoid spamming the user + // with the hidden plugin notification bar when third-party iframes + // attempt to access navigator.plugins after the user has already + // expressed that the top-level document has this permission. + nsCOMPtr<nsIDocument> topDoc = currentDoc->GetTopLevelContentDocument(); + + if (topDoc) { + nsIPrincipal* principal = topDoc->NodePrincipal(); + nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager(); + permMgr->TestPermissionFromPrincipal(principal, permString.get(), &permission); + } } } } diff --git a/dom/base/nsXHTMLContentSerializer.cpp b/dom/base/nsXHTMLContentSerializer.cpp index 0dc31d7ae..111ed46c7 100644..100755 --- a/dom/base/nsXHTMLContentSerializer.cpp +++ b/dom/base/nsXHTMLContentSerializer.cpp @@ -306,7 +306,7 @@ nsXHTMLContentSerializer::SerializeAttributes(nsIContent* aContent, continue; } - BorrowedAttrInfo info = aContent->GetAttrInfoAt(index); + mozilla::dom::BorrowedAttrInfo info = aContent->GetAttrInfoAt(index); const nsAttrName* name = info.mName; int32_t namespaceID = name->NamespaceID(); diff --git a/dom/base/test/test_bug1375050.html b/dom/base/test/test_bug1375050.html new file mode 100644 index 000000000..b91b859d0 --- /dev/null +++ b/dom/base/test/test_bug1375050.html @@ -0,0 +1,33 @@ +<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1375050
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1375050</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">
+ try { o1 = document.createElement('input'); } catch(e) { console.log(e); };
+ try { o2 = document.createElement('col'); } catch(e) { console.log(e); };
+ try { o4 = document.createRange(); } catch(e) { console.log(e); };
+ try { document.documentElement.appendChild(o1); } catch(e) { console.log(e); };
+ try { for (let p in o1) { let x = o1[p] }; } catch(e) { console.log(e); };
+ try { o4.selectNode(o1); } catch(e) { console.log(e); };
+ try { o6 = document.createComment(" x"); } catch(e) { console.log(e); }
+ try { o4.surroundContents(o6); } catch(e) { console.log(e); }
+ try { o7 = document.implementation.createDocument('', '', null).adoptNode(o1); } catch(e) { console.log(e);};
+ try { o2.appendChild(o1); } catch(e) { console.log(e); };
+ ok(true, "Didn't crash.");
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1375050">Mozilla Bug 1375050</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug403852.html b/dom/base/test/test_bug403852.html index 30192cb1b..592711500 100644 --- a/dom/base/test/test_bug403852.html +++ b/dom/base/test/test_bug403852.html @@ -38,7 +38,8 @@ function onOpened(message) { ok("lastModifiedDate" in domFile, "lastModifiedDate must be present"); var d = new Date(message.mtime); - is(d.getTime(), domFile.lastModifiedDate.getTime(), "lastModifiedDate should be the same"); + // Commented out: lastModifiedDate is rounded because it is a DOM API, message is a special-powers Chrome thing + // is(d.getTime(), domFile.lastModifiedDate.getTime(), "lastModifiedDate should be the same"); var x = new Date(); @@ -53,8 +54,8 @@ function onOpened(message) { ok((x.getTime() <= y.getTime()) && (y.getTime() <= z.getTime()), "lastModifiedDate of file which does not have last modified date should be current time"); - var d = new Date(message.fileDate); - is(d.getTime(), message.fileWithDate.lastModifiedDate.getTime(), "lastModifiedDate should be the same when lastModified is set: " + message.fileWithDate.lastModified); + // var d = new Date(message.fileDate); + // is(d.getTime(), message.fileWithDate.lastModifiedDate.getTime(), "lastModifiedDate should be the same when lastModified is set: " + message.fileWithDate.lastModified); script.destroy(); SimpleTest.finish(); diff --git a/dom/base/test/test_file_negative_date.html b/dom/base/test/test_file_negative_date.html index ebfa9bd0d..26cf3b82e 100644 --- a/dom/base/test/test_file_negative_date.html +++ b/dom/base/test/test_file_negative_date.html @@ -22,13 +22,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1158437 var blob = new Blob(['hello world']); var f1 = new File([blob], 'f1.txt', { lastModified: 0 }); -var f2 = new File([blob], 'f2.txt', { lastModified: -1 }); +var f2 = new File([blob], 'f2.txt', { lastModified: -2 }); var f3 = new File([blob], 'f3.txt', { lastModified: -1000 }); is(f1.lastModified, 0, "lastModified == 0 is supported"); ok(f1.lastModifiedDate.toString(), (new Date(0)).toString(), "Correct f1.lastModifiedDate value"); -is(f2.lastModified, -1, "lastModified == -1 is supported"); -ok(f2.lastModifiedDate.toString(), (new Date(-1)).toString(), "Correct f2.lastModifiedDate value"); +is(f2.lastModified, -2, "lastModified == -2 is supported"); +ok(f2.lastModifiedDate.toString(), (new Date(-2)).toString(), "Correct f2.lastModifiedDate value"); is(f3.lastModified, -1000, "lastModified == -1000 is supported"); ok(f3.lastModifiedDate.toString(), (new Date(-1000)).toString(), "Correct f3.lastModifiedDate value"); diff --git a/dom/base/test/test_viewport_scroll.html b/dom/base/test/test_viewport_scroll.html index 9b812360b..7db02b781 100644 --- a/dom/base/test/test_viewport_scroll.html +++ b/dom/base/test/test_viewport_scroll.html @@ -28,10 +28,10 @@ function subtest(winProp, elemProp, win, correctElement, elemToSet, otherElem1, win.scrollTo(50, 50); elemToSet[elemProp] = 100; if (elemToSet == correctElement) { - is(win[winProp], 100, "Setting " + elemToSet.name + "." + elemProp + " should scroll"); + is(Math.round(win[winProp]), 100, "Setting " + elemToSet.name + "." + elemProp + " should scroll"); is(elemToSet[elemProp], 100, "Reading back " + elemToSet.name + "." + elemProp + " after scrolling"); } else { - is(win[winProp], 50, "Setting " + elemToSet.name + "." + elemProp + " should not scroll"); + is(Math.round(win[winProp]), 50, "Setting " + elemToSet.name + "." + elemProp + " should not scroll"); is(elemToSet[elemProp], 0, "Reading back " + elemToSet.name + "." + elemProp + " after not scrolling"); } if (otherElem1 == correctElement) { diff --git a/dom/bindings/moz.build b/dom/bindings/moz.build index eb00482c6..f1ce9e276 100644 --- a/dom/bindings/moz.build +++ b/dom/bindings/moz.build @@ -139,7 +139,7 @@ FINAL_LIBRARY = 'xul' SPHINX_TREES['webidl'] = 'docs' SPHINX_PYTHON_PACKAGE_DIRS += ['mozwebidlcodegen'] -if CONFIG['MOZ_BUILD_APP'] in ['mobile/android', 'xulrunner'] or CONFIG['MOZ_PHOENIX']: +if CONFIG['MOZ_PHOENIX'] or CONFIG['MOZ_FENNEC'] or CONFIG['MOZ_XULRUNNER']: # This is needed for Window.webidl DEFINES['HAVE_SIDEBAR'] = True diff --git a/dom/bindings/test/test_promise_rejections_from_jsimplemented.html b/dom/bindings/test/test_promise_rejections_from_jsimplemented.html index 5428030c5..68de079ed 100644 --- a/dom/bindings/test/test_promise_rejections_from_jsimplemented.html +++ b/dom/bindings/test/test_promise_rejections_from_jsimplemented.html @@ -93,7 +93,7 @@ doTest@${ourFile}:56:7 checkExn.bind(null, 90, "ReferenceError", "thereIsNoSuchContentFunction3 is not defined", undefined, ourFile, 6, - `doTest/<.then@${ourFile}:90:32 + `then@${ourFile}:90:32 ` + (asyncStack ? `Async*doTest@${ourFile}:89:7\n` + parentFrame : ""))), t.testPromiseWithDOMExceptionThrowingPromiseInit().then( ensurePromiseFail.bind(null, 7), diff --git a/dom/browser-element/mochitest/browserElement_ScrollEvent.js b/dom/browser-element/mochitest/browserElement_ScrollEvent.js index 5c4b4dcf9..06dc91b86 100644 --- a/dom/browser-element/mochitest/browserElement_ScrollEvent.js +++ b/dom/browser-element/mochitest/browserElement_ScrollEvent.js @@ -16,8 +16,8 @@ function runTest() { iframe.addEventListener("mozbrowserscroll", function(e) { ok(true, "got mozbrowserscroll event."); ok(e.detail, "event.detail is not null."); - ok(e.detail.top === 4000, "top position is correct."); - ok(e.detail.left === 4000, "left position is correct."); + ok(Math.round(e.detail.top) == 4000, "top position is correct."); + ok(Math.round(e.detail.left) == 4000, "left position is correct."); SimpleTest.finish(); }); diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index b0a430fe4..15df2b337 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -92,8 +92,6 @@ #include "mozilla/gfx/PathHelpers.h" #include "mozilla/gfx/DataSurfaceHelpers.h" #include "mozilla/gfx/PatternHelpers.h" -#include "mozilla/ipc/DocumentRendererParent.h" -#include "mozilla/ipc/PDocumentRendererParent.h" #include "mozilla/layers/PersistentBufferProvider.h" #include "mozilla/MathAlgorithms.h" #include "mozilla/Preferences.h" @@ -4977,10 +4975,12 @@ CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage, return; } +#ifdef MOZ_EME if (video->ContainsRestrictedContent()) { aError.Throw(NS_ERROR_NOT_AVAILABLE); return; } +#endif uint16_t readyState; if (NS_SUCCEEDED(video->GetReadyState(&readyState)) && diff --git a/dom/canvas/DocumentRendererChild.cpp b/dom/canvas/DocumentRendererChild.cpp deleted file mode 100644 index 15dd5fc52..000000000 --- a/dom/canvas/DocumentRendererChild.cpp +++ /dev/null @@ -1,94 +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/. */ - -#include "mozilla/ipc/DocumentRendererChild.h" - -#include "base/basictypes.h" - -#include "gfx2DGlue.h" -#include "gfxPattern.h" -#include "mozilla/gfx/2D.h" -#include "mozilla/RefPtr.h" -#include "nsPIDOMWindow.h" -#include "nsIDOMWindow.h" -#include "nsIDocShell.h" -#include "nsIInterfaceRequestorUtils.h" -#include "nsComponentManagerUtils.h" -#include "nsCSSParser.h" -#include "nsPresContext.h" -#include "nsCOMPtr.h" -#include "nsColor.h" -#include "gfxContext.h" -#include "nsLayoutUtils.h" -#include "nsContentUtils.h" -#include "nsCSSValue.h" -#include "nsRuleNode.h" -#include "mozilla/gfx/Matrix.h" - -using namespace mozilla; -using namespace mozilla::gfx; -using namespace mozilla::ipc; - -DocumentRendererChild::DocumentRendererChild() -{} - -DocumentRendererChild::~DocumentRendererChild() -{} - -bool -DocumentRendererChild::RenderDocument(nsPIDOMWindowOuter* window, - const nsRect& documentRect, - const mozilla::gfx::Matrix& transform, - const nsString& aBGColor, - uint32_t renderFlags, - bool flushLayout, - const nsIntSize& renderSize, - nsCString& data) -{ - if (flushLayout) - nsContentUtils::FlushLayoutForTree(window); - - RefPtr<nsPresContext> presContext; - if (window) { - nsIDocShell* docshell = window->GetDocShell(); - if (docshell) { - docshell->GetPresContext(getter_AddRefs(presContext)); - } - } - if (!presContext) - return false; - - nsCSSParser parser; - nsCSSValue bgColorValue; - if (!parser.ParseColorString(aBGColor, nullptr, 0, bgColorValue)) { - return false; - } - - nscolor bgColor; - if (!nsRuleNode::ComputeColor(bgColorValue, presContext, nullptr, bgColor)) { - return false; - } - - // Draw directly into the output array. - data.SetLength(renderSize.width * renderSize.height * 4); - - RefPtr<DrawTarget> dt = - Factory::CreateDrawTargetForData(BackendType::CAIRO, - reinterpret_cast<uint8_t*>(data.BeginWriting()), - IntSize(renderSize.width, renderSize.height), - 4 * renderSize.width, - SurfaceFormat::B8G8R8A8); - if (!dt || !dt->IsValid()) { - gfxWarning() << "DocumentRendererChild::RenderDocument failed to Factory::CreateDrawTargetForData"; - return false; - } - RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(dt); - MOZ_ASSERT(ctx); // already checked the draw target above - ctx->SetMatrix(mozilla::gfx::ThebesMatrix(transform)); - - nsCOMPtr<nsIPresShell> shell = presContext->PresShell(); - shell->RenderDocument(documentRect, renderFlags, bgColor, ctx); - - return true; -} diff --git a/dom/canvas/DocumentRendererChild.h b/dom/canvas/DocumentRendererChild.h deleted file mode 100644 index 463ba2707..000000000 --- a/dom/canvas/DocumentRendererChild.h +++ /dev/null @@ -1,37 +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/. */ - -#ifndef mozilla_dom_DocumentRendererChild -#define mozilla_dom_DocumentRendererChild - -#include "mozilla/ipc/PDocumentRendererChild.h" -#include "nsString.h" -#include "gfxContext.h" - -class nsIDOMWindow; - -namespace mozilla { -namespace ipc { - -class DocumentRendererChild : public PDocumentRendererChild -{ -public: - DocumentRendererChild(); - virtual ~DocumentRendererChild(); - - bool RenderDocument(nsPIDOMWindowOuter* window, - const nsRect& documentRect, const gfx::Matrix& transform, - const nsString& bgcolor, - uint32_t renderFlags, bool flushLayout, - const nsIntSize& renderSize, nsCString& data); - -private: - - DISALLOW_EVIL_CONSTRUCTORS(DocumentRendererChild); -}; - -} // namespace ipc -} // namespace mozilla - -#endif diff --git a/dom/canvas/DocumentRendererParent.cpp b/dom/canvas/DocumentRendererParent.cpp deleted file mode 100644 index d9578ac4e..000000000 --- a/dom/canvas/DocumentRendererParent.cpp +++ /dev/null @@ -1,63 +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/. */ - -#include "mozilla/ipc/DocumentRendererParent.h" - -#include "gfx2DGlue.h" -#include "mozilla/gfx/2D.h" -#include "mozilla/gfx/PathHelpers.h" -#include "mozilla/RefPtr.h" -#include "nsICanvasRenderingContextInternal.h" - -using namespace mozilla; -using namespace mozilla::gfx; -using namespace mozilla::ipc; - -DocumentRendererParent::DocumentRendererParent() -{} - -DocumentRendererParent::~DocumentRendererParent() -{} - -void DocumentRendererParent::SetCanvasContext(nsICanvasRenderingContextInternal* aCanvas, - gfxContext* ctx) -{ - mCanvas = aCanvas; - mCanvasContext = ctx; -} - -void DocumentRendererParent::DrawToCanvas(const nsIntSize& aSize, - const nsCString& aData) -{ - if (!mCanvas || !mCanvasContext) - return; - - DrawTarget* drawTarget = mCanvasContext->GetDrawTarget(); - Rect rect(0, 0, aSize.width, aSize.height); - MaybeSnapToDevicePixels(rect, *drawTarget, true); - RefPtr<DataSourceSurface> dataSurface = - Factory::CreateWrappingDataSourceSurface(reinterpret_cast<uint8_t*>(const_cast<nsCString&>(aData).BeginWriting()), - aSize.width * 4, - IntSize(aSize.width, aSize.height), - SurfaceFormat::B8G8R8A8); - SurfacePattern pattern(dataSurface, ExtendMode::CLAMP); - drawTarget->FillRect(rect, pattern); - - gfxRect damageRect = mCanvasContext->UserToDevice(ThebesRect(rect)); - mCanvas->Redraw(damageRect); -} - -void -DocumentRendererParent::ActorDestroy(ActorDestroyReason aWhy) -{ - // Implement me! Bug 1005139 -} - -bool -DocumentRendererParent::Recv__delete__(const nsIntSize& renderedSize, - const nsCString& data) -{ - DrawToCanvas(renderedSize, data); - return true; -} diff --git a/dom/canvas/DocumentRendererParent.h b/dom/canvas/DocumentRendererParent.h deleted file mode 100644 index 432aa8264..000000000 --- a/dom/canvas/DocumentRendererParent.h +++ /dev/null @@ -1,44 +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/. */ - -#ifndef mozilla_dom_DocumentRendererParent -#define mozilla_dom_DocumentRendererParent - -#include "mozilla/ipc/PDocumentRendererParent.h" -#include "nsCOMPtr.h" -#include "nsString.h" -#include "gfxContext.h" - -class nsICanvasRenderingContextInternal; - -namespace mozilla { -namespace ipc { - -class DocumentRendererParent : public PDocumentRendererParent -{ -public: - DocumentRendererParent(); - virtual ~DocumentRendererParent(); - - void SetCanvasContext(nsICanvasRenderingContextInternal* aCanvas, - gfxContext* ctx); - void DrawToCanvas(const nsIntSize& renderedSize, - const nsCString& aData); - - virtual void ActorDestroy(ActorDestroyReason aWhy) override; - - virtual bool Recv__delete__(const nsIntSize& renderedSize, - const nsCString& data) override; - -private: - nsCOMPtr<nsICanvasRenderingContextInternal> mCanvas; - RefPtr<gfxContext> mCanvasContext; - - DISALLOW_EVIL_CONSTRUCTORS(DocumentRendererParent); -}; - -} // namespace ipc -} // namespace mozilla - -#endif diff --git a/dom/canvas/WebGL2ContextState.cpp b/dom/canvas/WebGL2ContextState.cpp index be0a7a3cb..e6283b12d 100644 --- a/dom/canvas/WebGL2ContextState.cpp +++ b/dom/canvas/WebGL2ContextState.cpp @@ -7,6 +7,7 @@ #include "WebGL2Context.h" #include "GLContext.h" +#include "GLScreenBuffer.h" #include "WebGLBuffer.h" #include "WebGLContextUtils.h" #include "WebGLFramebuffer.h" diff --git a/dom/canvas/WebGLContextDraw.cpp b/dom/canvas/WebGLContextDraw.cpp index 66fca7689..867e47cbd 100644 --- a/dom/canvas/WebGLContextDraw.cpp +++ b/dom/canvas/WebGLContextDraw.cpp @@ -16,6 +16,7 @@ #include "WebGLRenderbuffer.h" #include "WebGLShader.h" #include "WebGLTexture.h" +#include "WebGLTransformFeedback.h" #include "WebGLVertexArray.h" #include "WebGLVertexAttribData.h" diff --git a/dom/canvas/WebGLContextExtensions.cpp b/dom/canvas/WebGLContextExtensions.cpp index 28ba14fa2..4a5a23274 100644 --- a/dom/canvas/WebGLContextExtensions.cpp +++ b/dom/canvas/WebGLContextExtensions.cpp @@ -89,6 +89,8 @@ bool WebGLContext::IsExtensionSupported(dom::CallerType callerType, if (allowPrivilegedExts) { switch (ext) { + case WebGLExtensionID::EXT_disjoint_timer_query: + return WebGLExtensionDisjointTimerQuery::IsSupported(this); case WebGLExtensionID::WEBGL_debug_renderer_info: return true; case WebGLExtensionID::WEBGL_debug_shaders: @@ -112,8 +114,6 @@ WebGLContext::IsExtensionSupported(WebGLExtensionID ext) const switch (ext) { // In alphabetical order // EXT_ - case WebGLExtensionID::EXT_disjoint_timer_query: - return WebGLExtensionDisjointTimerQuery::IsSupported(this); case WebGLExtensionID::EXT_texture_filter_anisotropic: return gl->IsExtensionSupported(gl::GLContext::EXT_texture_filter_anisotropic); diff --git a/dom/canvas/WebGLFramebuffer.cpp b/dom/canvas/WebGLFramebuffer.cpp index 35efa4f16..0abaf3dd7 100644 --- a/dom/canvas/WebGLFramebuffer.cpp +++ b/dom/canvas/WebGLFramebuffer.cpp @@ -17,7 +17,9 @@ #include "WebGLContextUtils.h" #include "WebGLExtensions.h" #include "WebGLRenderbuffer.h" +#include "WebGLShader.h" #include "WebGLTexture.h" +#include "WebGLObjectModel.h" namespace mozilla { @@ -1940,6 +1942,7 @@ ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback, } } + NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLFramebuffer, mDepthAttachment, mStencilAttachment, diff --git a/dom/canvas/WebGLObjectModel.h b/dom/canvas/WebGLObjectModel.h index e19d2fd8e..b18b790c0 100644 --- a/dom/canvas/WebGLObjectModel.h +++ b/dom/canvas/WebGLObjectModel.h @@ -15,6 +15,7 @@ namespace mozilla { template<typename> class LinkedList; class WebGLContext; + //// // This class is a mixin for objects that are tied to a specific @@ -355,6 +356,16 @@ ImplCycleCollectionUnlink(mozilla::WebGLRefPtr<T>& field) template <typename T> inline void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback, + mozilla::WebGLRefPtr<T>& field, + const char* name, + uint32_t flags = 0) +{ + CycleCollectionNoteChild(callback, field.get(), name, flags); +} + +template <typename T> +inline void +ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback, const mozilla::WebGLRefPtr<T>& field, const char* name, uint32_t flags = 0) @@ -362,4 +373,5 @@ ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback, CycleCollectionNoteChild(callback, field.get(), name, flags); } + #endif diff --git a/dom/canvas/WebGLProgram.cpp b/dom/canvas/WebGLProgram.cpp index fa7997f22..9b204358b 100644 --- a/dom/canvas/WebGLProgram.cpp +++ b/dom/canvas/WebGLProgram.cpp @@ -17,6 +17,7 @@ #include "WebGLTransformFeedback.h" #include "WebGLUniformLocation.h" #include "WebGLValidateStrings.h" +#include "WebGLObjectModel.h" namespace mozilla { diff --git a/dom/canvas/WebGLTransformFeedback.cpp b/dom/canvas/WebGLTransformFeedback.cpp index feec581ea..78e366531 100644 --- a/dom/canvas/WebGLTransformFeedback.cpp +++ b/dom/canvas/WebGLTransformFeedback.cpp @@ -8,6 +8,7 @@ #include "GLContext.h" #include "mozilla/dom/WebGL2RenderingContextBinding.h" #include "WebGL2Context.h" +#include "WebGLProgram.h" namespace mozilla { diff --git a/dom/canvas/moz.build b/dom/canvas/moz.build index 2b2ceba52..f7555b33d 100644 --- a/dom/canvas/moz.build +++ b/dom/canvas/moz.build @@ -25,11 +25,6 @@ EXPORTS += [ 'nsICanvasRenderingContextInternal.h', ] -EXPORTS.mozilla.ipc += [ - 'DocumentRendererChild.h', - 'DocumentRendererParent.h', -] - EXPORTS.mozilla.dom += [ 'CanvasGradient.h', 'CanvasPath.h', @@ -52,8 +47,6 @@ UNIFIED_SOURCES += [ 'CanvasRenderingContext2D.cpp', 'CanvasRenderingContextHelper.cpp', 'CanvasUtils.cpp', - 'DocumentRendererChild.cpp', - 'DocumentRendererParent.cpp', 'ImageBitmap.cpp', 'ImageBitmapColorUtils.cpp', 'ImageBitmapRenderingContext.cpp', @@ -162,7 +155,7 @@ SOURCES += [ ] # Suppress warnings from third-party code. -if CONFIG['CLANG_CXX']: +if CONFIG['CLANG_CXX'] or CONFIG['GNU_CXX']: SOURCES['MurmurHash3.cpp'].flags += ['-Wno-implicit-fallthrough'] LOCAL_INCLUDES += [ diff --git a/dom/canvas/test/webgl-mochitest/mochitest.ini b/dom/canvas/test/webgl-mochitest/mochitest.ini index d5bc8701d..ddd0dd762 100644 --- a/dom/canvas/test/webgl-mochitest/mochitest.ini +++ b/dom/canvas/test/webgl-mochitest/mochitest.ini @@ -14,7 +14,7 @@ fail-if = (os == 'android') [ensure-exts/test_EXT_color_buffer_half_float.html] fail-if = (os == 'android') [ensure-exts/test_EXT_disjoint_timer_query.html] -fail-if = (os == 'android') || (os == 'mac') || (os == 'win' && os_version == '5.1') +fail-if = 1 [ensure-exts/test_EXT_frag_depth.html] fail-if = (os == 'android') [ensure-exts/test_EXT_sRGB.html] diff --git a/dom/console/Console.cpp b/dom/console/Console.cpp index 9ede26501..79e3eadc5 100644..100755 --- a/dom/console/Console.cpp +++ b/dom/console/Console.cpp @@ -30,6 +30,7 @@ #include "nsContentUtils.h" #include "nsDocShell.h" #include "nsProxyRelease.h" +#include "mozilla/TimerClamping.h" #include "mozilla/ConsoleTimelineMarker.h" #include "mozilla/TimestampTimelineMarker.h" @@ -1338,7 +1339,7 @@ Console::MethodInternal(JSContext* aCx, MethodName aMethodName, TimeDuration duration = mozilla::TimeStamp::Now() - workerPrivate->NowBaseTimeStamp(); - monotonicTimer = duration.ToMilliseconds(); + monotonicTimer = TimerClamping::ReduceMsTimeValue(duration.ToMilliseconds()); } } diff --git a/dom/events/Event.cpp b/dom/events/Event.cpp index a85a0d66b..2af34136e 100644..100755 --- a/dom/events/Event.cpp +++ b/dom/events/Event.cpp @@ -32,6 +32,7 @@ #include "nsJSEnvironment.h" #include "nsLayoutUtils.h" #include "nsPIWindowRoot.h" +#include "mozilla/TimerClamping.h" #include "WorkerPrivate.h" namespace mozilla { @@ -1085,6 +1086,12 @@ Event::DefaultPrevented(JSContext* aCx) const double Event::TimeStamp() const { + return TimerClamping::ReduceMsTimeValue(TimeStampImpl()); +} + +double +Event::TimeStampImpl() const +{ if (!sReturnHighResTimeStamp) { return static_cast<double>(mEvent->mTime); } diff --git a/dom/events/Event.h b/dom/events/Event.h index 4ac6a68d5..c28226e8a 100644..100755 --- a/dom/events/Event.h +++ b/dom/events/Event.h @@ -62,6 +62,7 @@ private: void ConstructorInit(EventTarget* aOwner, nsPresContext* aPresContext, WidgetEvent* aEvent); + double TimeStampImpl() const; public: static Event* FromSupports(nsISupports* aSupports) diff --git a/dom/events/EventListenerManager.cpp b/dom/events/EventListenerManager.cpp index c8db4f2a1..a8c48ede8 100644 --- a/dom/events/EventListenerManager.cpp +++ b/dom/events/EventListenerManager.cpp @@ -996,14 +996,12 @@ EventListenerManager::CompileEventHandlerInternal(Listener* aListener, } aListener = nullptr; - uint32_t lineNo = 0; nsAutoCString url (NS_LITERAL_CSTRING("-moz-evil:lying-event-listener")); MOZ_ASSERT(body); MOZ_ASSERT(aElement); nsIURI *uri = aElement->OwnerDoc()->GetDocumentURI(); if (uri) { uri->GetSpec(url); - lineNo = 1; } nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(mTarget); @@ -1073,8 +1071,9 @@ EventListenerManager::CompileEventHandlerInternal(Listener* aListener, return NS_ERROR_FAILURE; } JS::CompileOptions options(cx); + // Use line 0 to make the function body starts from line 1. options.setIntroductionType("eventHandler") - .setFileAndLine(url.get(), lineNo) + .setFileAndLine(url.get(), 0) .setVersion(JSVERSION_DEFAULT) .setElement(&v.toObject()) .setElementAttributeName(jsStr); diff --git a/dom/events/EventNameList.h b/dom/events/EventNameList.h index b1be6dd76..ba2427623 100644 --- a/dom/events/EventNameList.h +++ b/dom/events/EventNameList.h @@ -674,6 +674,10 @@ DOCUMENT_ONLY_EVENT(selectionchange, eSelectionChange, EventNameType_HTMLXUL, eBasicEventClass) +DOCUMENT_ONLY_EVENT(visibilitychange, + eVisibilityChange, + EventNameType_HTMLXUL, + eBasicEventClass) NON_IDL_EVENT(MozMouseHittest, eMouseHitTest, diff --git a/dom/events/EventStateManager.cpp b/dom/events/EventStateManager.cpp index 659629066..c23cdb575 100644 --- a/dom/events/EventStateManager.cpp +++ b/dom/events/EventStateManager.cpp @@ -4151,9 +4151,10 @@ EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent, // content associated with our subdocument. EnsureDocument(mPresContext); if (nsIDocument *parentDoc = mDocument->GetParentDocument()) { - if (nsIContent *docContent = parentDoc->FindContentForSubDocument(mDocument)) { + if (nsCOMPtr<nsIContent> docContent = + parentDoc->FindContentForSubDocument(mDocument)) { if (nsIPresShell *parentShell = parentDoc->GetShell()) { - EventStateManager* parentESM = + RefPtr<EventStateManager> parentESM = parentShell->GetPresContext()->EventStateManager(); parentESM->NotifyMouseOver(aMouseEvent, docContent); } diff --git a/dom/events/test/test_eventTimeStamp.html b/dom/events/test/test_eventTimeStamp.html index a3d096432..107a21f87 100644 --- a/dom/events/test/test_eventTimeStamp.html +++ b/dom/events/test/test_eventTimeStamp.html @@ -60,8 +60,8 @@ function testRegularEvents() { var timeBeforeEvent = window.performance.now(); window.addEventListener("load", function(evt) { var timeAfterEvent = window.performance.now(); - ok(evt.timeStamp > timeBeforeEvent && - evt.timeStamp < timeAfterEvent, + ok(evt.timeStamp >= timeBeforeEvent && + evt.timeStamp <= timeAfterEvent, "Event timestamp (" + evt.timeStamp + ") is in expected range: (" + timeBeforeEvent + ", " + timeAfterEvent + ")"); testWorkerEvents(); @@ -74,11 +74,12 @@ function testWorkerEvents() { var worker = new Worker(window.URL.createObjectURL(blob)); worker.onmessage = function(evt) { var timeAfterEvent = window.performance.now(); - ok(evt.data > timeBeforeEvent && - evt.data < timeAfterEvent, - "Event timestamp in dedicated worker (" + evt.data + - ") is in expected range: (" + - timeBeforeEvent + ", " + timeAfterEvent + ")"); + // Comparing times across timelines may break now + // ok(evt.data >= timeBeforeEvent && + // evt.data <= timeAfterEvent, + // "Event timestamp in dedicated worker (" + evt.data + + // ") is in expected range: (" + + // timeBeforeEvent + ", " + timeAfterEvent + ")"); worker.terminate(); testSharedWorkerEvents(); }; @@ -97,11 +98,12 @@ function testSharedWorkerEvents() { var worker = new SharedWorker(window.URL.createObjectURL(blob)); worker.port.onmessage = function(evt) { var timeAfterEvent = window.performance.now(); - ok(evt.data > 0 && - evt.data < timeAfterEvent - timeBeforeWorkerCreation, - "Event timestamp in shared worker (" + evt.data + - ") is in expected range: (0, " + - (timeAfterEvent - timeBeforeWorkerCreation) + ")"); + // Comparing times across timelines may break now + // ok(evt.data >= 0 && + // evt.data <= timeAfterEvent - timeBeforeWorkerCreation, + // "Event timestamp in shared worker (" + evt.data + + // ") is in expected range: (0, " + + // (timeAfterEvent - timeBeforeWorkerCreation) + ")"); worker.port.close(); finishTests(); }; diff --git a/dom/html/HTMLAllCollection.cpp b/dom/html/HTMLAllCollection.cpp index afa160e0c..6305cce31 100644 --- a/dom/html/HTMLAllCollection.cpp +++ b/dom/html/HTMLAllCollection.cpp @@ -8,6 +8,7 @@ #include "mozilla/dom/HTMLAllCollectionBinding.h" #include "mozilla/dom/Nullable.h" +#include "mozilla/dom/Element.h" #include "nsHTMLDocument.h" namespace mozilla { @@ -86,14 +87,14 @@ IsAllNamedElement(nsIContent* aContent) } static bool -DocAllResultMatch(nsIContent* aContent, int32_t aNamespaceID, nsIAtom* aAtom, +DocAllResultMatch(Element* aElement, int32_t aNamespaceID, nsIAtom* aAtom, void* aData) { - if (aContent->GetID() == aAtom) { + if (aElement->GetID() == aAtom) { return true; } - nsGenericHTMLElement* elm = nsGenericHTMLElement::FromContent(aContent); + nsGenericHTMLElement* elm = nsGenericHTMLElement::FromContent(aElement); if (!elm) { return false; } diff --git a/dom/html/HTMLDataListElement.cpp b/dom/html/HTMLDataListElement.cpp index d9ad4da09..5aa772645 100644 --- a/dom/html/HTMLDataListElement.cpp +++ b/dom/html/HTMLDataListElement.cpp @@ -35,11 +35,11 @@ NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement) NS_IMPL_ELEMENT_CLONE(HTMLDataListElement) bool -HTMLDataListElement::MatchOptions(nsIContent* aContent, int32_t aNamespaceID, +HTMLDataListElement::MatchOptions(Element* aElement, int32_t aNamespaceID, nsIAtom* aAtom, void* aData) { - return aContent->NodeInfo()->Equals(nsGkAtoms::option, kNameSpaceID_XHTML) && - !aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::disabled); + return aElement->NodeInfo()->Equals(nsGkAtoms::option, kNameSpaceID_XHTML) && + !aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::disabled); } } // namespace dom diff --git a/dom/html/HTMLDataListElement.h b/dom/html/HTMLDataListElement.h index e0aff818b..ba2a2e0b4 100644 --- a/dom/html/HTMLDataListElement.h +++ b/dom/html/HTMLDataListElement.h @@ -37,8 +37,8 @@ public: virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override; // This function is used to generate the nsContentList (option elements). - static bool MatchOptions(nsIContent* aContent, int32_t aNamespaceID, - nsIAtom* aAtom, void* aData); + static bool MatchOptions(Element* aElement, int32_t aNamespaceID, + nsIAtom* aAtom, void* aData); NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLDataListElement, nsGenericHTMLElement) diff --git a/dom/html/HTMLFieldSetElement.cpp b/dom/html/HTMLFieldSetElement.cpp index 865d3c9cf..d72fd1061 100644 --- a/dom/html/HTMLFieldSetElement.cpp +++ b/dom/html/HTMLFieldSetElement.cpp @@ -120,10 +120,10 @@ HTMLFieldSetElement::GetType(nsAString& aType) /* static */ bool -HTMLFieldSetElement::MatchListedElements(nsIContent* aContent, int32_t aNamespaceID, +HTMLFieldSetElement::MatchListedElements(Element* aElement, int32_t aNamespaceID, nsIAtom* aAtom, void* aData) { - nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(aContent); + nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(aElement); return formControl; } diff --git a/dom/html/HTMLFieldSetElement.h b/dom/html/HTMLFieldSetElement.h index d169434ae..96fff4582 100644 --- a/dom/html/HTMLFieldSetElement.h +++ b/dom/html/HTMLFieldSetElement.h @@ -124,8 +124,8 @@ private: void NotifyElementsForFirstLegendChange(bool aNotify); // This function is used to generate the nsContentList (listed form elements). - static bool MatchListedElements(nsIContent* aContent, int32_t aNamespaceID, - nsIAtom* aAtom, void* aData); + static bool MatchListedElements(Element* aElement, int32_t aNamespaceID, + nsIAtom* aAtom, void* aData); // listed form controls elements. RefPtr<nsContentList> mElements; diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp index 78f74ae0c..d46eccdbc 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -8800,6 +8800,16 @@ HTMLInputElement::GetWebkitEntries(nsTArray<RefPtr<FileSystemEntry>>& aSequence) aSequence.AppendElements(mEntries); } +already_AddRefed<nsINodeList> +HTMLInputElement::GetLabels() +{ + if (!IsLabelable()) { + return nullptr; + } + + return nsGenericHTMLElement::Labels(); +} + } // namespace dom } // namespace mozilla diff --git a/dom/html/HTMLInputElement.h b/dom/html/HTMLInputElement.h index e5d670e08..9ca876aee 100644 --- a/dom/html/HTMLInputElement.h +++ b/dom/html/HTMLInputElement.h @@ -704,6 +704,8 @@ public: // XPCOM GetCustomVisibility() is OK + already_AddRefed<nsINodeList> GetLabels(); + // XPCOM Select() is OK Nullable<int32_t> GetSelectionStart(ErrorResult& aRv); diff --git a/dom/html/HTMLLabelElement.cpp b/dom/html/HTMLLabelElement.cpp index c1d22b0a6..d1c037336 100644 --- a/dom/html/HTMLLabelElement.cpp +++ b/dom/html/HTMLLabelElement.cpp @@ -14,6 +14,7 @@ #include "nsFocusManager.h" #include "nsIDOMMouseEvent.h" #include "nsQueryObject.h" +#include "mozilla/dom/ShadowRoot.h" // construction, destruction @@ -268,17 +269,23 @@ HTMLLabelElement::GetLabeledElement() const return GetFirstLabelableDescendant(); } - // We have a @for. The id has to be linked to an element in the same document + // We have a @for. The id has to be linked to an element in the same tree // and this element should be a labelable form control. - //XXXsmaug It is unclear how this should work in case the element is in - // Shadow DOM. - // See https://www.w3.org/Bugs/Public/show_bug.cgi?id=26365. - nsIDocument* doc = GetUncomposedDoc(); - if (!doc) { - return nullptr; + nsINode* root = SubtreeRoot(); + ShadowRoot* shadow = ShadowRoot::FromNode(root); + Element* element = nullptr; + + if (shadow) { + element = shadow->GetElementById(elementId); + } else { + nsIDocument* doc = GetUncomposedDoc(); + if (doc) { + element = doc->GetElementById(elementId); + } else { + element = nsContentUtils::MatchElementId(root->AsContent(), elementId); + } } - Element* element = doc->GetElementById(elementId); if (element && element->IsLabelable()) { return static_cast<nsGenericHTMLElement*>(element); } diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp index e81cd20bc..1f1a545fa 100644 --- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -11,7 +11,9 @@ #include "mozilla/ArrayUtils.h" #include "mozilla/MathAlgorithms.h" #include "mozilla/AsyncEventDispatcher.h" +#ifdef MOZ_EME #include "mozilla/dom/MediaEncryptedEvent.h" +#endif #include "base/basictypes.h" #include "nsIDOMHTMLMediaElement.h" @@ -820,7 +822,9 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTM NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTextTrackManager) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAudioTrackList) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVideoTrackList) +#ifdef MOZ_EME NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaKeys) +#endif NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSelectedVideoStreamTrack) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END @@ -845,7 +849,9 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTMLE NS_IMPL_CYCLE_COLLECTION_UNLINK(mTextTrackManager) NS_IMPL_CYCLE_COLLECTION_UNLINK(mAudioTrackList) NS_IMPL_CYCLE_COLLECTION_UNLINK(mVideoTrackList) +#ifdef MOZ_EME NS_IMPL_CYCLE_COLLECTION_UNLINK(mMediaKeys) +#endif NS_IMPL_CYCLE_COLLECTION_UNLINK(mSelectedVideoStreamTrack) NS_IMPL_CYCLE_COLLECTION_UNLINK_END @@ -1020,12 +1026,14 @@ 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; @@ -1084,7 +1092,9 @@ void HTMLMediaElement::AbortExistingLoads() mDownloadSuspendedByCache = false; mMediaInfo = MediaInfo(); mIsEncrypted = false; +#ifdef MOZ_EME mPendingEncryptedInitData.mInitDatas.Clear(); +#endif mWaitingForKey = NOT_WAITING_FOR_KEY; mSourcePointer = nullptr; @@ -2681,9 +2691,11 @@ HTMLMediaElement::CaptureStreamInternal(bool aFinishWhenEnded, if (!window) { return nullptr; } +#ifdef MOZ_EME if (ContainsRestrictedContent()) { return nullptr; } +#endif if (!mOutputStreams.IsEmpty() && aGraph != mOutputStreams[0].mStream->GetInputStream()->Graph()) { @@ -3638,6 +3650,7 @@ void HTMLMediaElement::HiddenVideoStop() mVideoDecodeSuspendTimer = nullptr; } +#ifdef MOZ_EME void HTMLMediaElement::ReportEMETelemetry() { @@ -3649,6 +3662,7 @@ HTMLMediaElement::ReportEMETelemetry() this, mLoadedDataFired ? "true" : "false")); } } +#endif void HTMLMediaElement::ReportTelemetry() @@ -3997,6 +4011,7 @@ nsresult HTMLMediaElement::FinishDecoderSetup(MediaDecoder* aDecoder, ms.mFinishWhenEnded); } +#ifdef MOZ_EME if (mMediaKeys) { if (mMediaKeys->GetCDMProxy()) { mDecoder->SetCDMProxy(mMediaKeys->GetCDMProxy()); @@ -4006,6 +4021,7 @@ nsresult HTMLMediaElement::FinishDecoderSetup(MediaDecoder* aDecoder, return NS_ERROR_FAILURE; } } +#endif MediaEventSource<void>* waitingForKeyProducer = mDecoder->WaitingForKeyEvent(); // Not every decoder will produce waitingForKey events, only add ones that can @@ -4468,7 +4484,11 @@ void HTMLMediaElement::MetadataLoaded(const MediaInfo* aInfo, SetMediaInfo(*aInfo); - mIsEncrypted = aInfo->IsEncrypted() || mPendingEncryptedInitData.IsEncrypted(); + mIsEncrypted = aInfo->IsEncrypted() +#ifdef MOZ_EME + || mPendingEncryptedInitData.IsEncrypted() +#endif + ; mTags = aTags.forget(); mLoadedDataFired = false; ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_METADATA); @@ -4494,11 +4514,13 @@ void HTMLMediaElement::MetadataLoaded(const MediaInfo* aInfo, return; } +#ifdef MOZ_EME // Dispatch a distinct 'encrypted' event for each initData we have. for (const auto& initData : mPendingEncryptedInitData.mInitDatas) { DispatchEncrypted(initData.mInitData, initData.mType); } mPendingEncryptedInitData.mInitDatas.Clear(); +#endif } mWatchManager.ManualNotify(&HTMLMediaElement::UpdateReadyStateInternal); @@ -5431,9 +5453,12 @@ void HTMLMediaElement::SuspendOrResumeElement(bool aPauseElement, bool aSuspendE UpdateAudioChannelPlayingState(); if (aPauseElement) { ReportTelemetry(); +#ifdef MOZ_EME ReportEMETelemetry(); +#endif - // For EME content, force destruction of the CDM client (and CDM +#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 // the CDM's decoder. This ensures the CDM gets reliable and prompt // shutdown notifications, as it may have book-keeping it needs @@ -5445,6 +5470,7 @@ void HTMLMediaElement::SuspendOrResumeElement(bool aPauseElement, bool aSuspendE ShutdownDecoder(); } } +#endif if (mDecoder) { mDecoder->Pause(); mDecoder->Suspend(); @@ -5495,6 +5521,17 @@ void HTMLMediaElement::NotifyOwnerDocumentActivityChanged() bool pauseElement = ShouldElementBePaused(); SuspendOrResumeElement(pauseElement, !IsActive()); +#ifdef MOZ_EME + // If the owning document has become inactive we should shutdown the CDM. + if (!OwnerDoc()->IsCurrentActiveDocument() && mMediaKeys) { + mMediaKeys->Shutdown(); + mMediaKeys = nullptr; + if (mDecoder) { + ShutdownDecoder(); + } + } +#endif + AddRemoveSelfReference(); } @@ -6270,6 +6307,7 @@ HTMLMediaElement::OnVisibilityChange(Visibility aNewVisibility) } +#ifdef MOZ_EME MediaKeys* HTMLMediaElement::GetMediaKeys() const { @@ -6479,6 +6517,7 @@ HTMLMediaElement::GetTopLevelPrincipal() principal = doc->NodePrincipal(); return principal.forget(); } +#endif //MOZ_EME void HTMLMediaElement::CannotDecryptWaitingForKey() diff --git a/dom/html/HTMLMediaElement.h b/dom/html/HTMLMediaElement.h index d40e9df46..b65049206 100644 --- a/dom/html/HTMLMediaElement.h +++ b/dom/html/HTMLMediaElement.h @@ -20,7 +20,9 @@ #include "mozilla/dom/TextTrackManager.h" #include "mozilla/WeakPtr.h" #include "MediaDecoder.h" +#ifdef MOZ_EME #include "mozilla/dom/MediaKeys.h" +#endif #include "mozilla/StateWatching.h" #include "nsGkAtoms.h" #include "PrincipalChangeObserver.h" @@ -630,6 +632,7 @@ public: // XPCOM MozPreservesPitch() is OK +#ifdef MOZ_EME MediaKeys* GetMediaKeys() const; already_AddRefed<Promise> SetMediaKeys(MediaKeys* mediaKeys, @@ -651,6 +654,7 @@ public: already_AddRefed<nsIPrincipal> GetTopLevelPrincipal(); bool ContainsRestrictedContent(); +#endif // MOZ_EME void CannotDecryptWaitingForKey(); @@ -1198,7 +1202,9 @@ protected: */ void HiddenVideoStop(); +#ifdef MOZ_EME void ReportEMETelemetry(); +#endif void ReportTelemetry(); @@ -1471,8 +1477,10 @@ protected: // Timer used to simulate video-suspend. nsCOMPtr<nsITimer> mVideoDecodeSuspendTimer; +#ifdef MOZ_EME // Encrypted Media Extension media keys. RefPtr<MediaKeys> mMediaKeys; +#endif // Stores the time at the start of the current 'played' range. double mCurrentPlayRangeStart; @@ -1627,8 +1635,10 @@ protected: // Listens for waitingForKey events from the owned decoder. MediaEventListener mWaitingForKeyListener; +#ifdef MOZ_EME // Init Data that needs to be sent in 'encrypted' events in MetadataLoaded(). EncryptionInfo mPendingEncryptedInitData; +#endif // True if the media's channel's download has been suspended. Watchable<bool> mDownloadSuspendedByCache; diff --git a/dom/html/HTMLSelectElement.cpp b/dom/html/HTMLSelectElement.cpp index 24ddabb65..53f42317a 100644 --- a/dom/html/HTMLSelectElement.cpp +++ b/dom/html/HTMLSelectElement.cpp @@ -735,12 +735,12 @@ HTMLSelectElement::SetLength(uint32_t aLength, ErrorResult& aRv) /* static */ bool -HTMLSelectElement::MatchSelectedOptions(nsIContent* aContent, +HTMLSelectElement::MatchSelectedOptions(Element* aElement, int32_t /* unused */, nsIAtom* /* unused */, void* /* unused*/) { - HTMLOptionElement* option = HTMLOptionElement::FromContent(aContent); + HTMLOptionElement* option = HTMLOptionElement::FromContent(aElement); return option && option->Selected(); } diff --git a/dom/html/HTMLSelectElement.h b/dom/html/HTMLSelectElement.h index d7e4350b4..8a25385de 100644 --- a/dom/html/HTMLSelectElement.h +++ b/dom/html/HTMLSelectElement.h @@ -247,7 +247,7 @@ public: mOptions->IndexedSetter(aIndex, aOption, aRv); } - static bool MatchSelectedOptions(nsIContent* aContent, int32_t, nsIAtom*, + static bool MatchSelectedOptions(Element* aElement, int32_t, nsIAtom*, void*); nsIHTMLCollection* SelectedOptions(); diff --git a/dom/html/HTMLTableRowElement.cpp b/dom/html/HTMLTableRowElement.cpp index 2dec9c883..ac2463400 100644 --- a/dom/html/HTMLTableRowElement.cpp +++ b/dom/html/HTMLTableRowElement.cpp @@ -120,10 +120,10 @@ HTMLTableRowElement::SectionRowIndex() const } static bool -IsCell(nsIContent *aContent, int32_t aNamespaceID, +IsCell(Element *aElement, int32_t aNamespaceID, nsIAtom* aAtom, void *aData) { - return aContent->IsAnyOfHTMLElements(nsGkAtoms::td, nsGkAtoms::th); + return aElement->IsAnyOfHTMLElements(nsGkAtoms::td, nsGkAtoms::th); } nsIHTMLCollection* diff --git a/dom/html/nsGenericHTMLElement.cpp b/dom/html/nsGenericHTMLElement.cpp index d75001a83..2f890325a 100644 --- a/dom/html/nsGenericHTMLElement.cpp +++ b/dom/html/nsGenericHTMLElement.cpp @@ -108,6 +108,7 @@ #include "mozilla/StyleSetHandle.h" #include "mozilla/StyleSetHandleInlines.h" #include "ReferrerPolicy.h" +#include "mozilla/dom/HTMLLabelElement.h" using namespace mozilla; using namespace mozilla::dom; @@ -493,6 +494,14 @@ nsGenericHTMLElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, } } + // We need to consider a labels element is moved to another subtree + // with different root, it needs to update labels list and its root + // as well. + nsDOMSlots* slots = GetExistingDOMSlots(); + if (slots && slots->mLabelsList) { + slots->mLabelsList->MaybeResetRoot(SubtreeRoot()); + } + return rv; } @@ -513,6 +522,13 @@ nsGenericHTMLElement::UnbindFromTree(bool aDeep, bool aNullParent) } } + // We need to consider a labels element is removed from tree, + // it needs to update labels list and its root as well. + nsDOMSlots* slots = GetExistingDOMSlots(); + if (slots && slots->mLabelsList) { + slots->mLabelsList->MaybeResetRoot(SubtreeRoot()); + } + nsStyledElement::UnbindFromTree(aDeep, aNullParent); } @@ -1701,6 +1717,30 @@ nsGenericHTMLElement::IsLabelable() const return IsAnyOfHTMLElements(nsGkAtoms::progress, nsGkAtoms::meter); } +/* static */ bool +nsGenericHTMLElement::MatchLabelsElement(Element* aElement, int32_t aNamespaceID, + nsIAtom* aAtom, void* aData) +{ + HTMLLabelElement* element = HTMLLabelElement::FromContent(aElement); + return element && element->GetControl() == aData; +} + +already_AddRefed<nsINodeList> +nsGenericHTMLElement::Labels() +{ + MOZ_ASSERT(IsLabelable(), + "Labels() only allow labelable elements to use it."); + nsDOMSlots* slots = DOMSlots(); + + if (!slots->mLabelsList) { + slots->mLabelsList = new nsLabelsNodeList(SubtreeRoot(), MatchLabelsElement, + nullptr, this); + } + + RefPtr<nsLabelsNodeList> labels = slots->mLabelsList; + return labels.forget(); +} + bool nsGenericHTMLElement::IsInteractiveHTMLContent(bool aIgnoreTabindex) const { diff --git a/dom/html/nsGenericHTMLElement.h b/dom/html/nsGenericHTMLElement.h index 3cca41c3d..0635c27e1 100644 --- a/dom/html/nsGenericHTMLElement.h +++ b/dom/html/nsGenericHTMLElement.h @@ -834,6 +834,12 @@ public: } virtual bool IsLabelable() const override; + + static bool MatchLabelsElement(Element* aElement, int32_t aNamespaceID, + nsIAtom* aAtom, void* aData); + + already_AddRefed<nsINodeList> Labels(); + virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const override; static bool TouchEventsEnabled(JSContext* /* unused */, JSObject* /* unused */); diff --git a/dom/html/nsHTMLDocument.cpp b/dom/html/nsHTMLDocument.cpp index 7d66aab04..be5a34d41 100644 --- a/dom/html/nsHTMLDocument.cpp +++ b/dom/html/nsHTMLDocument.cpp @@ -1100,31 +1100,31 @@ nsHTMLDocument::Applets() } bool -nsHTMLDocument::MatchLinks(nsIContent *aContent, int32_t aNamespaceID, +nsHTMLDocument::MatchLinks(Element* aElement, int32_t aNamespaceID, nsIAtom* aAtom, void* aData) { - nsIDocument* doc = aContent->GetUncomposedDoc(); + nsIDocument* doc = aElement->GetUncomposedDoc(); if (doc) { - NS_ASSERTION(aContent->IsInUncomposedDoc(), + NS_ASSERTION(aElement->IsInUncomposedDoc(), "This method should never be called on content nodes that " "are not in a document!"); #ifdef DEBUG { nsCOMPtr<nsIHTMLDocument> htmldoc = - do_QueryInterface(aContent->GetUncomposedDoc()); + do_QueryInterface(aElement->GetUncomposedDoc()); NS_ASSERTION(htmldoc, "Huh, how did this happen? This should only be used with " "HTML documents!"); } #endif - mozilla::dom::NodeInfo *ni = aContent->NodeInfo(); + mozilla::dom::NodeInfo *ni = aElement->NodeInfo(); nsIAtom *localName = ni->NameAtom(); if (ni->NamespaceID() == kNameSpaceID_XHTML && (localName == nsGkAtoms::a || localName == nsGkAtoms::area)) { - return aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::href); + return aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::href); } } @@ -1148,24 +1148,24 @@ nsHTMLDocument::Links() } bool -nsHTMLDocument::MatchAnchors(nsIContent *aContent, int32_t aNamespaceID, +nsHTMLDocument::MatchAnchors(Element* aElement, int32_t aNamespaceID, nsIAtom* aAtom, void* aData) { - NS_ASSERTION(aContent->IsInUncomposedDoc(), + NS_ASSERTION(aElement->IsInUncomposedDoc(), "This method should never be called on content nodes that " "are not in a document!"); #ifdef DEBUG { nsCOMPtr<nsIHTMLDocument> htmldoc = - do_QueryInterface(aContent->GetUncomposedDoc()); + do_QueryInterface(aElement->GetUncomposedDoc()); NS_ASSERTION(htmldoc, "Huh, how did this happen? This should only be used with " "HTML documents!"); } #endif - if (aContent->NodeInfo()->Equals(nsGkAtoms::a, kNameSpaceID_XHTML)) { - return aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::name); + if (aElement->IsHTMLElement(nsGkAtoms::a)) { + return aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::name); } return false; @@ -1536,6 +1536,18 @@ nsHTMLDocument::Open(JSContext* cx, nsCOMPtr<nsIDocument> ret = this; return ret.forget(); } + + // Now double-check that our invariants still hold. + if (!mScriptGlobalObject) { + nsCOMPtr<nsIDocument> ret = this; + return ret.forget(); + } + + nsPIDOMWindowOuter* outer = GetWindow(); + if (!outer || (GetInnerWindow() != outer->GetCurrentInnerWindow())) { + nsCOMPtr<nsIDocument> ret = this; + return ret.forget(); + } } nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(shell)); @@ -1952,14 +1964,14 @@ nsHTMLDocument::Writeln(JSContext* cx, const Sequence<nsString>& aText, } bool -nsHTMLDocument::MatchNameAttribute(nsIContent* aContent, int32_t aNamespaceID, +nsHTMLDocument::MatchNameAttribute(Element* aElement, int32_t aNamespaceID, nsIAtom* aAtom, void* aData) { - NS_PRECONDITION(aContent, "Must have content node to work with!"); + NS_PRECONDITION(aElement, "Must have element to work with!"); nsString* elementName = static_cast<nsString*>(aData); return - aContent->GetNameSpaceID() == kNameSpaceID_XHTML && - aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name, + aElement->GetNameSpaceID() == kNameSpaceID_XHTML && + aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name, *elementName, eCaseMatters); } @@ -2279,10 +2291,10 @@ nsHTMLDocument::GetForms() return mForms; } -static bool MatchFormControls(nsIContent* aContent, int32_t aNamespaceID, - nsIAtom* aAtom, void* aData) +static bool MatchFormControls(Element* aElement, int32_t aNamespaceID, + nsIAtom* aAtom, void* aData) { - return aContent->IsNodeOfType(nsIContent::eHTML_FORM_CONTROL); + return aElement->IsNodeOfType(nsIContent::eHTML_FORM_CONTROL); } nsContentList* diff --git a/dom/html/nsHTMLDocument.h b/dom/html/nsHTMLDocument.h index 2dbbf2b57..426ebddc5 100644 --- a/dom/html/nsHTMLDocument.h +++ b/dom/html/nsHTMLDocument.h @@ -261,12 +261,13 @@ protected: nsIContent *MatchId(nsIContent *aContent, const nsAString& aId); - static bool MatchLinks(nsIContent *aContent, int32_t aNamespaceID, + static bool MatchLinks(mozilla::dom::Element* aElement, int32_t aNamespaceID, + nsIAtom* aAtom, void* aData); + static bool MatchAnchors(mozilla::dom::Element* aElement, int32_t aNamespaceID, nsIAtom* aAtom, void* aData); - static bool MatchAnchors(nsIContent *aContent, int32_t aNamespaceID, - nsIAtom* aAtom, void* aData); - static bool MatchNameAttribute(nsIContent* aContent, int32_t aNamespaceID, - nsIAtom* aAtom, void* aData); + static bool MatchNameAttribute(mozilla::dom::Element* aElement, + int32_t aNamespaceID, + nsIAtom* aAtom, void* aData); static void* UseExistingNameString(nsINode* aRootNode, const nsString* aName); static void DocumentWriteTerminationFunc(nsISupports *aRef); diff --git a/dom/html/test/forms/test_button_attributes_reflection.html b/dom/html/test/forms/test_button_attributes_reflection.html index 26858e939..4e702b3ac 100644 --- a/dom/html/test/forms/test_button_attributes_reflection.html +++ b/dom/html/test/forms/test_button_attributes_reflection.html @@ -128,9 +128,12 @@ is(typeof(document.createElement("button").setCustomValidity), "function", "button.setCustomValidity should be a function"); // .labels -todo("labels" in document.createElement("button"), - "button.labels isn't implemented yet"); - +ok("labels" in document.createElement("button"), + "button.labels should be an IDL attribute of the button element"); +is(typeof(document.createElement("button").labels), "object", + "button.labels should be an object"); +ok(document.createElement("button").labels instanceof NodeList, + "button.labels sohuld be an instance of NodeList"); </script> </pre> </body> diff --git a/dom/interfaces/security/nsIContentSecurityPolicy.idl b/dom/interfaces/security/nsIContentSecurityPolicy.idl index ade5b1243..da4297f33 100644 --- a/dom/interfaces/security/nsIContentSecurityPolicy.idl +++ b/dom/interfaces/security/nsIContentSecurityPolicy.idl @@ -61,6 +61,7 @@ interface nsIContentSecurityPolicy : nsISerializable const unsigned short BLOCK_ALL_MIXED_CONTENT = 19; const unsigned short REQUIRE_SRI_FOR = 20; const unsigned short SANDBOX_DIRECTIVE = 21; + const unsigned short WORKER_SRC_DIRECTIVE = 22; /** * Accessor method for a read-only string version of the policy at a given @@ -98,6 +99,11 @@ interface nsIContentSecurityPolicy : nsISerializable readonly attribute bool blockAllMixedContent; /** + * Returns whether this policy enforces the frame-ancestors directive. + */ + readonly attribute bool enforcesFrameAncestors; + + /** * Obtains the referrer policy (as integer) for this browsing context as * specified in CSP. If there are multiple policies and... * - only one sets a referrer policy: that policy is returned diff --git a/dom/ipc/PBrowser.ipdl b/dom/ipc/PBrowser.ipdl index 249657c26..9dfccbc5c 100644 --- a/dom/ipc/PBrowser.ipdl +++ b/dom/ipc/PBrowser.ipdl @@ -11,7 +11,6 @@ include protocol PContent; include protocol PContentBridge; include protocol PDatePicker; include protocol PDocAccessible; -include protocol PDocumentRenderer; include protocol PFilePicker; include protocol PIndexedDBPermissionRequest; include protocol PRenderFrame; @@ -119,7 +118,6 @@ nested(upto inside_cpow) sync protocol PBrowser manages PColorPicker; manages PDatePicker; manages PDocAccessible; - manages PDocumentRenderer; manages PFilePicker; manages PIndexedDBPermissionRequest; manages PRenderFrame; @@ -739,24 +737,6 @@ child: async LoadRemoteScript(nsString aURL, bool aRunInGlobalScope); /** - * Create a asynchronous request to render whatever document is - * loaded in the child when this message arrives. When the - * request finishes, PDocumentRenderer:__delete__ is sent back to - * this side to notify completion. - * - * |documentRect| is the area of the remote document to draw, - * transformed by |transform|. The rendered area will have the - * default background color |bgcolor|. |renderFlags| are the - * nsIPresShell::RenderDocument() flags to use on the remote side, - * and if true, |flushLayout| will do just that before rendering - * the document. The rendered image will be of size |renderSize|. - */ - async PDocumentRenderer(nsRect documentRect, Matrix transform, - nsString bgcolor, - uint32_t renderFlags, bool flushLayout, - IntSize renderSize); - - /** * Sent by the chrome process when it no longer wants this remote * <browser>. The child side cleans up in response, then * finalizing its death by sending back __delete__() to the diff --git a/dom/ipc/PDocumentRenderer.ipdl b/dom/ipc/PDocumentRenderer.ipdl deleted file mode 100644 index bdaed45d7..000000000 --- a/dom/ipc/PDocumentRenderer.ipdl +++ /dev/null @@ -1,25 +0,0 @@ -/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */ -/* 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 protocol PBrowser; - -include "mozilla/GfxMessageUtils.h"; - -using nsIntSize from "nsSize.h"; - -namespace mozilla { -namespace ipc { - -protocol PDocumentRenderer -{ - manager PBrowser; - -parent: - // Returns the width and height, in pixels, of the returned ARGB32 data. - async __delete__(nsIntSize renderedSize, nsCString data); -}; - -} // namespace ipc -} // namespace mozilla diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp index eaf4a32ed..f46a917d5 100644 --- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -22,7 +22,6 @@ #include "mozilla/dom/indexedDB/PIndexedDBPermissionRequestChild.h" #include "mozilla/plugins/PluginWidgetChild.h" #include "mozilla/IMEStateManager.h" -#include "mozilla/ipc/DocumentRendererChild.h" #include "mozilla/ipc/URIUtils.h" #include "mozilla/layers/APZChild.h" #include "mozilla/layers/APZCCallbackHelper.h" @@ -2006,57 +2005,6 @@ TabChild::DeallocPDocAccessibleChild(a11y::PDocAccessibleChild* aChild) return true; } -PDocumentRendererChild* -TabChild::AllocPDocumentRendererChild(const nsRect& documentRect, - const mozilla::gfx::Matrix& transform, - const nsString& bgcolor, - const uint32_t& renderFlags, - const bool& flushLayout, - const nsIntSize& renderSize) -{ - return new DocumentRendererChild(); -} - -bool -TabChild::DeallocPDocumentRendererChild(PDocumentRendererChild* actor) -{ - delete actor; - return true; -} - -bool -TabChild::RecvPDocumentRendererConstructor(PDocumentRendererChild* actor, - const nsRect& documentRect, - const mozilla::gfx::Matrix& transform, - const nsString& bgcolor, - const uint32_t& renderFlags, - const bool& flushLayout, - const nsIntSize& renderSize) -{ - DocumentRendererChild *render = static_cast<DocumentRendererChild *>(actor); - - nsCOMPtr<nsIWebBrowser> browser = do_QueryInterface(WebNavigation()); - if (!browser) - return true; // silently ignore - nsCOMPtr<mozIDOMWindowProxy> window; - if (NS_FAILED(browser->GetContentDOMWindow(getter_AddRefs(window))) || - !window) - { - return true; // silently ignore - } - - nsCString data; - bool ret = render->RenderDocument(nsPIDOMWindowOuter::From(window), - documentRect, transform, - bgcolor, - renderFlags, flushLayout, - renderSize, data); - if (!ret) - return true; // silently ignore - - return PDocumentRendererChild::Send__delete__(actor, renderSize, data); -} - PColorPickerChild* TabChild::AllocPColorPickerChild(const nsString&, const nsString&) { diff --git a/dom/ipc/TabChild.h b/dom/ipc/TabChild.h index b23c7c19e..2232ffeaf 100644 --- a/dom/ipc/TabChild.h +++ b/dom/ipc/TabChild.h @@ -445,27 +445,6 @@ public: virtual bool DeallocPDocAccessibleChild(PDocAccessibleChild*) override; - virtual PDocumentRendererChild* - AllocPDocumentRendererChild(const nsRect& aDocumentRect, - const gfx::Matrix& aTransform, - const nsString& aBggcolor, - const uint32_t& aRenderFlags, - const bool& aFlushLayout, - const nsIntSize& arenderSize) override; - - virtual bool - DeallocPDocumentRendererChild(PDocumentRendererChild* aCctor) override; - - virtual bool - RecvPDocumentRendererConstructor(PDocumentRendererChild* aActor, - const nsRect& aDocumentRect, - const gfx::Matrix& aTransform, - const nsString& aBgcolor, - const uint32_t& aRenderFlags, - const bool& aFlushLayout, - const nsIntSize& aRenderSize) override; - - virtual PColorPickerChild* AllocPColorPickerChild(const nsString& aTitle, const nsString& aInitialColor) override; diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index 0df4c1253..8e98de3ce 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -28,7 +28,6 @@ #include "mozilla/gfx/GPUProcessManager.h" #include "mozilla/Hal.h" #include "mozilla/IMEStateManager.h" -#include "mozilla/ipc/DocumentRendererParent.h" #include "mozilla/jsipc/CrossProcessObjectWrappers.h" #include "mozilla/layers/AsyncDragMetrics.h" #include "mozilla/layers/InputAPZContext.h" @@ -957,24 +956,6 @@ TabParent::GetTopLevelDocAccessible() const return nullptr; } -PDocumentRendererParent* -TabParent::AllocPDocumentRendererParent(const nsRect& documentRect, - const gfx::Matrix& transform, - const nsString& bgcolor, - const uint32_t& renderFlags, - const bool& flushLayout, - const nsIntSize& renderSize) -{ - return new DocumentRendererParent(); -} - -bool -TabParent::DeallocPDocumentRendererParent(PDocumentRendererParent* actor) -{ - delete actor; - return true; -} - PFilePickerParent* TabParent::AllocPFilePickerParent(const nsString& aTitle, const int16_t& aMode) { diff --git a/dom/ipc/TabParent.h b/dom/ipc/TabParent.h index 43afb0538..09bb999f3 100644 --- a/dom/ipc/TabParent.h +++ b/dom/ipc/TabParent.h @@ -473,17 +473,6 @@ public: const ScrollableLayerGuid& aGuid, uint64_t aInputBlockId); - virtual PDocumentRendererParent* - AllocPDocumentRendererParent(const nsRect& documentRect, - const gfx::Matrix& transform, - const nsString& bgcolor, - const uint32_t& renderFlags, - const bool& flushLayout, - const nsIntSize& renderSize) override; - - virtual bool - DeallocPDocumentRendererParent(PDocumentRendererParent* actor) override; - virtual PFilePickerParent* AllocPFilePickerParent(const nsString& aTitle, const int16_t& aMode) override; diff --git a/dom/ipc/moz.build b/dom/ipc/moz.build index 153bd3aae..ff3880bc2 100644 --- a/dom/ipc/moz.build +++ b/dom/ipc/moz.build @@ -96,7 +96,6 @@ IPDL_SOURCES += [ 'PCrashReporter.ipdl', 'PCycleCollectWithLogs.ipdl', 'PDatePicker.ipdl', - 'PDocumentRenderer.ipdl', 'PFilePicker.ipdl', 'PMemoryReportRequest.ipdl', 'PPluginWidget.ipdl', diff --git a/dom/locales/en-US/chrome/security/csp.properties b/dom/locales/en-US/chrome/security/csp.properties index fc7fc04ba..4c4054cee 100644 --- a/dom/locales/en-US/chrome/security/csp.properties +++ b/dom/locales/en-US/chrome/security/csp.properties @@ -91,6 +91,10 @@ ignoringReportOnlyDirective = Ignoring sandbox directive when delivered in a rep # LOCALIZATION NOTE (deprecatedReferrerDirective): # %1$S is the value of the deprecated Referrer Directive. deprecatedReferrerDirective = Referrer Directive ‘%1$S’ has been deprecated. Please use the Referrer-Policy header instead. +# LOCALIZATION NOTE (IgnoringSrcBecauseOfDirective): +# %1$S is the name of the src that is ignored. +# %2$S is the name of the directive that causes the src to be ignored. +IgnoringSrcBecauseOfDirective=Ignoring ‘%1$S’ because of ‘%2$S’ directive. # CSP Errors: # LOCALIZATION NOTE (couldntParseInvalidSource): @@ -108,9 +112,10 @@ couldntParsePort = Couldn’t parse port in %1$S # LOCALIZATION NOTE (duplicateDirective): # %1$S is the name of the duplicate directive duplicateDirective = Duplicate %1$S directives detected. All but the first instance will be ignored. -# LOCALIZATION NOTE (deprecatedDirective): -# %1$S is the name of the deprecated directive, %2$S is the name of the replacement. -deprecatedDirective = Directive ‘%1$S’ has been deprecated. Please use directive ‘%2$S’ instead. +# LOCALIZATION NOTE (deprecatedChildSrcDirective): +# %1$S is the value of the deprecated directive. +# Do not localize: worker-src, frame-src +deprecatedChildSrcDirective = Directive ‘%1$S’ has been deprecated. Please use directive ‘worker-src’ to control workers, or directive ‘frame-src’ to control frames respectively. # LOCALIZATION NOTE (couldntParseInvalidSandboxFlag): # %1$S is the option that could not be understood couldntParseInvalidSandboxFlag = Couldn’t parse invalid sandbox flag ‘%1$S’ diff --git a/dom/media/DOMMediaStream.cpp b/dom/media/DOMMediaStream.cpp index 6794ee32f..c1d451035 100644..100755 --- a/dom/media/DOMMediaStream.cpp +++ b/dom/media/DOMMediaStream.cpp @@ -9,6 +9,7 @@ #include "nsIScriptError.h" #include "nsIUUIDGenerator.h" #include "nsPIDOMWindow.h" +#include "mozilla/TimerClamping.h" #include "mozilla/dom/MediaStreamBinding.h" #include "mozilla/dom/MediaStreamTrackEvent.h" #include "mozilla/dom/LocalMediaStreamBinding.h" @@ -544,8 +545,8 @@ DOMMediaStream::CurrentTime() if (!mPlaybackStream) { return 0.0; } - return mPlaybackStream-> - StreamTimeToSeconds(mPlaybackStream->GetCurrentTime() - mLogicalStreamStartTime); + return TimerClamping::ReduceSTimeValue(mPlaybackStream-> + StreamTimeToSeconds(mPlaybackStream->GetCurrentTime() - mLogicalStreamStartTime)); } void diff --git a/dom/media/GraphDriver.cpp b/dom/media/GraphDriver.cpp index 9b74bd58c..40e3b72cf 100644 --- a/dom/media/GraphDriver.cpp +++ b/dom/media/GraphDriver.cpp @@ -1055,6 +1055,7 @@ AudioCallbackDriver::StateCallback(cubeb_state aState) { STREAM_LOG(LogLevel::Debug, ("AudioCallbackDriver State: %d", aState)); if (aState == CUBEB_STATE_ERROR && mShouldFallbackIfError) { + mShouldFallbackIfError = false; MonitorAutoLock lock(GraphImpl()->GetMonitor()); // Fall back to a driver using a normal thread. If needed, // the graph will try to re-open an audio stream later. diff --git a/dom/media/MediaData.cpp b/dom/media/MediaData.cpp index 0439a7473..4a52c22ae 100644 --- a/dom/media/MediaData.cpp +++ b/dom/media/MediaData.cpp @@ -90,7 +90,7 @@ ValidatePlane(const VideoData::YCbCrBuffer::Plane& aPlane) return aPlane.mWidth <= PlanarYCbCrImage::MAX_DIMENSION && aPlane.mHeight <= PlanarYCbCrImage::MAX_DIMENSION && aPlane.mWidth * aPlane.mHeight < MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT && - aPlane.mStride > 0; + aPlane.mStride > 0 && aPlane.mWidth <= aPlane.mStride; } #ifdef MOZ_WIDGET_GONK diff --git a/dom/media/MediaDecoderOwner.h b/dom/media/MediaDecoderOwner.h index f884686fb..f993b4324 100644 --- a/dom/media/MediaDecoderOwner.h +++ b/dom/media/MediaDecoderOwner.h @@ -143,11 +143,13 @@ public: // reference to the decoder to prevent further calls into the decoder. virtual void NotifyXPCOMShutdown() = 0; +#ifdef MOZ_EME // Dispatches a "encrypted" event to the HTMLMediaElement, with the // provided init data. Actual dispatch may be delayed until HAVE_METADATA. // Main thread only. virtual void DispatchEncrypted(const nsTArray<uint8_t>& aInitData, const nsAString& aInitDataType) = 0; +#endif }; } // namespace mozilla diff --git a/dom/media/MediaFormatReader.cpp b/dom/media/MediaFormatReader.cpp index 2093803ad..06e8b963b 100644 --- a/dom/media/MediaFormatReader.cpp +++ b/dom/media/MediaFormatReader.cpp @@ -346,8 +346,12 @@ MediaFormatReader::DecoderFactory::DoCreateDecoder(TrackType aTrack) if (!mOwner->mPlatform) { mOwner->mPlatform = new PDMFactory(); if (mOwner->IsEncrypted()) { +#ifdef MOZ_EME MOZ_ASSERT(mOwner->mCDMProxy); mOwner->mPlatform->SetCDMProxy(mOwner->mCDMProxy); +#else + return MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, "EME not supported"); +#endif } } @@ -577,6 +581,7 @@ MediaFormatReader::InitInternal() return NS_OK; } +#ifdef MOZ_EME class DispatchKeyNeededEvent : public Runnable { public: DispatchKeyNeededEvent(AbstractMediaDecoder* aDecoder, @@ -602,6 +607,7 @@ private: nsTArray<uint8_t> mInitData; nsString mInitDataType; }; +#endif void MediaFormatReader::SetCDMProxy(CDMProxy* aProxy) @@ -618,7 +624,11 @@ MediaFormatReader::SetCDMProxy(CDMProxy* aProxy) bool MediaFormatReader::IsWaitingOnCDMResource() { MOZ_ASSERT(OnTaskQueue()); +#ifdef MOZ_EME return IsEncrypted() && !mCDMProxy; +#else + return false; +#endif } RefPtr<MediaDecoderReader::MetadataPromise> @@ -725,11 +735,13 @@ MediaFormatReader::OnDemuxerInitDone(nsresult) UniquePtr<EncryptionInfo> crypto = mDemuxer->GetCrypto(); if (mDecoder && crypto && crypto->IsEncrypted()) { +#ifdef MOZ_EME // Try and dispatch 'encrypted'. Won't go if ready state still HAVE_NOTHING. for (uint32_t i = 0; i < crypto->mInitDatas.Length(); i++) { NS_DispatchToMainThread( new DispatchKeyNeededEvent(mDecoder, crypto->mInitDatas[i].mInitData, crypto->mInitDatas[i].mType)); } +#endif mInfo.mCrypto = *crypto; } diff --git a/dom/media/MediaPrefs.h b/dom/media/MediaPrefs.h index 62b8fc47b..b237ecd3d 100644 --- a/dom/media/MediaPrefs.h +++ b/dom/media/MediaPrefs.h @@ -156,10 +156,6 @@ private: DECL_MEDIA_PREF("media.ogg.flac.enabled", FlacInOgg, bool, false); DECL_MEDIA_PREF("media.flac.enabled", FlacEnabled, bool, true); -#if defined(MOZ_RUST_MP4PARSE) && !defined(RELEASE_OR_BETA) - DECL_MEDIA_PREF("media.rust.test_mode", RustTestMode, bool, false); -#endif - public: // Manage the singleton: static MediaPrefs& GetSingleton(); diff --git a/dom/media/gtest/moz.build b/dom/media/gtest/moz.build index fc92d5ef3..d5d02bced 100644 --- a/dom/media/gtest/moz.build +++ b/dom/media/gtest/moz.build @@ -35,10 +35,6 @@ if CONFIG['MOZ_WEBM_ENCODER']: 'TestWebMWriter.cpp', ] -if CONFIG['MOZ_RUST']: - UNIFIED_SOURCES += ['TestRust.cpp',] - - TEST_HARNESS_FILES.gtest += [ '../test/gizmo-frag.mp4', '../test/gizmo.mp4', diff --git a/dom/media/mediasource/TrackBuffersManager.cpp b/dom/media/mediasource/TrackBuffersManager.cpp index 4265aed81..ac6d82411 100644 --- a/dom/media/mediasource/TrackBuffersManager.cpp +++ b/dom/media/mediasource/TrackBuffersManager.cpp @@ -58,6 +58,7 @@ AppendStateToStr(SourceBufferAttributes::AppendState aState) static Atomic<uint32_t> sStreamSourceID(0u); +#ifdef MOZ_EME class DispatchKeyNeededEvent : public Runnable { public: DispatchKeyNeededEvent(AbstractMediaDecoder* aDecoder, @@ -83,6 +84,7 @@ private: nsTArray<uint8_t> mInitData; nsString mInitDataType; }; +#endif TrackBuffersManager::TrackBuffersManager(MediaSourceDecoder* aParentDecoder, const nsACString& aType) @@ -1097,12 +1099,14 @@ TrackBuffersManager::OnDemuxerInitDone(nsresult) UniquePtr<EncryptionInfo> crypto = mInputDemuxer->GetCrypto(); if (crypto && crypto->IsEncrypted()) { +#ifdef MOZ_EME // Try and dispatch 'encrypted'. Won't go if ready state still HAVE_NOTHING. for (uint32_t i = 0; i < crypto->mInitDatas.Length(); i++) { NS_DispatchToMainThread( new DispatchKeyNeededEvent(mParentDecoder, crypto->mInitDatas[i].mInitData, crypto->mInitDatas[i].mType)); } +#endif info.mCrypto = *crypto; // We clear our crypto init data array, so the MediaFormatReader will // not emit an encrypted event for the same init data again. diff --git a/dom/media/test/test_background_video_suspend.html b/dom/media/test/test_background_video_suspend.html index e872eacf8..a5ac5cc2c 100644..100755 --- a/dom/media/test/test_background_video_suspend.html +++ b/dom/media/test/test_background_video_suspend.html @@ -15,7 +15,7 @@ var MIN_DELAY = 100; function testDelay(v, start, min) { let end = performance.now(); let delay = end - start; - ok(delay > min, `${v.token} suspended with a delay of ${delay} ms`); + ok(delay >= min, `${v.token} suspended with a delay of ${delay} ms`); } startTest({ @@ -25,7 +25,7 @@ startTest({ [ "media.suspend-bkgnd-video.enabled", true ], // User a short delay to ensure video decode suspend happens before end // of video. - [ "media.suspend-bkgnd-video.delay-ms", MIN_DELAY ] + [ "media.suspend-bkgnd-video.delay-ms", MIN_DELAY ], ], tests: gDecodeSuspendTests, runTest: (test, token) => { diff --git a/dom/media/test/test_streams_element_capture.html b/dom/media/test/test_streams_element_capture.html index 5e30a3ce4..a29eeef4d 100644..100755 --- a/dom/media/test/test_streams_element_capture.html +++ b/dom/media/test/test_streams_element_capture.html @@ -38,7 +38,8 @@ function startTest(test) { var stream; var checkEnded = function() { - is(stream.currentTime, vout.currentTime, test.name + " stream final currentTime"); + // We know the video time won't match up to the stream time + // is(stream.currentTime, vout.currentTime, test.name + " stream final currentTime"); if (test.duration) { isGreaterThanOrEqualEps(vout.currentTime, test.duration, test.name + " current time at end"); diff --git a/dom/media/test/test_streams_element_capture_createObjectURL.html b/dom/media/test/test_streams_element_capture_createObjectURL.html index d5d7efc5c..d952c7142 100644..100755 --- a/dom/media/test/test_streams_element_capture_createObjectURL.html +++ b/dom/media/test/test_streams_element_capture_createObjectURL.html @@ -38,7 +38,8 @@ function startTest(test, token) { var stream; var checkEnded = function() { - is(stream.currentTime, vout.currentTime, test.name + " stream final currentTime"); + // We know the video time won't match up to the stream time + // is(stream.currentTime, vout.currentTime, test.name + " stream final currentTime"); if (test.duration) { isGreaterThanOrEqualEps(vout.currentTime, test.duration, test.name + " current time at end"); diff --git a/dom/media/webaudio/AudioContext.cpp b/dom/media/webaudio/AudioContext.cpp index f61226a48..85842c811 100644..100755 --- a/dom/media/webaudio/AudioContext.cpp +++ b/dom/media/webaudio/AudioContext.cpp @@ -41,6 +41,7 @@ #include "nsNetUtil.h" #include "nsPIDOMWindow.h" #include "nsPrintfCString.h" +#include "mozilla/TimerClamping.h" #include "OscillatorNode.h" #include "PannerNode.h" #include "PeriodicWave.h" @@ -379,10 +380,12 @@ AudioContext::CreateMediaElementSource(HTMLMediaElement& aMediaElement, return nullptr; } +#ifdef MOZ_EME if (aMediaElement.ContainsRestrictedContent()) { aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); return nullptr; } +#endif if (CheckClosed(aRv)) { return nullptr; @@ -744,7 +747,7 @@ double AudioContext::CurrentTime() const { MediaStream* stream = Destination()->Stream(); - return stream->StreamTimeToSeconds(stream->GetCurrentTime()); + return TimerClamping::ReduceSTimeValue(stream->StreamTimeToSeconds(stream->GetCurrentTime())); } void diff --git a/dom/performance/Performance.cpp b/dom/performance/Performance.cpp index 17273c55d..8dc239b05 100644..100755 --- a/dom/performance/Performance.cpp +++ b/dom/performance/Performance.cpp @@ -21,6 +21,7 @@ #include "mozilla/dom/PerformanceObserverBinding.h" #include "mozilla/IntegerPrintfMacros.h" #include "mozilla/Preferences.h" +#include "mozilla/TimerClamping.h" #include "WorkerPrivate.h" #include "WorkerRunnable.h" @@ -228,9 +229,9 @@ Performance::ClearResourceTimings() DOMHighResTimeStamp Performance::RoundTime(double aTime) const { - // Round down to the nearest 20us, because if the timer is too accurate people + // Round down to the nearest 2ms, because if the timer is too accurate people // can do nasty timing attacks with it. - const double maxResolutionMs = 0.020; + const double maxResolutionMs = 2; return floor(aTime / maxResolutionMs) * maxResolutionMs; } diff --git a/dom/performance/PerformanceMainThread.cpp b/dom/performance/PerformanceMainThread.cpp index b60b68f62..86d42c5f8 100644 --- a/dom/performance/PerformanceMainThread.cpp +++ b/dom/performance/PerformanceMainThread.cpp @@ -200,7 +200,7 @@ PerformanceMainThread::IsPerformanceTimingAttribute(const nsAString& aName) static const char* attributes[] = {"navigationStart", "unloadEventStart", "unloadEventEnd", "redirectStart", "redirectEnd", "fetchStart", "domainLookupStart", "domainLookupEnd", - "connectStart", "connectEnd", "requestStart", "responseStart", + "connectStart", "secureConnectionStart", "connectEnd", "requestStart", "responseStart", "responseEnd", "domLoading", "domInteractive", "domContentLoadedEventStart", "domContentLoadedEventEnd", "domComplete", "loadEventStart", "loadEventEnd", nullptr}; @@ -249,6 +249,9 @@ PerformanceMainThread::GetPerformanceTimingFromString(const nsAString& aProperty if (aProperty.EqualsLiteral("connectStart")) { return Timing()->ConnectStart(); } + if (aProperty.EqualsLiteral("secureConnectionStart")) { + return Timing()->SecureConnectionStart(); + } if (aProperty.EqualsLiteral("connectEnd")) { return Timing()->ConnectEnd(); } diff --git a/dom/performance/PerformanceResourceTiming.h b/dom/performance/PerformanceResourceTiming.h index abb653d66..2dd6b4a06 100644 --- a/dom/performance/PerformanceResourceTiming.h +++ b/dom/performance/PerformanceResourceTiming.h @@ -128,9 +128,9 @@ public: DOMHighResTimeStamp SecureConnectionStart() const { - // This measurement is not available for Navigation Timing either. - // There is a different bug submitted for it. - return 0; + return mTiming && mTiming->TimingAllowed() + ? mTiming->SecureConnectionStartHighRes() + : 0; } virtual const PerformanceResourceTiming* ToResourceTiming() const override diff --git a/dom/performance/PerformanceTiming.cpp b/dom/performance/PerformanceTiming.cpp index 527cf9441..e2f76a21f 100644..100755 --- a/dom/performance/PerformanceTiming.cpp +++ b/dom/performance/PerformanceTiming.cpp @@ -21,7 +21,7 @@ PerformanceTiming::PerformanceTiming(Performance* aPerformance, DOMHighResTimeStamp aZeroTime) : mPerformance(aPerformance), mFetchStart(0.0), - mZeroTime(aZeroTime), + mZeroTime(TimerClamping::ReduceMsTimeValue(aZeroTime)), mRedirectCount(0), mTimingAllowed(true), mAllRedirectsSameOrigin(true), @@ -46,6 +46,23 @@ PerformanceTiming::PerformanceTiming(Performance* aPerformance, mReportCrossOriginRedirect = mTimingAllowed && redirectsPassCheck; } + mSecureConnection = false; + nsCOMPtr<nsIURI> uri; + if (aHttpChannel) { + aHttpChannel->GetURI(getter_AddRefs(uri)); + } else { + nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel); + if (httpChannel) { + httpChannel->GetURI(getter_AddRefs(uri)); + } + } + + if (uri) { + nsresult rv = uri->SchemeIs("https", &mSecureConnection); + if (NS_FAILED(rv)) { + mSecureConnection = false; + } + } InitializeTimingInfo(aChannel); } @@ -63,12 +80,41 @@ PerformanceTiming::InitializeTimingInfo(nsITimedChannel* aChannel) aChannel->GetDomainLookupStart(&mDomainLookupStart); aChannel->GetDomainLookupEnd(&mDomainLookupEnd); aChannel->GetConnectStart(&mConnectStart); + aChannel->GetSecureConnectionStart(&mSecureConnectionStart); aChannel->GetConnectEnd(&mConnectEnd); aChannel->GetRequestStart(&mRequestStart); aChannel->GetResponseStart(&mResponseStart); aChannel->GetCacheReadStart(&mCacheReadStart); aChannel->GetResponseEnd(&mResponseEnd); aChannel->GetCacheReadEnd(&mCacheReadEnd); + + // the performance timing api essentially requires that the event timestamps + // are >= asyncOpen().. but in truth the browser engages in a number of + // speculative activities that sometimes mean connections and lookups begin + // earlier. Workaround that here by just using asyncOpen as the minimum + // timestamp for dns and connection info. + if (!mAsyncOpen.IsNull()) { + if (!mDomainLookupStart.IsNull() && mDomainLookupStart < mAsyncOpen) { + mDomainLookupStart = mAsyncOpen; + } + + if (!mDomainLookupEnd.IsNull() && mDomainLookupEnd < mAsyncOpen) { + mDomainLookupEnd = mAsyncOpen; + } + + if (!mConnectStart.IsNull() && mConnectStart < mAsyncOpen) { + mConnectStart = mAsyncOpen; + } + + if (mSecureConnection && !mSecureConnectionStart.IsNull() && + mSecureConnectionStart < mAsyncOpen) { + mSecureConnectionStart = mAsyncOpen; + } + + if (!mConnectEnd.IsNull() && mConnectEnd < mAsyncOpen) { + mConnectEnd = mAsyncOpen; + } + } } } @@ -89,7 +135,7 @@ PerformanceTiming::FetchStartHighRes() ? TimeStampToDOMHighRes(mAsyncOpen) : 0.0; } - return mFetchStart; + return TimerClamping::ReduceMsTimeValue(mFetchStart); } DOMTimeMilliSec @@ -175,7 +221,7 @@ PerformanceTiming::RedirectStartHighRes() if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) { return mZeroTime; } - return TimeStampToDOMHighResOrFetchStart(mRedirectStart); + return TimeStampToReducedDOMHighResOrFetchStart(mRedirectStart); } DOMTimeMilliSec @@ -208,7 +254,7 @@ PerformanceTiming::RedirectEndHighRes() if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) { return mZeroTime; } - return TimeStampToDOMHighResOrFetchStart(mRedirectEnd); + return TimeStampToReducedDOMHighResOrFetchStart(mRedirectEnd); } DOMTimeMilliSec @@ -231,7 +277,7 @@ PerformanceTiming::DomainLookupStartHighRes() if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) { return mZeroTime; } - return TimeStampToDOMHighResOrFetchStart(mDomainLookupStart); + return TimeStampToReducedDOMHighResOrFetchStart(mDomainLookupStart); } DOMTimeMilliSec @@ -248,7 +294,7 @@ PerformanceTiming::DomainLookupEndHighRes() } // Bug 1155008 - nsHttpTransaction is racy. Return DomainLookupStart when null return mDomainLookupEnd.IsNull() ? DomainLookupStartHighRes() - : TimeStampToDOMHighRes(mDomainLookupEnd); + : TimerClamping::ReduceMsTimeValue(TimeStampToDOMHighRes(mDomainLookupEnd)); } DOMTimeMilliSec @@ -264,7 +310,7 @@ PerformanceTiming::ConnectStartHighRes() return mZeroTime; } return mConnectStart.IsNull() ? DomainLookupEndHighRes() - : TimeStampToDOMHighRes(mConnectStart); + : TimerClamping::ReduceMsTimeValue(TimeStampToDOMHighRes(mConnectStart)); } DOMTimeMilliSec @@ -274,6 +320,25 @@ PerformanceTiming::ConnectStart() } DOMHighResTimeStamp +PerformanceTiming::SecureConnectionStartHighRes() +{ + if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) { + return mZeroTime; + } + return !mSecureConnection + ? 0 // We use 0 here, because mZeroTime is sometimes set to the navigation + // start time. + : (mSecureConnectionStart.IsNull() ? mZeroTime + : TimerClamping::ReduceMsTimeValue(TimeStampToDOMHighRes(mSecureConnectionStart))); +} + +DOMTimeMilliSec +PerformanceTiming::SecureConnectionStart() +{ + return static_cast<int64_t>(SecureConnectionStartHighRes()); +} + +DOMHighResTimeStamp PerformanceTiming::ConnectEndHighRes() { if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) { @@ -281,7 +346,7 @@ PerformanceTiming::ConnectEndHighRes() } // Bug 1155008 - nsHttpTransaction is racy. Return ConnectStart when null return mConnectEnd.IsNull() ? ConnectStartHighRes() - : TimeStampToDOMHighRes(mConnectEnd); + : TimerClamping::ReduceMsTimeValue(TimeStampToDOMHighRes(mConnectEnd)); } DOMTimeMilliSec @@ -296,7 +361,7 @@ PerformanceTiming::RequestStartHighRes() if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) { return mZeroTime; } - return TimeStampToDOMHighResOrFetchStart(mRequestStart); + return TimeStampToReducedDOMHighResOrFetchStart(mRequestStart); } DOMTimeMilliSec @@ -315,7 +380,7 @@ PerformanceTiming::ResponseStartHighRes() (!mCacheReadStart.IsNull() && mCacheReadStart < mResponseStart)) { mResponseStart = mCacheReadStart; } - return TimeStampToDOMHighResOrFetchStart(mResponseStart); + return TimeStampToReducedDOMHighResOrFetchStart(mResponseStart); } DOMTimeMilliSec @@ -336,7 +401,7 @@ PerformanceTiming::ResponseEndHighRes() } // Bug 1155008 - nsHttpTransaction is racy. Return ResponseStart when null return mResponseEnd.IsNull() ? ResponseStartHighRes() - : TimeStampToDOMHighRes(mResponseEnd); + : TimerClamping::ReduceMsTimeValue(TimeStampToDOMHighRes(mResponseEnd)); } DOMTimeMilliSec diff --git a/dom/performance/PerformanceTiming.h b/dom/performance/PerformanceTiming.h index aef54a258..fc7e7d5bd 100644..100755 --- a/dom/performance/PerformanceTiming.h +++ b/dom/performance/PerformanceTiming.h @@ -10,6 +10,7 @@ #include "mozilla/Attributes.h" #include "nsContentUtils.h" #include "nsDOMNavigationTiming.h" +#include "mozilla/TimerClamping.h" #include "nsWrapperCache.h" #include "Performance.h" @@ -68,10 +69,10 @@ public: * page), if the given TimeStamp is valid. Otherwise, it will return * the FetchStart timing value. */ - inline DOMHighResTimeStamp TimeStampToDOMHighResOrFetchStart(TimeStamp aStamp) + inline DOMHighResTimeStamp TimeStampToReducedDOMHighResOrFetchStart(TimeStamp aStamp) { return (!aStamp.IsNull()) - ? TimeStampToDOMHighRes(aStamp) + ? TimerClamping::ReduceMsTimeValue(TimeStampToDOMHighRes(aStamp)) : FetchStartHighRes(); } @@ -119,7 +120,7 @@ public: if (!nsContentUtils::IsPerformanceTimingEnabled()) { return 0; } - return GetDOMTiming()->GetNavigationStart(); + return TimerClamping::ReduceMsTimeValue(GetDOMTiming()->GetNavigationStart()); } DOMTimeMilliSec UnloadEventStart() @@ -127,7 +128,7 @@ public: if (!nsContentUtils::IsPerformanceTimingEnabled()) { return 0; } - return GetDOMTiming()->GetUnloadEventStart(); + return TimerClamping::ReduceMsTimeValue(GetDOMTiming()->GetUnloadEventStart()); } DOMTimeMilliSec UnloadEventEnd() @@ -135,7 +136,7 @@ public: if (!nsContentUtils::IsPerformanceTimingEnabled()) { return 0; } - return GetDOMTiming()->GetUnloadEventEnd(); + return TimerClamping::ReduceMsTimeValue(GetDOMTiming()->GetUnloadEventEnd()); } uint16_t GetRedirectCount() const; @@ -161,6 +162,7 @@ public: DOMHighResTimeStamp DomainLookupStartHighRes(); DOMHighResTimeStamp DomainLookupEndHighRes(); DOMHighResTimeStamp ConnectStartHighRes(); + DOMHighResTimeStamp SecureConnectionStartHighRes(); DOMHighResTimeStamp ConnectEndHighRes(); DOMHighResTimeStamp RequestStartHighRes(); DOMHighResTimeStamp ResponseStartHighRes(); @@ -173,6 +175,7 @@ public: DOMTimeMilliSec DomainLookupStart(); DOMTimeMilliSec DomainLookupEnd(); DOMTimeMilliSec ConnectStart(); + DOMTimeMilliSec SecureConnectionStart(); DOMTimeMilliSec ConnectEnd(); DOMTimeMilliSec RequestStart(); DOMTimeMilliSec ResponseStart(); @@ -183,7 +186,7 @@ public: if (!nsContentUtils::IsPerformanceTimingEnabled()) { return 0; } - return GetDOMTiming()->GetDomLoading(); + return TimerClamping::ReduceMsTimeValue(GetDOMTiming()->GetDomLoading()); } DOMTimeMilliSec DomInteractive() const @@ -191,7 +194,7 @@ public: if (!nsContentUtils::IsPerformanceTimingEnabled()) { return 0; } - return GetDOMTiming()->GetDomInteractive(); + return TimerClamping::ReduceMsTimeValue(GetDOMTiming()->GetDomInteractive()); } DOMTimeMilliSec DomContentLoadedEventStart() const @@ -199,7 +202,7 @@ public: if (!nsContentUtils::IsPerformanceTimingEnabled()) { return 0; } - return GetDOMTiming()->GetDomContentLoadedEventStart(); + return TimerClamping::ReduceMsTimeValue(GetDOMTiming()->GetDomContentLoadedEventStart()); } DOMTimeMilliSec DomContentLoadedEventEnd() const @@ -207,7 +210,7 @@ public: if (!nsContentUtils::IsPerformanceTimingEnabled()) { return 0; } - return GetDOMTiming()->GetDomContentLoadedEventEnd(); + return TimerClamping::ReduceMsTimeValue(GetDOMTiming()->GetDomContentLoadedEventEnd()); } DOMTimeMilliSec DomComplete() const @@ -215,7 +218,7 @@ public: if (!nsContentUtils::IsPerformanceTimingEnabled()) { return 0; } - return GetDOMTiming()->GetDomComplete(); + return TimerClamping::ReduceMsTimeValue(GetDOMTiming()->GetDomComplete()); } DOMTimeMilliSec LoadEventStart() const @@ -223,7 +226,7 @@ public: if (!nsContentUtils::IsPerformanceTimingEnabled()) { return 0; } - return GetDOMTiming()->GetLoadEventStart(); + return TimerClamping::ReduceMsTimeValue(GetDOMTiming()->GetLoadEventStart()); } DOMTimeMilliSec LoadEventEnd() const @@ -231,7 +234,7 @@ public: if (!nsContentUtils::IsPerformanceTimingEnabled()) { return 0; } - return GetDOMTiming()->GetLoadEventEnd(); + return TimerClamping::ReduceMsTimeValue(GetDOMTiming()->GetLoadEventEnd()); } private: @@ -255,6 +258,7 @@ private: TimeStamp mDomainLookupStart; TimeStamp mDomainLookupEnd; TimeStamp mConnectStart; + TimeStamp mSecureConnectionStart; TimeStamp mConnectEnd; TimeStamp mRequestStart; TimeStamp mResponseStart; @@ -270,6 +274,8 @@ private: // redirectEnd attributes. It is false if there were no redirects, or if // any of the responses didn't pass the timing-allow-check bool mReportCrossOriginRedirect; + + bool mSecureConnection; }; } // namespace dom diff --git a/dom/performance/tests/test_performance_user_timing.js b/dom/performance/tests/test_performance_user_timing.js index 3d05ebb77..cd8261bbd 100644 --- a/dom/performance/tests/test_performance_user_timing.js +++ b/dom/performance/tests/test_performance_user_timing.js @@ -263,7 +263,7 @@ var steps = [ performance.measure("test", n); ok(true, "Measure created from reserved name as starting time: " + n); } catch (e) { - ok(["redirectStart", "redirectEnd", "unloadEventStart", "unloadEventEnd", "loadEventEnd"].indexOf(n) >= 0, + ok(["redirectStart", "redirectEnd", "unloadEventStart", "unloadEventEnd", "loadEventEnd", "secureConnectionStart"].indexOf(n) >= 0, "Measure created from reserved name as starting time: " + n + " and threw expected error"); } }; diff --git a/dom/performance/tests/test_worker_performance_now.js b/dom/performance/tests/test_worker_performance_now.js index c2a905031..dee4efce6 100644 --- a/dom/performance/tests/test_worker_performance_now.js +++ b/dom/performance/tests/test_worker_performance_now.js @@ -26,51 +26,5 @@ var n = self.performance.now(), d = Date.now(); ok(n >= 0, "The value of now() should be equal to or greater than 0."); ok(self.performance.now() >= n, "The value of now() should monotonically increase."); -// The spec says performance.now() should have micro-second resolution, but allows 1ms if the platform doesn't support it. -// Our implementation does provide micro-second resolution, except for windows XP combined with some HW properties -// where we can't use QueryPerformanceCounters (see comments at mozilla-central/xpcom/ds/TimeStamp_windows.cpp). -// This XP-low-res case results in about 15ms resolutions, and can be identified when perf.now() returns only integers. -// -// Since setTimeout might return too early/late, our goal is that perf.now() changed within 2ms -// (or 25ms for XP-low-res), rather than specific number of setTimeout(N) invocations. -// See bug 749894 (intermittent failures of this test) -var platformPossiblyLowRes; -workerTestGetOSCPU(function(oscpu) { - platformPossiblyLowRes = oscpu.indexOf("Windows NT 5.1") == 0; // XP only - setTimeout(checkAfterTimeout, 1); -}); -var allInts = (n % 1) == 0; // Indicator of limited HW resolution. -var checks = 0; +workerTestDone(); -function checkAfterTimeout() { - checks++; - var d2 = Date.now(); - var n2 = self.performance.now(); - - allInts = allInts && (n2 % 1) == 0; - var lowResCounter = platformPossiblyLowRes && allInts; - - if ( n2 == n && checks < 50 && // 50 is just a failsafe. Our real goals are 2ms or 25ms. - ( (d2 - d) < 2 // The spec allows 1ms resolution. We allow up to measured 2ms to ellapse. - || - lowResCounter && - (d2 - d) < 25 - ) - ) { - setTimeout(checkAfterTimeout, 1); - return; - } - - // Loose spec: 1ms resolution, or 15ms resolution for the XP-low-res case. - // We shouldn't test that dt is actually within 2/25ms since the iterations break if it isn't, and timeout could be late. - ok(n2 > n, "Loose - the value of now() should increase within 2ms (or 25ms if low-res counter) (delta now(): " + (n2 - n) + " ms)."); - - // Strict spec: if it's not the XP-low-res case, while the spec allows 1ms resolution, it prefers microseconds, which we provide. - // Since the fastest setTimeout return which I observed was ~500 microseconds, a microseconds counter should change in 1 iteretion. - ok(n2 > n && (lowResCounter || checks == 1), - "Strict - [if high-res counter] the value of now() should increase after one setTimeout (hi-res: " + (!lowResCounter) + - ", iters: " + checks + - ", dt: " + (d2 - d) + - ", now(): " + n2 + ")."); - workerTestDone(); -}; diff --git a/dom/push/moz.build b/dom/push/moz.build index b96099161..35683120f 100644 --- a/dom/push/moz.build +++ b/dom/push/moz.build @@ -16,7 +16,7 @@ EXTRA_JS_MODULES += [ 'PushService.jsm', ] -if CONFIG['MOZ_BUILD_APP'] != 'mobile/android': +if not CONFIG['MOZ_FENNEC']: # Everything but Fennec. EXTRA_JS_MODULES += [ 'PushServiceHttp2.jsm', diff --git a/dom/security/nsCSPContext.cpp b/dom/security/nsCSPContext.cpp index 815c7734d..5e435d4ca 100644 --- a/dom/security/nsCSPContext.cpp +++ b/dom/security/nsCSPContext.cpp @@ -156,10 +156,13 @@ nsCSPContext::ShouldLoad(nsContentPolicyType aContentType, nsAutoString nonce; bool parserCreated = false; if (!isPreload) { - nsCOMPtr<nsIDOMHTMLElement> htmlElement = do_QueryInterface(aRequestContext); - if (htmlElement) { - rv = htmlElement->GetAttribute(NS_LITERAL_STRING("nonce"), nonce); - NS_ENSURE_SUCCESS(rv, rv); + if (aContentType == nsIContentPolicy::TYPE_SCRIPT || + aContentType == nsIContentPolicy::TYPE_STYLESHEET) { + nsCOMPtr<nsIDOMHTMLElement> htmlElement = do_QueryInterface(aRequestContext); + if (htmlElement) { + rv = htmlElement->GetAttribute(NS_LITERAL_STRING("nonce"), nonce); + NS_ENSURE_SUCCESS(rv, rv); + } } nsCOMPtr<nsIScriptElement> script = do_QueryInterface(aRequestContext); @@ -343,6 +346,20 @@ nsCSPContext::GetBlockAllMixedContent(bool *outBlockAllMixedContent) } NS_IMETHODIMP +nsCSPContext::GetEnforcesFrameAncestors(bool *outEnforcesFrameAncestors) +{ + *outEnforcesFrameAncestors = false; + for (uint32_t i = 0; i < mPolicies.Length(); i++) { + if (!mPolicies[i]->getReportOnlyFlag() && + mPolicies[i]->hasDirective(nsIContentSecurityPolicy::FRAME_ANCESTORS_DIRECTIVE)) { + *outEnforcesFrameAncestors = true; + return NS_OK; + } + } + return NS_OK; +} + +NS_IMETHODIMP nsCSPContext::GetReferrerPolicy(uint32_t* outPolicy, bool* outIsSet) { *outIsSet = false; diff --git a/dom/security/nsCSPParser.cpp b/dom/security/nsCSPParser.cpp index f1b5d8ba7..a0eba6918 100644 --- a/dom/security/nsCSPParser.cpp +++ b/dom/security/nsCSPParser.cpp @@ -136,6 +136,8 @@ nsCSPParser::nsCSPParser(cspTokens& aTokens, , mUnsafeInlineKeywordSrc(nullptr) , mChildSrc(nullptr) , mFrameSrc(nullptr) + , mWorkerSrc(nullptr) + , mScriptSrc(nullptr) , mParsingFrameAncestorsDir(false) , mTokens(aTokens) , mSelfURI(aSelfURI) @@ -532,7 +534,7 @@ nsCSPParser::keywordSource() // Special case handling for 'self' which is not stored internally as a keyword, // but rather creates a nsCSPHostSrc using the selfURI if (CSP_IsKeyword(mCurToken, CSP_SELF)) { - return CSP_CreateHostSrcFromURI(mSelfURI); + return CSP_CreateHostSrcFromSelfURI(mSelfURI); } if (CSP_IsKeyword(mCurToken, CSP_STRICT_DYNAMIC)) { @@ -1099,21 +1101,37 @@ nsCSPParser::directiveName() return new nsUpgradeInsecureDirective(CSP_StringToCSPDirective(mCurToken)); } - // child-src has it's own class to handle frame-src if necessary + // child-src by itself is deprecatd but will be enforced + // * for workers (if worker-src is not explicitly specified) + // * for frames (if frame-src is not explicitly specified) if (CSP_IsDirective(mCurToken, nsIContentSecurityPolicy::CHILD_SRC_DIRECTIVE)) { + const char16_t* params[] = { mCurToken.get() }; + logWarningErrorToConsole(nsIScriptError::warningFlag, + "deprecatedChildSrcDirective", + params, ArrayLength(params)); mChildSrc = new nsCSPChildSrcDirective(CSP_StringToCSPDirective(mCurToken)); return mChildSrc; } - // if we have a frame-src, cache it so we can decide whether to use child-src + // if we have a frame-src, cache it so we can discard child-src for frames if (CSP_IsDirective(mCurToken, nsIContentSecurityPolicy::FRAME_SRC_DIRECTIVE)) { - const char16_t* params[] = { mCurToken.get(), NS_LITERAL_STRING("child-src").get() }; - logWarningErrorToConsole(nsIScriptError::warningFlag, "deprecatedDirective", - params, ArrayLength(params)); mFrameSrc = new nsCSPDirective(CSP_StringToCSPDirective(mCurToken)); return mFrameSrc; } + // if we have a worker-src, cache it so we can discard child-src for workers + if (CSP_IsDirective(mCurToken, nsIContentSecurityPolicy::WORKER_SRC_DIRECTIVE)) { + mWorkerSrc = new nsCSPDirective(CSP_StringToCSPDirective(mCurToken)); + return mWorkerSrc; + } + + // if we have a script-src, cache it as a fallback for worker-src + // in case child-src is not present + if (CSP_IsDirective(mCurToken, nsIContentSecurityPolicy::SCRIPT_SRC_DIRECTIVE)) { + mScriptSrc = new nsCSPScriptSrcDirective(CSP_StringToCSPDirective(mCurToken)); + return mScriptSrc; + } + if (CSP_IsDirective(mCurToken, nsIContentSecurityPolicy::REQUIRE_SRI_FOR)) { return new nsRequireSRIForDirective(CSP_StringToCSPDirective(mCurToken)); } @@ -1290,9 +1308,22 @@ nsCSPParser::policy() directive(); } - if (mChildSrc && !mFrameSrc) { - // if we have a child-src, it handles frame-src too, unless frame-src is set - mChildSrc->setHandleFrameSrc(); + if (mChildSrc) { + if (!mFrameSrc) { + // if frame-src is specified explicitly for that policy than child-src should + // not restrict frames; if not, than child-src needs to restrict frames. + mChildSrc->setRestrictFrames(); + } + if (!mWorkerSrc) { + // if worker-src is specified explicitly for that policy than child-src should + // not restrict workers; if not, than child-src needs to restrict workers. + mChildSrc->setRestrictWorkers(); + } + } + // if script-src is specified, but not worker-src and also no child-src, then + // script-src has to govern workers. + if (mScriptSrc && !mWorkerSrc && !mChildSrc) { + mScriptSrc->setRestrictWorkers(); } return mPolicy; diff --git a/dom/security/nsCSPParser.h b/dom/security/nsCSPParser.h index 1bfc56c65..d500a1c18 100644 --- a/dom/security/nsCSPParser.h +++ b/dom/security/nsCSPParser.h @@ -243,14 +243,17 @@ class nsCSPParser { bool mStrictDynamic; // false, if 'strict-dynamic' is not defined nsCSPKeywordSrc* mUnsafeInlineKeywordSrc; // null, otherwise invlidate() - // cache variables for child-src and frame-src directive handling. - // frame-src is deprecated in favor of child-src, however if we - // see a frame-src directive, it takes precedence for frames and iframes. - // At the end of parsing, if we have a child-src directive, we need to - // decide whether it will handle frames, or if there is a frame-src we - // should honor instead. - nsCSPChildSrcDirective* mChildSrc; - nsCSPDirective* mFrameSrc; + // cache variables for child-src, frame-src and worker-src handling; + // in CSP 3 child-src is deprecated. For backwards compatibility + // child-src needs to restrict: + // (*) frames, in case frame-src is not expicitly specified + // (*) workers, in case worker-src is not expicitly specified + // If neither worker-src, nor child-src is present, then script-src + // needs to govern workers. + nsCSPChildSrcDirective* mChildSrc; + nsCSPDirective* mFrameSrc; + nsCSPDirective* mWorkerSrc; + nsCSPScriptSrcDirective* mScriptSrc; // cache variable to let nsCSPHostSrc know that it's within // the frame-ancestors directive. diff --git a/dom/security/nsCSPUtils.cpp b/dom/security/nsCSPUtils.cpp index b074a980c..49832f8f4 100644 --- a/dom/security/nsCSPUtils.cpp +++ b/dom/security/nsCSPUtils.cpp @@ -230,7 +230,7 @@ CSP_ContentTypeToDirective(nsContentPolicyType aType) case nsIContentPolicy::TYPE_INTERNAL_WORKER: case nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER: case nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER: - return nsIContentSecurityPolicy::CHILD_SRC_DIRECTIVE; + return nsIContentSecurityPolicy::WORKER_SRC_DIRECTIVE; case nsIContentPolicy::TYPE_SUBDOCUMENT: return nsIContentSecurityPolicy::FRAME_SRC_DIRECTIVE; @@ -266,20 +266,21 @@ CSP_ContentTypeToDirective(nsContentPolicyType aType) } nsCSPHostSrc* -CSP_CreateHostSrcFromURI(nsIURI* aURI) +CSP_CreateHostSrcFromSelfURI(nsIURI* aSelfURI) { // Create the host first nsCString host; - aURI->GetHost(host); + aSelfURI->GetAsciiHost(host); nsCSPHostSrc *hostsrc = new nsCSPHostSrc(NS_ConvertUTF8toUTF16(host)); + hostsrc->setGeneratedFromSelfKeyword(); // Add the scheme. nsCString scheme; - aURI->GetScheme(scheme); + aSelfURI->GetScheme(scheme); hostsrc->setScheme(NS_ConvertUTF8toUTF16(scheme)); int32_t port; - aURI->GetPort(&port); + aSelfURI->GetPort(&port); // Only add port if it's not default port. if (port > 0) { nsAutoString portStr; @@ -348,13 +349,17 @@ CSP_IsQuotelessKeyword(const nsAString& aKey) * @param aUpgradeInsecure * Whether the policy makes use of the directive * 'upgrade-insecure-requests'. + * @param aFromSelfURI + * Whether a scheme was generated from the keyword 'self' + * which then allows schemeless sources to match ws and wss. */ bool permitsScheme(const nsAString& aEnforcementScheme, nsIURI* aUri, bool aReportOnly, - bool aUpgradeInsecure) + bool aUpgradeInsecure, + bool aFromSelfURI) { nsAutoCString scheme; nsresult rv = aUri->GetScheme(scheme); @@ -373,8 +378,20 @@ permitsScheme(const nsAString& aEnforcementScheme, // allow scheme-less sources where the protected resource is http // and the load is https, see: // http://www.w3.org/TR/CSP2/#match-source-expression - if (aEnforcementScheme.EqualsASCII("http") && - scheme.EqualsASCII("https")) { + if (aEnforcementScheme.EqualsASCII("http")) { + if (scheme.EqualsASCII("https")) { + return true; + } + if ((scheme.EqualsASCII("ws") || scheme.EqualsASCII("wss")) && aFromSelfURI) { + return true; + } + } + if (aEnforcementScheme.EqualsASCII("https")) { + if (scheme.EqualsLiteral("wss") && aFromSelfURI) { + return true; + } + } + if (aEnforcementScheme.EqualsASCII("ws") && scheme.EqualsASCII("wss")) { return true; } @@ -483,7 +500,7 @@ nsCSPSchemeSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirect if (mInvalidated) { return false; } - return permitsScheme(mScheme, aUri, aReportOnly, aUpgradeInsecure); + return permitsScheme(mScheme, aUri, aReportOnly, aUpgradeInsecure, false); } bool @@ -503,6 +520,7 @@ nsCSPSchemeSrc::toString(nsAString& outStr) const nsCSPHostSrc::nsCSPHostSrc(const nsAString& aHost) : mHost(aHost) + , mGeneratedFromSelfKeyword(false) , mWithinFrameAncstorsDir(false) { ToLowerCase(mHost); @@ -612,7 +630,7 @@ nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected // http://www.w3.org/TR/CSP11/#match-source-expression // 4.3) scheme matching: Check if the scheme matches. - if (!permitsScheme(mScheme, aUri, aReportOnly, aUpgradeInsecure)) { + if (!permitsScheme(mScheme, aUri, aReportOnly, aUpgradeInsecure, mGeneratedFromSelfKeyword)) { return false; } @@ -643,7 +661,7 @@ nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected // Before we can check if the host matches, we have to // extract the host part from aUri. nsAutoCString uriHost; - nsresult rv = aUri->GetHost(uriHost); + nsresult rv = aUri->GetAsciiHost(uriHost); NS_ENSURE_SUCCESS(rv, false); nsString decodedUriHost; @@ -1166,6 +1184,11 @@ nsCSPDirective::toDomCSPStruct(mozilla::dom::CSP& outCSP) const outCSP.mSandbox.Value() = mozilla::Move(srcs); return; + case nsIContentSecurityPolicy::WORKER_SRC_DIRECTIVE: + outCSP.mWorker_src.Construct(); + outCSP.mWorker_src.Value() = mozilla::Move(srcs); + return; + // REFERRER_DIRECTIVE and REQUIRE_SRI_FOR are handled in nsCSPPolicy::toDomCSPStruct() default: @@ -1218,7 +1241,8 @@ bool nsCSPDirective::equals(CSPDirective aDirective) const nsCSPChildSrcDirective::nsCSPChildSrcDirective(CSPDirective aDirective) : nsCSPDirective(aDirective) - , mHandleFrameSrc(false) + , mRestrictFrames(false) + , mRestrictWorkers(false) { } @@ -1226,30 +1250,58 @@ nsCSPChildSrcDirective::~nsCSPChildSrcDirective() { } -void nsCSPChildSrcDirective::setHandleFrameSrc() -{ - mHandleFrameSrc = true; -} - bool nsCSPChildSrcDirective::restrictsContentType(nsContentPolicyType aContentType) const { if (aContentType == nsIContentPolicy::TYPE_SUBDOCUMENT) { - return mHandleFrameSrc; + return mRestrictFrames; } - - return (aContentType == nsIContentPolicy::TYPE_INTERNAL_WORKER - || aContentType == nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER - || aContentType == nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER - ); + if (aContentType == nsIContentPolicy::TYPE_INTERNAL_WORKER || + aContentType == nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER || + aContentType == nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER) { + return mRestrictWorkers; + } + return false; } bool nsCSPChildSrcDirective::equals(CSPDirective aDirective) const { if (aDirective == nsIContentSecurityPolicy::FRAME_SRC_DIRECTIVE) { - return mHandleFrameSrc; + return mRestrictFrames; } + if (aDirective == nsIContentSecurityPolicy::WORKER_SRC_DIRECTIVE) { + return mRestrictWorkers; + } + return (mDirective == aDirective); +} + +/* =============== nsCSPScriptSrcDirective ============= */ + +nsCSPScriptSrcDirective::nsCSPScriptSrcDirective(CSPDirective aDirective) + : nsCSPDirective(aDirective) + , mRestrictWorkers(false) +{ +} + +nsCSPScriptSrcDirective::~nsCSPScriptSrcDirective() +{ +} - return (aDirective == nsIContentSecurityPolicy::CHILD_SRC_DIRECTIVE); +bool nsCSPScriptSrcDirective::restrictsContentType(nsContentPolicyType aContentType) const +{ + if (aContentType == nsIContentPolicy::TYPE_INTERNAL_WORKER || + aContentType == nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER || + aContentType == nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER) { + return mRestrictWorkers; + } + return mDirective == CSP_ContentTypeToDirective(aContentType); +} + +bool nsCSPScriptSrcDirective::equals(CSPDirective aDirective) const +{ + if (aDirective == nsIContentSecurityPolicy::WORKER_SRC_DIRECTIVE) { + return mRestrictWorkers; + } + return (mDirective == aDirective); } /* =============== nsBlockAllMixedContentDirective ============= */ diff --git a/dom/security/nsCSPUtils.h b/dom/security/nsCSPUtils.h index 468c734a2..91096712a 100644 --- a/dom/security/nsCSPUtils.h +++ b/dom/security/nsCSPUtils.h @@ -93,7 +93,8 @@ static const char* CSPStrDirectives[] = { "child-src", // CHILD_SRC_DIRECTIVE "block-all-mixed-content", // BLOCK_ALL_MIXED_CONTENT "require-sri-for", // REQUIRE_SRI_FOR - "sandbox" // SANDBOX_DIRECTIVE + "sandbox", // SANDBOX_DIRECTIVE + "worker-src" // WORKER_SRC_DIRECTIVE }; inline const char* CSP_CSPDirectiveToString(CSPDirective aDir) @@ -186,7 +187,7 @@ nsresult CSP_AppendCSPFromHeader(nsIContentSecurityPolicy* aCsp, class nsCSPHostSrc; -nsCSPHostSrc* CSP_CreateHostSrcFromURI(nsIURI* aURI); +nsCSPHostSrc* CSP_CreateHostSrcFromSelfURI(nsIURI* aSelfURI); bool CSP_IsValidDirective(const nsAString& aDir); bool CSP_IsDirective(const nsAString& aValue, CSPDirective aDir); bool CSP_IsKeyword(const nsAString& aValue, enum CSPKeyword aKey); @@ -256,6 +257,9 @@ class nsCSPHostSrc : public nsCSPBaseSrc { void setPort(const nsAString& aPort); void appendPath(const nsAString &aPath); + inline void setGeneratedFromSelfKeyword() const + { mGeneratedFromSelfKeyword = true;} + inline void setWithinFrameAncestorsDir(bool aValue) const { mWithinFrameAncstorsDir = aValue; } @@ -276,6 +280,7 @@ class nsCSPHostSrc : public nsCSPBaseSrc { nsString mHost; nsString mPort; nsString mPath; + mutable bool mGeneratedFromSelfKeyword; mutable bool mWithinFrameAncstorsDir; }; @@ -441,7 +446,7 @@ class nsCSPDirective { bool visitSrcs(nsCSPSrcVisitor* aVisitor) const; - private: + protected: CSPDirective mDirective; nsTArray<nsCSPBaseSrc*> mSrcs; }; @@ -449,26 +454,52 @@ class nsCSPDirective { /* =============== nsCSPChildSrcDirective ============= */ /* - * In CSP 2, the child-src directive covers both workers and - * subdocuments (i.e., frames and iframes). Workers were removed - * from script-src, but frames can be controlled by either child-src - * or frame-src directives, so child-src needs to know whether it should - * also restrict frames. When both are present the frame-src directive - * takes precedent. + * In CSP 3 child-src is deprecated. For backwards compatibility + * child-src needs to restrict: + * (*) frames, in case frame-src is not expicitly specified + * (*) workers, in case worker-src is not expicitly specified */ class nsCSPChildSrcDirective : public nsCSPDirective { public: explicit nsCSPChildSrcDirective(CSPDirective aDirective); virtual ~nsCSPChildSrcDirective(); - void setHandleFrameSrc(); + void setRestrictFrames() + { mRestrictFrames = true; } + + void setRestrictWorkers() + { mRestrictWorkers = true; } + + virtual bool restrictsContentType(nsContentPolicyType aContentType) const; + + virtual bool equals(CSPDirective aDirective) const; + + private: + bool mRestrictFrames; + bool mRestrictWorkers; +}; + +/* =============== nsCSPScriptSrcDirective ============= */ + +/* + * In CSP 3 worker-src restricts workers, for backwards compatibily + * script-src has to restrict workers as the ultimate fallback if + * neither worker-src nor child-src is present in a CSP. + */ +class nsCSPScriptSrcDirective : public nsCSPDirective { + public: + explicit nsCSPScriptSrcDirective(CSPDirective aDirective); + virtual ~nsCSPScriptSrcDirective(); + + void setRestrictWorkers() + { mRestrictWorkers = true; } virtual bool restrictsContentType(nsContentPolicyType aContentType) const; virtual bool equals(CSPDirective aDirective) const; private: - bool mHandleFrameSrc; + bool mRestrictWorkers; }; /* =============== nsBlockAllMixedContentDirective === */ diff --git a/dom/security/test/csp/file_frame_src.js b/dom/security/test/csp/file_frame_src.js new file mode 100644 index 000000000..8e81f0743 --- /dev/null +++ b/dom/security/test/csp/file_frame_src.js @@ -0,0 +1,14 @@ +let testframe = document.getElementById("testframe"); +testframe.onload = function() { + parent.postMessage({ + result: "frame-allowed", + href: document.location.href, + }, "*"); +} +testframe.onerror = function() { + parent.postMessage({ + result: "frame-blocked", + href: document.location.href, + }, "*"); +} +testframe.src = "file_frame_src_inner.html" diff --git a/dom/security/test/csp/file_frame_src_child_governs.html b/dom/security/test/csp/file_frame_src_child_governs.html new file mode 100644 index 000000000..a51cb75be --- /dev/null +++ b/dom/security/test/csp/file_frame_src_child_governs.html @@ -0,0 +1,10 @@ +<html> +<head> + <meta charset="utf-8"> + <meta http-equiv="Content-Security-Policy" content="child-src https://example.com">"; +</head> +<body> +<iframe id="testframe"></iframe> +<script type="text/javascript" src="file_frame_src.js"></script> +</body> +</html> diff --git a/dom/security/test/csp/file_frame_src_frame_governs.html b/dom/security/test/csp/file_frame_src_frame_governs.html new file mode 100644 index 000000000..2c5d5857f --- /dev/null +++ b/dom/security/test/csp/file_frame_src_frame_governs.html @@ -0,0 +1,10 @@ +<html> +<head> + <meta charset="utf-8"> + <meta http-equiv="Content-Security-Policy" content="frame-src https://example.com; child-src 'none'">"; +</head> +<body> +<iframe id="testframe"></iframe> +<script type="text/javascript" src="file_frame_src.js"></script> +</body> +</html> diff --git a/dom/security/test/csp/file_frame_src_inner.html b/dom/security/test/csp/file_frame_src_inner.html new file mode 100644 index 000000000..4a2fc6095 --- /dev/null +++ b/dom/security/test/csp/file_frame_src_inner.html @@ -0,0 +1,5 @@ +<html> +<body> +dummy iframe +</body> +</html> diff --git a/dom/security/test/csp/file_ignore_xfo.html b/dom/security/test/csp/file_ignore_xfo.html new file mode 100644 index 000000000..6746a3adb --- /dev/null +++ b/dom/security/test/csp/file_ignore_xfo.html @@ -0,0 +1,10 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Bug 1024557: Ignore x-frame-options if CSP with frame-ancestors exists</title> +</head> +<body> +<div id="cspmessage">Ignoring XFO because of CSP</div> +</body> +</html> diff --git a/dom/security/test/csp/file_ignore_xfo.html^headers^ b/dom/security/test/csp/file_ignore_xfo.html^headers^ new file mode 100644 index 000000000..e93f9e3ec --- /dev/null +++ b/dom/security/test/csp/file_ignore_xfo.html^headers^ @@ -0,0 +1,3 @@ +Content-Security-Policy: frame-ancestors http://mochi.test:8888 +X-Frame-Options: deny +Cache-Control: no-cache diff --git a/dom/security/test/csp/file_image_nonce.html b/dom/security/test/csp/file_image_nonce.html new file mode 100644 index 000000000..5d57bb837 --- /dev/null +++ b/dom/security/test/csp/file_image_nonce.html @@ -0,0 +1,39 @@ +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'> + <title>Bug 1355801: Nonce should not apply to images</title> + </head> +<body> + +<img id='matchingNonce' src='http://mochi.test:8888/tests/image/test/mochitest/blue.png?a' nonce='abc'></img> +<img id='nonMatchingNonce' src='http://mochi.test:8888/tests/image/test/mochitest/blue.png?b' nonce='bca'></img> +<img id='noNonce' src='http://mochi.test:8888/tests/image/test/mochitest/blue.png?c'></img> + +<script type='application/javascript'> + var matchingNonce = document.getElementById('matchingNonce'); + matchingNonce.onload = function(e) { + window.parent.postMessage({result: 'img-with-matching-nonce-loaded'}, '*'); + }; + matchingNonce.onerror = function(e) { + window.parent.postMessage({result: 'img-with-matching-nonce-blocked'}, '*'); + } + + var nonMatchingNonce = document.getElementById('nonMatchingNonce'); + nonMatchingNonce.onload = function(e) { + window.parent.postMessage({result: 'img-with_non-matching-nonce-loaded'}, '*'); + }; + nonMatchingNonce.onerror = function(e) { + window.parent.postMessage({result: 'img-with_non-matching-nonce-blocked'}, '*'); + } + + var noNonce = document.getElementById('noNonce'); + noNonce.onload = function(e) { + window.parent.postMessage({result: 'img-without-nonce-loaded'}, '*'); + }; + noNonce.onerror = function(e) { + window.parent.postMessage({result: 'img-without-nonce-blocked'}, '*'); + } +</script> +</body> +</html> diff --git a/dom/security/test/csp/file_image_nonce.html^headers^ b/dom/security/test/csp/file_image_nonce.html^headers^ new file mode 100644 index 000000000..0d63558c4 --- /dev/null +++ b/dom/security/test/csp/file_image_nonce.html^headers^ @@ -0,0 +1,2 @@ +Content-Security-Policy: img-src 'nonce-abc'; +Cache-Control: no-cache diff --git a/dom/security/test/csp/file_punycode_host_src.js b/dom/security/test/csp/file_punycode_host_src.js new file mode 100644 index 000000000..3505faf70 --- /dev/null +++ b/dom/security/test/csp/file_punycode_host_src.js @@ -0,0 +1,2 @@ +const LOADED = true; +parent.postMessage({result: 'script-allowed'}, "*");
\ No newline at end of file diff --git a/dom/security/test/csp/file_punycode_host_src.sjs b/dom/security/test/csp/file_punycode_host_src.sjs new file mode 100644 index 000000000..3189cc063 --- /dev/null +++ b/dom/security/test/csp/file_punycode_host_src.sjs @@ -0,0 +1,45 @@ +// custom *.sjs for Bug 1224225 +// Punycode in CSP host sources + +const HTML_PART1 = + "<!DOCTYPE HTML>" + + "<html><head><meta charset=\"utf-8\">" + + "<title>Bug 1224225 - CSP source matching should work for punycoded domain names</title>" + + "</head>" + + "<body>" + + "<script id='script' src='"; + +const TESTCASE1 = "http://sub2.ält.example.org/"; +const TESTCASE2 = "http://sub2.xn--lt-uia.example.org/" + +const HTML_PART2 = "tests/dom/security/test/csp/file_punycode_host_src.js'></script>" + + "</body>" + + "</html>"; + +function handleRequest(request, response) +{ + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + response.setHeader("Content-Type", "text/html", false); + + Components.utils.importGlobalProperties(["URLSearchParams"]); + const query = new URLSearchParams(request.queryString); + + + if (query.get("csp")) { + response.setHeader("Content-Security-Policy", query.get("csp"), false); + } + if (query.get("action") == "script-unicode-csp-punycode") { + response.write(HTML_PART1 + TESTCASE1 + HTML_PART2); + return + } + if (query.get("action") == "script-punycode-csp-punycode") { + response.write(HTML_PART1 + TESTCASE2 + HTML_PART2); + return + } + + + // we should never get here, but just in case + // return something unexpected + response.write("do'h"); +} diff --git a/dom/security/test/csp/file_ro_ignore_xfo.html b/dom/security/test/csp/file_ro_ignore_xfo.html new file mode 100644 index 000000000..85e7f0092 --- /dev/null +++ b/dom/security/test/csp/file_ro_ignore_xfo.html @@ -0,0 +1,10 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Bug 1024557: Ignore x-frame-options if CSP with frame-ancestors exists</title> +</head> +<body> +<div id="cspmessage">Ignoring XFO because of CSP_RO</div> +</body> +</html>
\ No newline at end of file diff --git a/dom/security/test/csp/file_ro_ignore_xfo.html^headers^ b/dom/security/test/csp/file_ro_ignore_xfo.html^headers^ new file mode 100644 index 000000000..ab8366f06 --- /dev/null +++ b/dom/security/test/csp/file_ro_ignore_xfo.html^headers^ @@ -0,0 +1,3 @@ +Content-Security-Policy-Report-Only: frame-ancestors http://mochi.test:8888 +X-Frame-Options: deny +Cache-Control: no-cache diff --git a/dom/security/test/csp/file_spawn_service_worker.js b/dom/security/test/csp/file_spawn_service_worker.js new file mode 100644 index 000000000..b262fa10a --- /dev/null +++ b/dom/security/test/csp/file_spawn_service_worker.js @@ -0,0 +1 @@ +// dummy file diff --git a/dom/security/test/csp/file_spawn_shared_worker.js b/dom/security/test/csp/file_spawn_shared_worker.js new file mode 100644 index 000000000..00063bc5c --- /dev/null +++ b/dom/security/test/csp/file_spawn_shared_worker.js @@ -0,0 +1,7 @@ +onconnect = function(e) { + var port = e.ports[0]; + port.addEventListener("message", function(e) { + port.postMessage("shared worker is executing"); + }); + port.start(); +} diff --git a/dom/security/test/csp/file_spawn_worker.js b/dom/security/test/csp/file_spawn_worker.js new file mode 100644 index 000000000..acde7408c --- /dev/null +++ b/dom/security/test/csp/file_spawn_worker.js @@ -0,0 +1 @@ +postMessage("worker is executing"); diff --git a/dom/security/test/csp/file_upgrade_insecure_navigation.sjs b/dom/security/test/csp/file_upgrade_insecure_navigation.sjs new file mode 100644 index 000000000..51afa39bf --- /dev/null +++ b/dom/security/test/csp/file_upgrade_insecure_navigation.sjs @@ -0,0 +1,79 @@ +// Custom *.sjs file specifically for the needs of +// https://bugzilla.mozilla.org/show_bug.cgi?id=1271173 + +"use strict"; +Components.utils.importGlobalProperties(["URLSearchParams"]); + +const TEST_NAVIGATIONAL_UPGRADE = ` + <!DOCTYPE html> + <html> + <head><meta charset="utf-8"></head> + <body> + <a href="http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_navigation.sjs?action=framenav" id="testlink">clickme</a> + <script type="text/javascript"> + // before navigating the current frame we open the window and check that uir applies + var myWin = window.open("http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_navigation.sjs?action=docnav"); + + window.addEventListener("message", receiveMessage, false); + function receiveMessage(event) { + myWin.close(); + var link = document.getElementById('testlink'); + link.click(); + } + </script> + </body> + </html>`; + +const FRAME_NAV = ` + <!DOCTYPE html> + <html> + <head><meta charset="utf-8"></head> + <body> + <script type="text/javascript"> + parent.postMessage({result: document.documentURI}, "*"); + </script> + </body> + </html>`; + +const DOC_NAV = ` + <!DOCTYPE html> + <html> + <head><meta charset="utf-8"></head> + <body> + <script type="text/javascript"> + // call back to the main testpage signaling whether the upgraded succeeded + window.opener.parent.postMessage({result: document.documentURI}, "*"); + // let the opener (iframe) now that we can now close the window and move on with the test. + window.opener.postMessage({result: "readyToMoveOn"}, "*"); + </script> + </body> + </html>`; + +function handleRequest(request, response) { + const query = new URLSearchParams(request.queryString); + + response.setHeader("Cache-Control", "no-cache", false); + response.setHeader("Content-Type", "text/html", false); + if (query.get("csp")) { + response.setHeader("Content-Security-Policy", query.get("csp"), false); + } + + if (query.get("action") === "perform_navigation") { + response.write(TEST_NAVIGATIONAL_UPGRADE); + return; + } + + if (query.get("action") === "framenav") { + response.write(FRAME_NAV); + return; + } + + if (query.get("action") === "docnav") { + response.write(DOC_NAV); + return; + } + + // we should never get here, but just in case + // return something unexpected + response.write("do'h"); +} diff --git a/dom/security/test/csp/file_websocket_explicit.html b/dom/security/test/csp/file_websocket_explicit.html new file mode 100644 index 000000000..51462ab74 --- /dev/null +++ b/dom/security/test/csp/file_websocket_explicit.html @@ -0,0 +1,31 @@ +<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1345615: Allow websocket schemes when using 'self' in CSP</title>
+ <meta http-equiv="Content-Security-Policy" content="connect-src ws:">
+</head>
+<body>
+ <script type="application/javascript">
+ /* load socket using ws */
+ var wsSocket = new WebSocket("ws://example.com/tests/dom/security/test/csp/file_websocket_self");
+ wsSocket.onopen = function(e) {
+ window.parent.postMessage({result: "explicit-ws-loaded"}, "*");
+ wsSocket.close();
+ };
+ wsSocket.onerror = function(e) {
+ window.parent.postMessage({result: "explicit-ws-blocked"}, "*");
+ };
+
+ /* load socket using wss */
+ var wssSocket = new WebSocket("wss://example.com/tests/dom/security/test/csp/file_websocket_self");
+ wssSocket.onopen = function(e) {
+ window.parent.postMessage({result: "explicit-wss-loaded"}, "*");
+ wssSocket.close();
+ };
+ wssSocket.onerror = function(e) {
+ window.parent.postMessage({result: "explicit-wss-blocked"}, "*");
+ };
+ </script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_websocket_self.html b/dom/security/test/csp/file_websocket_self.html new file mode 100644 index 000000000..3ff5f0558 --- /dev/null +++ b/dom/security/test/csp/file_websocket_self.html @@ -0,0 +1,31 @@ +<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1345615: Allow websocket schemes when using 'self' in CSP</title>
+ <meta http-equiv="Content-Security-Policy" content="connect-src 'self'">
+</head>
+<body>
+ <script type="application/javascript">
+ /* load socket using ws */
+ var wsSocket = new WebSocket("ws://example.com/tests/dom/security/test/csp/file_websocket_self");
+ wsSocket.onopen = function(e) {
+ window.parent.postMessage({result: "self-ws-loaded"}, "*");
+ wsSocket.close();
+ };
+ wsSocket.onerror = function(e) {
+ window.parent.postMessage({result: "self-ws-blocked"}, "*");
+ };
+
+ /* load socket using wss */
+ var wssSocket = new WebSocket("wss://example.com/tests/dom/security/test/csp/file_websocket_self");
+ wssSocket.onopen = function(e) {
+ window.parent.postMessage({result: "self-wss-loaded"}, "*");
+ wssSocket.close();
+ };
+ wssSocket.onerror = function(e) {
+ window.parent.postMessage({result: "self-wss-blocked"}, "*");
+ };
+ </script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_websocket_self_wsh.py b/dom/security/test/csp/file_websocket_self_wsh.py new file mode 100644 index 000000000..5fe508a91 --- /dev/null +++ b/dom/security/test/csp/file_websocket_self_wsh.py @@ -0,0 +1,7 @@ +from mod_pywebsocket import msgutil
+
+def web_socket_do_extra_handshake(request):
+ pass
+
+def web_socket_transfer_data(request):
+ pass
diff --git a/dom/security/test/csp/file_worker_src.js b/dom/security/test/csp/file_worker_src.js new file mode 100644 index 000000000..ad3ade6a6 --- /dev/null +++ b/dom/security/test/csp/file_worker_src.js @@ -0,0 +1,52 @@ + +let myWorker = new Worker("file_spawn_worker.js"); +myWorker.onmessage = function(event) { + parent.postMessage({ + result: "worker-allowed", + href: document.location.href, + }, "*"); +} +myWorker.onerror = function(event) { + parent.postMessage({ + result: "worker-blocked", + href: document.location.href, + }, "*"); +} + +// -------------------------------------------- + +var mySharedWorker = new SharedWorker('file_spawn_shared_worker.js'); +mySharedWorker.port.onmessage = function(ev) { + parent.postMessage({ + result: "shared-worker-allowed", + href: document.location.href, + }, "*"); +} +mySharedWorker.onerror = function(evt) { + evt.preventDefault(); + parent.postMessage({ + result: "shared-worker-blocked", + href: document.location.href, + }, "*"); +} +mySharedWorker.port.start(); +mySharedWorker.port.postMessage('foo'); + +// -------------------------------------------- + +navigator.serviceWorker.register('file_spawn_service_worker.js') +.then(function(reg) { + // registration worked + reg.unregister().then(function() { + parent.postMessage({ + result: "service-worker-allowed", + href: document.location.href, + }, "*"); + }); +}).catch(function(error) { + // registration failed + parent.postMessage({ + result: "service-worker-blocked", + href: document.location.href, + }, "*"); +}); diff --git a/dom/security/test/csp/file_worker_src_child_governs.html b/dom/security/test/csp/file_worker_src_child_governs.html new file mode 100644 index 000000000..ca8a683aa --- /dev/null +++ b/dom/security/test/csp/file_worker_src_child_governs.html @@ -0,0 +1,9 @@ +<html> +<head> + <meta charset="utf-8"> + <meta http-equiv="Content-Security-Policy" content="child-src https://example.com; script-src 'nonce-foo'">"; +</head> +<body> +<script type="text/javascript" src="file_worker_src.js" nonce="foo"></script> +</body> +</html> diff --git a/dom/security/test/csp/file_worker_src_script_governs.html b/dom/security/test/csp/file_worker_src_script_governs.html new file mode 100644 index 000000000..0385fee57 --- /dev/null +++ b/dom/security/test/csp/file_worker_src_script_governs.html @@ -0,0 +1,9 @@ +<html> +<head> + <meta charset="utf-8"> + <meta http-equiv="Content-Security-Policy" content="script-src 'nonce-foo' https://example.com">"; +</head> +<body> +<script type="text/javascript" src="file_worker_src.js" nonce="foo"></script> +</body> +</html> diff --git a/dom/security/test/csp/file_worker_src_worker_governs.html b/dom/security/test/csp/file_worker_src_worker_governs.html new file mode 100644 index 000000000..93c8f6122 --- /dev/null +++ b/dom/security/test/csp/file_worker_src_worker_governs.html @@ -0,0 +1,9 @@ +<html> +<head> + <meta charset="utf-8"> + <meta http-equiv="Content-Security-Policy" content="worker-src https://example.com; child-src 'none'; script-src 'nonce-foo'">"; +</head> +<body> +<script type="text/javascript" src="file_worker_src.js" nonce="foo"></script> +</body> +</html> diff --git a/dom/security/test/csp/mochitest.ini b/dom/security/test/csp/mochitest.ini index 8add999c3..ca5c2c6ea 100644 --- a/dom/security/test/csp/mochitest.ini +++ b/dom/security/test/csp/mochitest.ini @@ -206,6 +206,18 @@ support-files = file_iframe_srcdoc.sjs file_iframe_sandbox_srcdoc.html file_iframe_sandbox_srcdoc.html^headers^ + file_ignore_xfo.html + file_ignore_xfo.html^headers^ + file_ro_ignore_xfo.html + file_ro_ignore_xfo.html^headers^ + file_upgrade_insecure_navigation.sjs + file_image_nonce.html + file_image_nonce.html^headers^ + file_punycode_host_src.sjs + file_punycode_host_src.js + file_websocket_self.html + file_websocket_explicit.html + file_websocket_self_wsh.py [test_base-uri.html] [test_blob_data_schemes.html] @@ -292,9 +304,30 @@ tags = mcb [test_strict_dynamic.html] [test_strict_dynamic_parser_inserted.html] [test_strict_dynamic_default_src.html] +[test_upgrade_insecure_navigation.html] [test_iframe_sandbox_srcdoc.html] [test_iframe_srcdoc.html] [test_sandbox_allow_scripts.html] support-files = file_sandbox_allow_scripts.html file_sandbox_allow_scripts.html^headers^ +[test_ignore_xfo.html] +[test_image_nonce.html] +[test_punycode_host_src.html] +[test_websocket_self.html] +skip-if = toolkit == 'android' +[test_worker_src.html] +support-files = + file_worker_src_worker_governs.html + file_worker_src_child_governs.html + file_worker_src_script_governs.html + file_worker_src.js + file_spawn_worker.js + file_spawn_shared_worker.js + file_spawn_service_worker.js +[test_frame_src.html] +support-files = + file_frame_src_frame_governs.html + file_frame_src_child_governs.html + file_frame_src.js + file_frame_src_inner.html diff --git a/dom/security/test/csp/test_child-src_worker.html b/dom/security/test/csp/test_child-src_worker.html index 7dcbd03f6..ea9e7b28e 100644 --- a/dom/security/test/csp/test_child-src_worker.html +++ b/dom/security/test/csp/test_child-src_worker.html @@ -83,19 +83,19 @@ id: "script-src-worker", file: WORKER_TEST_FILE, result : "blocked", - policy : "default-src 'none'; script-src 'self' 'unsafe-inline'" + policy : "default-src 'none'; script-src https://www.example.org 'unsafe-inline'" }, 'script-src-service_worker': { id: "script-src-service_worker", file: SERVICE_WORKER_TEST_FILE, result : "blocked", - policy : "default-src 'none'; script-src 'self' 'unsafe-inline'" + policy : "default-src 'none'; script-src https://www.example.org 'unsafe-inline'" }, 'script-src-self-shared_worker': { id: "script-src-self-shared_worker", file: SHARED_WORKER_TEST_FILE, result : "blocked", - policy : "default-src 'none'; script-src 'self' 'unsafe-inline'" + policy : "default-src 'none'; script-src https://www.example.org 'unsafe-inline'" }, }; diff --git a/dom/security/test/csp/test_frame_src.html b/dom/security/test/csp/test_frame_src.html new file mode 100644 index 000000000..07de90cfa --- /dev/null +++ b/dom/security/test/csp/test_frame_src.html @@ -0,0 +1,84 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Bug 1302667 - Test frame-src</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<iframe style="width:100%;" id="testframe"></iframe> + +<script class="testbody" type="text/javascript"> + +SimpleTest.waitForExplicitFinish(); + +/* Description of the test: + * We load a page inlcuding a frame a CSP of: + * >> frame-src https://example.com; child-src 'none' + * and make sure that frame-src governs frames correctly. In addition, + * we make sure that child-src is discarded in case frame-src is specified. + */ + +const ORIGIN_1 = "https://example.com/tests/dom/security/test/csp/"; +const ORIGIN_2 = "https://test1.example.com/tests/dom/security/test/csp/"; + +let TESTS = [ + // frame-src tests + ORIGIN_1 + "file_frame_src_frame_governs.html", + ORIGIN_2 + "file_frame_src_frame_governs.html", + // child-src tests + ORIGIN_1 + "file_frame_src_child_governs.html", + ORIGIN_2 + "file_frame_src_child_governs.html", +]; + +let testIndex = 0; + +function checkFinish() { + if (testIndex >= TESTS.length) { + window.removeEventListener("message", receiveMessage); + SimpleTest.finish(); + return; + } + runNextTest(); +} + +window.addEventListener("message", receiveMessage); +function receiveMessage(event) { + let href = event.data.href; + let result = event.data.result; + + if (href.startsWith("https://example.com")) { + if (result == "frame-allowed") { + ok(true, "allowing frame from https://example.com (" + result + ")"); + } + else { + ok(false, "blocking frame from https://example.com (" + result + ")"); + } + } + else if (href.startsWith("https://test1.example.com")) { + if (result == "frame-blocked") { + ok(true, "blocking frame from https://test1.example.com (" + result + ")"); + } + else { + ok(false, "allowing frame from https://test1.example.com (" + result + ")"); + } + } + else { + // sanity check, we should never enter that branch, bust just in case... + ok(false, "unexpected result: " + result); + } + checkFinish(); +} + +function runNextTest() { + document.getElementById("testframe").src = TESTS[testIndex]; + testIndex++; +} + +// fire up the tests +runNextTest(); + +</script> +</body> +</html> diff --git a/dom/security/test/csp/test_ignore_xfo.html b/dom/security/test/csp/test_ignore_xfo.html new file mode 100644 index 000000000..fb3aadc6c --- /dev/null +++ b/dom/security/test/csp/test_ignore_xfo.html @@ -0,0 +1,59 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Bug 1024557: Ignore x-frame-options if CSP with frame-ancestors exists</title> + <!-- Including SimpleTest.js so we can use waitForExplicitFinish !--> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<iframe style="width:100%;" id="csp_testframe"></iframe> +<iframe style="width:100%;" id="csp_ro_testframe"></iframe> + +<script class="testbody" type="text/javascript"> + +/* + * We load two frames using: + * x-frame-options: deny + * where the first frame uses a csp and the second a csp_ro including frame-ancestors. + * We make sure that xfo is ignored for regular csp but not for csp_ro. + */ + +SimpleTest.waitForExplicitFinish(); + +var testcounter = 0; +function checkFinished() { + testcounter++; + if (testcounter < 2) { + return; + } + SimpleTest.finish(); +} + +// 1) test XFO with CSP +var csp_testframe = document.getElementById("csp_testframe"); +csp_testframe.onload = function() { + var msg = csp_testframe.contentWindow.document.getElementById("cspmessage"); + is(msg.innerHTML, "Ignoring XFO because of CSP", "Loading frame with with XFO and CSP"); + checkFinished(); +} +csp_testframe.onerror = function() { + ok(false, "sanity: should not fire onerror for csp_testframe"); +} +csp_testframe.src = "file_ignore_xfo.html"; + +// 2) test XFO with CSP_RO +var csp_ro_testframe = document.getElementById("csp_ro_testframe"); +csp_ro_testframe.onload = function() { + var msg = csp_ro_testframe.contentWindow.document.getElementById("cspmessage"); + is(msg, null, "Blocking frame with with XFO and CSP_RO"); + checkFinished(); +} +csp_ro_testframe.onerror = function() { + ok(false, "sanity: should not fire onerror for csp_ro_testframe"); +} +csp_ro_testframe.src = "file_ro_ignore_xfo.html"; + +</script> +</body> +</html> diff --git a/dom/security/test/csp/test_image_nonce.html b/dom/security/test/csp/test_image_nonce.html new file mode 100644 index 000000000..ff6d636b6 --- /dev/null +++ b/dom/security/test/csp/test_image_nonce.html @@ -0,0 +1,60 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Bug 1139297 - Implement CSP upgrade-insecure-requests directive</title> + <!-- Including SimpleTest.js so we can use waitForExplicitFinish !--> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<iframe style="width:100%;" id="testframe"></iframe> + +<script class="testbody" type="text/javascript"> + +/* Description of the test: + * We load three images: (a) with a matching nonce, + (b) with a non matching nonce, + * (c) with no nonce + * and make sure that all three images get blocked because + * "img-src nonce-bla" should not allow an image load, not + * even if the nonce matches*. + */ + +SimpleTest.waitForExplicitFinish(); + +var counter = 0; + +function finishTest() { + window.removeEventListener("message", receiveMessage); + SimpleTest.finish(); +} + +function checkResults(aResult) { + counter++; + if (aResult === "img-with-matching-nonce-blocked" || + aResult === "img-with_non-matching-nonce-blocked" || + aResult === "img-without-nonce-blocked") { + ok (true, "correct result for: " + aResult); + } + else { + ok(false, "unexpected result: " + aResult + "\n\n"); + } + if (counter < 3) { + return; + } + finishTest(); +} + +// a postMessage handler that is used by sandboxed iframes without +// 'allow-same-origin' to bubble up results back to this main page. +window.addEventListener("message", receiveMessage); +function receiveMessage(event) { + checkResults(event.data.result); +} + +document.getElementById("testframe").src = "file_image_nonce.html"; + +</script> +</body> +</html> diff --git a/dom/security/test/csp/test_punycode_host_src.html b/dom/security/test/csp/test_punycode_host_src.html new file mode 100644 index 000000000..8d891725c --- /dev/null +++ b/dom/security/test/csp/test_punycode_host_src.html @@ -0,0 +1,81 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Bug 1224225 - CSP source matching should work for punycoded domain names</title> + <!-- Including SimpleTest.js so we can use waitForExplicitFinish !--> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<iframe style="width:100%;" id="testframe"></iframe> + +<script class="testbody" type="text/javascript"> + +/* Description of the test: + * We load scripts within an iframe and make sure that the + * CSP matching is same for punycode domain names as well as IDNA. + */ + +SimpleTest.waitForExplicitFinish(); + + +var curTest; +var counter = -1; + +const tests = [ + { // test 1 + description: "loads script as sub2.ält.example.org, but whitelist in CSP as sub2.xn--lt-uia.example.org", + action: "script-unicode-csp-punycode", + csp: "script-src http://sub2.xn--lt-uia.example.org;", + expected: "script-allowed", + + }, + { // test 2 + description: "loads script as sub2.xn--lt-uia.example.org, and whitelist in CSP as sub2.xn--lt-uia.example.org", + action: "script-punycode-csp-punycode", + csp: "script-src http://sub2.xn--lt-uia.example.org;", + expected: "script-allowed", + + }, + { // test 3 + description: "loads script as sub2.xn--lt-uia.example.org, and whitelist in CSP as sub2.xn--lt-uia.example.org", + action: "script-punycode-csp-punycode", + csp: "script-src *.xn--lt-uia.example.org;", + expected: "script-allowed", + + }, + +]; + +function finishTest() { + window.removeEventListener("message", receiveMessage); + SimpleTest.finish(); +} + +function checkResults(result) { + is(result, curTest.expected, curTest.description); + loadNextTest(); +} + +window.addEventListener("message", receiveMessage); +function receiveMessage(event) { + checkResults(event.data.result); +} + +function loadNextTest() { + counter++; + if (counter == tests.length) { + finishTest(); + return; + } + curTest = tests[counter]; + var testframe = document.getElementById("testframe"); + testframe.src = `file_punycode_host_src.sjs?action=${curTest.action}&csp=${curTest.csp}`; +} + +loadNextTest(); + +</script> +</body> +</html> diff --git a/dom/security/test/csp/test_upgrade_insecure_navigation.html b/dom/security/test/csp/test_upgrade_insecure_navigation.html new file mode 100644 index 000000000..db6a6a1be --- /dev/null +++ b/dom/security/test/csp/test_upgrade_insecure_navigation.html @@ -0,0 +1,103 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Bug 1271173 - Missing spec on Upgrade Insecure Requests(Navigational Upgrades) </title> + <!-- Including SimpleTest.js so we can use waitForExplicitFinish !--> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<iframe style="width:100%;" id="testframe"></iframe> +<iframe style="width:100%;" id="sandboxedtestframe" + sandbox="allow-scripts allow-top-navigation allow-same-origin allow-pointer-lock allow-popups"></iframe> + +<script class="testbody" type="text/javascript"> +/* + * Description of the test: + * We load a page into an iframe that performs a navigational request. + * We make sure that upgrade-insecure-requests applies and the page + * gets upgraded to https if same origin. + * Please note that uir only applies to sandboxed iframes if + * the value 'allow-same-origin' is specified. + */ + +SimpleTest.waitForExplicitFinish(); + +var tests = [ + { + csp: "upgrade-insecure-requests;", + result: "https", + origin: "http://example.com", + desc: "upgrade-insecure-requests same origin should upgrade" + }, + { + csp: "", + result: "http", + origin: "http://example.com", + desc: "No upgrade-insecure-requests same origin should not upgrade" + }, + { + csp: "upgrade-insecure-requests;", + result: "http", + origin: "http://mochi.test:8888", + desc: "upgrade-insecure-requests cross origin should not upgrade" + }, + { + csp: "", + result: "http", + origin: "http://mochi.test:8888", + desc: "No upgrade-insecure-requests cross origin should not upgrade" + }, +]; + +// initializing to -1 so we start at index 0 when we start the test +var counter = -1; + +function finishTest() { + window.removeEventListener("message", receiveMessage, false); + SimpleTest.finish(); +} + +var subtests = 0; + +window.addEventListener("message", receiveMessage, false); +function receiveMessage(event) { + var result = event.data.result; + // query the scheme from the URL before comparing the result + var scheme = result.substring(0, result.indexOf(":")); + is(scheme, tests[counter].result, tests[counter].desc); + + // @hardcoded 4: + // each test run contains of two subtests (frame and top-level) + // and we load each test into a regular iframe and into a + // sandboxed iframe. only move on to the next test once all + // four results from the subtests have bubbled up. + subtests++; + if (subtests != 4) { + return; + } + subtests = 0; + loadNextTest(); +} + +function loadNextTest() { + counter++; + if (counter == tests.length) { + finishTest(); + return; + } + + var src = tests[counter].origin; + src += "/tests/dom/security/test/csp/file_upgrade_insecure_navigation.sjs"; + src += "?csp=" + escape(tests[counter].csp); + src += "&action=perform_navigation"; + document.getElementById("testframe").src = src; + document.getElementById("sandboxedtestframe").src = src; +} + +// start running the tests +loadNextTest(); + +</script> +</body> +</html> diff --git a/dom/security/test/csp/test_websocket_self.html b/dom/security/test/csp/test_websocket_self.html new file mode 100644 index 000000000..a03c32704 --- /dev/null +++ b/dom/security/test/csp/test_websocket_self.html @@ -0,0 +1,61 @@ +<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1345615: Allow websocket schemes when using 'self' in CSP</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="test_ws_self_frame"></iframe>
+<iframe style="width:100%;" id="test_ws_explicit_frame"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/* Description of the test:
+ * We load an iframe using connect-src 'self' and one
+ * iframe using connect-src ws: and make
+ * sure that in both cases ws: as well as wss: is allowed to load.
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+function finishTest() {
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+}
+
+const TOTAL_TESTS = 4;
+var counter = 0;
+
+function checkResults(result) {
+ counter++;
+ if (result === "self-ws-loaded" || result === "self-wss-loaded" ||
+ result === "explicit-ws-loaded" || result === "explicit-wss-loaded") {
+ ok(true, "Evaluating: " + result);
+ }
+ else {
+ ok(false, "Evaluating: " + result);
+ }
+ if (counter < TOTAL_TESTS) {
+ return;
+ }
+ finishTest();
+}
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ checkResults(event.data.result);
+}
+
+const HOST = "http://example.com/tests/dom/security/test/csp/";
+var test_ws_self_frame = document.getElementById("test_ws_self_frame");
+test_ws_self_frame.src = HOST + "file_websocket_self.html";
+
+var test_ws_explicit_frame = document.getElementById("test_ws_explicit_frame");
+test_ws_explicit_frame.src = HOST + "file_websocket_explicit.html";
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_worker_src.html b/dom/security/test/csp/test_worker_src.html new file mode 100644 index 000000000..3f2b44c9f --- /dev/null +++ b/dom/security/test/csp/test_worker_src.html @@ -0,0 +1,94 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Bug 1302667 - Test worker-src</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<iframe style="width:100%;" id="worker-testframe"></iframe> +<iframe style="width:100%;" id="child-testframe"></iframe> +<iframe style="width:100%;" id="script-testframe"></iframe> + +<script class="testbody" type="text/javascript"> + +SimpleTest.waitForExplicitFinish(); + +/* Description of the test: + * We load a page inlcuding a worker, a shared worker as well as a + * service worker with a CSP of: + * >> worker-src https://example.com; child-src 'none'; script-src 'nonce-foo' + * and make sure that worker-src governs these three kinds of workers correctly. + * In addition, we make sure that child-src as well as script-src is discarded + * in case worker-src is specified. Ideally we would use "script-src 'none'" but + * we have to whitelist the actual script that spawns the workers, hence the nonce. + */ + +let testRuns = 0; +let messageCounter = 0; +let numberSubTests = 9; // 3 workers * 3 frames = 9 + +function checkFinish() { + messageCounter = 0; + if (testRuns == 0) { + testRuns++; + runTests("https://test1.example.com/tests/dom/security/test/csp/") + return; + } + window.removeEventListener("message", receiveMessage); + SimpleTest.finish(); +} + +window.addEventListener("message", receiveMessage); +function receiveMessage(event) { + let href = event.data.href; + let result = event.data.result; + + if (href.startsWith("https://example.com")) { + if (result == "worker-allowed" || + result == "shared-worker-allowed" || + result == "service-worker-allowed") { + ok(true, "allowing worker from https://example.com (" + result + ")"); + } + else { + ok(false, "blocking worker from https://example.com (" + result + ")"); + } + } + else if (href.startsWith("https://test1.example.com")) { + if (result == "worker-blocked" || + result == "shared-worker-blocked" || + result == "service-worker-blocked") { + ok(true, "blocking worker from https://test1.example.com (" + result + ")"); + } + else { + ok(false, "allowing worker from https://test1.example.com (" + result + ")"); + } + } + else { + // sanity check, we should never enter that branch, bust just in case... + ok(false, "unexpected result: " + result); + } + messageCounter++; + if (messageCounter < numberSubTests) { + return; + } + checkFinish(); +} + +function runTests(aPath) { + document.getElementById("worker-testframe").src = aPath + "file_worker_src_worker_governs.html"; + document.getElementById("child-testframe").src = aPath + "file_worker_src_child_governs.html"; + document.getElementById("script-testframe").src = aPath + "file_worker_src_script_governs.html"; +} + +SpecialPowers.pushPrefEnv({"set": [ + ["dom.serviceWorkers.enabled", true], + ["dom.serviceWorkers.testing.enabled", true], +]}, function() { + runTests("https://example.com/tests/dom/security/test/csp/"); +}); + +</script> +</body> +</html> diff --git a/dom/security/test/gtest/TestCSPParser.cpp b/dom/security/test/gtest/TestCSPParser.cpp index fafa7b5d9..893e02db5 100644 --- a/dom/security/test/gtest/TestCSPParser.cpp +++ b/dom/security/test/gtest/TestCSPParser.cpp @@ -204,6 +204,8 @@ TEST(CSPParser, Directives) { static const PolicyTest policies[] = { + { "connect-src xn--mnchen-3ya.de", + "connect-src http://xn--mnchen-3ya.de"}, { "default-src http://www.example.com", "default-src http://www.example.com" }, { "script-src http://www.example.com", @@ -238,6 +240,10 @@ TEST(CSPParser, Directives) "script-src 'nonce-foo' 'strict-dynamic' 'unsafe-inline' https:" }, { "default-src 'sha256-siVR8' 'strict-dynamic' 'unsafe-inline' https: ", "default-src 'sha256-siVR8' 'unsafe-inline' https:" }, + { "worker-src https://example.com", + "worker-src https://example.com" }, + { "worker-src http://worker.com; frame-src http://frame.com; child-src http://child.com", + "worker-src http://worker.com; frame-src http://frame.com; child-src http://child.com" }, }; uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest); diff --git a/dom/svg/DOMSVGPathSegList.cpp b/dom/svg/DOMSVGPathSegList.cpp index edacdfc93..0b811cdb1 100644 --- a/dom/svg/DOMSVGPathSegList.cpp +++ b/dom/svg/DOMSVGPathSegList.cpp @@ -460,6 +460,18 @@ DOMSVGPathSegList::ReplaceItem(DOMSVGPathSeg& aNewItem, float segAsRaw[1 + NS_SVG_PATH_SEG_MAX_ARGS]; domItem->ToSVGPathSegEncodedData(segAsRaw); + if (AnimListMirrorsBaseList()) { + // The anim val list is in sync with the base val list - remove mirroring + // animVal item if necessary. We do this *before* touching InternalList() + // so the removed item can correctly store its internal value. + DOMSVGPathSegList* animVal = + GetDOMWrapperIfExists(InternalAList().GetAnimValKey()); + if (animVal->ItemAt(aIndex)) { + animVal->ItemAt(aIndex)->RemovingFromList(); + animVal->ItemAt(aIndex) = nullptr; + } + } + if (!InternalList().mData.ReplaceElementsAt(internalIndex, 1 + oldArgCount, segAsRaw, 1 + newArgCount, fallible)) { @@ -474,8 +486,13 @@ DOMSVGPathSegList::ReplaceItem(DOMSVGPathSeg& aNewItem, int32_t delta = newArgCount - oldArgCount; if (delta != 0) { - for (uint32_t i = aIndex + 1; i < LengthNoFlush(); ++i) { - mItems[i].mInternalDataIndex += delta; + // Sync up the internal indexes of all ItemProxys that come after aIndex: + UpdateListIndicesFromIndex(aIndex + 1, delta); + if (AnimListMirrorsBaseList()) { + // The anim val list is in sync with the base val list + DOMSVGPathSegList* animVal = + GetDOMWrapperIfExists(InternalAList().GetAnimValKey()); + animVal->UpdateListIndicesFromIndex(aIndex + 1, delta); } } diff --git a/dom/svg/SVGGradientElement.cpp b/dom/svg/SVGGradientElement.cpp index 1bcac67e6..93767c934 100644 --- a/dom/svg/SVGGradientElement.cpp +++ b/dom/svg/SVGGradientElement.cpp @@ -198,13 +198,14 @@ SVGRadialGradientElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenP return SVGRadialGradientElementBinding::Wrap(aCx, this, aGivenProto); } -nsSVGElement::LengthInfo SVGRadialGradientElement::sLengthInfo[5] = +nsSVGElement::LengthInfo SVGRadialGradientElement::sLengthInfo[6] = { { &nsGkAtoms::cx, 50, nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE, SVGContentUtils::X }, { &nsGkAtoms::cy, 50, nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE, SVGContentUtils::Y }, { &nsGkAtoms::r, 50, nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE, SVGContentUtils::XY }, { &nsGkAtoms::fx, 50, nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE, SVGContentUtils::X }, { &nsGkAtoms::fy, 50, nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE, SVGContentUtils::Y }, + { &nsGkAtoms::fr, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE, SVGContentUtils::XY }, }; //---------------------------------------------------------------------- @@ -252,6 +253,12 @@ SVGRadialGradientElement::Fy() return mLengthAttributes[ATTR_FY].ToDOMAnimatedLength(this); } +already_AddRefed<SVGAnimatedLength> +SVGRadialGradientElement::Fr() +{ + return mLengthAttributes[ATTR_FR].ToDOMAnimatedLength(this); +} + //---------------------------------------------------------------------- // nsSVGElement methods diff --git a/dom/svg/SVGGradientElement.h b/dom/svg/SVGGradientElement.h index 7b2c6b220..ce9f3b4b1 100644 --- a/dom/svg/SVGGradientElement.h +++ b/dom/svg/SVGGradientElement.h @@ -139,13 +139,14 @@ public: already_AddRefed<SVGAnimatedLength> R(); already_AddRefed<SVGAnimatedLength> Fx(); already_AddRefed<SVGAnimatedLength> Fy(); + already_AddRefed<SVGAnimatedLength> Fr(); protected: virtual LengthAttributesInfo GetLengthInfo() override; - enum { ATTR_CX, ATTR_CY, ATTR_R, ATTR_FX, ATTR_FY }; - nsSVGLength2 mLengthAttributes[5]; - static LengthInfo sLengthInfo[5]; + enum { ATTR_CX, ATTR_CY, ATTR_R, ATTR_FX, ATTR_FY, ATTR_FR }; + nsSVGLength2 mLengthAttributes[6]; + static LengthInfo sLengthInfo[6]; }; } // namespace dom diff --git a/dom/tests/browser/browser.ini b/dom/tests/browser/browser.ini index 35ebd56c6..4d3a60a2c 100644..100755 --- a/dom/tests/browser/browser.ini +++ b/dom/tests/browser/browser.ini @@ -8,6 +8,7 @@ support-files = worker_bug1004814.js geo_leak_test.html dummy.html + file_workerPerformance.js test_largeAllocation.html test_largeAllocation.html^headers^ !/dom/tests/mochitest/geolocation/network_geolocation.sjs @@ -44,3 +45,4 @@ support-files = support-files = test_new_window_from_content_child.html [browser_xhr_sandbox.js] +[browser_performanceAPI.js] diff --git a/dom/tests/browser/browser_performanceAPI.js b/dom/tests/browser/browser_performanceAPI.js new file mode 100755 index 000000000..2c28fe3d1 --- /dev/null +++ b/dom/tests/browser/browser_performanceAPI.js @@ -0,0 +1,139 @@ +/** + * Bug 1369303 - A test for making sure that performance APIs have been correctly + * spoofed or disabled. + */ + +const TEST_PATH = "http://example.net/browser/" + + "dom/tests/browser/"; + +const PERFORMANCE_TIMINGS = [ + "navigationStart", + "unloadEventStart", + "unloadEventEnd", + "redirectStart", + "redirectEnd", + "fetchStart", + "domainLookupStart", + "domainLookupEnd", + "connectStart", + "connectEnd", + "requestStart", + "responseStart", + "responseEnd", + "domLoading", + "domInteractive", + "domContentLoadedEventStart", + "domContentLoadedEventEnd", + "domComplete", + "loadEventStart", + "loadEventEnd", +]; + +let isRounded = (x, expectedPrecision) => { + let rounded = (Math.floor(x / expectedPrecision) * expectedPrecision); + // First we do the perfectly normal check that should work just fine + if (rounded === x || x === 0) + return true; + + // When we're diving by non-whole numbers, we may not get perfect + // multiplication/division because of floating points + if (Math.abs(rounded - x + expectedPrecision) < .0000001) { + return true; + } else if (Math.abs(rounded - x) < .0000001) { + return true; + } + + // Then we handle the case where you're sub-millisecond and the timer is not + // We check that the timer is not sub-millisecond by assuming it is not if it + // returns an even number of milliseconds + if (expectedPrecision < 1 && Math.round(x) == x) { + if (Math.round(rounded) == x) { + return true; + } + } + + ok(false, "Looming Test Failure, Additional Debugging Info: Expected Precision: " + expectedPrecision + " Measured Value: " + x + + " Rounded Vaue: " + rounded + " Fuzzy1: " + Math.abs(rounded - x + expectedPrecision) + + " Fuzzy 2: " + Math.abs(rounded - x)); + + return false; +}; + +// ================================================================================================ +// ================================================================================================ +add_task(function* () { + let tab = yield BrowserTestUtils.openNewForegroundTab( + gBrowser, TEST_PATH + "dummy.html"); + + yield ContentTask.spawn(tab.linkedBrowser, { + list: PERFORMANCE_TIMINGS, + precision: 2, + isRoundedFunc: isRounded.toString() + }, (data) => { + let timerlist = data.list; + let expectedPrecision = data.precision; + // eslint beleives that isrounded is available in this scope, but if you + // remove the assignment, you will see it is not + // eslint-disable-next-line + let isRounded = eval(data.isRoundedFunc); + + // Check that whether the performance timing API is correctly spoofed. + for (let time of timerlist) { + ok(isRounded(content.performance.timing[time], expectedPrecision), `For reduceTimerPrecision(` + expectedPrecision + `), the timing(${time}) is not correctly rounded: ` + content.performance.timing[time]); + } + + // Try to add some entries. + content.performance.mark("Test"); + content.performance.mark("Test-End"); + content.performance.measure("Test-Measure", "Test", "Test-End"); + + // Check the entries for performance.getEntries/getEntriesByType/getEntriesByName. + is(content.performance.getEntries().length, 3, "For reduceTimerPrecision, there should be 3 entries for performance.getEntries()"); + for (var i = 0; i < 3; i++) { + let startTime = content.performance.getEntries()[i].startTime; + let duration = content.performance.getEntries()[i].duration; + ok(isRounded(startTime, expectedPrecision), "For reduceTimerPrecision(" + expectedPrecision + "), performance.getEntries(" + i + ").startTime is not rounded: " + startTime); + ok(isRounded(duration, expectedPrecision), "For reduceTimerPrecision(" + expectedPrecision + "), performance.getEntries(" + i + ").duration is not rounded: " + duration); + } + is(content.performance.getEntriesByType("mark").length, 2, "For reduceTimerPrecision, there should be 2 entries for performance.getEntriesByType()"); + is(content.performance.getEntriesByName("Test", "mark").length, 1, "For reduceTimerPrecision, there should be 1 entry for performance.getEntriesByName()"); + content.performance.clearMarks(); + content.performance.clearMeasures(); + content.performance.clearResourceTimings(); + }); + gBrowser.removeTab(tab); +}); + +// ================================================================================================ +// ================================================================================================ +add_task(function*() { + let tab = yield BrowserTestUtils.openNewForegroundTab( + gBrowser, TEST_PATH + "dummy.html"); + + yield ContentTask.spawn(tab.linkedBrowser, { + list: PERFORMANCE_TIMINGS, + precision: 2, + isRoundedFunc: isRounded.toString() + }, (data) => { + let expectedPrecision = data.precision; + let workerCall = data.workerCall; + return new Promise(resolve => { + let worker = new content.Worker("file_workerPerformance.js"); + worker.onmessage = function(e) { + if (e.data.type == "status") { + ok(e.data.status, e.data.msg); + } else if (e.data.type == "finish") { + worker.terminate(); + resolve(); + } else { + ok(false, "Unknown message type"); + worker.terminate(); + resolve(); + } + }; + worker.postMessage({precision: expectedPrecision}); + }); + }); + + gBrowser.removeTab(tab); +}); diff --git a/dom/tests/browser/file_workerPerformance.js b/dom/tests/browser/file_workerPerformance.js new file mode 100755 index 000000000..c77ba4377 --- /dev/null +++ b/dom/tests/browser/file_workerPerformance.js @@ -0,0 +1,65 @@ +function ok(a, msg) { + postMessage({type: "status", status: !!a, msg}); +} + +function is(a, b, msg) { + ok(a === b, msg); +} + +function finish() { + postMessage({type: "finish"}); +} + +let isRounded = (x, expectedPrecision) => { + let rounded = (Math.floor(x / expectedPrecision) * expectedPrecision); + // First we do the perfectly normal check that should work just fine + if (rounded === x || x === 0) + return true; + + // When we're diving by non-whole numbers, we may not get perfect + // multiplication/division because of floating points + if (Math.abs(rounded - x + expectedPrecision) < .0000001) { + return true; + } else if (Math.abs(rounded - x) < .0000001) { + return true; + } + + // Then we handle the case where you're sub-millisecond and the timer is not + // We check that the timer is not sub-millisecond by assuming it is not if it + // returns an even number of milliseconds + if (expectedPrecision < 1 && Math.round(x) == x) { + if (Math.round(rounded) == x) { + return true; + } + } + + ok(false, "Looming Test Failure, Additional Debugging Info: Expected Precision: " + expectedPrecision + " Measured Value: " + x + + " Rounded Vaue: " + rounded + " Fuzzy1: " + Math.abs(rounded - x + expectedPrecision) + + " Fuzzy 2: " + Math.abs(rounded - x)); + + return false; +}; + +function runRTPTests(expectedPrecision) { + // Try to add some entries. + performance.mark("Test"); + performance.mark("Test-End"); + performance.measure("Test-Measure", "Test", "Test-End"); + + // Check the entries in performance.getEntries/getEntriesByType/getEntriesByName. + is(performance.getEntries().length, 3, "In a worker, for reduceTimerPrecision: Incorrect number of entries for performance.getEntries() for workers: " + performance.getEntries().length); + for (var i = 0; i < 3; i++) { + let startTime = performance.getEntries()[i].startTime; + let duration = performance.getEntries()[i].duration; + ok(isRounded(startTime, expectedPrecision), "In a worker, for reduceTimerPrecision(" + expectedPrecision + "), performance.getEntries(" + i.toString() + ").startTime is not rounded: " + startTime.toString()); + ok(isRounded(duration, expectedPrecision), "In a worker, for reduceTimerPrecision(" + expectedPrecision + "), performance.getEntries(" + i.toString() + ").duration is not rounded: " + duration.toString()); + } + is(performance.getEntriesByType("mark").length, 2, "In a worker, for reduceTimerPrecision: Incorrect number of entries for performance.getEntriesByType() for workers: " + performance.getEntriesByType("resource").length); + is(performance.getEntriesByName("Test", "mark").length, 1, "In a worker, for reduceTimerPrecision: Incorrect number of entries for performance.getEntriesByName() for workers: " + performance.getEntriesByName("Test", "mark").length); + + finish(); +} + +self.onmessage = function(e) { + runRTPTests(e.data.precision); +}; diff --git a/dom/tests/mochitest/general/mochitest.ini b/dom/tests/mochitest/general/mochitest.ini index d59527801..d00ea1d4b 100644..100755 --- a/dom/tests/mochitest/general/mochitest.ini +++ b/dom/tests/mochitest/general/mochitest.ini @@ -43,6 +43,8 @@ support-files = frameStoragePrevented.html frameStorageChrome.html frameStorageNullprincipal.sjs + worker_child.js + worker_grandchild.js workerStorageAllowed.js workerStoragePrevented.js storagePermissionsUtils.js @@ -108,6 +110,7 @@ support-files = test_offsets.js [test_picture_mutations.html] [test_pointerPreserves3D.html] [test_pointerPreserves3DClip.html] +[test_reduce_time_precision.html] [test_resource_timing.html] [test_resource_timing_cross_origin.html] [test_resource_timing_frameset.html] diff --git a/dom/tests/mochitest/general/test_domWindowUtils_scrollXY.html b/dom/tests/mochitest/general/test_domWindowUtils_scrollXY.html index c6ee89ee3..cf27e5d87 100644 --- a/dom/tests/mochitest/general/test_domWindowUtils_scrollXY.html +++ b/dom/tests/mochitest/general/test_domWindowUtils_scrollXY.html @@ -31,13 +31,13 @@ function checkGetScrollXYState(flush, vals, testName) { let scrollX = {}, scrollY = {}; domWindowUtils.getScrollXY(flush, scrollX, scrollY); - is(scrollX.value, vals[0], "getScrollXY x for test: " + testName); - is(scrollY.value, vals[1], "getScrollXY y for test: " + testName); + is(Math.round(scrollX.value), vals[0], "getScrollXY x for test: " + testName); + is(Math.round(scrollY.value), vals[1], "getScrollXY y for test: " + testName); } function checkWindowScrollState(vals, testName) { - is(cwindow.scrollX, vals[0], "scrollX for test: " + testName); - is(cwindow.scrollY, vals[1], "scrollY for test: " + testName); + is(Math.round(cwindow.scrollX), vals[0], "scrollX for test: " + testName); + is(Math.round(cwindow.scrollY), vals[1], "scrollY for test: " + testName); } // Check initial state (0, 0) @@ -67,8 +67,8 @@ let scrollX = {}, scrollY = {}; domWindowUtils.getScrollXY(false, scrollX, scrollY); - is(scrollX.value, 0, "scrollX is zero for display:none iframe"); - is(scrollY.value, 0, "scrollY is zero for display:none iframe"); + is(Math.round(scrollX.value), 0, "scrollX is zero for display:none iframe"); + is(Math.round(scrollY.value), 0, "scrollY is zero for display:none iframe"); } SimpleTest.waitForExplicitFinish(); diff --git a/dom/tests/mochitest/general/test_reduce_time_precision.html b/dom/tests/mochitest/general/test_reduce_time_precision.html new file mode 100755 index 000000000..6f149f28d --- /dev/null +++ b/dom/tests/mochitest/general/test_reduce_time_precision.html @@ -0,0 +1,143 @@ +<!DOCTYPE HTML> +<html> +<!-- +Tor bug +https://trac.torproject.org/projects/tor/ticket/1517 +--> +<head> + <meta charset="utf-8"> + <title>Test for Tor Bug 1517 and Mozilla Bug 1424341</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="/tests/SimpleTest/SpawnTask.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://trac.torproject.org/projects/tor/ticket/1517">Tor Bug 1517</a> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1424341">Mozilla Bug 1424341</a> + +<!-- Canvas for testing 'currentTime' --> +<canvas id="test-canvas" width="100" height="100"></canvas> + +<!-- The main testing script --> +<script type="application/javascript"> + SimpleTest.requestFlakyTimeout("testing JS time-based fingerprinting"); + + // Prepare for test of AudioContext.currentTime + let audioContext = new AudioContext(); + // Prepare for test of CanvasStream.currentTime + let canvas = document.getElementById("test-canvas"); + let context = canvas.getContext("2d"); + context.fillText("test", 20, 20); + let canvasStream = canvas.captureStream(25); + + // Known ways to generate time stamps, in milliseconds + const timeStampCodes = [ + "performance.now()", + "new Date().getTime()", + "new Event(\"\").timeStamp", + "new File([], \"\").lastModified", + "new File([], \"\").lastModifiedDate.getTime()", + ]; + // These are measured in seconds, so we need to scale them up + var timeStampCodesDOM = timeStampCodes.concat([ + "audioContext.currentTime * 1000", + "canvasStream.currentTime * 1000", + ]); + + let isRounded = (x) => { + expectedPrecision = 2; + let rounded = (Math.floor(x / expectedPrecision) * expectedPrecision); + // First we do the perfectly normal check that should work just fine + if (rounded === x || x === 0) + return true; + + // When we're diving by non-whole numbers, we may not get perfect + // multiplication/division because of floating points. + // When dealing with ms since epoch, a double's precision is on the order + // of 1/5 of a microsecond, so we use a value a little higher than that as + // our epsilon. + // To be clear, this error is introduced in our re-calculation of 'rounded' + // above in JavaScript. + if (Math.abs(rounded - x + expectedPrecision) < .0005) { + return true; + } else if (Math.abs(rounded - x) < .0005) { + return true; + } + + // Then we handle the case where you're sub-millisecond and the timer is not + // We check that the timer is not sub-millisecond by assuming it is not if it + // returns an even number of milliseconds + if (expectedPrecision < 1 && Math.round(x) == x) { + if (Math.round(rounded) == x) { + return true; + } + } + + ok(false, "Looming Test Failure, Additional Debugging Info: Expected Precision: " + expectedPrecision + " Measured Value: " + x + + " Rounded Vaue: " + rounded + " Fuzzy1: " + Math.abs(rounded - x + expectedPrecision) + + " Fuzzy 2: " + Math.abs(rounded - x)); + + return false; + }; + + // ================================================================================================ + // ================================================================================================ + + function* checkWorker(worker) { + // The child worker will send the results back. + let checkWorkerTimeStamps = () => new Promise(function(resolve) { + let onMessage = function(event) { + worker.removeEventListener("message", onMessage); + + let timeStamps = event.data; + for (let i = 0; i < timeStampCodes.length; i++) { + let timeStamp = timeStamps[i]; + ok(isRounded(timeStamp), + "'" + timeStampCodes[i] + + "' should be rounded to nearest 2 ms in workers; saw " + + timeStamp); + } + resolve(); + }; + worker.addEventListener("message", onMessage); + }); + + // Send the codes to its child worker. + worker.postMessage(timeStampCodes); + + // First, check the child's results. + yield checkWorkerTimeStamps(); + // Then, check the grandchild's results. + yield checkWorkerTimeStamps(); + + worker.terminate(); + } + + add_task(function*() { + let worker = new Worker("worker_child.js"); + // Allow ~550 ms to elapse, so we can get non-zero + // time values for all elements. + yield new Promise(resolve => window.setTimeout(resolve, 550)); + yield checkWorker(worker); + }); + + // ================================================================================================ + // ================================================================================================ + + + add_task(function*() { + // Loop through each timeStampCode, evaluate it, + // and check if it is rounded + for (let timeStampCode of timeStampCodesDOM) { + let timeStamp = eval(timeStampCode); + ok(isRounded(timeStamp), + "'" + timeStampCode + "' should be rounded to nearest 2ms" + + " saw " + timeStamp); + } + }); + +</script> + + +</body> +</html> diff --git a/dom/tests/mochitest/general/worker_child.js b/dom/tests/mochitest/general/worker_child.js new file mode 100755 index 000000000..fa340fc65 --- /dev/null +++ b/dom/tests/mochitest/general/worker_child.js @@ -0,0 +1,28 @@ +let timeStampCodes; +let worker = new Worker("worker_grandchild.js"); + +function listenToParent(event) { + self.removeEventListener("message", listenToParent); + timeStampCodes = event.data; + + let timeStamps = []; + for (let timeStampCode of timeStampCodes) { + timeStamps.push(eval(timeStampCode)); + } + // Send the timeStamps to the parent. + postMessage(timeStamps); + + // Tell the grandchild to start. + worker.postMessage(timeStampCodes); +} + +// The worker grandchild will send results back. +function listenToChild(event) { + worker.removeEventListener("message", listenToChild); + // Pass the results to the parent. + postMessage(event.data); + worker.terminate(); +} + +worker.addEventListener("message", listenToChild); +self.addEventListener("message", listenToParent); diff --git a/dom/tests/mochitest/general/worker_grandchild.js b/dom/tests/mochitest/general/worker_grandchild.js new file mode 100755 index 000000000..cd21508b2 --- /dev/null +++ b/dom/tests/mochitest/general/worker_grandchild.js @@ -0,0 +1,10 @@ +self.addEventListener("message", function(event) { + let timeStampCodes = event.data; + + let timeStamps = []; + for (let timeStampCode of timeStampCodes) { + timeStamps.push(eval(timeStampCode)); + } + // Send the timeStamps to the parent. + postMessage(timeStamps); +}); diff --git a/dom/url/URL.h b/dom/url/URL.h index 16b4678ba..45e4dd289 100644 --- a/dom/url/URL.h +++ b/dom/url/URL.h @@ -155,6 +155,12 @@ public: GetHref(aRetval, aRv); } + void + ToJSON(nsAString& aResult, ErrorResult& aRv) const + { + GetHref(aResult, aRv); + } + // URLSearchParamsObserver void URLSearchParamsUpdated(URLSearchParams* aSearchParams) override; diff --git a/dom/url/tests/test_url.html b/dom/url/tests/test_url.html index 3f3f727d6..d07a752bb 100644 --- a/dom/url/tests/test_url.html +++ b/dom/url/tests/test_url.html @@ -438,5 +438,11 @@ url = new URL("data:text/html,<a href=\"http://example.org/?q\">Link</a>"); is(url.href, "data:text/html,<a%20href=\"http://example.org/?q\">Link</a>"); </script> + + <script> + var u = new URL('http://www.example.org'); + ok(u.toJSON(), 'http://www.example.org', "URL.toJSON()"); + is(JSON.stringify(u), "\"http://www.example.org/\"", "JSON.stringify(u) works"); + </script> </body> </html> diff --git a/dom/webidl/CSPDictionaries.webidl b/dom/webidl/CSPDictionaries.webidl index 54008f13a..f8de1c9ad 100644 --- a/dom/webidl/CSPDictionaries.webidl +++ b/dom/webidl/CSPDictionaries.webidl @@ -30,6 +30,7 @@ dictionary CSP { sequence<DOMString> block-all-mixed-content; sequence<DOMString> require-sri-for; sequence<DOMString> sandbox; + sequence<DOMString> worker-src; }; dictionary CSPPolicies { diff --git a/dom/webidl/Document.webidl b/dom/webidl/Document.webidl index c895fad39..f05656e84 100644 --- a/dom/webidl/Document.webidl +++ b/dom/webidl/Document.webidl @@ -275,10 +275,11 @@ partial interface Document { object registerElement(DOMString name, optional ElementRegistrationOptions options); }; -// http://dvcs.w3.org/hg/webperf/raw-file/tip/specs/PageVisibility/Overview.html#sec-document-interface +// https://w3c.github.io/page-visibility/#extensions-to-the-document-interface partial interface Document { readonly attribute boolean hidden; readonly attribute VisibilityState visibilityState; + attribute EventHandler onvisibilitychange; }; // http://dev.w3.org/csswg/cssom/#extensions-to-the-document-interface diff --git a/dom/webidl/HTMLButtonElement.webidl b/dom/webidl/HTMLButtonElement.webidl index c50e09ae0..579efa39c 100644 --- a/dom/webidl/HTMLButtonElement.webidl +++ b/dom/webidl/HTMLButtonElement.webidl @@ -44,6 +44,5 @@ interface HTMLButtonElement : HTMLElement { boolean reportValidity(); void setCustomValidity(DOMString error); -// Not yet implemented: -// readonly attribute NodeList labels; + readonly attribute NodeList labels; }; diff --git a/dom/webidl/HTMLInputElement.webidl b/dom/webidl/HTMLInputElement.webidl index d3d537f84..050d19510 100644 --- a/dom/webidl/HTMLInputElement.webidl +++ b/dom/webidl/HTMLInputElement.webidl @@ -111,7 +111,7 @@ interface HTMLInputElement : HTMLElement { boolean reportValidity(); void setCustomValidity(DOMString error); - // Bug 850365 readonly attribute NodeList labels; + readonly attribute NodeList? labels; void select(); diff --git a/dom/webidl/HTMLMediaElement.webidl b/dom/webidl/HTMLMediaElement.webidl index 456579ec1..313686dac 100644 --- a/dom/webidl/HTMLMediaElement.webidl +++ b/dom/webidl/HTMLMediaElement.webidl @@ -153,6 +153,7 @@ partial interface HTMLMediaElement { attribute EventHandler onmozinterruptend; }; +#ifdef MOZ_EME // Encrypted Media Extensions partial interface HTMLMediaElement { [Pref="media.eme.apiVisible"] @@ -168,6 +169,7 @@ partial interface HTMLMediaElement { [Pref="media.eme.apiVisible"] attribute EventHandler onwaitingforkey; }; +#endif // This is just for testing partial interface HTMLMediaElement { diff --git a/dom/webidl/HTMLMeterElement.webidl b/dom/webidl/HTMLMeterElement.webidl index 1f80764e9..104e00353 100644 --- a/dom/webidl/HTMLMeterElement.webidl +++ b/dom/webidl/HTMLMeterElement.webidl @@ -26,8 +26,5 @@ interface HTMLMeterElement : HTMLElement { [SetterThrows] attribute double optimum; - /** - * The labels attribute will be done with bug 556743. - */ - //readonly attribute NodeList labels; + readonly attribute NodeList labels; }; diff --git a/dom/webidl/HTMLOutputElement.webidl b/dom/webidl/HTMLOutputElement.webidl index 05dcf1800..d0e4ecbe6 100644 --- a/dom/webidl/HTMLOutputElement.webidl +++ b/dom/webidl/HTMLOutputElement.webidl @@ -33,6 +33,5 @@ interface HTMLOutputElement : HTMLElement { boolean reportValidity(); void setCustomValidity(DOMString error); -// Not yet implemented (bug 556743). -// readonly attribute NodeList labels; + readonly attribute NodeList labels; }; diff --git a/dom/webidl/HTMLProgressElement.webidl b/dom/webidl/HTMLProgressElement.webidl index 3d1000d22..028728e22 100644 --- a/dom/webidl/HTMLProgressElement.webidl +++ b/dom/webidl/HTMLProgressElement.webidl @@ -17,9 +17,5 @@ interface HTMLProgressElement : HTMLElement { [SetterThrows] attribute double max; readonly attribute double position; - - /** - * The labels attribute will be done with bug 567740. - */ - //readonly attribute NodeList labels; + readonly attribute NodeList labels; }; diff --git a/dom/webidl/HTMLSelectElement.webidl b/dom/webidl/HTMLSelectElement.webidl index 74fc7b2cf..b18ca3634 100644 --- a/dom/webidl/HTMLSelectElement.webidl +++ b/dom/webidl/HTMLSelectElement.webidl @@ -53,7 +53,7 @@ interface HTMLSelectElement : HTMLElement { boolean reportValidity(); void setCustomValidity(DOMString error); -// NYI: readonly attribute NodeList labels; + readonly attribute NodeList labels; // https://www.w3.org/Bugs/Public/show_bug.cgi?id=20720 void remove(); diff --git a/dom/webidl/HTMLTextAreaElement.webidl b/dom/webidl/HTMLTextAreaElement.webidl index b1005ed42..4df687a0b 100644 --- a/dom/webidl/HTMLTextAreaElement.webidl +++ b/dom/webidl/HTMLTextAreaElement.webidl @@ -57,7 +57,7 @@ interface HTMLTextAreaElement : HTMLElement { boolean reportValidity(); void setCustomValidity(DOMString error); - // readonly attribute NodeList labels; + readonly attribute NodeList labels; void select(); [Throws] diff --git a/dom/webidl/Navigator.webidl b/dom/webidl/Navigator.webidl index 56461e429..5452f3247 100644 --- a/dom/webidl/Navigator.webidl +++ b/dom/webidl/Navigator.webidl @@ -348,12 +348,14 @@ partial interface Navigator { readonly attribute LegacyMozTCPSocket mozTCPSocket; }; +#ifdef MOZ_EME partial interface Navigator { [Pref="media.eme.apiVisible", NewObject] Promise<MediaKeySystemAccess> requestMediaKeySystemAccess(DOMString keySystem, sequence<MediaKeySystemConfiguration> supportedConfigurations); }; +#endif #ifdef NIGHTLY_BUILD partial interface Navigator { diff --git a/dom/webidl/PerformanceTiming.webidl b/dom/webidl/PerformanceTiming.webidl index f75a46b7c..e14201440 100644 --- a/dom/webidl/PerformanceTiming.webidl +++ b/dom/webidl/PerformanceTiming.webidl @@ -21,8 +21,7 @@ interface PerformanceTiming { readonly attribute unsigned long long domainLookupEnd; readonly attribute unsigned long long connectStart; readonly attribute unsigned long long connectEnd; - // secureConnectionStart will be implemneted in bug 772589 - // readonly attribute unsigned long long secureConnectionStart; + readonly attribute unsigned long long secureConnectionStart; readonly attribute unsigned long long requestStart; readonly attribute unsigned long long responseStart; readonly attribute unsigned long long responseEnd; diff --git a/dom/webidl/SVGRadialGradientElement.webidl b/dom/webidl/SVGRadialGradientElement.webidl index d4a3724f6..8d7ce9016 100644 --- a/dom/webidl/SVGRadialGradientElement.webidl +++ b/dom/webidl/SVGRadialGradientElement.webidl @@ -21,5 +21,7 @@ interface SVGRadialGradientElement : SVGGradientElement { readonly attribute SVGAnimatedLength fx; [Constant] readonly attribute SVGAnimatedLength fy; - // readonly attribute SVGAnimatedLength fr; + // XXX: Bug 1242048 + // [SameObject] + readonly attribute SVGAnimatedLength fr; }; diff --git a/dom/webidl/URL.webidl b/dom/webidl/URL.webidl index 0baa9913c..4d491e1b3 100644 --- a/dom/webidl/URL.webidl +++ b/dom/webidl/URL.webidl @@ -44,9 +44,12 @@ interface URL { attribute USVString pathname; [Throws] attribute USVString search; - readonly attribute URLSearchParams searchParams; + [SameObject] readonly attribute URLSearchParams searchParams; [Throws] attribute USVString hash; + + [Throws] + USVString toJSON(); }; partial interface URL { diff --git a/dom/webidl/Window.webidl b/dom/webidl/Window.webidl index 055a274cc..36b1f0313 100644 --- a/dom/webidl/Window.webidl +++ b/dom/webidl/Window.webidl @@ -182,14 +182,10 @@ partial interface Window { [ChromeOnly] void mozScrollSnap(); // The four properties below are double per spec at the moment, but whether // that will continue is unclear. - //[Replaceable, Throws] readonly attribute double scrollX; - //[Replaceable, Throws] readonly attribute double pageXOffset; - //[Replaceable, Throws] readonly attribute double scrollY; - //[Replaceable, Throws] readonly attribute double pageYOffset; - [Replaceable, Throws] readonly attribute long scrollX; - [Replaceable, Throws] readonly attribute long pageXOffset; - [Replaceable, Throws] readonly attribute long scrollY; - [Replaceable, Throws] readonly attribute long pageYOffset; + [Replaceable, Throws] readonly attribute double scrollX; + [Throws] readonly attribute double pageXOffset; + [Replaceable, Throws] readonly attribute double scrollY; + [Throws] readonly attribute double pageYOffset; // client // These are writable because we allow chrome to write them. And they need diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index f24c366e8..8682aee97 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -9,6 +9,7 @@ GENERATED_WEBIDL_FILES = [ ] PREPROCESSED_WEBIDL_FILES = [ + 'HTMLMediaElement.webidl', 'Navigator.webidl', 'Node.webidl', 'Promise.webidl', @@ -210,7 +211,6 @@ WEBIDL_FILES = [ 'HTMLLIElement.webidl', 'HTMLLinkElement.webidl', 'HTMLMapElement.webidl', - 'HTMLMediaElement.webidl', 'HTMLMenuElement.webidl', 'HTMLMenuItemElement.webidl', 'HTMLMetaElement.webidl', @@ -773,7 +773,7 @@ if CONFIG['MOZ_BUILD_APP'] in ['xulrunner'] or CONFIG['MOZ_PHOENIX'] or CONFIG[' 'BrowserFeedWriter.webidl', ] -if CONFIG['MOZ_BUILD_APP'] in ['mobile/android', 'xulrunner'] or CONFIG['MOZ_PHOENIX']: +if CONFIG['MOZ_PHOENIX'] or CONFIG['MOZ_FENNEC'] or CONFIG['MOZ_XULRUNNER']: WEBIDL_FILES += [ 'External.webidl', ] diff --git a/dom/workers/WorkerScope.cpp b/dom/workers/WorkerScope.cpp index d9a987b62..54252e53b 100644 --- a/dom/workers/WorkerScope.cpp +++ b/dom/workers/WorkerScope.cpp @@ -968,11 +968,4 @@ IsDebuggerSandbox(JSObject* object) SimpleGlobalObject::GlobalType::WorkerDebuggerSandbox; } -bool -GetterOnlyJSNative(JSContext* aCx, unsigned aArgc, JS::Value* aVp) -{ - JS_ReportErrorNumberASCII(aCx, js::GetErrorMessage, nullptr, JSMSG_GETTER_ONLY); - return false; -} - END_WORKERS_NAMESPACE diff --git a/dom/workers/Workers.h b/dom/workers/Workers.h index ad083d3b8..cd15a4d7c 100644 --- a/dom/workers/Workers.h +++ b/dom/workers/Workers.h @@ -362,14 +362,6 @@ IsDebuggerGlobal(JSObject* global); bool IsDebuggerSandbox(JSObject* object); -// Throws the JSMSG_GETTER_ONLY exception. This shouldn't be used going -// forward -- getter-only properties should just use JS_PSG for the setter -// (implying no setter at all), which will not throw when set in non-strict -// code but will in strict code. Old code should use this only for temporary -// compatibility reasons. -extern bool -GetterOnlyJSNative(JSContext* aCx, unsigned aArgc, JS::Value* aVp); - END_WORKERS_NAMESPACE #endif // mozilla_dom_workers_workers_h__ diff --git a/dom/xul/XULDocument.cpp b/dom/xul/XULDocument.cpp index ae3cdb7eb..1dcb55aee 100644 --- a/dom/xul/XULDocument.cpp +++ b/dom/xul/XULDocument.cpp @@ -1919,26 +1919,26 @@ XULDocument::StartLayout(void) /* static */ bool -XULDocument::MatchAttribute(nsIContent* aContent, +XULDocument::MatchAttribute(Element* aElement, int32_t aNamespaceID, nsIAtom* aAttrName, void* aData) { - NS_PRECONDITION(aContent, "Must have content node to work with!"); + NS_PRECONDITION(aElement, "Must have content node to work with!"); nsString* attrValue = static_cast<nsString*>(aData); if (aNamespaceID != kNameSpaceID_Unknown && aNamespaceID != kNameSpaceID_Wildcard) { return attrValue->EqualsLiteral("*") ? - aContent->HasAttr(aNamespaceID, aAttrName) : - aContent->AttrValueIs(aNamespaceID, aAttrName, *attrValue, + aElement->HasAttr(aNamespaceID, aAttrName) : + aElement->AttrValueIs(aNamespaceID, aAttrName, *attrValue, eCaseMatters); } // Qualified name match. This takes more work. - uint32_t count = aContent->GetAttrCount(); + uint32_t count = aElement->GetAttrCount(); for (uint32_t i = 0; i < count; ++i) { - const nsAttrName* name = aContent->GetAttrNameAt(i); + const nsAttrName* name = aElement->GetAttrNameAt(i); bool nameMatch; if (name->IsAtom()) { nameMatch = name->Atom() == aAttrName; @@ -1950,7 +1950,7 @@ XULDocument::MatchAttribute(nsIContent* aContent, if (nameMatch) { return attrValue->EqualsLiteral("*") || - aContent->AttrValueIs(name->NamespaceID(), name->LocalName(), + aElement->AttrValueIs(name->NamespaceID(), name->LocalName(), *attrValue, eCaseMatters); } } diff --git a/dom/xul/XULDocument.h b/dom/xul/XULDocument.h index a2f82bb89..06abb797f 100644 --- a/dom/xul/XULDocument.h +++ b/dom/xul/XULDocument.h @@ -180,7 +180,7 @@ public: NS_IMETHOD OnScriptCompileComplete(JSScript* aScript, nsresult aStatus) override; static bool - MatchAttribute(nsIContent* aContent, + MatchAttribute(Element* aContent, int32_t aNameSpaceID, nsIAtom* aAttrName, void* aData); |