summaryrefslogtreecommitdiffstats
path: root/dom/base/nsContentSink.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/base/nsContentSink.h')
-rw-r--r--dom/base/nsContentSink.h362
1 files changed, 362 insertions, 0 deletions
diff --git a/dom/base/nsContentSink.h b/dom/base/nsContentSink.h
new file mode 100644
index 000000000..b1a758874
--- /dev/null
+++ b/dom/base/nsContentSink.h
@@ -0,0 +1,362 @@
+/* -*- 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/. */
+
+/*
+ * Base class for the XML and HTML content sinks, which construct a
+ * DOM based on information from the parser.
+ */
+
+#ifndef _nsContentSink_h_
+#define _nsContentSink_h_
+
+// Base class for contentsink implementations.
+
+#include "mozilla/Attributes.h"
+#include "nsICSSLoaderObserver.h"
+#include "nsWeakReference.h"
+#include "nsCOMPtr.h"
+#include "nsString.h"
+#include "nsAutoPtr.h"
+#include "nsGkAtoms.h"
+#include "nsITimer.h"
+#include "nsStubDocumentObserver.h"
+#include "nsIContentSink.h"
+#include "mozilla/Logging.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsThreadUtils.h"
+
+class nsIDocument;
+class nsIURI;
+class nsIChannel;
+class nsIDocShell;
+class nsIAtom;
+class nsIChannel;
+class nsIContent;
+class nsNodeInfoManager;
+class nsScriptLoader;
+class nsIApplicationCache;
+
+namespace mozilla {
+namespace css {
+class Loader;
+} // namespace css
+} // namespace mozilla
+
+#ifdef DEBUG
+
+extern mozilla::LazyLogModule gContentSinkLogModuleInfo;
+
+#define SINK_TRACE_CALLS 0x1
+#define SINK_TRACE_REFLOW 0x2
+#define SINK_ALWAYS_REFLOW 0x4
+
+#define SINK_LOG_TEST(_lm, _bit) (int((_lm)->Level()) & (_bit))
+
+#define SINK_TRACE(_lm, _bit, _args) \
+ PR_BEGIN_MACRO \
+ if (SINK_LOG_TEST(_lm, _bit)) { \
+ PR_LogPrint _args; \
+ } \
+ PR_END_MACRO
+
+#else
+#define SINK_TRACE(_lm, _bit, _args)
+#endif
+
+#undef SINK_NO_INCREMENTAL
+
+//----------------------------------------------------------------------
+
+// 1/2 second fudge factor for window creation
+#define NS_DELAY_FOR_WINDOW_CREATION 500000
+
+class nsContentSink : public nsICSSLoaderObserver,
+ public nsSupportsWeakReference,
+ public nsStubDocumentObserver,
+ public nsITimerCallback
+{
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+ NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsContentSink,
+ nsICSSLoaderObserver)
+ // nsITimerCallback
+ NS_DECL_NSITIMERCALLBACK
+
+ // nsICSSLoaderObserver
+ NS_IMETHOD StyleSheetLoaded(mozilla::StyleSheet* aSheet,
+ bool aWasAlternate,
+ nsresult aStatus) override;
+
+ virtual nsresult ProcessMETATag(nsIContent* aContent);
+
+ // nsIContentSink implementation helpers
+ nsresult WillParseImpl(void);
+ nsresult WillInterruptImpl(void);
+ nsresult WillResumeImpl(void);
+ nsresult DidProcessATokenImpl(void);
+ void WillBuildModelImpl(void);
+ void DidBuildModelImpl(bool aTerminated);
+ void DropParserAndPerfHint(void);
+ bool IsScriptExecutingImpl();
+
+ void NotifyAppend(nsIContent* aContent, uint32_t aStartIndex);
+
+ // nsIDocumentObserver
+ NS_DECL_NSIDOCUMENTOBSERVER_BEGINUPDATE
+ NS_DECL_NSIDOCUMENTOBSERVER_ENDUPDATE
+
+ virtual void UpdateChildCounts() = 0;
+
+ bool IsTimeToNotify();
+ bool LinkContextIsOurDocument(const nsSubstring& aAnchor);
+ bool Decode5987Format(nsAString& aEncoded);
+
+ static void InitializeStatics();
+
+protected:
+ nsContentSink();
+ virtual ~nsContentSink();
+
+ enum CacheSelectionAction {
+ // There is no offline cache manifest specified by the document,
+ // or the document was loaded from a cache other than the one it
+ // specifies via its manifest attribute and IS NOT a top-level
+ // document, or an error occurred during the cache selection
+ // algorithm.
+ CACHE_SELECTION_NONE = 0,
+
+ // The offline cache manifest must be updated.
+ CACHE_SELECTION_UPDATE = 1,
+
+ // The document was loaded from a cache other than the one it
+ // specifies via its manifest attribute and IS a top-level
+ // document. In this case, the document is marked as foreign in
+ // the cache it was loaded from and must be reloaded from the
+ // correct cache (the one it specifies).
+ CACHE_SELECTION_RELOAD = 2,
+
+ // Some conditions require we must reselect the cache without the manifest
+ CACHE_SELECTION_RESELECT_WITHOUT_MANIFEST = 3
+ };
+
+ nsresult Init(nsIDocument* aDoc, nsIURI* aURI,
+ nsISupports* aContainer, nsIChannel* aChannel);
+
+ nsresult ProcessHTTPHeaders(nsIChannel* aChannel);
+ nsresult ProcessHeaderData(nsIAtom* aHeader, const nsAString& aValue,
+ nsIContent* aContent = nullptr);
+ nsresult ProcessLinkHeader(const nsAString& aLinkData);
+ nsresult ProcessLink(const nsSubstring& aAnchor,
+ const nsSubstring& aHref, const nsSubstring& aRel,
+ const nsSubstring& aTitle, const nsSubstring& aType,
+ const nsSubstring& aMedia, const nsSubstring& aCrossOrigin);
+
+ virtual nsresult ProcessStyleLink(nsIContent* aElement,
+ const nsSubstring& aHref,
+ bool aAlternate,
+ const nsSubstring& aTitle,
+ const nsSubstring& aType,
+ const nsSubstring& aMedia);
+
+ void PrefetchHref(const nsAString &aHref, nsINode *aSource,
+ bool aExplicit);
+
+ // For PrefetchDNS() aHref can either be the usual
+ // URI format or of the form "//www.hostname.com" without a scheme.
+ void PrefetchDNS(const nsAString &aHref);
+
+ // Gets the cache key (used to identify items in a cache) of the channel.
+ nsresult GetChannelCacheKey(nsIChannel* aChannel, nsACString& aCacheKey);
+
+ // There is an offline cache manifest attribute specified and the
+ // document is allowed to use the offline cache. Process the cache
+ // selection algorithm for this document and the manifest. Result is
+ // an action that must be taken on the manifest, see
+ // CacheSelectionAction enum above.
+ //
+ // @param aLoadApplicationCache
+ // The application cache from which the load originated, if
+ // any.
+ // @param aManifestURI
+ // The manifest URI listed in the document.
+ // @param aFetchedWithHTTPGetOrEquiv
+ // TRUE if this was fetched using the HTTP GET method.
+ // @param aAction
+ // Out parameter, returns the action that should be performed
+ // by the calling function.
+ nsresult SelectDocAppCache(nsIApplicationCache *aLoadApplicationCache,
+ nsIURI *aManifestURI,
+ bool aFetchedWithHTTPGetOrEquiv,
+ CacheSelectionAction *aAction);
+
+ // There is no offline cache manifest attribute specified. Process
+ // the cache selection algorithm w/o the manifest. Result is an
+ // action that must be taken, see CacheSelectionAction enum
+ // above. In case the offline cache manifest has to be updated the
+ // manifest URI is returned in aManifestURI.
+ //
+ // @param aLoadApplicationCache
+ // The application cache from which the load originated, if
+ // any.
+ // @param aManifestURI
+ // Out parameter, returns the manifest URI of the cache that
+ // was selected.
+ // @param aAction
+ // Out parameter, returns the action that should be performed
+ // by the calling function.
+ nsresult SelectDocAppCacheNoManifest(nsIApplicationCache *aLoadApplicationCache,
+ nsIURI **aManifestURI,
+ CacheSelectionAction *aAction);
+
+public:
+ // Searches for the offline cache manifest attribute and calls one
+ // of the above defined methods to select the document's application
+ // cache, let it be associated with the document and eventually
+ // schedule the cache update process.
+ // This method MUST be called with the empty string as the argument
+ // when there is no manifest attribute!
+ void ProcessOfflineManifest(const nsAString& aManifestSpec);
+
+ // Extracts the manifest attribute from the element if it is the root
+ // element and calls the above method.
+ void ProcessOfflineManifest(nsIContent *aElement);
+
+ // For Preconnect() aHref can either be the usual
+ // URI format or of the form "//www.hostname.com" without a scheme.
+ void Preconnect(const nsAString& aHref, const nsAString& aCrossOrigin);
+
+protected:
+ // Tries to scroll to the URI's named anchor. Once we've successfully
+ // done that, further calls to this method will be ignored.
+ void ScrollToRef();
+
+ // Start layout. If aIgnorePendingSheets is true, this will happen even if
+ // we still have stylesheet loads pending. Otherwise, we'll wait until the
+ // stylesheets are all done loading.
+public:
+ void StartLayout(bool aIgnorePendingSheets);
+
+ static void NotifyDocElementCreated(nsIDocument* aDoc);
+
+protected:
+ void
+ FavorPerformanceHint(bool perfOverStarvation, uint32_t starvationDelay);
+
+ inline int32_t GetNotificationInterval()
+ {
+ if (mDynamicLowerValue) {
+ return 1000;
+ }
+
+ return sNotificationInterval;
+ }
+
+ virtual nsresult FlushTags() = 0;
+
+ // Later on we might want to make this more involved somehow
+ // (e.g. stop waiting after some timeout or whatnot).
+ bool WaitForPendingSheets() { return mPendingSheetCount > 0; }
+
+ void DoProcessLinkHeader();
+
+ void StopDeflecting() {
+ mDeflectedCount = sPerfDeflectCount;
+ }
+
+protected:
+
+ nsCOMPtr<nsIDocument> mDocument;
+ RefPtr<nsParserBase> mParser;
+ nsCOMPtr<nsIURI> mDocumentURI;
+ nsCOMPtr<nsIDocShell> mDocShell;
+ RefPtr<mozilla::css::Loader> mCSSLoader;
+ RefPtr<nsNodeInfoManager> mNodeInfoManager;
+ RefPtr<nsScriptLoader> mScriptLoader;
+
+ // back off timer notification after count
+ int32_t mBackoffCount;
+
+ // Time of last notification
+ // Note: mLastNotificationTime is only valid once mLayoutStarted is true.
+ PRTime mLastNotificationTime;
+
+ // Timer used for notification
+ nsCOMPtr<nsITimer> mNotificationTimer;
+
+ // Have we already called BeginUpdate for this set of content changes?
+ uint8_t mBeganUpdate : 1;
+ uint8_t mLayoutStarted : 1;
+ uint8_t mDynamicLowerValue : 1;
+ uint8_t mParsing : 1;
+ uint8_t mDroppedTimer : 1;
+ // If true, we deferred starting layout until sheets load
+ uint8_t mDeferredLayoutStart : 1;
+ // If true, we deferred notifications until sheets load
+ uint8_t mDeferredFlushTags : 1;
+ // If false, we're not ourselves a document observer; that means we
+ // shouldn't be performing any more content model notifications,
+ // since we're not longer updating our child counts.
+ uint8_t mIsDocumentObserver : 1;
+ // True if this is parser is a fragment parser or an HTML DOMParser.
+ // XML DOMParser leaves this to false for now!
+ uint8_t mRunsToCompletion : 1;
+
+ //
+ // -- Can interrupt parsing members --
+ //
+
+ // The number of tokens that have been processed since we measured
+ // if it's time to return to the main event loop.
+ uint32_t mDeflectedCount;
+
+ // Is there currently a pending event?
+ bool mHasPendingEvent;
+
+ // When to return to the main event loop
+ uint32_t mCurrentParseEndTime;
+
+ int32_t mBeginLoadTime;
+
+ // Last mouse event or keyboard event time sampled by the content
+ // sink
+ uint32_t mLastSampledUserEventTime;
+
+ int32_t mInMonolithicContainer;
+
+ int32_t mInNotification;
+ uint32_t mUpdatesInNotification;
+
+ uint32_t mPendingSheetCount;
+
+ nsRevocableEventPtr<nsRunnableMethod<nsContentSink, void, false> >
+ mProcessLinkHeaderEvent;
+
+ // Do we notify based on time?
+ static bool sNotifyOnTimer;
+ // Back off timer notification after count.
+ static int32_t sBackoffCount;
+ // Notification interval in microseconds
+ static int32_t sNotificationInterval;
+ // How many times to deflect in interactive/perf modes
+ static int32_t sInteractiveDeflectCount;
+ static int32_t sPerfDeflectCount;
+ // 0 = don't check for pending events
+ // 1 = don't deflect if there are pending events
+ // 2 = bail if there are pending events
+ static int32_t sPendingEventMode;
+ // How often to probe for pending events. 1=every token
+ static int32_t sEventProbeRate;
+ // How long to stay off the event loop in interactive/perf modes
+ static int32_t sInteractiveParseTime;
+ static int32_t sPerfParseTime;
+ // How long to be in interactive mode after an event
+ static int32_t sInteractiveTime;
+ // How long to stay in perf mode after initial loading
+ static int32_t sInitialPerfTime;
+ // Should we switch between perf-mode and interactive-mode
+ static int32_t sEnablePerfMode;
+};
+
+#endif // _nsContentSink_h_