Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/base/nsContentSink.h
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
/*
8
 * Base class for the XML and HTML content sinks, which construct a
9
 * DOM based on information from the parser.
10
 */
11
12
#ifndef _nsContentSink_h_
13
#define _nsContentSink_h_
14
15
// Base class for contentsink implementations.
16
17
#include "mozilla/Attributes.h"
18
#include "nsICSSLoaderObserver.h"
19
#include "nsWeakReference.h"
20
#include "nsCOMPtr.h"
21
#include "nsString.h"
22
#include "nsAutoPtr.h"
23
#include "nsGkAtoms.h"
24
#include "nsITimer.h"
25
#include "nsStubDocumentObserver.h"
26
#include "nsIContentSink.h"
27
#include "mozilla/Logging.h"
28
#include "nsCycleCollectionParticipant.h"
29
#include "nsThreadUtils.h"
30
31
class nsIDocument;
32
class nsIURI;
33
class nsIChannel;
34
class nsIDocShell;
35
class nsAtom;
36
class nsIChannel;
37
class nsIContent;
38
class nsNodeInfoManager;
39
class nsIApplicationCache;
40
41
namespace mozilla {
42
namespace css {
43
class Loader;
44
} // namespace css
45
46
namespace dom {
47
class ScriptLoader;
48
} // namespace dom
49
} // namespace mozilla
50
51
#ifdef DEBUG
52
53
extern mozilla::LazyLogModule gContentSinkLogModuleInfo;
54
55
#define SINK_TRACE_CALLS              0x1
56
#define SINK_TRACE_REFLOW             0x2
57
#define SINK_ALWAYS_REFLOW            0x4
58
59
#define SINK_LOG_TEST(_lm, _bit) (int((_lm)->Level()) & (_bit))
60
61
#define SINK_TRACE(_lm, _bit, _args) \
62
  do {                     \
63
    if (SINK_LOG_TEST(_lm, _bit)) {  \
64
      printf_stderr _args;             \
65
    }                                \
66
  } while(0)
67
68
#else
69
#define SINK_TRACE(_lm, _bit, _args)
70
#endif
71
72
#undef SINK_NO_INCREMENTAL
73
74
//----------------------------------------------------------------------
75
76
class nsContentSink : public nsICSSLoaderObserver,
77
                      public nsSupportsWeakReference,
78
                      public nsStubDocumentObserver,
79
                      public nsITimerCallback,
80
                      public nsINamed
81
{
82
  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
83
  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsContentSink,
84
                                           nsICSSLoaderObserver)
85
    // nsITimerCallback
86
  NS_DECL_NSITIMERCALLBACK
87
88
  NS_DECL_NSINAMED
89
90
  // nsICSSLoaderObserver
91
  NS_IMETHOD StyleSheetLoaded(mozilla::StyleSheet* aSheet,
92
                              bool aWasAlternate,
93
                              nsresult aStatus) override;
94
95
  virtual nsresult ProcessMETATag(nsIContent* aContent);
96
97
  // nsIContentSink implementation helpers
98
  nsresult WillParseImpl(void);
99
  nsresult WillInterruptImpl(void);
100
  nsresult WillResumeImpl(void);
101
  nsresult DidProcessATokenImpl(void);
102
  void WillBuildModelImpl(void);
103
  void DidBuildModelImpl(bool aTerminated);
104
  void DropParserAndPerfHint(void);
105
  bool IsScriptExecutingImpl();
106
107
  void NotifyAppend(nsIContent* aContent, uint32_t aStartIndex);
108
109
  // nsIDocumentObserver
110
  NS_DECL_NSIDOCUMENTOBSERVER_BEGINUPDATE
111
  NS_DECL_NSIDOCUMENTOBSERVER_ENDUPDATE
112
113
  virtual void UpdateChildCounts() = 0;
114
115
  bool IsTimeToNotify();
116
  bool LinkContextIsOurDocument(const nsAString& aAnchor);
117
  bool Decode5987Format(nsAString& aEncoded);
118
119
  static void InitializeStatics();
120
121
protected:
122
  nsContentSink();
123
  virtual ~nsContentSink();
124
125
  enum CacheSelectionAction {
126
    // There is no offline cache manifest specified by the document,
127
    // or the document was loaded from a cache other than the one it
128
    // specifies via its manifest attribute and IS NOT a top-level
129
    // document, or an error occurred during the cache selection
130
    // algorithm.
131
    CACHE_SELECTION_NONE = 0,
132
133
    // The offline cache manifest must be updated.
134
    CACHE_SELECTION_UPDATE = 1,
135
136
    // The document was loaded from a cache other than the one it
137
    // specifies via its manifest attribute and IS a top-level
138
    // document.  In this case, the document is marked as foreign in
139
    // the cache it was loaded from and must be reloaded from the
140
    // correct cache (the one it specifies).
141
    CACHE_SELECTION_RELOAD = 2,
142
143
    // Some conditions require we must reselect the cache without the manifest
144
    CACHE_SELECTION_RESELECT_WITHOUT_MANIFEST = 3
145
  };
