summaryrefslogtreecommitdiffstats
path: root/dom/base
diff options
context:
space:
mode:
Diffstat (limited to 'dom/base')
-rw-r--r--dom/base/SimpleTreeIterator.h71
-rwxr-xr-xdom/base/moz.build1
-rw-r--r--dom/base/nsDocument.cpp50
-rw-r--r--dom/base/nsDocument.h33
-rw-r--r--dom/base/nsIDocument.h15
5 files changed, 147 insertions, 23 deletions
diff --git a/dom/base/SimpleTreeIterator.h b/dom/base/SimpleTreeIterator.h
new file mode 100644
index 000000000..7ca504082
--- /dev/null
+++ b/dom/base/SimpleTreeIterator.h
@@ -0,0 +1,71 @@
+/* -*- 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/. */
+
+/**
+ * This is a light-weight tree iterator for `for` loops when full iterator
+ * functionality isn't required.
+ */
+
+#ifndef mozilla_dom_SimpleTreeIterator_h
+#define mozilla_dom_SimpleTreeIterator_h
+
+#include "nsINode.h"
+#include "nsTArray.h"
+#include "mozilla/dom/Element.h"
+
+namespace mozilla {
+namespace dom {
+
+class SimpleTreeIterator {
+public:
+ /**
+ * Initialize an iterator with aRoot. After that it can be iterated with a
+ * range-based for loop. At the moment, that's the only supported form of use
+ * for this iterator.
+ */
+ explicit SimpleTreeIterator(nsINode& aRoot)
+ : mCurrent(&aRoot)
+ {
+ mTree.AppendElement(&aRoot);
+ }
+
+ // Basic support for range-based for loops.
+ // This will modify the iterator as it goes.
+ SimpleTreeIterator& begin() { return *this; }
+
+ SimpleTreeIterator end() { return SimpleTreeIterator(); }
+
+ bool operator!=(const SimpleTreeIterator& aOther) {
+ return mCurrent != aOther.mCurrent;
+ }
+
+ void operator++() { Next(); }
+
+ nsINode* operator*() { return mCurrent; }
+
+private:
+ // Constructor used only for end() to represent a drained iterator.
+ SimpleTreeIterator()
+ : mCurrent(nullptr)
+ {}
+
+ void Next() {
+ MOZ_ASSERT(mCurrent, "Don't call Next() when we have no current node");
+
+ mCurrent = mCurrent->GetNextNode(mTree.LastElement());
+ }
+
+ // The current node.
+ nsINode* mCurrent;
+
+ // The DOM tree that we're inside of right now.
+ AutoTArray<nsINode*, 1> mTree;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_SimpleTreeIterator_h
diff --git a/dom/base/moz.build b/dom/base/moz.build
index ebb76d617..75ddefded 100755
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -210,6 +210,7 @@ EXPORTS.mozilla.dom += [
'ScreenOrientation.h',
'ScriptSettings.h',
'ShadowRoot.h',
+ 'SimpleTreeIterator.h',
'StructuredCloneHolder.h',
'StructuredCloneTags.h',
'StyleSheetList.h',
diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp
index e2be6b664..0f663636f 100644
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -1968,22 +1968,10 @@ nsDocument::Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup)
}
void
-nsDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
- nsIPrincipal* aPrincipal)
-{
- NS_PRECONDITION(aURI, "Null URI passed to ResetToURI");
-
- if (gDocumentLeakPRLog && MOZ_LOG_TEST(gDocumentLeakPRLog, LogLevel::Debug)) {
- PR_LogPrint("DOCUMENT %p ResetToURI %s", this,
- aURI->GetSpecOrDefault().get());
- }
-
- mSecurityInfo = nullptr;
-
- mDocumentLoadGroup = nullptr;
-
+nsDocument::DisconnectNodeTree() {
// Delete references to sub-documents and kill the subdocument map,
- // if any. It holds strong references
+ // if any. This is not strictly needed, but makes the node tree
+ // teardown a bit faster.
delete mSubDocuments;
mSubDocuments = nullptr;
@@ -2019,6 +2007,22 @@ nsDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
"After removing all children, there should be no root elem");
}
mInUnlinkOrDeletion = oldVal;
+}
+
+void
+nsDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
+ nsIPrincipal* aPrincipal)
+{
+ NS_PRECONDITION(aURI, "Null URI passed to ResetToURI");
+
+ if (gDocumentLeakPRLog && MOZ_LOG_TEST(gDocumentLeakPRLog, LogLevel::Debug)) {
+ PR_LogPrint("DOCUMENT %p ResetToURI %s", this,
+ aURI->GetSpecOrDefault().get());
+ }
+
+ mSecurityInfo = nullptr;
+
+ mDocumentLoadGroup = nullptr;
// Reset our stylesheets
ResetStylesheetsToURI(aURI);
@@ -2029,6 +2033,8 @@ nsDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
mListenerManager = nullptr;
}
+ DisconnectNodeTree();
+
// Release the stylesheets list.
mDOMStyleSheets = nullptr;
@@ -9077,7 +9083,8 @@ nsDocument::CloneDocHelper(nsDocument* clone) const
}
void
-nsDocument::SetReadyStateInternal(ReadyState rs)
+nsDocument::SetReadyStateInternal(ReadyState rs,
+ bool updateTimingInformation)
{
mReadyState = rs;
if (rs == READYSTATE_UNINITIALIZED) {
@@ -9086,7 +9093,12 @@ nsDocument::SetReadyStateInternal(ReadyState rs)
// transition undetectable by Web content.
return;
}
- if (mTiming) {
+
+ if (updateTimingInformation && READYSTATE_LOADING == rs) {
+ mLoadingTimeStamp = mozilla::TimeStamp::Now();
+ }
+
+ if (updateTimingInformation && mTiming) {
switch (rs) {
case READYSTATE_LOADING:
mTiming->NotifyDOMLoading(nsIDocument::GetDocumentURI());
@@ -9102,10 +9114,6 @@ nsDocument::SetReadyStateInternal(ReadyState rs)
break;
}
}
- // At the time of loading start, we don't have timing object, record time.
- if (READYSTATE_LOADING == rs) {
- mLoadingTimeStamp = mozilla::TimeStamp::Now();
- }
RefPtr<AsyncEventDispatcher> asyncDispatcher =
new AsyncEventDispatcher(this, NS_LITERAL_STRING("readystatechange"),
diff --git a/dom/base/nsDocument.h b/dom/base/nsDocument.h
index ac600eb43..c2b1d3cdb 100644
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -704,7 +704,11 @@ public:
virtual void BeginLoad() override;
virtual void EndLoad() override;
- virtual void SetReadyStateInternal(ReadyState rs) override;
+ // Set the readystate of the document. If updateTimingInformation is true,
+ // this will record relevant timestamps in the document's performance timing.
+ // Some consumers like document.open() don't want to do that.
+ virtual void SetReadyStateInternal(ReadyState rs,
+ bool updateTimingInformation = true) override;
virtual void ContentStateChanged(nsIContent* aContent,
mozilla::EventStates aStateMask)
@@ -916,6 +920,14 @@ public:
UpdateFrameRequestCallbackSchedulingState();
}
+ void SetLoadEventFiring(bool aFiring) override { mLoadEventFiring = aFiring; }
+
+ bool SkipLoadEventAfterClose() override {
+ bool skip = mSkipLoadEventAfterClose;
+ mSkipLoadEventAfterClose = false;
+ return skip;
+ }
+
virtual nsIDocument* GetTemplateContentsOwner() override;
NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsDocument,
@@ -1255,6 +1267,11 @@ protected:
*/
Element* GetTitleElement();
+ /**
+ * Perform tree disconnection needed by ResetToURI and document.open()
+ */
+ void DisconnectNodeTree();
+
public:
// Get our title
virtual void GetTitle(nsString& aTitle) override;
@@ -1458,6 +1475,20 @@ public:
// additional sheets and sheets from the nsStyleSheetService.
bool mStyleSetFilled:1;
+ // The HTML spec has a "iframe load in progress" flag, but that doesn't seem
+ // to have the right semantics. See <https://github.com/whatwg/html/issues/4292>.
+ // What we have instead is a flag that is set while the window's 'load' event is
+ // firing if this document is the window's document.
+ bool mLoadEventFiring : 1;
+
+ // The HTML spec has a "mute iframe load" flag, but that doesn't seem to have
+ // the right semantics. See <https://github.com/whatwg/html/issues/4292>.
+ // What we have instead is a flag that is set if completion of our document
+ // via document.close() should skip firing the load event. Note that this
+ // flag is only relevant for HTML documents, but lives here for reasons that
+ // are documented above on SkipLoadEventAfterClose().
+ bool mSkipLoadEventAfterClose : 1;
+
uint8_t mPendingFullscreenRequests;
uint8_t mXMLDeclarationBits;
diff --git a/dom/base/nsIDocument.h b/dom/base/nsIDocument.h
index d76a12d71..e2b34f7e3 100644
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -1448,7 +1448,7 @@ public:
virtual void EndLoad() = 0;
enum ReadyState { READYSTATE_UNINITIALIZED = 0, READYSTATE_LOADING = 1, READYSTATE_INTERACTIVE = 3, READYSTATE_COMPLETE = 4};
- virtual void SetReadyStateInternal(ReadyState rs) = 0;
+ virtual void SetReadyStateInternal(ReadyState rs, bool updateTimingInformation = true) = 0;
ReadyState GetReadyStateEnum()
{
return mReadyState;
@@ -2187,6 +2187,19 @@ public:
}
/**
+ * Flag whether we're about to fire the window's load event for this document.
+ */
+ virtual void SetLoadEventFiring(bool aFiring) = 0;
+
+ /**
+ * Test whether we should be firing a load event for this document after a
+ * document.close().
+ * This method should only be called at the point when the load event is about
+ * to be fired, since it resets `skip`.
+ */
+ virtual bool SkipLoadEventAfterClose() = 0;
+
+ /**
* Returns the template content owner document that owns the content of
* HTMLTemplateElement.
*/