author Oleg Romashin <>
Sat, 22 Nov 2014 12:15:00 +0100
changeset 219062 cadfee0aa2af0fa0c5d3e192423024d417b3183a
parent 212358 2db29c0ae60b6eb0e196165631127d195fe2ef0b
child 222174 75a20fb5f86430a9dc8ef49a6cdd0aa7bea9d50c
permissions -rw-r--r--
Bug 1103412 - Gecko does not compile with printing disabled. r=mconley

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 */

 * Class for managing loading of a subframe (creation of the docshell,
 * handling of loads in it, recursion-checking).

#ifndef nsFrameLoader_h_
#define nsFrameLoader_h_

#include "nsIDocShell.h"
#include "nsStringFwd.h"
#include "nsIFrameLoader.h"
#include "nsPoint.h"
#include "nsSize.h"
#include "nsIURI.h"
#include "nsAutoPtr.h"
#include "nsFrameMessageManager.h"
#include "mozilla/dom/Element.h"
#include "mozilla/Attributes.h"
#include "FrameMetrics.h"
#include "nsStubMutationObserver.h"

class nsIURI;
class nsSubDocumentFrame;
class nsView;
class nsIInProcessContentFrameMessageManager;
class AutoResetInShow;
class nsITabParent;
class nsIDocShellTreeItem;
class nsIDocShellTreeOwner;
class mozIApplication;

namespace mozilla {
namespace dom {
class ContentParent;
class PBrowserParent;
class TabParent;
struct StructuredCloneData;

namespace layout {
class RenderFrameParent;

#if defined(MOZ_WIDGET_GTK)
typedef struct _GtkWidget GtkWidget;
class QX11EmbedContainer;

class nsFrameLoader MOZ_FINAL : public nsIFrameLoader,
                                public nsStubMutationObserver,
                                public mozilla::dom::ipc::MessageManagerCallback
  friend class AutoResetInShow;
  typedef mozilla::dom::PBrowserParent PBrowserParent;
  typedef mozilla::dom::TabParent TabParent;
  typedef mozilla::layout::RenderFrameParent RenderFrameParent;

  nsFrameLoader(mozilla::dom::Element* aOwner, bool aNetworkCreated);


  static nsFrameLoader* Create(mozilla::dom::Element* aOwner,
                               bool aNetworkCreated);

  nsresult CheckForRecursiveLoad(nsIURI* aURI);
  nsresult ReallyStartLoading();
  void Finalize();
  nsIDocShell* GetExistingDocShell() { return mDocShell; }
  mozilla::dom::EventTarget* GetTabChildGlobalAsEventTarget();
  nsresult CreateStaticClone(nsIFrameLoader* aDest);

   * MessageManagerCallback methods that we override.
  virtual bool DoLoadFrameScript(const nsAString& aURL,
                                 bool aRunInGlobalScope) MOZ_OVERRIDE;
  virtual bool DoSendAsyncMessage(JSContext* aCx,
                                  const nsAString& aMessage,
                                  const mozilla::dom::StructuredCloneData& aData,
                                  JS::Handle<JSObject *> aCpows,
                                  nsIPrincipal* aPrincipal) MOZ_OVERRIDE;
  virtual bool CheckPermission(const nsAString& aPermission) MOZ_OVERRIDE;
  virtual bool CheckManifestURL(const nsAString& aManifestURL) MOZ_OVERRIDE;
  virtual bool CheckAppHasPermission(const nsAString& aPermission) MOZ_OVERRIDE;

   * Called from the layout frame associated with this frame loader;
   * this notifies us to hook up with the widget and view.
  bool Show(int32_t marginWidth, int32_t marginHeight,
              int32_t scrollbarPrefX, int32_t scrollbarPrefY,
              nsSubDocumentFrame* frame);

   * Called when the margin properties of the containing frame are changed.
  void MarginsChanged(uint32_t aMarginWidth, uint32_t aMarginHeight);

   * Called from the layout frame associated with this frame loader, when
   * the frame is being torn down; this notifies us that out widget and view
   * are going away and we should unhook from them.
  void Hide();

  nsresult CloneForStatic(nsIFrameLoader* aOriginal);

  // The guts of an nsIFrameLoaderOwner::SwapFrameLoader implementation.  A
  // frame loader owner needs to call this, and pass in the two references to
  // nsRefPtrs for frame loaders that need to be swapped.
  nsresult SwapWithOtherLoader(nsFrameLoader* aOther,
                               nsRefPtr<nsFrameLoader>& aFirstToSwap,
                               nsRefPtr<nsFrameLoader>& aSecondToSwap);

