Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/base/nsFrameLoader.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
 * Class for managing loading of a subframe (creation of the docshell,
9
 * handling of loads in it, recursion-checking).
10
 */
11
12
#ifndef nsFrameLoader_h_
13
#define nsFrameLoader_h_
14
15
#include "nsIDocShell.h"
16
#include "nsStringFwd.h"
17
#include "nsIFrameLoaderOwner.h"
18
#include "nsPoint.h"
19
#include "nsSize.h"
20
#include "nsWrapperCache.h"
21
#include "nsIURI.h"
22
#include "nsFrameMessageManager.h"
23
#include "mozilla/dom/BindingUtils.h"
24
#include "mozilla/dom/Element.h"
25
#include "mozilla/dom/ParentSHistory.h"
26
#include "mozilla/Attributes.h"
27
#include "nsStubMutationObserver.h"
28
#include "Units.h"
29
#include "nsIFrame.h"
30
#include "nsPluginTags.h"
31
32
class nsIURI;
33
class nsSubDocumentFrame;
34
class nsView;
35
class AutoResetInShow;
36
class AutoResetInFrameSwap;
37
class nsITabParent;
38
class nsIDocShellTreeItem;
39
class nsIDocShellTreeOwner;
40
class nsILoadContext;
41
class nsIMessageSender;
42
class nsIPrintSettings;
43
class nsIWebBrowserPersistDocumentReceiver;
44
class nsIWebProgressListener;
45
46
namespace mozilla {
47
48
class OriginAttributes;
49
50
namespace dom {
51
class ChromeMessageSender;
52
class ContentParent;
53
class InProcessTabChildMessageManager;
54
class MessageSender;
55
class PBrowserParent;
56
class ProcessMessageManager;
57
class Promise;
58
class TabParent;
59
class MutableTabContext;
60
61
namespace ipc {
62
class StructuredCloneData;
63
} // namespace ipc
64
65
} // namespace dom
66
67
namespace layout {
68
class RenderFrameParent;
69
} // namespace layout
70
} // namespace mozilla
71
72
#if defined(MOZ_WIDGET_GTK)
73
typedef struct _GtkWidget GtkWidget;
74
#endif
75
76
// IID for nsFrameLoader, because some places want to QI to it.
77
#define NS_FRAMELOADER_IID                                      \
78
  { 0x297fd0ea, 0x1b4a, 0x4c9a,                                 \
79
      { 0xa4, 0x04, 0xe5, 0x8b, 0xe8, 0x95, 0x10, 0x50 } }
80
81
class nsFrameLoader final : public nsStubMutationObserver,
82
                            public mozilla::dom::ipc::MessageManagerCallback,
83
                            public nsWrapperCache
84
{
85
  friend class AutoResetInShow;
86
  friend class AutoResetInFrameSwap;
87
  typedef mozilla::dom::PBrowserParent PBrowserParent;
88
  typedef mozilla::dom::TabParent TabParent;
89
  typedef mozilla::layout::RenderFrameParent RenderFrameParent;
90
91
public:
92
  static nsFrameLoader* Create(mozilla::dom::Element* aOwner,
93
                               nsPIDOMWindowOuter* aOpener,
94
                               bool aNetworkCreated,
95
                               int32_t aJSPluginID = nsFakePluginTag::NOT_JSPLUGIN);
96
97
  NS_DECLARE_STATIC_IID_ACCESSOR(NS_FRAMELOADER_IID)
98
99
  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
100
  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsFrameLoader)
101
102
  NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
103
  nsresult CheckForRecursiveLoad(nsIURI* aURI);
104
  nsresult ReallyStartLoading();
105
  void StartDestroy();
106
  void DestroyDocShell();
107
  void DestroyComplete();
108
0
  nsIDocShell* GetExistingDocShell() { return mDocShell; }
109
  mozilla::dom::InProcessTabChildMessageManager* GetTabChildMessageManager() const
110
0
  {
111
0
    return mChildMessageManager;
112
0
  }
113
  nsresult CreateStaticClone(nsFrameLoader* aDest);
114
  nsresult UpdatePositionAndSize(nsSubDocumentFrame *aIFrame);
115
116
  // WebIDL methods
117
118
  nsIDocShell* GetDocShell(mozilla::ErrorResult& aRv);
119
120
  already_AddRefed<nsITabParent> GetTabParent();