146
147
  nsresult Init(nsIDocument* aDoc, nsIURI* aURI,
148
                nsISupports* aContainer, nsIChannel* aChannel);
149
150
  nsresult ProcessHTTPHeaders(nsIChannel* aChannel);
151
  nsresult ProcessHeaderData(nsAtom* aHeader, const nsAString& aValue,
152
                             nsIContent* aContent = nullptr);
153
  nsresult ProcessLinkHeader(const nsAString& aLinkData);
154
  nsresult ProcessLinkFromHeader(const nsAString& aAnchor,
155
                                 const nsAString& aHref, const nsAString& aRel,
156
                                 const nsAString& aTitle, const nsAString& aType,
157
                                 const nsAString& aMedia,
158
                                 const nsAString& aCrossOrigin,
159
                                 const nsAString& aReferrerPolicy,
160
                                 const nsAString& aAs);
161
162
  virtual nsresult ProcessStyleLinkFromHeader(const nsAString& aHref,
163
                                              bool aAlternate,
164
                                              const nsAString& aTitle,
165
                                              const nsAString& aType,
166
                                              const nsAString& aMedia,
167
                                              const nsAString& aReferrerPolicy);
168
169
  void PrefetchPreloadHref(const nsAString &aHref, nsINode *aSource,
170
                           uint32_t aLinkTypes, const nsAString& aAs,
171
                           const nsAString& aType,
172
                           const nsAString& aMedia);
173
174
  // For PrefetchDNS() aHref can either be the usual
175
  // URI format or of the form "//www.hostname.com" without a scheme.
176
  void PrefetchDNS(const nsAString &aHref);
177
178
  // Gets the cache key (used to identify items in a cache) of the channel.
179
  nsresult GetChannelCacheKey(nsIChannel* aChannel, nsACString& aCacheKey);
180
181
  // There is an offline cache manifest attribute specified and the
182
  // document is allowed to use the offline cache.  Process the cache
183
  // selection algorithm for this document and the manifest. Result is
184
  // an action that must be taken on the manifest, see
185
  // CacheSelectionAction enum above.
186
  //
187
  // @param aLoadApplicationCache
188
  //        The application cache from which the load originated, if
189
  //        any.
190
  // @param aManifestURI
191
  //        The manifest URI listed in the document.
192
  // @param aFetchedWithHTTPGetOrEquiv
193
  //        TRUE if this was fetched using the HTTP GET method.
194
  // @param aAction
195
  //        Out parameter, returns the action that should be performed
196
  //        by the calling function.
197
  nsresult SelectDocAppCache(nsIApplicationCache *aLoadApplicationCache,
198
                             nsIURI *aManifestURI,
199
                             bool aFetchedWithHTTPGetOrEquiv,
200
                             CacheSelectionAction *aAction);
201
202
  // There is no offline cache manifest attribute specified.  Process
203
  // the cache selection algorithm w/o the manifest. Result is an
204
  // action that must be taken, see CacheSelectionAction enum
205
  // above. In case the offline cache manifest has to be updated the
206
  // manifest URI is returned in aManifestURI.
207
  //
208
  // @param aLoadApplicationCache
209
  //        The application cache from which the load originated, if
210
  //        any.
211
  // @param aManifestURI
212
  //        Out parameter, returns the manifest URI of the cache that
213
  //        was selected.
214
  // @param aAction
215
  //        Out parameter, returns the action that should be performed
216
  //        by the calling function.
217
  nsresult SelectDocAppCacheNoManifest(nsIApplicationCache *aLoadApplicationCache,
218
                                       nsIURI **aManifestURI,
219
                                       CacheSelectionAction *aAction);
220
221
public:
222
  // Searches for the offline cache manifest attribute and calls one
223
  // of the above defined methods to select the document's application
224
  // cache, let it be associated with the document and eventually
225
  // schedule the cache update process.
226
  // This method MUST be called with the empty string as the argument
227
  // when there is no manifest attribute!
228
  void ProcessOfflineManifest(const nsAString& aManifestSpec);
229
230
  // Extracts the manifest attribute from the element if it is the root
231
  // element and calls the above method.
232
  void ProcessOfflineManifest(nsIContent *aElement);
233
234
  // For Preconnect() aHref can either be the usual
235
  // URI format or of the form "//www.hostname.com" without a scheme.
236
  void Preconnect(const nsAString& aHref, const nsAString& aCrossOrigin);
237
238
protected:
239
  // Tries to scroll to the URI's named anchor. Once we've successfully
240
  // done that, further calls to this method will be ignored.
241
  void ScrollToRef();
242
243
  // Start layout.  If aIgnorePendingSheets is true, this will happen even if
244
  // we still have stylesheet loads pending.  Otherwise, we'll wait until the
245
  // stylesheets are all done loading.