  nsresult SwapWithOtherRemoteLoader(nsFrameLoader* aOther,
                                     nsRefPtr<nsFrameLoader>& aFirstToSwap,
                                     nsRefPtr<nsFrameLoader>& aSecondToSwap);

  // When IPC is enabled, destroy any associated child process.
  void DestroyChild();

   * Return the primary frame for our owning content, or null if it
   * can't be found.
  nsIFrame* GetPrimaryFrameOfOwningContent() const
    return mOwnerContent ? mOwnerContent->GetPrimaryFrame() : nullptr;

   * Return the document that owns this, or null if we don't have
   * an owner.
  nsIDocument* GetOwnerDoc() const
  { return mOwnerContent ? mOwnerContent->OwnerDoc() : nullptr; }

  PBrowserParent* GetRemoteBrowser();

   * The "current" render frame is the one on which the most recent
   * remote layer-tree transaction was executed.  If no content has
   * been drawn yet, or the remote browser doesn't have any drawn
   * content for whatever reason, return nullptr.  The returned render
   * frame has an associated shadow layer tree.
   * Note that the returned render frame might not be a frame
   * constructed for this->GetURL().  This can happen, e.g., if the
   * <browser> was just navigated to a new URL, but hasn't painted the
   * new page yet.  A render frame for the previous page may be
   * returned.  (In-process <browser> behaves similarly, and this
   * behavior seems desirable.)
  RenderFrameParent* GetCurrentRemoteFrame() const
    return mCurrentRemoteFrame;

   * |aFrame| can be null.  If non-null, it must be the remote frame
   * on which the most recent layer transaction completed for this's
   * <browser>.
  void SetCurrentRemoteFrame(RenderFrameParent* aFrame)
    mCurrentRemoteFrame = aFrame;
  nsFrameMessageManager* GetFrameMessageManager() { return mMessageManager; }

  mozilla::dom::Element* GetOwnerContent() { return mOwnerContent; }
  bool ShouldClipSubdocument() { return mClipSubdocument; }

  bool ShouldClampScrollPosition() { return mClampScrollPosition; }

   * Tell this FrameLoader to use a particular remote browser.
   * This will assert if mRemoteBrowser or mCurrentRemoteFrame is non-null.  In
   * practice, this means you can't have successfully run TryRemoteBrowser() on
   * this object, which means you can't have called ShowRemoteFrame() or
   * ReallyStartLoading().
  void SetRemoteBrowser(nsITabParent* aTabParent);

   * Stashes a detached view on the frame loader. We do this when we're
   * destroying the nsSubDocumentFrame. If the nsSubdocumentFrame is
   * being reframed we'll restore the detached view when it's recreated,
   * otherwise we'll discard the old presentation and set the detached
   * subdoc view to null. aContainerDoc is the document containing the
   * the subdoc frame. This enables us to detect when the containing
   * document has changed during reframe, so we can discard the presentation 
   * in that case.
  void SetDetachedSubdocView(nsView* aDetachedView,
                             nsIDocument* aContainerDoc);

   * Retrieves the detached view and the document containing the view,
   * as set by SetDetachedSubdocView().
  nsView* GetDetachedSubdocView(nsIDocument** aContainerDoc) const;

   * Applies a new set of sandbox flags. These are merged with the sandbox
   * flags from our owning content's owning document with a logical OR, this
   * ensures that we can only add restrictions and never remove them.
  void ApplySandboxFlags(uint32_t sandboxFlags);

  void GetURL(nsString& aURL);


  void SetOwnerContent(mozilla::dom::Element* aContent);

  bool ShouldUseRemoteProcess();

   * Is this a frameloader for a bona fide <iframe mozbrowser> or
   * <iframe mozapp>?  (I.e., does the frame return true for
   * nsIMozBrowserFrame::GetReallyIsBrowserOrApp()?)
  bool OwnerIsBrowserOrAppFrame();

   * Is this a frameloader for a bona fide <iframe mozwidget>?  (I.e., does the
   * frame return true for nsIMozBrowserFrame::GetReallyIsWidget()?)
  bool OwnerIsWidget();

   * Is this a frameloader for a bona fide <iframe mozapp>?  (I.e., does the
   * frame return true for nsIMozBrowserFrame::GetReallyIsApp()?)
  bool OwnerIsAppFrame();

   * Is this a frame loader for a bona fide <iframe mozbrowser>?
  bool OwnerIsBrowserFrame();