121
122
  already_AddRefed<nsILoadContext> LoadContext();
123
124
  /**
125
   * Start loading the frame. This method figures out what to load
126
   * from the owner content in the frame loader.
127
   */
128
  void LoadFrame(bool aOriginalSrc);
129
130
  /**
131
   * Loads the specified URI in this frame. Behaves identically to loadFrame,
132
   * except that this method allows specifying the URI to load.
133
   */
134
  nsresult LoadURI(nsIURI* aURI, bool aOriginalSrc);
135
136
  void AddProcessChangeBlockingPromise(mozilla::dom::Promise& aPromise, mozilla::ErrorResult& aRv);
137
138
  /**
139
   * Destroy the frame loader and everything inside it. This will
140
   * clear the weak owner content reference.
141
   */
142
  void Destroy();
143
144
  void ActivateRemoteFrame(mozilla::ErrorResult& aRv);
145
146
  void DeactivateRemoteFrame(mozilla::ErrorResult& aRv);
147
148
  void SendCrossProcessMouseEvent(const nsAString& aType,
149
                                  float aX,
150
                                  float aY,
151
                                  int32_t aButton,
152
                                  int32_t aClickCount,
153
                                  int32_t aModifiers,
154
                                  bool aIgnoreRootScrollFrame,
155
                                  mozilla::ErrorResult& aRv);
156
157
  void ActivateFrameEvent(const nsAString& aType,
158
                          bool aCapture,
159
                          mozilla::ErrorResult& aRv);
160
161
  void RequestNotifyAfterRemotePaint();
162
163
  void RequestFrameLoaderClose(mozilla::ErrorResult& aRv);
164
165
  void RequestUpdatePosition(mozilla::ErrorResult& aRv);
166
167
  void Print(uint64_t aOuterWindowID,
168
             nsIPrintSettings* aPrintSettings,
169
             nsIWebProgressListener* aProgressListener,
170
             mozilla::ErrorResult& aRv);
171
172
  void StartPersistence(uint64_t aOuterWindowID,
173
                        nsIWebBrowserPersistDocumentReceiver* aRecv,
174
                        mozilla::ErrorResult& aRv);
175
176
  // WebIDL getters
177
178
  already_AddRefed<mozilla::dom::MessageSender> GetMessageManager();
179
180
  already_AddRefed<Element> GetOwnerElement();
181
182
  uint32_t LazyWidth() const;
183
184
  uint32_t LazyHeight() const;
185
186
0
  uint64_t ChildID() const { return mChildID; }
187
188
0
  bool ClampScrollPosition() const { return mClampScrollPosition; }
189
  void SetClampScrollPosition(bool aClamp);
190
191
0
  bool ClipSubdocument() const { return mClipSubdocument; }
192
  void SetClipSubdocument(bool aClip);
193
194
0
  bool DepthTooGreat() const { return mDepthTooGreat; }
195
196
0
  bool IsDead() const { return mDestroyCalled; }
197
198
  /**
199
   * Is this a frame loader for a bona fide <iframe mozbrowser>?
200
   * <xul:browser> is not a mozbrowser, so this is false for that case.
201
   */
202
  bool OwnerIsMozBrowserFrame();
203
204
0
  nsIContent* GetParentObject() const { return mOwnerContent; }
205
206
207
  /**
208
   * MessageManagerCallback methods that we override.
209
   */
210
  virtual bool DoLoadMessageManagerScript(const nsAString& aURL,
211
                                          bool aRunInGlobalScope) override;
212
  virtual nsresult DoSendAsyncMessage(JSContext* aCx,
213
                                      const nsAString& aMessage,
214
                                      mozilla::dom::ipc::StructuredCloneData& aData,
215
                                      JS::Handle<JSObject *> aCpows,
216
                                      nsIPrincipal* aPrincipal) override;
217
218
  /**
219
   * Called from the layout frame associated with this frame loader;
220
   * this notifies us to hook up with the widget and view.
221
   */
222
  bool Show(int32_t marginWidth, int32_t marginHeight,
223
              int32_t scrollbarPrefX, int32_t scrollbarPrefY,
224
              nsSubDocumentFrame* frame);
225
226
  void MaybeShowFrame();
227
228
  /**
229
   * Called when the margin properties of the containing frame are changed.
230
   */