246
public:
247
  void StartLayout(bool aIgnorePendingSheets);
248
249
  static void NotifyDocElementCreated(nsIDocument* aDoc);
250
251
protected:
252
  void
253
  FavorPerformanceHint(bool perfOverStarvation, uint32_t starvationDelay);
254
255
  inline int32_t GetNotificationInterval()
256
0
  {
257
0
    if (mDynamicLowerValue) {
258
0
      return 1000;
259
0
    }
260
0
261
0
    return sNotificationInterval;
262
0
  }
263
264
  virtual nsresult FlushTags() = 0;
265
266
  // Later on we might want to make this more involved somehow
267
  // (e.g. stop waiting after some timeout or whatnot).
268
0
  bool WaitForPendingSheets() { return mPendingSheetCount > 0; }
269
270
  void DoProcessLinkHeader();
271
272
0
  void StopDeflecting() {
273
0
    mDeflectedCount = sPerfDeflectCount;
274
0
  }
275
276
protected:
277
278
  nsCOMPtr<nsIDocument>         mDocument;
279
  RefPtr<nsParserBase>        mParser;
280
  nsCOMPtr<nsIURI>              mDocumentURI;
281
  nsCOMPtr<nsIDocShell>         mDocShell;
282
  RefPtr<mozilla::css::Loader> mCSSLoader;
283
  RefPtr<nsNodeInfoManager>   mNodeInfoManager;
284
  RefPtr<mozilla::dom::ScriptLoader> mScriptLoader;
285
286
  // back off timer notification after count
287
  int32_t mBackoffCount;
288
289
  // Time of last notification
290
  // Note: mLastNotificationTime is only valid once mLayoutStarted is true.
291
  PRTime mLastNotificationTime;
292
293
  // Timer used for notification
294
  nsCOMPtr<nsITimer> mNotificationTimer;
295
296
  // Have we already called BeginUpdate for this set of content changes?
297
  uint8_t mBeganUpdate : 1;
298
  uint8_t mLayoutStarted : 1;
299
  uint8_t mDynamicLowerValue : 1;
300
  uint8_t mParsing : 1;
301
  uint8_t mDroppedTimer : 1;
302
  // If true, we deferred starting layout until sheets load
303
  uint8_t mDeferredLayoutStart : 1;
304
  // If true, we deferred notifications until sheets load
305
  uint8_t mDeferredFlushTags : 1;
306
  // If false, we're not ourselves a document observer; that means we
307
  // shouldn't be performing any more content model notifications,
308
  // since we're not longer updating our child counts.
309
  uint8_t mIsDocumentObserver : 1;
310
  // True if this is parser is a fragment parser or an HTML DOMParser.
311
  // XML DOMParser leaves this to false for now!
312
  uint8_t mRunsToCompletion : 1;
313
  // True if we are blocking load event.
314
  bool mIsBlockingOnload : 1;
315
316
  //
317
  // -- Can interrupt parsing members --
318
  //
319
320
  // The number of tokens that have been processed since we measured
321
  // if it's time to return to the main event loop.
322
  uint32_t mDeflectedCount;
323
324
  // Is there currently a pending event?
325
  bool mHasPendingEvent;
326
327
  // When to return to the main event loop
328
  uint32_t mCurrentParseEndTime;
329
330
  int32_t mBeginLoadTime;
331
332
  // Last mouse event or keyboard event time sampled by the content
333
  // sink
334
  uint32_t mLastSampledUserEventTime;
335
336
  int32_t mInMonolithicContainer;
337
338
  int32_t mInNotification;
339
  uint32_t mUpdatesInNotification;
340
341
  uint32_t mPendingSheetCount;
342
343
  nsRevocableEventPtr<nsRunnableMethod<nsContentSink, void, false> >
344
    mProcessLinkHeaderEvent;
345
346
  // Do we notify based on time?
347
  static bool sNotifyOnTimer;
348
  // Back off timer notification after count.
349
  static int32_t sBackoffCount;
350
  // Notification interval in microseconds
351
  static int32_t sNotificationInterval;
352
  // How many times to deflect in interactive/perf modes
353
  static int32_t sInteractiveDeflectCount;
354
  static int32_t sPerfDeflectCount;
355
  // 0 = don't check for pending events
356
  // 1 = don't deflect if there are pending events
357
  // 2 = bail if there are pending events
358
  static int32_t sPendingEventMode;
359
  // How often to probe for pending events. 1=every token
360
  static int32_t sEventProbeRate;
361
  // How long to stay off the event loop in interactive/perf modes
362
  static int32_t sInteractiveParseTime;
363
  static int32_t sPerfParseTime;
364
  // How long to be in interactive mode after an event
365
  static int32_t sInteractiveTime;
366
  // How long to stay in perf mode after initial loading
367
  static int32_t sInitialPerfTime;
368
  // Should we switch between perf-mode and interactive-mode
369
  static int32_t sEnablePerfMode;
370
};
371
372
#endif // _nsContentSink_h_