LCOV - code coverage report
Current view: top level - dom/browser-element - BrowserElementParent.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 104 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 5 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : #include "TabParent.h"
       8             : 
       9             : // TabParent.h transitively includes <windows.h>, which does
      10             : //   #define CreateEvent CreateEventW
      11             : // That messes up our call to EventDispatcher::CreateEvent below.
      12             : 
      13             : #ifdef CreateEvent
      14             : #undef CreateEvent
      15             : #endif
      16             : 
      17             : #include "BrowserElementParent.h"
      18             : #include "mozilla/EventDispatcher.h"
      19             : #include "mozilla/dom/HTMLIFrameElement.h"
      20             : #include "mozilla/dom/ToJSValue.h"
      21             : #include "nsIInterfaceRequestorUtils.h"
      22             : #include "nsVariant.h"
      23             : #include "mozilla/dom/BrowserElementDictionariesBinding.h"
      24             : #include "mozilla/dom/CustomEvent.h"
      25             : #include "mozilla/layout/RenderFrameParent.h"
      26             : 
      27             : using namespace mozilla;
      28             : using namespace mozilla::dom;
      29             : using namespace mozilla::layers;
      30             : using namespace mozilla::layout;
      31             : 
      32             : namespace {
      33             : 
      34             : using mozilla::BrowserElementParent;
      35             : /**
      36             :  * Create an <iframe mozbrowser> owned by the same document as
      37             :  * aOpenerFrameElement.
      38             :  */
      39             : already_AddRefed<HTMLIFrameElement>
      40           0 : CreateIframe(Element* aOpenerFrameElement, const nsAString& aName, bool aRemote)
      41             : {
      42             :   nsNodeInfoManager *nodeInfoManager =
      43           0 :     aOpenerFrameElement->OwnerDoc()->NodeInfoManager();
      44             : 
      45             :   RefPtr<NodeInfo> nodeInfo =
      46           0 :     nodeInfoManager->GetNodeInfo(nsGkAtoms::iframe,
      47             :                                  /* aPrefix = */ nullptr,
      48             :                                  kNameSpaceID_XHTML,
      49           0 :                                  nsIDOMNode::ELEMENT_NODE);
      50             : 
      51             :   RefPtr<HTMLIFrameElement> popupFrameElement =
      52             :     static_cast<HTMLIFrameElement*>(
      53           0 :       NS_NewHTMLIFrameElement(nodeInfo.forget(), mozilla::dom::NOT_FROM_PARSER));
      54             : 
      55           0 :   popupFrameElement->SetMozbrowser(true);
      56             : 
      57             :   // Copy the window name onto the iframe.
      58           0 :   popupFrameElement->SetAttr(kNameSpaceID_None, nsGkAtoms::name,
      59           0 :                              aName, /* aNotify = */ false);
      60             : 
      61             :   // Indicate whether the iframe is should be remote.
      62           0 :   popupFrameElement->SetAttr(kNameSpaceID_None, nsGkAtoms::Remote,
      63           0 :                              aRemote ? NS_LITERAL_STRING("true") :
      64           0 :                                        NS_LITERAL_STRING("false"),
      65           0 :                              /* aNotify = */ false);
      66             : 
      67             :   // Copy the opener frame's mozprivatebrowsing attribute to the popup frame.
      68           0 :   nsAutoString mozprivatebrowsing;
      69           0 :   if (aOpenerFrameElement->GetAttr(kNameSpaceID_None, nsGkAtoms::mozprivatebrowsing,
      70             :                                    mozprivatebrowsing)) {
      71           0 :     popupFrameElement->SetAttr(kNameSpaceID_None, nsGkAtoms::mozprivatebrowsing,
      72           0 :                                mozprivatebrowsing, /* aNotify = */ false);
      73             :   }
      74             : 
      75           0 :   return popupFrameElement.forget();
      76             : }
      77             : 
      78             : bool
      79           0 : DispatchCustomDOMEvent(Element* aFrameElement, const nsAString& aEventName,
      80             :                        JSContext* cx, JS::Handle<JS::Value> aDetailValue,
      81             :                        nsEventStatus *aStatus)
      82             : {
      83           0 :   NS_ENSURE_TRUE(aFrameElement, false);
      84           0 :   nsIPresShell *shell = aFrameElement->OwnerDoc()->GetShell();
      85           0 :   RefPtr<nsPresContext> presContext;
      86           0 :   if (shell) {
      87           0 :     presContext = shell->GetPresContext();
      88             :   }
      89             : 
      90             :   RefPtr<CustomEvent> event =
      91           0 :     NS_NewDOMCustomEvent(aFrameElement, presContext, nullptr);
      92             : 
      93           0 :   ErrorResult res;
      94           0 :   event->InitCustomEvent(cx,
      95             :                          aEventName,
      96             :                          /* aCanBubble = */ true,
      97             :                          /* aCancelable = */ true,
      98             :                          aDetailValue,
      99           0 :                          res);
     100           0 :   if (res.Failed()) {
     101           0 :     return false;
     102             :   }
     103           0 :   event->SetTrusted(true);
     104             :   // Dispatch the event.
     105             :   // We don't initialize aStatus here, as our callers have already done so.
     106             :   nsresult rv =
     107           0 :     EventDispatcher::DispatchDOMEvent(aFrameElement, nullptr, event,
     108           0 :                                       presContext, aStatus);
     109           0 :   return NS_SUCCEEDED(rv);
     110             : }
     111             : 
     112             : } // namespace
     113             : 
     114             : namespace mozilla {
     115             : 
     116             : /**
     117             :  * Dispatch a mozbrowseropenwindow event to the given opener frame element.
     118             :  * The "popup iframe" (event.detail.frameElement) will be |aPopupFrameElement|.
     119             :  *
     120             :  * Returns true iff there were no unexpected failures and the window.open call
     121             :  * was accepted by the embedder.
     122             :  */
     123             : /*static*/
     124             : BrowserElementParent::OpenWindowResult
     125           0 : BrowserElementParent::DispatchOpenWindowEvent(Element* aOpenerFrameElement,
     126             :                         Element* aPopupFrameElement,
     127             :                         const nsAString& aURL,
     128             :                         const nsAString& aName,
     129             :                         const nsAString& aFeatures)
     130             : {
     131             :   // Dispatch a CustomEvent at aOpenerFrameElement with a detail object
     132             :   // (OpenWindowEventDetail) containing aPopupFrameElement, aURL, aName, and
     133             :   // aFeatures.
     134             : 
     135             :   // Create the event's detail object.
     136           0 :   OpenWindowEventDetail detail;
     137           0 :   if (aURL.IsEmpty()) {
     138             :     // URL should never be empty. Assign about:blank as default.
     139           0 :     detail.mUrl = NS_LITERAL_STRING("about:blank");
     140             :   } else {
     141           0 :     detail.mUrl = aURL;
     142             :   }
     143           0 :   detail.mName = aName;
     144           0 :   detail.mFeatures = aFeatures;
     145           0 :   detail.mFrameElement = aPopupFrameElement;
     146             : 
     147           0 :   AutoJSContext cx;
     148           0 :   JS::Rooted<JS::Value> val(cx);
     149             : 
     150           0 :   nsIGlobalObject* sgo = aPopupFrameElement->OwnerDoc()->GetScopeObject();
     151           0 :   if (!sgo) {
     152           0 :     return BrowserElementParent::OPEN_WINDOW_IGNORED;
     153             :   }
     154             : 
     155           0 :   JS::Rooted<JSObject*> global(cx, sgo->GetGlobalJSObject());
     156           0 :   JSAutoCompartment ac(cx, global);
     157           0 :   if (!ToJSValue(cx, detail, &val)) {
     158           0 :     MOZ_CRASH("Failed to convert dictionary to JS::Value due to OOM.");
     159             :     return BrowserElementParent::OPEN_WINDOW_IGNORED;
     160             :   }
     161             : 
     162           0 :   nsEventStatus status = nsEventStatus_eIgnore;
     163             :   bool dispatchSucceeded =
     164           0 :     DispatchCustomDOMEvent(aOpenerFrameElement,
     165           0 :                            NS_LITERAL_STRING("mozbrowseropenwindow"),
     166             :                            cx,
     167           0 :                            val, &status);
     168             : 
     169           0 :   if (dispatchSucceeded) {
     170           0 :     if (aPopupFrameElement->IsInUncomposedDoc()) {
     171           0 :       return BrowserElementParent::OPEN_WINDOW_ADDED;
     172             :     }
     173           0 :     if (status == nsEventStatus_eConsumeNoDefault) {
     174             :       // If the frame was not added to a document, report to callers whether
     175             :       // preventDefault was called on or not
     176           0 :       return BrowserElementParent::OPEN_WINDOW_CANCELLED;
     177             :     }
     178             :   }
     179             : 
     180           0 :   return BrowserElementParent::OPEN_WINDOW_IGNORED;
     181             : }
     182             : 
     183             : /*static*/
     184             : BrowserElementParent::OpenWindowResult
     185           0 : BrowserElementParent::OpenWindowOOP(TabParent* aOpenerTabParent,
     186             :                                     TabParent* aPopupTabParent,
     187             :                                     PRenderFrameParent* aRenderFrame,
     188             :                                     const nsAString& aURL,
     189             :                                     const nsAString& aName,
     190             :                                     const nsAString& aFeatures,
     191             :                                     TextureFactoryIdentifier* aTextureFactoryIdentifier,
     192             :                                     uint64_t* aLayersId)
     193             : {
     194             :   // Create an iframe owned by the same document which owns openerFrameElement.
     195           0 :   nsCOMPtr<Element> openerFrameElement = aOpenerTabParent->GetOwnerElement();
     196           0 :   NS_ENSURE_TRUE(openerFrameElement,
     197             :                  BrowserElementParent::OPEN_WINDOW_IGNORED);
     198             :   RefPtr<HTMLIFrameElement> popupFrameElement =
     199           0 :     CreateIframe(openerFrameElement, aName, /* aRemote = */ true);
     200             : 
     201             :   // Normally an <iframe> element will try to create a frameLoader when the
     202             :   // page touches iframe.contentWindow or sets iframe.src.
     203             :   //
     204             :   // But in our case, we want to delay the creation of the frameLoader until
     205             :   // we've verified that the popup has gone through successfully.  If the popup
     206             :   // is "blocked" by the embedder, we don't want to load the popup's url.
     207             :   //
     208             :   // Therefore we call DisallowCreateFrameLoader() on the element and call
     209             :   // AllowCreateFrameLoader() only after we've verified that the popup was
     210             :   // allowed.
     211           0 :   popupFrameElement->DisallowCreateFrameLoader();
     212             : 
     213             :   OpenWindowResult opened =
     214           0 :     DispatchOpenWindowEvent(openerFrameElement, popupFrameElement,
     215           0 :                             aURL, aName, aFeatures);
     216             : 
     217           0 :   if (opened != BrowserElementParent::OPEN_WINDOW_ADDED) {
     218           0 :     return opened;
     219             :   }
     220             : 
     221             :   // The popup was not blocked, so hook up the frame element and the popup tab
     222             :   // parent, and return success.
     223           0 :   aPopupTabParent->SetOwnerElement(popupFrameElement);
     224           0 :   popupFrameElement->AllowCreateFrameLoader();
     225           0 :   popupFrameElement->CreateRemoteFrameLoader(aPopupTabParent);
     226             : 
     227           0 :   RenderFrameParent* rfp = static_cast<RenderFrameParent*>(aRenderFrame);
     228           0 :   if (!aPopupTabParent->SetRenderFrame(rfp) ||
     229           0 :       !aPopupTabParent->GetRenderFrameInfo(aTextureFactoryIdentifier, aLayersId)) {
     230           0 :     return BrowserElementParent::OPEN_WINDOW_IGNORED;
     231             :   }
     232             : 
     233           0 :   return opened;
     234             : }
     235             : 
     236             : /* static */
     237             : BrowserElementParent::OpenWindowResult
     238           0 : BrowserElementParent::OpenWindowInProcess(nsPIDOMWindowOuter* aOpenerWindow,
     239             :                                           nsIURI* aURI,
     240             :                                           const nsAString& aName,
     241             :                                           const nsACString& aFeatures,
     242             :                                           bool aForceNoOpener,
     243             :                                           mozIDOMWindowProxy** aReturnWindow)
     244             : {
     245           0 :   *aReturnWindow = nullptr;
     246             : 
     247             :   // If we call window.open from an <iframe> inside an <iframe mozbrowser>,
     248             :   // it's as though the top-level document inside the <iframe mozbrowser>
     249             :   // called window.open.  (Indeed, in the OOP case, the inner <iframe> lives
     250             :   // out-of-process, so we couldn't touch it if we tried.)
     251             :   //
     252             :   // GetScriptableTop gets us the <iframe mozbrowser>'s window; we'll use its
     253             :   // frame element, rather than aOpenerWindow's frame element, as our "opener
     254             :   // frame element" below.
     255           0 :   nsCOMPtr<nsPIDOMWindowOuter> win = aOpenerWindow->GetScriptableTop();
     256             : 
     257           0 :   nsCOMPtr<Element> openerFrameElement = win->GetFrameElementInternal();
     258           0 :   NS_ENSURE_TRUE(openerFrameElement, BrowserElementParent::OPEN_WINDOW_IGNORED);
     259             : 
     260             : 
     261             :   RefPtr<HTMLIFrameElement> popupFrameElement =
     262           0 :     CreateIframe(openerFrameElement, aName, /* aRemote = */ false);
     263           0 :   NS_ENSURE_TRUE(popupFrameElement, BrowserElementParent::OPEN_WINDOW_IGNORED);
     264             : 
     265           0 :   nsAutoCString spec;
     266           0 :   if (aURI) {
     267           0 :     aURI->GetSpec(spec);
     268             :   }
     269             : 
     270           0 :   if (!aForceNoOpener) {
     271           0 :     ErrorResult res;
     272           0 :     popupFrameElement->PresetOpenerWindow(aOpenerWindow, res);
     273           0 :     MOZ_ASSERT(!res.Failed());
     274             :   }
     275             : 
     276             :   OpenWindowResult opened =
     277           0 :     DispatchOpenWindowEvent(openerFrameElement, popupFrameElement,
     278           0 :                             NS_ConvertUTF8toUTF16(spec),
     279             :                             aName,
     280           0 :                             NS_ConvertUTF8toUTF16(aFeatures));
     281             : 
     282           0 :   if (opened != BrowserElementParent::OPEN_WINDOW_ADDED) {
     283           0 :     return opened;
     284             :   }
     285             : 
     286             :   // Return popupFrameElement's window.
     287           0 :   RefPtr<nsFrameLoader> frameLoader = popupFrameElement->GetFrameLoader();
     288           0 :   NS_ENSURE_TRUE(frameLoader, BrowserElementParent::OPEN_WINDOW_IGNORED);
     289             : 
     290           0 :   nsCOMPtr<nsIDocShell> docshell;
     291           0 :   frameLoader->GetDocShell(getter_AddRefs(docshell));
     292           0 :   NS_ENSURE_TRUE(docshell, BrowserElementParent::OPEN_WINDOW_IGNORED);
     293             : 
     294           0 :   nsCOMPtr<nsPIDOMWindowOuter> window = docshell->GetWindow();
     295           0 :   window.forget(aReturnWindow);
     296             : 
     297           0 :   return !!*aReturnWindow ? opened : BrowserElementParent::OPEN_WINDOW_CANCELLED;
     298             : }
     299             : 
     300             : } // namespace mozilla

Generated by: LCOV version 1.13