231
  void MarginsChanged(uint32_t aMarginWidth, uint32_t aMarginHeight);
232
233
  /**
234
   * Called from the layout frame associated with this frame loader, when
235
   * the frame is being torn down; this notifies us that out widget and view
236
   * are going away and we should unhook from them.
237
   */
238
  void Hide();
239
240
  // Used when content is causing a FrameLoader to be created, and
241
  // needs to try forcing layout to flush in order to get accurate
242
  // dimensions for the content area.
243
  void ForceLayoutIfNecessary();
244
245
  // The guts of an nsIFrameLoaderOwner::SwapFrameLoader implementation.  A
246
  // frame loader owner needs to call this, and pass in the two references to
247
  // nsRefPtrs for frame loaders that need to be swapped.
248
  nsresult SwapWithOtherLoader(nsFrameLoader* aOther,
249
                               nsIFrameLoaderOwner* aThisOwner,
250
                               nsIFrameLoaderOwner* aOtherOwner);
251
252
  nsresult SwapWithOtherRemoteLoader(nsFrameLoader* aOther,
253
                                     nsIFrameLoaderOwner* aThisOwner,
254
                                     nsIFrameLoaderOwner* aOtherOwner);
255
256
  /**
257
   * Return the primary frame for our owning content, or null if it
258
   * can't be found.
259
   */
260
  nsIFrame* GetPrimaryFrameOfOwningContent() const
261
0
  {
262
0
    return mOwnerContent ? mOwnerContent->GetPrimaryFrame() : nullptr;
263
0
  }
264
265
  /**
266
   * Return the document that owns this, or null if we don't have
267
   * an owner.
268
   */
269
  nsIDocument* GetOwnerDoc() const
270
0
  { return mOwnerContent ? mOwnerContent->OwnerDoc() : nullptr; }
271
272
  PBrowserParent* GetRemoteBrowser() const;
273
274
  /**
275
   * The "current" render frame is the one on which the most recent
276
   * remote layer-tree transaction was executed.  If no content has
277
   * been drawn yet, or the remote browser doesn't have any drawn
278
   * content for whatever reason, return nullptr.  The returned render
279
   * frame has an associated shadow layer tree.
280
   *
281
   * Note that the returned render frame might not be a frame
282
   * constructed for this->GetURL().  This can happen, e.g., if the
283
   * <browser> was just navigated to a new URL, but hasn't painted the
284
   * new page yet.  A render frame for the previous page may be
285
   * returned.  (In-process <browser> behaves similarly, and this
286
   * behavior seems desirable.)
287
   */
288
  RenderFrameParent* GetCurrentRenderFrame() const;
289
290
0
  mozilla::dom::ChromeMessageSender* GetFrameMessageManager() { return mMessageManager; }
291
292
0
  mozilla::dom::Element* GetOwnerContent() { return mOwnerContent; }
293
0
  bool ShouldClipSubdocument() { return mClipSubdocument; }
294
295
0
  bool ShouldClampScrollPosition() { return mClampScrollPosition; }
296
297
0
  mozilla::dom::ParentSHistory* GetParentSHistory() { return mParentSHistory; }
298
299
  /**
300
   * Tell this FrameLoader to use a particular remote browser.
301
   *
302
   * This will assert if mRemoteBrowser is non-null.  In practice,
303
   * this means you can't have successfully run TryRemoteBrowser() on
304
   * this object, which means you can't have called ShowRemoteFrame()
305
   * or ReallyStartLoading().
306
   */
307
  void SetRemoteBrowser(nsITabParent* aTabParent);
308
309
  /**
310
   * Stashes a detached nsIFrame on the frame loader. We do this when we're
311
   * destroying the nsSubDocumentFrame. If the nsSubdocumentFrame is
312
   * being reframed we'll restore the detached nsIFrame when it's recreated,
313
   * otherwise we'll discard the old presentation and set the detached
314
   * subdoc nsIFrame to null. aContainerDoc is the document containing the
315
   * the subdoc frame. This enables us to detect when the containing
316
   * document has changed during reframe, so we can discard the presentation
317
   * in that case.
318
   */
319
  void SetDetachedSubdocFrame(nsIFrame* aDetachedFrame,
320
                              nsIDocument* aContainerDoc);
321
322
  /**
323
   * Retrieves the detached nsIFrame and the document containing the nsIFrame,
324
   * as set by SetDetachedSubdocFrame().
325
   */