   * Get our owning element's app manifest URL, or return the empty string if
   * our owning element doesn't have an app manifest URL.
  void GetOwnerAppManifestURL(nsAString& aOut);

   * Get the app for our frame.  This is the app whose manifest is returned by
   * GetOwnerAppManifestURL.
  already_AddRefed<mozIApplication> GetOwnApp();

   * Get the app which contains this frame.  This is the app associated with
   * the frame element's principal.
  already_AddRefed<mozIApplication> GetContainingApp();

   * If we are an IPC frame, set mRemoteFrame. Otherwise, create and
   * initialize mDocShell.
  nsresult MaybeCreateDocShell();
  nsresult EnsureMessageManager();

  // Properly retrieves documentSize of any subdocument type.
  nsresult GetWindowDimensions(nsIntRect& aRect);

  // Updates the subdocument position and size. This gets called only
  // when we have our own in-process DocShell.
  nsresult UpdateBaseWindowPositionAndSize(nsSubDocumentFrame *aIFrame);
  nsresult CheckURILoad(nsIURI* aURI);
  void FireErrorEvent();
  nsresult ReallyStartLoadingInternal();

  // Return true if remote browser created; nothing else to do
  bool TryRemoteBrowser();

  // Tell the remote browser that it's now "virtually visible"
  bool ShowRemoteFrame(const nsIntSize& size,
                       nsSubDocumentFrame *aFrame = nullptr);

  bool AddTreeItemToTreeOwner(nsIDocShellTreeItem* aItem,
                              nsIDocShellTreeOwner* aOwner,
                              int32_t aParentType,
                              nsIDocShell* aParentNode);

  nsIAtom* TypeAttrName() const {
    return mOwnerContent->IsXUL() ? nsGkAtoms::type : nsGkAtoms::mozframetype;

  // Update the permission manager's app-id refcount based on mOwnerContent's
  // own-or-containing-app.
  void ResetPermissionManagerStatus();

  nsCOMPtr<nsIDocShell> mDocShell;
  nsCOMPtr<nsIURI> mURIToLoad;
  mozilla::dom::Element* mOwnerContent; // WEAK

  // Note: this variable must be modified only by ResetPermissionManagerStatus()
  uint32_t mAppIdSentToPermissionManager;

  // public because a callback needs these.
  nsRefPtr<nsFrameMessageManager> mMessageManager;
  nsCOMPtr<nsIInProcessContentFrameMessageManager> mChildMessageManager;
  // Stores the root view of the subdocument while the subdocument is being
  // reframed. Used to restore the presentation after reframing.
  nsView* mDetachedSubdocViews;
  // Stores the containing document of the frame corresponding to this
  // frame loader. This is reference is kept valid while the subframe's
  // presentation is detached and stored in mDetachedSubdocViews. This
  // enables us to detect whether the frame has moved documents during
  // a reframe, so that we know not to restore the presentation.
  nsCOMPtr<nsIDocument> mContainerDocWhileDetached;

  bool mDepthTooGreat : 1;
  bool mIsTopLevelContent : 1;
  bool mDestroyCalled : 1;
  bool mNeedsAsyncDestroy : 1;
  bool mInSwap : 1;
  bool mInShow : 1;
  bool mHideCalled : 1;
  // True when the object is created for an element which the parser has
  // created using NS_FROM_PARSER_NETWORK flag. If the element is modified,
  // it may lose the flag.
  bool mNetworkCreated : 1;

  bool mRemoteBrowserShown : 1;
  bool mRemoteFrame : 1;
  bool mClipSubdocument : 1;
  bool mClampScrollPosition : 1;
  bool mRemoteBrowserInitialized : 1;
  bool mObservingOwnerContent : 1;

  // Backs nsIFrameLoader::{Get,Set}Visible.  Visibility state here relates to
  // whether this frameloader's <iframe mozbrowser> is setVisible(true)'ed, and
  // doesn't necessarily correlate with docshell/document visibility.
  bool mVisible : 1;

  // The ContentParent associated with mRemoteBrowser.  This was added as a
  // strong ref in bug 545237, and we're not sure if we can get rid of it.
  nsRefPtr<mozilla::dom::nsIContentParent> mContentParent;
  RenderFrameParent* mCurrentRemoteFrame;
  TabParent* mRemoteBrowser;
  uint64_t mChildID;

  // See nsIFrameLoader.idl. EVENT_MODE_NORMAL_DISPATCH automatically
  // forwards some input events to out-of-process content.
  uint32_t mEventMode;

  // Indicate if we have sent 'remote-browser-pending'.
  bool mPendingFrameSent;