diff options
Diffstat (limited to 'dom/base')
46 files changed, 1144 insertions, 461 deletions
diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index 886acc670..092755590 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,12 +177,18 @@ nsIContent::DoGetClasses() const } } - return AsElement()->GetParsedAttr(nsGkAtoms::_class); + return GetParsedAttr(nsGkAtoms::_class); } NS_IMETHODIMP Element::QueryInterface(REFNSIID aIID, void** aInstancePtr) { + if (aIID.Equals(NS_GET_IID(Element))) { + NS_ADDREF_THIS(); + *aInstancePtr = this; + return NS_OK; + } + NS_ASSERTION(aInstancePtr, "QueryInterface requires a non-NULL destination!"); nsresult rv = FragmentOrElement::QueryInterface(aIID, aInstancePtr); @@ -1839,6 +1844,24 @@ Element::UnbindFromTree(bool aDeep, bool aNullParent) SetParentIsContent(false); } +#ifdef DEBUG + // If we can get access to the PresContext, then we sanity-check that + // we're not leaving behind a pointer to ourselves as the PresContext's + // cached provider of the viewport's scrollbar styles. + if (document) { + nsIPresShell* presShell = document->GetShell(); + if (presShell) { + nsPresContext* presContext = presShell->GetPresContext(); + if (presContext) { + MOZ_ASSERT(this != + presContext->GetViewportScrollbarStylesOverrideNode(), + "Leaving behind a raw pointer to this node (as having " + "propagated scrollbar styles) - that's dangerous..."); + } + } + } +#endif + // Ensure that CSS transitions don't continue on an element at a // different place in the tree (even if reinserted before next // animation refresh). 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/FileReader.cpp b/dom/base/FileReader.cpp index 003edc61f..63a0ef2ee 100644 --- a/dom/base/FileReader.cpp +++ b/dom/base/FileReader.cpp @@ -452,8 +452,8 @@ FileReader::GetAsText(Blob *aBlob, } } - nsDependentCSubstring data(aFileData, aDataLen); - return nsContentUtils::ConvertStringFromEncoding(encoding, data, aResult); + return nsContentUtils::ConvertStringFromEncoding( + encoding, aFileData, aDataLen, aResult); } nsresult diff --git a/dom/base/FragmentOrElement.cpp b/dom/base/FragmentOrElement.cpp index 293177ce7..b22a0d4ff 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; @@ -1932,7 +1937,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_INTERFACE_MAP_BEGIN(FragmentOrElement) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(FragmentOrElement) - NS_INTERFACE_MAP_ENTRY(Element) NS_INTERFACE_MAP_ENTRY(nsIContent) NS_INTERFACE_MAP_ENTRY(nsINode) NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget) 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/IdleRequest.cpp b/dom/base/IdleRequest.cpp index 26190f98b..fb3983d37 100644 --- a/dom/base/IdleRequest.cpp +++ b/dom/base/IdleRequest.cpp @@ -9,7 +9,6 @@ #include "mozilla/Function.h" #include "mozilla/TimeStamp.h" #include "mozilla/dom/IdleDeadline.h" -#include "mozilla/dom/Performance.h" #include "mozilla/dom/PerformanceTiming.h" #include "mozilla/dom/WindowBinding.h" #include "nsComponentManagerUtils.h" @@ -20,138 +19,56 @@ namespace mozilla { namespace dom { -IdleRequest::IdleRequest(JSContext* aCx, nsPIDOMWindowInner* aWindow, - IdleRequestCallback& aCallback, uint32_t aHandle) - : mWindow(aWindow) - , mCallback(&aCallback) +IdleRequest::IdleRequest(IdleRequestCallback* aCallback, uint32_t aHandle) + : mCallback(aCallback) , mHandle(aHandle) , mTimeoutHandle(Nothing()) { - MOZ_ASSERT(aWindow); - - // Get the calling location. - nsJSUtils::GetCallingLocation(aCx, mFileName, &mLineNo, &mColumn); + MOZ_DIAGNOSTIC_ASSERT(mCallback); } IdleRequest::~IdleRequest() { } -NS_IMPL_CYCLE_COLLECTION_CLASS(IdleRequest) +NS_IMPL_CYCLE_COLLECTION(IdleRequest, mCallback) NS_IMPL_CYCLE_COLLECTING_ADDREF(IdleRequest) NS_IMPL_CYCLE_COLLECTING_RELEASE(IdleRequest) -NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IdleRequest) - NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow) - NS_IMPL_CYCLE_COLLECTION_UNLINK(mCallback) -NS_IMPL_CYCLE_COLLECTION_UNLINK_END - -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IdleRequest) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCallback) -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END - NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequest) - NS_INTERFACE_MAP_ENTRY(nsIRunnable) - NS_INTERFACE_MAP_ENTRY(nsICancelableRunnable) - NS_INTERFACE_MAP_ENTRY(nsIIncrementalRunnable) - NS_INTERFACE_MAP_ENTRY(nsITimeoutHandler) - NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsITimeoutHandler) NS_INTERFACE_MAP_END -nsresult -IdleRequest::SetTimeout(uint32_t aTimeout) -{ - int32_t handle; - nsresult rv = nsGlobalWindow::Cast(mWindow)->SetTimeoutOrInterval( - this, aTimeout, false, Timeout::Reason::eIdleCallbackTimeout, &handle); - mTimeoutHandle = Some(handle); - - return rv; -} - -nsresult -IdleRequest::Run() -{ - if (mCallback) { - RunIdleRequestCallback(false); - } - - return NS_OK; -} - -nsresult -IdleRequest::Cancel() +void +IdleRequest::SetTimeoutHandle(int32_t aHandle) { - mCallback = nullptr; - CancelTimeout(); - if (isInList()) { - remove(); - } - Release(); - - return NS_OK; + mTimeoutHandle = Some(aHandle); } -void -IdleRequest::SetDeadline(TimeStamp aDeadline) +uint32_t +IdleRequest::GetTimeoutHandle() const { - mozilla::dom::Performance* perf = mWindow->GetPerformance(); - mDeadline = - perf ? perf->GetDOMTiming()->TimeStampToDOMHighRes(aDeadline) : 0.0; + MOZ_DIAGNOSTIC_ASSERT(mTimeoutHandle.isSome()); + return mTimeoutHandle.value(); } nsresult -IdleRequest::RunIdleRequestCallback(bool aDidTimeout) +IdleRequest::IdleRun(nsPIDOMWindowInner* aWindow, + DOMHighResTimeStamp aDeadline, + bool aDidTimeout) { MOZ_ASSERT(NS_IsMainThread()); + MOZ_DIAGNOSTIC_ASSERT(mCallback); - if (!aDidTimeout) { - CancelTimeout(); - } - - remove(); ErrorResult error; RefPtr<IdleDeadline> deadline = - new IdleDeadline(mWindow, aDidTimeout, mDeadline); + new IdleDeadline(aWindow, aDidTimeout, aDeadline); mCallback->Call(*deadline, error, "requestIdleCallback handler"); - mCallback = nullptr; - Release(); + mCallback = nullptr; + error.SuppressException(); return error.StealNSResult(); } -void -IdleRequest::CancelTimeout() -{ - if (mTimeoutHandle.isSome()) { - nsGlobalWindow::Cast(mWindow)->ClearTimeoutOrInterval( - mTimeoutHandle.value(), Timeout::Reason::eIdleCallbackTimeout); - } -} - -nsresult -IdleRequest::Call() -{ - SetDeadline(TimeStamp::Now()); - return RunIdleRequestCallback(true); -} - -void -IdleRequest::GetLocation(const char** aFileName, uint32_t* aLineNo, - uint32_t* aColumn) -{ - *aFileName = mFileName.get(); - *aLineNo = mLineNo; - *aColumn = mColumn; -} - -void -IdleRequest::MarkForCC() -{ - mCallback->MarkForCC(); -} - } // namespace dom } // namespace mozilla diff --git a/dom/base/IdleRequest.h b/dom/base/IdleRequest.h index cb234430a..acf56f852 100644 --- a/dom/base/IdleRequest.h +++ b/dom/base/IdleRequest.h @@ -12,7 +12,6 @@ #include "nsCOMPtr.h" #include "nsCycleCollectionParticipant.h" #include "nsDOMNavigationTiming.h" -#include "nsITimeoutHandler.h" class nsPIDOMWindowInner; @@ -21,28 +20,19 @@ namespace dom { class IdleRequestCallback; -class IdleRequest final : public nsITimeoutHandler - , public nsIRunnable - , public nsICancelableRunnable - , public nsIIncrementalRunnable - , public LinkedListElement<IdleRequest> +class IdleRequest final : public nsISupports, + public LinkedListElement<IdleRequest> { public: - IdleRequest(JSContext* aCx, nsPIDOMWindowInner* aWindow, - IdleRequestCallback& aCallback, uint32_t aHandle); + IdleRequest(IdleRequestCallback* aCallback, uint32_t aHandle); - virtual nsresult Call() override; - virtual void GetLocation(const char** aFileName, uint32_t* aLineNo, - uint32_t* aColumn) override; - virtual void MarkForCC() override; + nsresult IdleRun(nsPIDOMWindowInner* aWindow, + DOMHighResTimeStamp aDeadline, + bool aDidTimeout); - nsresult SetTimeout(uint32_t aTimout); - nsresult RunIdleRequestCallback(bool aDidTimeout); - void CancelTimeout(); - - NS_DECL_NSIRUNNABLE; - virtual nsresult Cancel() override; - virtual void SetDeadline(mozilla::TimeStamp aDeadline) override; + void SetTimeoutHandle(int32_t aHandle); + bool HasTimeout() const { return mTimeoutHandle.isSome(); } + uint32_t GetTimeoutHandle() const; uint32_t Handle() const { @@ -50,22 +40,14 @@ public: } NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(IdleRequest, nsITimeoutHandler) + NS_DECL_CYCLE_COLLECTION_CLASS(IdleRequest) private: ~IdleRequest(); - // filename, line number and JS language version string of the - // caller of setTimeout() - nsCString mFileName; - uint32_t mLineNo; - uint32_t mColumn; - - nsCOMPtr<nsPIDOMWindowInner> mWindow; RefPtr<IdleRequestCallback> mCallback; - uint32_t mHandle; + const uint32_t mHandle; mozilla::Maybe<int32_t> mTimeoutHandle; - DOMHighResTimeStamp mDeadline; }; } // namespace dom diff --git a/dom/base/Location.cpp b/dom/base/Location.cpp index e3b614931..b6b95aaa6 100644 --- a/dom/base/Location.cpp +++ b/dom/base/Location.cpp @@ -577,19 +577,17 @@ Location::GetPathname(nsAString& aPathname) aPathname.Truncate(); nsCOMPtr<nsIURI> uri; - nsresult result = NS_OK; + nsresult result = GetURI(getter_AddRefs(uri)); + if (NS_FAILED(result) || !uri) { + return result; + } - result = GetURI(getter_AddRefs(uri)); + nsAutoCString file; - nsCOMPtr<nsIURIWithQuery> url(do_QueryInterface(uri)); - if (url) { - nsAutoCString file; + result = uri->GetFilePath(file); - result = url->GetFilePath(file); - - if (NS_SUCCEEDED(result)) { - AppendUTF8toUTF16(file, aPathname); - } + if (NS_SUCCEEDED(result)) { + AppendUTF8toUTF16(file, aPathname); } return result; @@ -604,8 +602,7 @@ Location::SetPathname(const nsAString& aPathname) return rv; } - nsCOMPtr<nsIURIWithQuery> url(do_QueryInterface(uri)); - if (url && NS_SUCCEEDED(url->SetFilePath(NS_ConvertUTF16toUTF8(aPathname)))) { + if (NS_SUCCEEDED(uri->SetFilePath(NS_ConvertUTF16toUTF8(aPathname)))) { return SetURI(uri); } 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/Timeout.h b/dom/base/Timeout.h index e929f3dd1..42e2f57f5 100644 --- a/dom/base/Timeout.h +++ b/dom/base/Timeout.h @@ -41,7 +41,11 @@ public: // default main thread being used. nsresult InitTimer(nsIEventTarget* aTarget, uint32_t aDelay); - enum class Reason { eTimeoutOrInterval, eIdleCallbackTimeout }; + enum class Reason + { + eTimeoutOrInterval, + eIdleCallbackTimeout, + }; #ifdef DEBUG bool HasRefCntOne() const; @@ -62,6 +66,8 @@ public: // True if this is a repeating/interval timer bool mIsInterval; + // Used to allow several reasons for setting a timeout, where each + // 'Reason' value is using a possibly overlapping set of id:s. Reason mReason; // Returned as value of setTimeout() diff --git a/dom/base/TimeoutHandler.cpp b/dom/base/TimeoutHandler.cpp new file mode 100644 index 000000000..78c3f16dd --- /dev/null +++ b/dom/base/TimeoutHandler.cpp @@ -0,0 +1,43 @@ +/* -*- 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 "TimeoutHandler.h" + +namespace mozilla { +namespace dom { + +TimeoutHandler::TimeoutHandler(JSContext* aCx) + : TimeoutHandler() +{ + nsJSUtils::GetCallingLocation(aCx, mFileName, &mLineNo, &mColumn); +} + +nsresult +TimeoutHandler::Call() +{ + return NS_OK; +} + +void +TimeoutHandler::GetLocation(const char** aFileName, uint32_t* aLineNo, + uint32_t* aColumn) +{ + *aFileName = mFileName.get(); + *aLineNo = mLineNo; + *aColumn = mColumn; +} + +NS_IMPL_CYCLE_COLLECTION_0(TimeoutHandler) + +NS_IMPL_CYCLE_COLLECTING_ADDREF(TimeoutHandler) +NS_IMPL_CYCLE_COLLECTING_RELEASE(TimeoutHandler) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TimeoutHandler) + NS_INTERFACE_MAP_ENTRY(nsITimeoutHandler) +NS_INTERFACE_MAP_END + +} // namespace dom +} // namespace mozilla diff --git a/dom/base/TimeoutHandler.h b/dom/base/TimeoutHandler.h new file mode 100644 index 000000000..cb0a0ce94 --- /dev/null +++ b/dom/base/TimeoutHandler.h @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_timeout_handler_h +#define mozilla_dom_timeout_handler_h + +#include "nsCOMPtr.h" +#include "nsISupports.h" +#include "nsITimeoutHandler.h" + +namespace mozilla { +namespace dom { + +/** + * Utility class for implementing nsITimeoutHandlers, designed to be subclassed. + */ +class TimeoutHandler : public nsITimeoutHandler +{ +public: + // TimeoutHandler doesn't actually contain cycles, but subclasses + // probably will. + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_CLASS(TimeoutHandler) + + virtual nsresult Call() override; + virtual void GetLocation(const char** aFileName, uint32_t* aLineNo, + uint32_t* aColumn) override; + virtual void MarkForCC() override {} +protected: + TimeoutHandler() : mFileName(""), mLineNo(0), mColumn(0) {} + explicit TimeoutHandler(JSContext *aCx); + + virtual ~TimeoutHandler() {} +private: + TimeoutHandler(const TimeoutHandler&) = delete; + TimeoutHandler& operator=(const TimeoutHandler&) = delete; + TimeoutHandler& operator=(const TimeoutHandler&&) = delete; + + nsCString mFileName; + uint32_t mLineNo; + uint32_t mColumn; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_timeout_handler_h 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 d237acb03..76c765b1c 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', ] @@ -216,6 +217,7 @@ EXPORTS.mozilla.dom += [ 'TabGroup.h', 'Text.h', 'Timeout.h', + 'TimeoutHandler.h', 'TreeWalker.h', 'WebKitCSSMatrix.h', 'WebSocket.h', @@ -363,6 +365,8 @@ UNIFIED_SOURCES += [ 'TextInputProcessor.cpp', 'ThirdPartyUtil.cpp', 'Timeout.cpp', + 'TimeoutHandler.cpp', + 'TimerClamping.cpp', 'TreeWalker.cpp', 'WebKitCSSMatrix.cpp', 'WebSocket.cpp', @@ -411,7 +415,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 +476,7 @@ include('/ipc/chromium/chromium-config.mozbuild') FINAL_LIBRARY = 'xul' -if CONFIG['MOZ_BUILD_APP'] in ['browser', 'mobile/android', 'xulrunner']: +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/nsContentPolicy.cpp b/dom/base/nsContentPolicy.cpp index 337debcea..5511b9086 100644 --- a/dom/base/nsContentPolicy.cpp +++ b/dom/base/nsContentPolicy.cpp @@ -20,6 +20,7 @@ #include "nsIDOMElement.h" #include "nsIDOMNode.h" #include "nsIDOMWindow.h" +#include "nsITabChild.h" #include "nsIContent.h" #include "nsILoadContext.h" #include "nsCOMArray.h" @@ -89,8 +90,9 @@ nsContentPolicy::CheckPolicy(CPMethod policyMethod, { nsCOMPtr<nsIDOMNode> node(do_QueryInterface(requestingContext)); nsCOMPtr<nsIDOMWindow> window(do_QueryInterface(requestingContext)); - NS_ASSERTION(!requestingContext || node || window, - "Context should be a DOM node or a DOM window!"); + nsCOMPtr<nsITabChild> tabChild(do_QueryInterface(requestingContext)); + NS_ASSERTION(!requestingContext || node || window || tabChild, + "Context should be a DOM node, DOM window or a tabChild!"); } #endif diff --git a/dom/base/nsContentSink.cpp b/dom/base/nsContentSink.cpp index 3d6f069d2..85b3d07bf 100644 --- a/dom/base/nsContentSink.cpp +++ b/dom/base/nsContentSink.cpp @@ -305,6 +305,11 @@ nsContentSink::ProcessHeaderData(nsIAtom* aHeader, const nsAString& aValue, mDocument->SetHeaderData(aHeader, aValue); if (aHeader == nsGkAtoms::setcookie) { + // Don't allow setting cookies in cookie-averse documents. + if (mDocument->IsCookieAverse()) { + return NS_OK; + } + // Note: Necko already handles cookies set via the channel. We can't just // call SetCookie on the channel because we want to do some security checks // here. diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 29d28f8ce..bc8cea35a 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -281,6 +281,7 @@ bool nsContentUtils::sIsCutCopyAllowed = true; bool nsContentUtils::sIsFrameTimingPrefEnabled = false; bool nsContentUtils::sIsPerformanceTimingEnabled = false; bool nsContentUtils::sIsResourceTimingEnabled = false; +bool nsContentUtils::sIsPerformanceNavigationTimingEnabled = false; bool nsContentUtils::sIsUserTimingLoggingEnabled = false; bool nsContentUtils::sIsExperimentalAutocompleteEnabled = false; bool nsContentUtils::sEncodeDecodeURLHash = false; @@ -571,6 +572,9 @@ nsContentUtils::Init() Preferences::AddBoolVarCache(&sIsResourceTimingEnabled, "dom.enable_resource_timing", true); + Preferences::AddBoolVarCache(&sIsPerformanceNavigationTimingEnabled, + "dom.enable_performance_navigation_timing", true); + Preferences::AddBoolVarCache(&sIsUserTimingLoggingEnabled, "dom.performance.enable_user_timing_logging", false); @@ -3717,11 +3721,15 @@ nsContentUtils::IsChildOfSameType(nsIDocument* aDoc) } bool -nsContentUtils::IsScriptType(const nsACString& aContentType) +nsContentUtils::IsPlainTextType(const nsACString& aContentType) { // NOTE: if you add a type here, add it to the CONTENTDLF_CATEGORIES // define in nsContentDLF.h as well. - return aContentType.EqualsLiteral(APPLICATION_JAVASCRIPT) || + return aContentType.EqualsLiteral(TEXT_PLAIN) || + aContentType.EqualsLiteral(TEXT_CSS) || + aContentType.EqualsLiteral(TEXT_CACHE_MANIFEST) || + aContentType.EqualsLiteral(TEXT_VTT) || + aContentType.EqualsLiteral(APPLICATION_JAVASCRIPT) || aContentType.EqualsLiteral(APPLICATION_XJAVASCRIPT) || aContentType.EqualsLiteral(TEXT_ECMASCRIPT) || aContentType.EqualsLiteral(APPLICATION_ECMASCRIPT) || @@ -3731,18 +3739,6 @@ nsContentUtils::IsScriptType(const nsACString& aContentType) } bool -nsContentUtils::IsPlainTextType(const nsACString& aContentType) -{ - // NOTE: if you add a type here, add it to the CONTENTDLF_CATEGORIES - // define in nsContentDLF.h as well. - return aContentType.EqualsLiteral(TEXT_PLAIN) || - aContentType.EqualsLiteral(TEXT_CSS) || - aContentType.EqualsLiteral(TEXT_CACHE_MANIFEST) || - aContentType.EqualsLiteral(TEXT_VTT) || - IsScriptType(aContentType); -} - -bool nsContentUtils::GetWrapperSafeScriptFilename(nsIDocument* aDocument, nsIURI* aURI, nsACString& aScriptURI, @@ -4128,9 +4124,15 @@ nsContentUtils::GetSubdocumentWithOuterWindowId(nsIDocument *aDocument, /* static */ nsresult nsContentUtils::ConvertStringFromEncoding(const nsACString& aEncoding, - const nsACString& aInput, + const char* aInput, + uint32_t aInputLen, nsAString& aOutput) { + CheckedInt32 len = aInputLen; + if (!len.isValid()) { + return NS_ERROR_OUT_OF_MEMORY; + } + nsAutoCString encoding; if (aEncoding.IsEmpty()) { encoding.AssignLiteral("UTF-8"); @@ -4142,7 +4144,7 @@ nsContentUtils::ConvertStringFromEncoding(const nsACString& aEncoding, nsAutoPtr<TextDecoder> decoder(new TextDecoder()); decoder->InitWithEncoding(encoding, false); - decoder->Decode(aInput.BeginReading(), aInput.Length(), false, + decoder->Decode(aInput, len.value(), false, aOutput, rv); return rv.StealNSResult(); } @@ -6281,11 +6283,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 278fbd008..9ae6d2155 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -554,9 +554,17 @@ public: * string (meaning UTF-8) */ static nsresult ConvertStringFromEncoding(const nsACString& aEncoding, - const nsACString& aInput, + const char* aInput, + uint32_t aInputLen, nsAString& aOutput); + static nsresult ConvertStringFromEncoding(const nsACString& aEncoding, + const nsACString& aInput, + nsAString& aOutput) { + return ConvertStringFromEncoding( + aEncoding, aInput.BeginReading(), aInput.Length(), aOutput); + } + /** * Determine whether a buffer begins with a BOM for UTF-8, UTF-16LE, * UTF-16BE @@ -1010,12 +1018,7 @@ public: static bool IsChildOfSameType(nsIDocument* aDoc); /** - '* Returns true if the content-type is any of the supported script types. - */ - static bool IsScriptType(const nsACString& aContentType); - - /** - '* Returns true if the content-type will be rendered as plain-text. + * Returns true if the content-type will be rendered as plain-text. */ static bool IsPlainTextType(const nsACString& aContentType); @@ -2030,6 +2033,14 @@ public: } /* + * Returns true if the performance timing APIs are enabled. + */ + static bool IsPerformanceNavigationTimingEnabled() + { + return sIsPerformanceNavigationTimingEnabled; + } + + /* * Returns true if notification should be sent for peformance timing events. */ static bool SendPerformanceTimingNotifications() @@ -2745,7 +2756,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, @@ -2821,6 +2833,7 @@ private: static uint32_t sHandlingInputTimeout; static bool sIsPerformanceTimingEnabled; static bool sIsResourceTimingEnabled; + static bool sIsPerformanceNavigationTimingEnabled; static bool sIsUserTimingLoggingEnabled; static bool sIsFrameTimingPrefEnabled; static bool sIsExperimentalAutocompleteEnabled; diff --git a/dom/base/nsDOMNavigationTiming.cpp b/dom/base/nsDOMNavigationTiming.cpp index 31b2932fb..32ce8a8cb 100644 --- a/dom/base/nsDOMNavigationTiming.cpp +++ b/dom/base/nsDOMNavigationTiming.cpp @@ -15,6 +15,9 @@ #include "nsPrintfCString.h" #include "mozilla/dom/PerformanceNavigation.h" #include "mozilla/TimeStamp.h" +#include "mozilla/Telemetry.h" + +using namespace mozilla; nsDOMNavigationTiming::nsDOMNavigationTiming() { @@ -30,47 +33,36 @@ nsDOMNavigationTiming::Clear() { mNavigationType = TYPE_RESERVED; mNavigationStartHighRes = 0; - mBeforeUnloadStart = 0; - mUnloadStart = 0; - mUnloadEnd = 0; - mLoadEventStart = 0; - mLoadEventEnd = 0; - mDOMLoading = 0; - mDOMInteractive = 0; - mDOMContentLoadedEventStart = 0; - mDOMContentLoadedEventEnd = 0; - mDOMComplete = 0; - - mLoadEventStartSet = false; - mLoadEventEndSet = false; - mDOMLoadingSet = false; - mDOMInteractiveSet = false; - mDOMContentLoadedEventStartSet = false; - mDOMContentLoadedEventEndSet = false; - mDOMCompleteSet = false; + mBeforeUnloadStart = TimeStamp(); + mUnloadStart = TimeStamp(); + mUnloadEnd = TimeStamp(); + mLoadEventStart = TimeStamp(); + mLoadEventEnd = TimeStamp(); + mDOMLoading = TimeStamp(); + mDOMInteractive = TimeStamp(); + mDOMContentLoadedEventStart = TimeStamp(); + mDOMContentLoadedEventEnd = TimeStamp(); + mDOMComplete = TimeStamp(); + mDocShellHasBeenActiveSinceNavigationStart = false; } DOMTimeMilliSec -nsDOMNavigationTiming::TimeStampToDOM(mozilla::TimeStamp aStamp) const +nsDOMNavigationTiming::TimeStampToDOM(TimeStamp aStamp) const { if (aStamp.IsNull()) { return 0; } - mozilla::TimeDuration duration = aStamp - mNavigationStartTimeStamp; - return GetNavigationStart() + static_cast<int64_t>(duration.ToMilliseconds()); -} -DOMTimeMilliSec nsDOMNavigationTiming::DurationFromStart() -{ - return TimeStampToDOM(mozilla::TimeStamp::Now()); + TimeDuration duration = aStamp - mNavigationStart; + return GetNavigationStart() + static_cast<int64_t>(duration.ToMilliseconds()); } void nsDOMNavigationTiming::NotifyNavigationStart(DocShellState aDocShellState) { mNavigationStartHighRes = (double)PR_Now() / PR_USEC_PER_MSEC; - mNavigationStartTimeStamp = mozilla::TimeStamp::Now(); + mNavigationStart = TimeStamp::Now(); mDocShellHasBeenActiveSinceNavigationStart = (aDocShellState == DocShellState::eActive); } @@ -86,7 +78,7 @@ nsDOMNavigationTiming::NotifyFetchStart(nsIURI* aURI, Type aNavigationType) void nsDOMNavigationTiming::NotifyBeforeUnload() { - mBeforeUnloadStart = DurationFromStart(); + mBeforeUnloadStart = TimeStamp::Now(); } void @@ -99,105 +91,107 @@ nsDOMNavigationTiming::NotifyUnloadAccepted(nsIURI* aOldURI) void nsDOMNavigationTiming::NotifyUnloadEventStart() { - mUnloadStart = DurationFromStart(); + mUnloadStart = TimeStamp::Now(); } void nsDOMNavigationTiming::NotifyUnloadEventEnd() { - mUnloadEnd = DurationFromStart(); + mUnloadEnd = TimeStamp::Now(); } void nsDOMNavigationTiming::NotifyLoadEventStart() { - if (!mLoadEventStartSet) { - mLoadEventStart = DurationFromStart(); - mLoadEventStartSet = true; + if (!mLoadEventStart.IsNull()) { + return; } + mLoadEventStart = TimeStamp::Now(); } void nsDOMNavigationTiming::NotifyLoadEventEnd() { - if (!mLoadEventEndSet) { - mLoadEventEnd = DurationFromStart(); - mLoadEventEndSet = true; + if (!mLoadEventEnd.IsNull()) { + return; } + mLoadEventEnd = TimeStamp::Now(); } void -nsDOMNavigationTiming::SetDOMLoadingTimeStamp(nsIURI* aURI, mozilla::TimeStamp aValue) +nsDOMNavigationTiming::SetDOMLoadingTimeStamp(nsIURI* aURI, TimeStamp aValue) { - if (!mDOMLoadingSet) { - mLoadedURI = aURI; - mDOMLoading = TimeStampToDOM(aValue); - mDOMLoadingSet = true; + if (!mDOMLoading.IsNull()) { + return; } + mLoadedURI = aURI; + mDOMLoading = aValue; } void nsDOMNavigationTiming::NotifyDOMLoading(nsIURI* aURI) { - if (!mDOMLoadingSet) { - mLoadedURI = aURI; - mDOMLoading = DurationFromStart(); - mDOMLoadingSet = true; + if (!mDOMLoading.IsNull()) { + return; } + mLoadedURI = aURI; + mDOMLoading = TimeStamp::Now(); } void nsDOMNavigationTiming::NotifyDOMInteractive(nsIURI* aURI) { - if (!mDOMInteractiveSet) { - mLoadedURI = aURI; - mDOMInteractive = DurationFromStart(); - mDOMInteractiveSet = true; + if (!mDOMInteractive.IsNull()) { + return; } + mLoadedURI = aURI; + mDOMInteractive = TimeStamp::Now(); } void nsDOMNavigationTiming::NotifyDOMComplete(nsIURI* aURI) { - if (!mDOMCompleteSet) { - mLoadedURI = aURI; - mDOMComplete = DurationFromStart(); - mDOMCompleteSet = true; + if (!mDOMComplete.IsNull()) { + return; } + mLoadedURI = aURI; + mDOMComplete = TimeStamp::Now(); } void nsDOMNavigationTiming::NotifyDOMContentLoadedStart(nsIURI* aURI) { - if (!mDOMContentLoadedEventStartSet) { - mLoadedURI = aURI; - mDOMContentLoadedEventStart = DurationFromStart(); - mDOMContentLoadedEventStartSet = true; + if (!mDOMContentLoadedEventStart.IsNull()) { + return; } + + mLoadedURI = aURI; + mDOMContentLoadedEventStart = TimeStamp::Now(); } void nsDOMNavigationTiming::NotifyDOMContentLoadedEnd(nsIURI* aURI) { - if (!mDOMContentLoadedEventEndSet) { - mLoadedURI = aURI; - mDOMContentLoadedEventEnd = DurationFromStart(); - mDOMContentLoadedEventEndSet = true; + if (!mDOMContentLoadedEventEnd.IsNull()) { + return; } + + mLoadedURI = aURI; + mDOMContentLoadedEventEnd = TimeStamp::Now(); } void nsDOMNavigationTiming::NotifyNonBlankPaintForRootContentDocument() { MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(!mNavigationStartTimeStamp.IsNull()); + MOZ_ASSERT(!mNavigationStart.IsNull()); - if (!mNonBlankPaintTimeStamp.IsNull()) { + if (!mNonBlankPaint.IsNull()) { return; } - mNonBlankPaintTimeStamp = TimeStamp::Now(); - TimeDuration elapsed = mNonBlankPaintTimeStamp - mNavigationStartTimeStamp; + mNonBlankPaint = TimeStamp::Now(); + TimeDuration elapsed = mNonBlankPaint - mNavigationStart; if (profiler_is_active()) { nsAutoCString spec; @@ -212,8 +206,8 @@ nsDOMNavigationTiming::NotifyNonBlankPaintForRootContentDocument() if (mDocShellHasBeenActiveSinceNavigationStart) { Telemetry::AccumulateTimeDelta(Telemetry::TIME_TO_NON_BLANK_PAINT_MS, - mNavigationStartTimeStamp, - mNonBlankPaintTimeStamp); + mNavigationStart, + mNonBlankPaint); } } @@ -224,24 +218,24 @@ nsDOMNavigationTiming::NotifyDocShellStateChanged(DocShellState aDocShellState) (aDocShellState == DocShellState::eActive); } -DOMTimeMilliSec -nsDOMNavigationTiming::GetUnloadEventStart() +mozilla::TimeStamp +nsDOMNavigationTiming::GetUnloadEventStartTimeStamp() const { nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager(); nsresult rv = ssm->CheckSameOriginURI(mLoadedURI, mUnloadedURI, false); if (NS_SUCCEEDED(rv)) { return mUnloadStart; } - return 0; + return mozilla::TimeStamp(); } -DOMTimeMilliSec -nsDOMNavigationTiming::GetUnloadEventEnd() +mozilla::TimeStamp +nsDOMNavigationTiming::GetUnloadEventEndTimeStamp() const { nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager(); nsresult rv = ssm->CheckSameOriginURI(mLoadedURI, mUnloadedURI, false); if (NS_SUCCEEDED(rv)) { return mUnloadEnd; } - return 0; + return mozilla::TimeStamp(); } diff --git a/dom/base/nsDOMNavigationTiming.h b/dom/base/nsDOMNavigationTiming.h index 9babece96..3be2527ca 100644 --- a/dom/base/nsDOMNavigationTiming.h +++ b/dom/base/nsDOMNavigationTiming.h @@ -47,38 +47,91 @@ public: mozilla::TimeStamp GetNavigationStartTimeStamp() const { - return mNavigationStartTimeStamp; + return mNavigationStart; + } + + DOMTimeMilliSec GetUnloadEventStart() + { + return TimeStampToDOM(GetUnloadEventStartTimeStamp()); + } + + DOMTimeMilliSec GetUnloadEventEnd() + { + return TimeStampToDOM(GetUnloadEventEndTimeStamp()); } - DOMTimeMilliSec GetUnloadEventStart(); - DOMTimeMilliSec GetUnloadEventEnd(); DOMTimeMilliSec GetDomLoading() const { - return mDOMLoading; + return TimeStampToDOM(mDOMLoading); } DOMTimeMilliSec GetDomInteractive() const { - return mDOMInteractive; + return TimeStampToDOM(mDOMInteractive); } DOMTimeMilliSec GetDomContentLoadedEventStart() const { - return mDOMContentLoadedEventStart; + return TimeStampToDOM(mDOMContentLoadedEventStart); } DOMTimeMilliSec GetDomContentLoadedEventEnd() const { - return mDOMContentLoadedEventEnd; + return TimeStampToDOM(mDOMContentLoadedEventEnd); } DOMTimeMilliSec GetDomComplete() const { - return mDOMComplete; + return TimeStampToDOM(mDOMComplete); } DOMTimeMilliSec GetLoadEventStart() const { - return mLoadEventStart; + return TimeStampToDOM(mLoadEventStart); } DOMTimeMilliSec GetLoadEventEnd() const { - return mLoadEventEnd; + return TimeStampToDOM(mLoadEventEnd); + } + DOMTimeMilliSec GetTimeToNonBlankPaint() const + { + return TimeStampToDOM(mNonBlankPaint); + } + + DOMHighResTimeStamp GetUnloadEventStartHighRes() + { + mozilla::TimeStamp stamp = GetUnloadEventStartTimeStamp(); + if (stamp.IsNull()) { + return 0; + } + return TimeStampToDOMHighRes(stamp); + } + DOMHighResTimeStamp GetUnloadEventEndHighRes() + { + mozilla::TimeStamp stamp = GetUnloadEventEndTimeStamp(); + if (stamp.IsNull()) { + return 0; + } + return TimeStampToDOMHighRes(stamp); + } + DOMHighResTimeStamp GetDomInteractiveHighRes() const + { + return TimeStampToDOMHighRes(mDOMInteractive); + } + DOMHighResTimeStamp GetDomContentLoadedEventStartHighRes() const + { + return TimeStampToDOMHighRes(mDOMContentLoadedEventStart); + } + DOMHighResTimeStamp GetDomContentLoadedEventEndHighRes() const + { + return TimeStampToDOMHighRes(mDOMContentLoadedEventEnd); + } + DOMHighResTimeStamp GetDomCompleteHighRes() const + { + return TimeStampToDOMHighRes(mDOMComplete); + } + DOMHighResTimeStamp GetLoadEventStartHighRes() const + { + return TimeStampToDOMHighRes(mLoadEventStart); + } + DOMHighResTimeStamp GetLoadEventEndHighRes() const + { + return TimeStampToDOMHighRes(mLoadEventEnd); } enum class DocShellState : uint8_t { @@ -108,9 +161,13 @@ public: DOMTimeMilliSec TimeStampToDOM(mozilla::TimeStamp aStamp) const; - inline DOMHighResTimeStamp TimeStampToDOMHighRes(mozilla::TimeStamp aStamp) + inline DOMHighResTimeStamp TimeStampToDOMHighRes(mozilla::TimeStamp aStamp) const { - mozilla::TimeDuration duration = aStamp - mNavigationStartTimeStamp; + MOZ_ASSERT(!aStamp.IsNull(), "The timestamp should not be null"); + if (aStamp.IsNull()) { + return 0; + } + mozilla::TimeDuration duration = aStamp - mNavigationStart; return duration.ToMilliseconds(); } @@ -120,37 +177,29 @@ private: void Clear(); + mozilla::TimeStamp GetUnloadEventStartTimeStamp() const; + mozilla::TimeStamp GetUnloadEventEndTimeStamp() const; + nsCOMPtr<nsIURI> mUnloadedURI; nsCOMPtr<nsIURI> mLoadedURI; Type mNavigationType; DOMHighResTimeStamp mNavigationStartHighRes; - mozilla::TimeStamp mNavigationStartTimeStamp; - mozilla::TimeStamp mNonBlankPaintTimeStamp; - DOMTimeMilliSec DurationFromStart(); - - DOMTimeMilliSec mBeforeUnloadStart; - DOMTimeMilliSec mUnloadStart; - DOMTimeMilliSec mUnloadEnd; - DOMTimeMilliSec mLoadEventStart; - DOMTimeMilliSec mLoadEventEnd; - - DOMTimeMilliSec mDOMLoading; - DOMTimeMilliSec mDOMInteractive; - DOMTimeMilliSec mDOMContentLoadedEventStart; - DOMTimeMilliSec mDOMContentLoadedEventEnd; - DOMTimeMilliSec mDOMComplete; - - // Booleans to keep track of what things we've already been notified - // about. We don't update those once we've been notified about them - // once. - bool mLoadEventStartSet : 1; - bool mLoadEventEndSet : 1; - bool mDOMLoadingSet : 1; - bool mDOMInteractiveSet : 1; - bool mDOMContentLoadedEventStartSet : 1; - bool mDOMContentLoadedEventEndSet : 1; - bool mDOMCompleteSet : 1; + mozilla::TimeStamp mNavigationStart; + mozilla::TimeStamp mNonBlankPaint; + + mozilla::TimeStamp mBeforeUnloadStart; + mozilla::TimeStamp mUnloadStart; + mozilla::TimeStamp mUnloadEnd; + mozilla::TimeStamp mLoadEventStart; + mozilla::TimeStamp mLoadEventEnd; + + mozilla::TimeStamp mDOMLoading; + mozilla::TimeStamp mDOMInteractive; + mozilla::TimeStamp mDOMContentLoadedEventStart; + mozilla::TimeStamp mDOMContentLoadedEventEnd; + mozilla::TimeStamp mDOMComplete; + bool mDocShellHasBeenActiveSinceNavigationStart : 1; }; diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index 8e6920a0e..fd3b52948 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 @@ -2053,10 +2054,17 @@ nsDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup, mFirstChild = content->GetNextSibling(); } mChildren.RemoveChildAt(i); + if (content == mCachedRootElement) { + // Immediately clear mCachedRootElement, now that it's been removed + // from mChildren, so that GetRootElement() will stop returning this + // now-stale value. + mCachedRootElement = nullptr; + } nsNodeUtils::ContentRemoved(this, content, i, previousSibling); content->UnbindFromTree(); } - mCachedRootElement = nullptr; + MOZ_ASSERT(!mCachedRootElement, + "After removing all children, there should be no root elem"); } mInUnlinkOrDeletion = oldVal; @@ -2456,6 +2464,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; } @@ -3903,8 +3920,18 @@ nsDocument::RemoveChildAt(uint32_t aIndex, bool aNotify) DestroyElementMaps(); } - doRemoveChildAt(aIndex, aNotify, oldKid, mChildren); + // Preemptively clear mCachedRootElement, since we may be about to remove it + // from our child list, and we don't want to return this maybe-obsolete value + // from any GetRootElement() calls that happen inside of doRemoveChildAt(). + // (NOTE: for this to be useful, doRemoveChildAt() must NOT trigger any + // GetRootElement() calls until after it's removed the child from mChildren. + // Any call before that point would restore this soon-to-be-obsolete cached + // answer, and our clearing here would be fruitless.) mCachedRootElement = nullptr; + doRemoveChildAt(aIndex, aNotify, oldKid, mChildren); + MOZ_ASSERT(mCachedRootElement != oldKid, + "Stale pointer in mCachedRootElement, after we tried to clear it " + "(maybe somebody called GetRootElement() too early?)"); } void @@ -4330,6 +4357,7 @@ nsDocument::SetScopeObject(nsIGlobalObject* aGlobal) } } +#ifdef MOZ_EME static void CheckIfContainsEMEContent(nsISupports* aSupports, void* aContainsEME) { @@ -4353,6 +4381,7 @@ nsDocument::ContainsEMEContent() static_cast<void*>(&containsEME)); return containsEME; } +#endif // MOZ_EME static void CheckIfContainsMSEContent(nsISupports* aSupports, void* aContainsMSE) @@ -8380,11 +8409,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. @@ -12832,3 +12863,19 @@ nsDocument::CheckCustomElementName(const ElementCreationOptions& aOptions, return is; } + +Selection* +nsIDocument::GetSelection(ErrorResult& aRv) +{ + nsCOMPtr<nsPIDOMWindowInner> window = GetInnerWindow(); + if (!window) { + return nullptr; + } + + NS_ASSERTION(window->IsInnerWindow(), "Should have inner window here!"); + if (!window->IsCurrentInnerWindow()) { + return nullptr; + } + + return nsGlobalWindow::Cast(window)->GetSelection(aRv); +} 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/nsFrameMessageManager.cpp b/dom/base/nsFrameMessageManager.cpp index a4bba4856..049bc0a1a 100644 --- a/dom/base/nsFrameMessageManager.cpp +++ b/dom/base/nsFrameMessageManager.cpp @@ -51,10 +51,6 @@ #include <algorithm> #include "chrome/common/ipc_channel.h" // for IPC::Channel::kMaximumMessageSize -#ifdef MOZ_CRASHREPORTER -#include "nsExceptionHandler.h" -#endif - #ifdef ANDROID #include <android/log.h> #endif diff --git a/dom/base/nsGkAtomList.h b/dom/base/nsGkAtomList.h index 5ece68634..aa4ef2ca3 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") @@ -951,6 +952,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") @@ -1450,6 +1452,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") @@ -2231,6 +2234,8 @@ GK_ATOM(scrollbar_end_backward, "scrollbar-end-backward") GK_ATOM(scrollbar_end_forward, "scrollbar-end-forward") GK_ATOM(scrollbar_thumb_proportional, "scrollbar-thumb-proportional") GK_ATOM(overlay_scrollbars, "overlay-scrollbars") +GK_ATOM(windows_accent_color_applies, "windows-accent-color-applies") +GK_ATOM(windows_accent_color_is_dark, "windows-accent-color-is-dark") GK_ATOM(windows_default_theme, "windows-default-theme") GK_ATOM(mac_graphite_theme, "mac-graphite-theme") GK_ATOM(mac_yosemite_theme, "mac-yosemite-theme") @@ -2260,6 +2265,8 @@ GK_ATOM(_moz_scrollbar_end_backward, "-moz-scrollbar-end-backward") GK_ATOM(_moz_scrollbar_end_forward, "-moz-scrollbar-end-forward") GK_ATOM(_moz_scrollbar_thumb_proportional, "-moz-scrollbar-thumb-proportional") GK_ATOM(_moz_overlay_scrollbars, "-moz-overlay-scrollbars") +GK_ATOM(_moz_windows_accent_color_applies, "-moz-windows-accent-color-applies") +GK_ATOM(_moz_windows_accent_color_is_dark, "-moz-windows-accent-color-is-dark") GK_ATOM(_moz_windows_default_theme, "-moz-windows-default-theme") GK_ATOM(_moz_mac_graphite_theme, "-moz-mac-graphite-theme") GK_ATOM(_moz_mac_yosemite_theme, "-moz-mac-yosemite-theme") diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 8ff4b84ce..738703ef1 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -23,6 +23,7 @@ #include "mozilla/dom/StorageEvent.h" #include "mozilla/dom/StorageEventBinding.h" #include "mozilla/dom/Timeout.h" +#include "mozilla/dom/TimeoutHandler.h" #include "mozilla/IntegerPrintfMacros.h" #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK) #include "mozilla/dom/WindowOrientationObserver.h" @@ -552,29 +553,284 @@ DialogValueHolder::Get(JSContext* aCx, JS::Handle<JSObject*> aScope, } } +class IdleRequestExecutor final : public nsIRunnable + , public nsICancelableRunnable + , public nsIIncrementalRunnable +{ +public: + explicit IdleRequestExecutor(nsGlobalWindow* aWindow) + : mDispatched(false) + , mDeadline(TimeStamp::Now()) + , mWindow(aWindow) + { + MOZ_DIAGNOSTIC_ASSERT(mWindow); + MOZ_DIAGNOSTIC_ASSERT(mWindow->IsInnerWindow()); + } + + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(IdleRequestExecutor, nsIRunnable) + + NS_DECL_NSIRUNNABLE + nsresult Cancel() override; + void SetDeadline(TimeStamp aDeadline) override; + + void MaybeDispatch(); +private: + ~IdleRequestExecutor() {} + + bool mDispatched; + TimeStamp mDeadline; + RefPtr<nsGlobalWindow> mWindow; +}; + +NS_IMPL_CYCLE_COLLECTION_CLASS(IdleRequestExecutor) + +NS_IMPL_CYCLE_COLLECTING_ADDREF(IdleRequestExecutor) +NS_IMPL_CYCLE_COLLECTING_RELEASE(IdleRequestExecutor) + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IdleRequestExecutor) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow) +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IdleRequestExecutor) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequestExecutor) + NS_INTERFACE_MAP_ENTRY(nsIRunnable) + NS_INTERFACE_MAP_ENTRY(nsICancelableRunnable) + NS_INTERFACE_MAP_ENTRY(nsIIncrementalRunnable) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIRunnable) +NS_INTERFACE_MAP_END + +NS_IMETHODIMP +IdleRequestExecutor::Run() +{ + MOZ_ASSERT(NS_IsMainThread()); + + mDispatched = false; + if (mWindow) { + return mWindow->ExecuteIdleRequest(mDeadline); + } + + return NS_OK; +} + +nsresult +IdleRequestExecutor::Cancel() +{ + MOZ_ASSERT(NS_IsMainThread()); + + mWindow = nullptr; + return NS_OK; +} + void -nsGlobalWindow::PostThrottledIdleCallback() +IdleRequestExecutor::SetDeadline(TimeStamp aDeadline) { - AssertIsOnMainThread(); + MOZ_ASSERT(NS_IsMainThread()); - if (mThrottledIdleRequestCallbacks.isEmpty()) + if (!mWindow) { return; + } + + mDeadline = aDeadline; +} - RefPtr<IdleRequest> request(mThrottledIdleRequestCallbacks.popFirst()); - // ownership transferred from mThrottledIdleRequestCallbacks to - // mIdleRequestCallbacks - mIdleRequestCallbacks.insertBack(request); +void +IdleRequestExecutor::MaybeDispatch() +{ + // If we've already dispatched the executor we don't want to do it + // again. Also, if we've called IdleRequestExecutor::Cancel mWindow + // will be null, which indicates that we shouldn't dispatch this + // executor either. + if (mDispatched || !mWindow) { + return; + } + + mDispatched = true; + RefPtr<IdleRequestExecutor> request = this; NS_IdleDispatchToCurrentThread(request.forget()); } -/* static */ void -nsGlobalWindow::InsertIdleCallbackIntoList(IdleRequest* aRequest, - IdleRequests& aList) +class IdleRequestExecutorTimeoutHandler final : public TimeoutHandler +{ +public: + explicit IdleRequestExecutorTimeoutHandler(IdleRequestExecutor* aExecutor) + : mExecutor(aExecutor) + { + } + + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IdleRequestExecutorTimeoutHandler, + TimeoutHandler) + + nsresult Call() override + { + mExecutor->MaybeDispatch(); + return NS_OK; + } +private: + ~IdleRequestExecutorTimeoutHandler() {} + RefPtr<IdleRequestExecutor> mExecutor; +}; + +NS_IMPL_CYCLE_COLLECTION_INHERITED(IdleRequestExecutorTimeoutHandler, TimeoutHandler, mExecutor) + +NS_IMPL_ADDREF_INHERITED(IdleRequestExecutorTimeoutHandler, TimeoutHandler) +NS_IMPL_RELEASE_INHERITED(IdleRequestExecutorTimeoutHandler, TimeoutHandler) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequestExecutorTimeoutHandler) + NS_INTERFACE_MAP_ENTRY(nsITimeoutHandler) +NS_INTERFACE_MAP_END_INHERITING(TimeoutHandler) + +void +nsGlobalWindow::ScheduleIdleRequestDispatch() +{ + AssertIsOnMainThread(); + + if (mIdleRequestCallbacks.isEmpty()) { + if (mIdleRequestExecutor) { + mIdleRequestExecutor->Cancel(); + mIdleRequestExecutor = nullptr; + } + + return; + } + + if (!mIdleRequestExecutor) { + mIdleRequestExecutor = new IdleRequestExecutor(this); + } + + nsPIDOMWindowOuter* outer = GetOuterWindow(); + if (outer && outer->AsOuter()->IsBackground()) { + nsCOMPtr<nsITimeoutHandler> handler = new IdleRequestExecutorTimeoutHandler(mIdleRequestExecutor); + int32_t dummy; + // Set a timeout handler with a timeout of 0 ms to throttle idle + // callback requests coming from a backround window using + // background timeout throttling. + SetTimeoutOrInterval(handler, 0, false, + Timeout::Reason::eIdleCallbackTimeout, &dummy); + return; + } + + mIdleRequestExecutor->MaybeDispatch(); +} + +void +nsGlobalWindow::SuspendIdleRequests() +{ + if (mIdleRequestExecutor) { + mIdleRequestExecutor->Cancel(); + mIdleRequestExecutor = nullptr; + } +} + +void +nsGlobalWindow::ResumeIdleRequests() +{ + MOZ_ASSERT(!mIdleRequestExecutor); + + ScheduleIdleRequestDispatch(); +} + +void +nsGlobalWindow::InsertIdleCallback(IdleRequest* aRequest) { - aList.insertBack(aRequest); + AssertIsOnMainThread(); + mIdleRequestCallbacks.insertBack(aRequest); aRequest->AddRef(); } +void +nsGlobalWindow::RemoveIdleCallback(mozilla::dom::IdleRequest* aRequest) +{ + AssertIsOnMainThread(); + + if (aRequest->HasTimeout()) { + ClearTimeoutOrInterval(aRequest->GetTimeoutHandle(), + Timeout::Reason::eIdleCallbackTimeout); + } + + aRequest->removeFrom(mIdleRequestCallbacks); + aRequest->Release(); +} + +nsresult +nsGlobalWindow::RunIdleRequest(IdleRequest* aRequest, + DOMHighResTimeStamp aDeadline, + bool aDidTimeout) +{ + AssertIsOnMainThread(); + RefPtr<IdleRequest> request(aRequest); + RemoveIdleCallback(request); + return request->IdleRun(AsInner(), aDeadline, aDidTimeout); +} + +nsresult +nsGlobalWindow::ExecuteIdleRequest(TimeStamp aDeadline) +{ + AssertIsOnMainThread(); + RefPtr<IdleRequest> request = mIdleRequestCallbacks.getFirst(); + + if (!request) { + // There are no more idle requests, so stop scheduling idle + // request callbacks. + return NS_OK; + } + + DOMHighResTimeStamp deadline = 0.0; + + if (Performance* perf = GetPerformance()) { + deadline = perf->GetDOMTiming()->TimeStampToDOMHighRes(aDeadline); + } + + nsresult result = RunIdleRequest(request, deadline, false); + + ScheduleIdleRequestDispatch(); + return result; +} + +class IdleRequestTimeoutHandler final : public TimeoutHandler +{ +public: + IdleRequestTimeoutHandler(JSContext* aCx, + IdleRequest* aIdleRequest, + nsPIDOMWindowInner* aWindow) + : TimeoutHandler(aCx) + , mIdleRequest(aIdleRequest) + , mWindow(aWindow) + { + } + + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IdleRequestTimeoutHandler, + TimeoutHandler) + + nsresult Call() override + { + return nsGlobalWindow::Cast(mWindow)->RunIdleRequest(mIdleRequest, 0.0, true); + } + +private: + ~IdleRequestTimeoutHandler() {} + + RefPtr<IdleRequest> mIdleRequest; + nsCOMPtr<nsPIDOMWindowInner> mWindow; +}; + +NS_IMPL_CYCLE_COLLECTION_INHERITED(IdleRequestTimeoutHandler, + TimeoutHandler, + mIdleRequest, + mWindow) + +NS_IMPL_ADDREF_INHERITED(IdleRequestTimeoutHandler, TimeoutHandler) +NS_IMPL_RELEASE_INHERITED(IdleRequestTimeoutHandler, TimeoutHandler) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequestTimeoutHandler) + NS_INTERFACE_MAP_ENTRY(nsITimeoutHandler) +NS_INTERFACE_MAP_END_INHERITING(TimeoutHandler) + uint32_t nsGlobalWindow::RequestIdleCallback(JSContext* aCx, IdleRequestCallback& aCallback, @@ -584,33 +840,36 @@ nsGlobalWindow::RequestIdleCallback(JSContext* aCx, MOZ_RELEASE_ASSERT(IsInnerWindow()); AssertIsOnMainThread(); - uint32_t handle = ++mIdleRequestCallbackCounter; + uint32_t handle = mIdleRequestCallbackCounter++; RefPtr<IdleRequest> request = - new IdleRequest(aCx, AsInner(), aCallback, handle); + new IdleRequest(&aCallback, handle); if (aOptions.mTimeout.WasPassed()) { - aError = request->SetTimeout(aOptions.mTimeout.Value()); - if (NS_WARN_IF(aError.Failed())) { + int32_t timeoutHandle; + nsCOMPtr<nsITimeoutHandler> handler(new IdleRequestTimeoutHandler(aCx, request, AsInner())); + + nsresult rv = SetTimeoutOrInterval( + handler, aOptions.mTimeout.Value(), false, + Timeout::Reason::eIdleCallbackTimeout, &timeoutHandle); + + if (NS_WARN_IF(NS_FAILED(rv))) { return 0; } - } - nsGlobalWindow* outer = GetOuterWindowInternal(); - if (outer && outer->AsOuter()->IsBackground()) { - // mThrottledIdleRequestCallbacks now owns request - InsertIdleCallbackIntoList(request, mThrottledIdleRequestCallbacks); - - NS_DelayedDispatchToCurrentThread( - NewRunnableMethod(this, &nsGlobalWindow::PostThrottledIdleCallback), - 10000); - } else { - MOZ_ASSERT(mThrottledIdleRequestCallbacks.isEmpty()); + request->SetTimeoutHandle(timeoutHandle); + } - // mIdleRequestCallbacks now owns request - InsertIdleCallbackIntoList(request, mIdleRequestCallbacks); + // If the list of idle callback requests is not empty it means that + // we've already dispatched the first idle request. If we're + // suspended we should only queue the idle callback and not schedule + // it to run, that will be done in ResumeIdleRequest. + bool needsScheduling = !IsSuspended() && mIdleRequestCallbacks.isEmpty(); + // mIdleRequestCallbacks now owns request + InsertIdleCallback(request); - NS_IdleDispatchToCurrentThread(request.forget()); + if (needsScheduling) { + ScheduleIdleRequestDispatch(); } return handle; @@ -623,7 +882,7 @@ nsGlobalWindow::CancelIdleCallback(uint32_t aHandle) for (IdleRequest* r : mIdleRequestCallbacks) { if (r->Handle() == aHandle) { - r->Cancel(); + RemoveIdleCallback(r); break; } } @@ -632,29 +891,17 @@ nsGlobalWindow::CancelIdleCallback(uint32_t aHandle) void nsGlobalWindow::DisableIdleCallbackRequests() { - while (!mIdleRequestCallbacks.isEmpty()) { - RefPtr<IdleRequest> request = mIdleRequestCallbacks.popFirst(); - request->Cancel(); + if (mIdleRequestExecutor) { + mIdleRequestExecutor->Cancel(); + mIdleRequestExecutor = nullptr; } - while (!mThrottledIdleRequestCallbacks.isEmpty()) { - RefPtr<IdleRequest> request = mThrottledIdleRequestCallbacks.popFirst(); - request->Cancel(); - } -} - -void nsGlobalWindow::UnthrottleIdleCallbackRequests() -{ - AssertIsOnMainThread(); - - while (!mThrottledIdleRequestCallbacks.isEmpty()) { - RefPtr<IdleRequest> request(mThrottledIdleRequestCallbacks.popFirst()); - mIdleRequestCallbacks.insertBack(request); - NS_IdleDispatchToCurrentThread(request.forget()); + while (!mIdleRequestCallbacks.isEmpty()) { + RefPtr<IdleRequest> request = mIdleRequestCallbacks.getFirst(); + RemoveIdleCallback(request); } } - namespace mozilla { namespace dom { extern uint64_t @@ -1306,6 +1553,7 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow) mSerial(0), mIdleCallbackTimeoutCounter(1), mIdleRequestCallbackCounter(1), + mIdleRequestExecutor(nullptr), #ifdef DEBUG mSetOpenerWindowCalled(false), #endif @@ -2033,14 +2281,11 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindow) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWakeLock) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingStorageEvents) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleRequestExecutor) for (IdleRequest* request : tmp->mIdleRequestCallbacks) { cb.NoteNativeChild(request, NS_CYCLE_COLLECTION_PARTICIPANT(IdleRequest)); } - for (IdleRequest* request : tmp->mThrottledIdleRequestCallbacks) { - cb.NoteNativeChild(request, NS_CYCLE_COLLECTION_PARTICIPANT(IdleRequest)); - } - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleObservers) #ifdef MOZ_GAMEPAD @@ -2147,6 +2392,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow) tmp->UnlinkHostObjectURIs(); + NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleRequestExecutor) tmp->DisableIdleCallbackRequests(); NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER @@ -2878,8 +3124,7 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument, newInnerWindow->mPerformance = Performance::CreateForMainThread(newInnerWindow->AsInner(), currentInner->mPerformance->GetDOMTiming(), - currentInner->mPerformance->GetChannel(), - currentInner->mPerformance->GetParentPerformance()); + currentInner->mPerformance->GetChannel()); } } @@ -4093,22 +4338,7 @@ nsPIDOMWindowInner::CreatePerformanceObjectIfNeeded() timedChannel = nullptr; } if (timing) { - // If we are dealing with an iframe, we will need the parent's performance - // object (so we can add the iframe as a resource of that page). - Performance* parentPerformance = nullptr; - nsCOMPtr<nsPIDOMWindowOuter> parentWindow = GetScriptableParentOrNull(); - if (parentWindow) { - nsPIDOMWindowInner* parentInnerWindow = nullptr; - if (parentWindow) { - parentInnerWindow = parentWindow->GetCurrentInnerWindow(); - } - if (parentInnerWindow) { - parentPerformance = parentInnerWindow->GetPerformance(); - } - } - mPerformance = - Performance::CreateForMainThread(this, timing, timedChannel, - parentPerformance); + mPerformance = Performance::CreateForMainThread(this, timing, timedChannel); } } @@ -6187,7 +6417,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 +6441,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); @@ -10237,12 +10467,6 @@ void nsGlobalWindow::SetIsBackground(bool aIsBackground) ResetTimersForThrottleReduction(gMinBackgroundTimeoutValue); } - if (!aIsBackground) { - nsGlobalWindow* inner = GetCurrentInnerWindowInternal(); - if (inner) { - inner->UnthrottleIdleCallbackRequests(); - } - } #ifdef MOZ_GAMEPAD if (!aIsBackground) { nsGlobalWindow* inner = GetCurrentInnerWindowInternal(); @@ -12036,6 +12260,8 @@ nsGlobalWindow::Suspend() mozilla::dom::workers::SuspendWorkersForWindow(AsInner()); + SuspendIdleRequests(); + for (Timeout* t = mTimeouts.getFirst(); t; t = t->getNext()) { // Leave the timers with the current time remaining. This will // cause the timers to potentially fire when the window is @@ -12146,6 +12372,8 @@ nsGlobalWindow::Resume() t->AddRef(); } + ResumeIdleRequests(); + // Resume all of the workers for this window. We must do this // after timeouts since workers may have queued events that can trigger // a setTimeout(). diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h index eab91c2e4..78bee63a1 100644 --- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -102,6 +102,8 @@ struct nsRect; class nsWindowSizes; +class IdleRequestExecutor; + namespace mozilla { class DOMEventTargetHelper; class ThrottledEventQueue; @@ -118,6 +120,7 @@ class Gamepad; enum class ImageBitmapFormat : uint32_t; class IdleRequest; class IdleRequestCallback; +class IncrementalRunnable; class Location; class MediaQueryList; class MozSelfSupport; @@ -1050,15 +1053,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); } @@ -1097,7 +1100,6 @@ public: mozilla::ErrorResult& aError); void CancelIdleCallback(uint32_t aHandle); - #ifdef MOZ_WEBSPEECH mozilla::dom::SpeechSynthesis* GetSpeechSynthesis(mozilla::ErrorResult& aError); @@ -1579,7 +1581,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); @@ -1762,6 +1764,21 @@ private: mozilla::dom::TabGroup* TabGroupInner(); mozilla::dom::TabGroup* TabGroupOuter(); +public: + void DisableIdleCallbackRequests(); + uint32_t IdleRequestHandle() const { return mIdleRequestCallbackCounter; } + nsresult RunIdleRequest(mozilla::dom::IdleRequest* aRequest, + DOMHighResTimeStamp aDeadline, bool aDidTimeout); + nsresult ExecuteIdleRequest(TimeStamp aDeadline); + void ScheduleIdleRequestDispatch(); + void SuspendIdleRequests(); + void ResumeIdleRequests(); + + typedef mozilla::LinkedList<mozilla::dom::IdleRequest> IdleRequests; + void InsertIdleCallback(mozilla::dom::IdleRequest* aRequest); + + void RemoveIdleCallback(mozilla::dom::IdleRequest* aRequest); + protected: // These members are only used on outer window objects. Make sure // you never set any of these on an inner object! @@ -1912,21 +1929,12 @@ protected: uint32_t mSerial; - void DisableIdleCallbackRequests(); - void UnthrottleIdleCallbackRequests(); - - void PostThrottledIdleCallback(); - - typedef mozilla::LinkedList<mozilla::dom::IdleRequest> IdleRequests; - static void InsertIdleCallbackIntoList(mozilla::dom::IdleRequest* aRequest, - IdleRequests& aList); - // The current idle request callback timeout handle uint32_t mIdleCallbackTimeoutCounter; // The current idle request callback handle uint32_t mIdleRequestCallbackCounter; IdleRequests mIdleRequestCallbacks; - IdleRequests mThrottledIdleRequestCallbacks; + RefPtr<IdleRequestExecutor> mIdleRequestExecutor; #ifdef DEBUG bool mSetOpenerWindowCalled; @@ -2002,6 +2010,7 @@ protected: friend class nsDOMWindowUtils; friend class mozilla::dom::PostMessageEvent; friend class DesktopNotification; + friend class IdleRequestExecutor; static WindowByIdTable* sWindowsById; static bool sWarnedAboutWindowInternal; 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/nsIDocument.h b/dom/base/nsIDocument.h index 5b10c9914..1e0c9562e 100644 --- a/dom/base/nsIDocument.h +++ b/dom/base/nsIDocument.h @@ -151,6 +151,7 @@ class NodeIterator; enum class OrientationType : uint32_t; class ProcessingInstruction; class Promise; +class Selection; class StyleSheetList; class SVGDocument; class SVGSVGElement; @@ -898,6 +899,8 @@ public: */ Element* GetRootElement() const; + mozilla::dom::Selection* GetSelection(mozilla::ErrorResult& aRv); + /** * Retrieve information about the viewport as a data structure. * This will return information in the viewport META data section @@ -1923,6 +1926,34 @@ public: return mMarkedCCGeneration; } + /** + * Returns whether this document is cookie-averse. See + * https://html.spec.whatwg.org/multipage/dom.html#cookie-averse-document-object + */ + bool IsCookieAverse() const + { + // If we are a document that "has no browsing context." + if (!GetInnerWindow()) { + return true; + } + + // If we are a document "whose URL's scheme is not a network scheme." + // NB: Explicitly allow file: URIs to store cookies. + nsCOMPtr<nsIURI> codebaseURI; + NodePrincipal()->GetURI(getter_AddRefs(codebaseURI)); + + if (!codebaseURI) { + return true; + } + + nsAutoCString scheme; + codebaseURI->GetScheme(scheme); + return !scheme.EqualsLiteral("http") && + !scheme.EqualsLiteral("https") && + !scheme.EqualsLiteral("ftp") && + !scheme.EqualsLiteral("file"); + } + bool IsLoadedAsData() { return mLoadedAsData; diff --git a/dom/base/nsINode.cpp b/dom/base/nsINode.cpp index 3a649a61d..715ca93ea 100644 --- a/dom/base/nsINode.cpp +++ b/dom/base/nsINode.cpp @@ -1907,6 +1907,10 @@ void nsINode::doRemoveChildAt(uint32_t aIndex, bool aNotify, nsIContent* aKid, nsAttrAndChildArray& aChildArray) { + // NOTE: This function must not trigger any calls to + // nsIDocument::GetRootElement() calls until *after* it has removed aKid from + // aChildArray. Any calls before then could potentially restore a stale + // value for our cached root element, per note in nsDocument::RemoveChildAt(). NS_PRECONDITION(aKid && aKid->GetParentNode() == this && aKid == GetChildAt(aIndex) && IndexOf(aKid) == (int32_t)aIndex, "Bogus aKid"); 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/nsRange.cpp b/dom/base/nsRange.cpp index 37ba147af..4b4ce7885 100644 --- a/dom/base/nsRange.cpp +++ b/dom/base/nsRange.cpp @@ -3194,7 +3194,7 @@ nsRange::AutoInvalidateSelection::~AutoInvalidateSelection() mIsNested = false; ::InvalidateAllFrames(mCommonAncestor); nsINode* commonAncestor = mRange->GetRegisteredCommonAncestor(); - if (commonAncestor != mCommonAncestor) { + if (commonAncestor && commonAncestor != mCommonAncestor) { ::InvalidateAllFrames(commonAncestor); } } diff --git a/dom/base/nsTreeSanitizer.cpp b/dom/base/nsTreeSanitizer.cpp index dc53ea5fa..323c851c1 100644 --- a/dom/base/nsTreeSanitizer.cpp +++ b/dom/base/nsTreeSanitizer.cpp @@ -169,6 +169,7 @@ nsIAtom** const kAttributesHTML[] = { &nsGkAtoms::contextmenu, &nsGkAtoms::controls, &nsGkAtoms::coords, + &nsGkAtoms::crossorigin, &nsGkAtoms::datetime, &nsGkAtoms::dir, &nsGkAtoms::disabled, @@ -185,6 +186,7 @@ nsIAtom** const kAttributesHTML[] = { &nsGkAtoms::hreflang, &nsGkAtoms::icon, &nsGkAtoms::id, + &nsGkAtoms::integrity, &nsGkAtoms::ismap, &nsGkAtoms::itemid, &nsGkAtoms::itemprop, 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/mochitest.ini b/dom/base/test/mochitest.ini index ea86290d9..ddfd57443 100644 --- a/dom/base/test/mochitest.ini +++ b/dom/base/test/mochitest.ini @@ -609,6 +609,7 @@ skip-if = toolkit == 'android' [test_bug1307730.html] [test_bug1308069.html] [test_bug1314032.html] +[test_bug1375050.html] [test_caretPositionFromPoint.html] [test_change_policy.html] [test_classList.html] 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) { |