326
  nsIFrame* GetDetachedSubdocFrame(nsIDocument** aContainerDoc) const;
327
328
  /**
329
   * Applies a new set of sandbox flags. These are merged with the sandbox
330
   * flags from our owning content's owning document with a logical OR, this
331
   * ensures that we can only add restrictions and never remove them.
332
   */
333
  void ApplySandboxFlags(uint32_t sandboxFlags);
334
335
  void GetURL(nsString& aURL, nsIPrincipal** aTriggeringPrincipal);
336
337
  // Properly retrieves documentSize of any subdocument type.
338
  nsresult GetWindowDimensions(nsIntRect& aRect);
339
340
  virtual mozilla::dom::ProcessMessageManager* GetProcessMessageManager() const override;
341
342
  // public because a callback needs these.
343
  RefPtr<mozilla::dom::ChromeMessageSender> mMessageManager;
344
  RefPtr<mozilla::dom::InProcessTabChildMessageManager> mChildMessageManager;
345
346
  virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> aGivenProto) override;
347
348
private:
349
  nsFrameLoader(mozilla::dom::Element* aOwner,
350
                nsPIDOMWindowOuter* aOpener,
351
                bool aNetworkCreated,
352
                int32_t aJSPluginID);
353
  ~nsFrameLoader();
354
355
  void SetOwnerContent(mozilla::dom::Element* aContent);
356
357
  bool ShouldUseRemoteProcess();
358
359
  /**
360
   * Return true if the frame is a remote frame. Return false otherwise
361
   */
362
  bool IsRemoteFrame();
363
364
  bool IsForJSPlugin()
365
0
  {
366
0
    return mJSPluginID != nsFakePluginTag::NOT_JSPLUGIN;
367
0
  }
368
369
  /**
370
   * Is this a frame loader for an isolated <iframe mozbrowser>?
371
   *
372
   * By default, mozbrowser frames are isolated.  Isolation can be disabled by
373
   * setting the frame's noisolation attribute.  Disabling isolation is
374
   * only allowed if the containing document is chrome.
375
   */
376
  bool OwnerIsIsolatedMozBrowserFrame();
377
378
  /**
379
   * Get our owning element's app manifest URL, or return the empty string if
380
   * our owning element doesn't have an app manifest URL.
381
   */
382
  void GetOwnerAppManifestURL(nsAString& aOut);
383
384
  /**
385
   * If we are an IPC frame, set mRemoteFrame. Otherwise, create and
386
   * initialize mDocShell.
387
   */
388
  nsresult MaybeCreateDocShell();
389
  nsresult EnsureMessageManager();
390
  nsresult ReallyLoadFrameScripts();
391
392
  // Updates the subdocument position and size. This gets called only
393
  // when we have our own in-process DocShell.
394
  void UpdateBaseWindowPositionAndSize(nsSubDocumentFrame *aIFrame);
395
396
  /**
397
   * Checks whether a load of the given URI should be allowed, and returns an
398
   * error result if it should not.
399
   *
400
   * @param aURI The URI to check.
401
   * @param aTriggeringPrincipal The triggering principal for the load. May be
402
   *        null, in which case the node principal of the owner content is used.
403
   */
404
  nsresult CheckURILoad(nsIURI* aURI, nsIPrincipal* aTriggeringPrincipal);
405
  void FireErrorEvent();
406
  nsresult ReallyStartLoadingInternal();
407
408
  // Return true if remote browser created; nothing else to do
409
  bool TryRemoteBrowser();
410
411
  // Tell the remote browser that it's now "virtually visible"
412
  bool ShowRemoteFrame(const mozilla::ScreenIntSize& size,
413
                       nsSubDocumentFrame *aFrame = nullptr);
414
415
  bool AddTreeItemToTreeOwner(nsIDocShellTreeItem* aItem,
416
                              nsIDocShellTreeOwner* aOwner,
417
                              int32_t aParentType,
418
                              nsIDocShell* aParentNode);
419
420
0
  nsAtom* TypeAttrName() const {
421
0
    return mOwnerContent->IsXULElement()
422
0
             ? nsGkAtoms::type : nsGkAtoms::mozframetype;
423
0
  }
424
425
  void InitializeBrowserAPI();
426
  void DestroyBrowserFrameScripts();
427
428
  nsresult GetNewTabContext(mozilla::dom::MutableTabContext* aTabContext,
429
                            nsIURI* aURI = nullptr);
430
431
  enum TabParentChange {
432
    eTabParentRemoved,
433
    eTabParentChanged
434
  };
435
  void MaybeUpdatePrimaryTabParent(TabParentChange aChange);
436
437
  nsresult
438
  PopulateUserContextIdFromAttribute(mozilla::OriginAttributes& aAttr);
439
440
  // Swap ourselves with the frameloader aOther, and notify chrome code with
441
  // a BrowserChangedProcess event.
442
  bool SwapBrowsersAndNotify(nsFrameLoader* aOther);
443
444
  // Returns a promise which will be resolved once all of the blockers have
445
  // resolved which were added during the BrowserWillChangeProcess event.
446
  already_AddRefed<mozilla::dom::Promise> FireWillChangeProcessEvent();
447
448
  /**
449
   * Triggers a load of the given URI.
450
   *
451
   * @param aURI The URI to load.
452
   * @param aTriggeringPrincipal The triggering principal for the load. May be
453
   *        null, in which case the node principal of the owner content will be
454
   *        used.
455
   */
456
  nsresult LoadURI(nsIURI* aURI, nsIPrincipal* aTriggeringPrincipal,
457
                   bool aOriginalSrc);
458
459
  nsCOMPtr<nsIDocShell> mDocShell;
460
  nsCOMPtr<nsIURI> mURIToLoad;
461
  nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
462
  mozilla::dom::Element* mOwnerContent; // WEAK
463
464
  // After the frameloader has been removed from the DOM but before all of the
465
  // messages from the frame have been received, we keep a strong reference to
466
  // our <browser> element.
467
  RefPtr<mozilla::dom::Element> mOwnerContentStrong;
468
469
  // Stores the root frame of the subdocument while the subdocument is being
470
  // reframed. Used to restore the presentation after reframing.
471
  WeakFrame mDetachedSubdocFrame;
472
  // Stores the containing document of the frame corresponding to this
473
  // frame loader. This is reference is kept valid while the subframe's
474
  // presentation is detached and stored in mDetachedSubdocFrame. This
475
  // enables us to detect whether the frame has moved documents during
476
  // a reframe, so that we know not to restore the presentation.
477
  nsCOMPtr<nsIDocument> mContainerDocWhileDetached;
478
479
  // An opener window which should be used when the docshell is created.
480
  nsCOMPtr<nsPIDOMWindowOuter> mOpener;
481
482
  TabParent* mRemoteBrowser;
483
  uint64_t mChildID;
484
485
  int32_t mJSPluginID;
486
487
  // Holds the last known size of the frame.
488
  mozilla::ScreenIntSize mLazySize;
489
490
  // A stack-maintained reference to an array of promises which are blocking
491
  // grouped history navigation
492
  nsTArray<RefPtr<mozilla::dom::Promise>>* mBrowserChangingProcessBlockers;
493
494
  RefPtr<mozilla::dom::ParentSHistory> mParentSHistory;
495
496
  bool mDepthTooGreat : 1;
497
  bool mIsTopLevelContent : 1;
498
  bool mDestroyCalled : 1;
499
  bool mNeedsAsyncDestroy : 1;
500
  bool mInSwap : 1;
501
  bool mInShow : 1;
502
  bool mHideCalled : 1;
503
  // True when the object is created for an element which the parser has
504
  // created using NS_FROM_PARSER_NETWORK flag. If the element is modified,
505
  // it may lose the flag.
506
  bool mNetworkCreated : 1;
507
508
  // True if a pending load corresponds to the original src (or srcdoc)
509
  // attribute of the frame element.
510
  bool mLoadingOriginalSrc : 1;
511
512
  bool mRemoteBrowserShown : 1;
513
  bool mRemoteFrame : 1;
514
  bool mClipSubdocument : 1;
515
  bool mClampScrollPosition : 1;
516
  bool mObservingOwnerContent : 1;
517
};
518
519
NS_DEFINE_STATIC_IID_ACCESSOR(nsFrameLoader, NS_FRAMELOADER_IID)
520
521
inline nsISupports*
522
ToSupports(nsFrameLoader* aFrameLoader)
523
0
{
524
0
  return aFrameLoader;
525
0
}
526
527
#endif