tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsWindowRoot.cpp (13754B)


      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 "nsWindowRoot.h"
      8 
      9 #include "mozilla/BasicEvents.h"
     10 #include "mozilla/EventDispatcher.h"
     11 #include "mozilla/EventListenerManager.h"
     12 #include "mozilla/StaticPrefs_browser.h"
     13 #include "mozilla/dom/BrowserParent.h"
     14 #include "mozilla/dom/CanonicalBrowsingContext.h"
     15 #include "mozilla/dom/HTMLInputElement.h"
     16 #include "mozilla/dom/HTMLTextAreaElement.h"
     17 #include "mozilla/dom/JSActorService.h"
     18 #include "mozilla/dom/WindowGlobalParent.h"
     19 #include "mozilla/dom/WindowRootBinding.h"
     20 #include "nsCOMPtr.h"
     21 #include "nsCycleCollectionParticipant.h"
     22 #include "nsFocusManager.h"
     23 #include "nsFrameLoader.h"
     24 #include "nsFrameLoaderOwner.h"
     25 #include "nsGlobalWindowOuter.h"
     26 #include "nsIContent.h"
     27 #include "nsIController.h"
     28 #include "nsIControllers.h"
     29 #include "nsPIDOMWindow.h"
     30 #include "nsPresContext.h"
     31 #include "nsQueryActor.h"
     32 #include "nsQueryObject.h"
     33 #include "nsString.h"
     34 #include "nsXULElement.h"
     35 #include "xpcpublic.h"
     36 
     37 using namespace mozilla;
     38 using namespace mozilla::dom;
     39 
     40 nsWindowRoot::nsWindowRoot(nsPIDOMWindowOuter* aWindow) {
     41  SetIsOnMainThread();
     42  mWindow = aWindow;
     43 }
     44 
     45 nsWindowRoot::~nsWindowRoot() {
     46  if (mListenerManager) {
     47    mListenerManager->Disconnect();
     48  }
     49 
     50  JSActorService::UnregisterChromeEventTarget(this);
     51 }
     52 
     53 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(nsWindowRoot)
     54 
     55 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsWindowRoot)
     56  JSActorService::UnregisterChromeEventTarget(tmp);
     57 
     58  NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
     59  NS_IMPL_CYCLE_COLLECTION_UNLINK(mListenerManager)
     60  NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
     61  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
     62 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     63 
     64 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsWindowRoot)
     65  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
     66  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListenerManager)
     67  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
     68 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     69 
     70 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsWindowRoot)
     71  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
     72  NS_INTERFACE_MAP_ENTRY(nsISupports)
     73  NS_INTERFACE_MAP_ENTRY(nsPIWindowRoot)
     74  NS_INTERFACE_MAP_ENTRY(mozilla::dom::EventTarget)
     75 NS_INTERFACE_MAP_END
     76 
     77 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsWindowRoot)
     78 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsWindowRoot)
     79 
     80 bool nsWindowRoot::DispatchEvent(Event& aEvent, CallerType aCallerType,
     81                                 ErrorResult& aRv) {
     82  nsEventStatus status = nsEventStatus_eIgnore;
     83  nsresult rv = EventDispatcher::DispatchDOMEvent(
     84      static_cast<EventTarget*>(this), nullptr, &aEvent, nullptr, &status);
     85  bool retval = !aEvent.DefaultPrevented(aCallerType);
     86  if (NS_FAILED(rv)) {
     87    aRv.Throw(rv);
     88  }
     89  return retval;
     90 }
     91 
     92 bool nsWindowRoot::ComputeDefaultWantsUntrusted(ErrorResult& aRv) {
     93  return false;
     94 }
     95 
     96 EventListenerManager* nsWindowRoot::GetOrCreateListenerManager() {
     97  if (!mListenerManager) {
     98    mListenerManager =
     99        new EventListenerManager(static_cast<EventTarget*>(this));
    100  }
    101 
    102  return mListenerManager;
    103 }
    104 
    105 EventListenerManager* nsWindowRoot::GetExistingListenerManager() const {
    106  return mListenerManager;
    107 }
    108 
    109 void nsWindowRoot::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
    110  aVisitor.mCanHandle = true;
    111  aVisitor.mForceContentDispatch = true;  // FIXME! Bug 329119
    112  // To keep mWindow alive
    113  aVisitor.mItemData = static_cast<nsISupports*>(mWindow);
    114  aVisitor.SetParentTarget(mParent, false);
    115 }
    116 
    117 nsresult nsWindowRoot::PostHandleEvent(EventChainPostVisitor& aVisitor) {
    118  return NS_OK;
    119 }
    120 
    121 nsPIDOMWindowOuter* nsWindowRoot::GetOwnerGlobalForBindingsInternal() {
    122  return mWindow;
    123 }
    124 
    125 nsIGlobalObject* nsWindowRoot::GetOwnerGlobal() const {
    126  nsCOMPtr<nsIGlobalObject> global =
    127      do_QueryInterface(mWindow->GetCurrentInnerWindow());
    128  // We're still holding a ref to it, so returning the raw pointer is ok...
    129  return global;
    130 }
    131 
    132 nsPIDOMWindowOuter* nsWindowRoot::GetWindow() { return mWindow; }
    133 
    134 nsresult nsWindowRoot::GetControllers(bool aForVisibleWindow,
    135                                      nsIControllers** aResult) {
    136  *aResult = nullptr;
    137 
    138  // XXX: we should fix this so there's a generic interface that
    139  // describes controllers, so this code would have no special
    140  // knowledge of what object might have controllers.
    141 
    142  nsFocusManager::SearchRange searchRange =
    143      aForVisibleWindow ? nsFocusManager::eIncludeVisibleDescendants
    144                        : nsFocusManager::eIncludeAllDescendants;
    145  nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
    146  nsIContent* focusedContent = nsFocusManager::GetFocusedDescendant(
    147      mWindow, searchRange, getter_AddRefs(focusedWindow));
    148  if (focusedContent) {
    149    if (auto* xulElement = nsXULElement::FromNode(focusedContent)) {
    150      *aResult = xulElement->GetExtantControllers();
    151      NS_IF_ADDREF(*aResult);
    152      return NS_OK;
    153    }
    154    auto* htmlTextArea = HTMLTextAreaElement::FromNode(focusedContent);
    155    if (htmlTextArea) {
    156      return htmlTextArea->GetControllers(aResult);
    157    }
    158    auto* htmlInputElement = HTMLInputElement::FromNode(focusedContent);
    159    if (htmlInputElement) {
    160      return htmlInputElement->GetControllers(aResult);
    161    }
    162    if (focusedContent->IsEditable() && focusedWindow) {
    163      return focusedWindow->GetControllers(aResult);
    164    }
    165  } else {
    166    return focusedWindow->GetControllers(aResult);
    167  }
    168 
    169  return NS_OK;
    170 }
    171 
    172 nsresult nsWindowRoot::GetControllerForCommand(const char* aCommand,
    173                                               bool aForVisibleWindow,
    174                                               nsIController** _retval) {
    175  NS_ENSURE_ARG_POINTER(_retval);
    176  *_retval = nullptr;
    177 
    178  // If this is the parent process, check if a child browsing context from
    179  // another process is focused, and ask if it has a controller actor that
    180  // supports the command.
    181  if (XRE_IsParentProcess()) {
    182    nsFocusManager* fm = nsFocusManager::GetFocusManager();
    183    if (!fm) {
    184      return NS_ERROR_FAILURE;
    185    }
    186 
    187    // Unfortunately, messages updating the active/focus state in the focus
    188    // manager don't happen fast enough in the case when switching focus between
    189    // processes when clicking on a chrome UI element while a child tab is
    190    // focused, so we need to check whether the focus manager thinks a child
    191    // frame is focused as well.
    192    nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
    193    nsIContent* focusedContent = nsFocusManager::GetFocusedDescendant(
    194        mWindow, nsFocusManager::eIncludeAllDescendants,
    195        getter_AddRefs(focusedWindow));
    196    RefPtr<nsFrameLoaderOwner> loaderOwner = do_QueryObject(focusedContent);
    197    if (loaderOwner) {
    198      // Only check browsing contexts if a remote frame is focused. If chrome is
    199      // focused, just check the controllers directly below.
    200      RefPtr<nsFrameLoader> frameLoader = loaderOwner->GetFrameLoader();
    201      if (frameLoader && frameLoader->IsRemoteFrame()) {
    202        // GetActiveBrowsingContextInChrome actually returns the top-level
    203        // browsing context if the focus is in a child process tab, or null if
    204        // the focus is in chrome.
    205        BrowsingContext* focusedBC =
    206            fm->GetActiveBrowsingContextInChrome()
    207                ? fm->GetFocusedBrowsingContextInChrome()
    208                : nullptr;
    209        if (focusedBC) {
    210          // At this point, it is known that a child process is focused, so ask
    211          // its Controllers actor if the command is supported.
    212          nsCOMPtr<nsIController> controller = do_QueryActor(
    213              "Controllers", focusedBC->Canonical()->GetCurrentWindowGlobal());
    214          if (controller) {
    215            bool supported;
    216            controller->SupportsCommand(aCommand, &supported);
    217            if (supported) {
    218              controller.forget(_retval);
    219              return NS_OK;
    220            }
    221          }
    222        }
    223      }
    224    }
    225  }
    226 
    227  {
    228    nsCOMPtr<nsIControllers> controllers;
    229    GetControllers(aForVisibleWindow, getter_AddRefs(controllers));
    230    if (controllers) {
    231      nsCOMPtr<nsIController> controller;
    232      controllers->GetControllerForCommand(aCommand,
    233                                           getter_AddRefs(controller));
    234      if (controller) {
    235        controller.forget(_retval);
    236        return NS_OK;
    237      }
    238    }
    239  }
    240 
    241  nsFocusManager::SearchRange searchRange =
    242      aForVisibleWindow ? nsFocusManager::eIncludeVisibleDescendants
    243                        : nsFocusManager::eIncludeAllDescendants;
    244  nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
    245  nsFocusManager::GetFocusedDescendant(mWindow, searchRange,
    246                                       getter_AddRefs(focusedWindow));
    247  while (focusedWindow) {
    248    nsCOMPtr<nsIControllers> controllers;
    249    focusedWindow->GetControllers(getter_AddRefs(controllers));
    250    if (controllers) {
    251      nsCOMPtr<nsIController> controller;
    252      controllers->GetControllerForCommand(aCommand,
    253                                           getter_AddRefs(controller));
    254      if (controller) {
    255        controller.forget(_retval);
    256        return NS_OK;
    257      }
    258    }
    259 
    260    // XXXndeakin P3 is this casting safe?
    261    nsGlobalWindowOuter* win = nsGlobalWindowOuter::Cast(focusedWindow);
    262    focusedWindow = win->GetPrivateParent();
    263  }
    264 
    265  return NS_OK;
    266 }
    267 
    268 void nsWindowRoot::GetEnabledDisabledCommandsForControllers(
    269    nsIControllers* aControllers, nsTHashSet<nsCString>& aCommandsHandled,
    270    nsTArray<nsCString>& aEnabledCommands,
    271    nsTArray<nsCString>& aDisabledCommands) {
    272  uint32_t controllerCount;
    273  aControllers->GetControllerCount(&controllerCount);
    274  for (uint32_t c = 0; c < controllerCount; c++) {
    275    nsCOMPtr<nsIController> controller;
    276    aControllers->GetControllerAt(c, getter_AddRefs(controller));
    277 
    278    nsCOMPtr<nsICommandController> commandController(
    279        do_QueryInterface(controller));
    280    if (commandController) {
    281      // All of our default command controllers have 20-60 commands.  Let's just
    282      // leave enough space here for all of them so we probably don't need to
    283      // heap-allocate.
    284      AutoTArray<nsCString, 64> commands;
    285      if (NS_SUCCEEDED(commandController->GetSupportedCommands(commands))) {
    286        for (auto& commandStr : commands) {
    287          // Use a hash to determine which commands have already been handled by
    288          // earlier controllers, as the earlier controller's result should get
    289          // priority.
    290          if (aCommandsHandled.EnsureInserted(commandStr)) {
    291            // We inserted a new entry into aCommandsHandled.
    292            bool enabled = false;
    293            controller->IsCommandEnabled(commandStr.get(), &enabled);
    294 
    295            if (enabled) {
    296              aEnabledCommands.AppendElement(commandStr);
    297            } else {
    298              aDisabledCommands.AppendElement(commandStr);
    299            }
    300          }
    301        }
    302      }
    303    }
    304  }
    305 }
    306 
    307 void nsWindowRoot::GetEnabledDisabledCommands(
    308    nsTArray<nsCString>& aEnabledCommands,
    309    nsTArray<nsCString>& aDisabledCommands) {
    310  nsTHashSet<nsCString> commandsHandled;
    311 
    312  nsCOMPtr<nsIControllers> controllers;
    313  GetControllers(false, getter_AddRefs(controllers));
    314  if (controllers) {
    315    GetEnabledDisabledCommandsForControllers(
    316        controllers, commandsHandled, aEnabledCommands, aDisabledCommands);
    317  }
    318 
    319  nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
    320  nsFocusManager::GetFocusedDescendant(mWindow,
    321                                       nsFocusManager::eIncludeAllDescendants,
    322                                       getter_AddRefs(focusedWindow));
    323  while (focusedWindow) {
    324    focusedWindow->GetControllers(getter_AddRefs(controllers));
    325    if (controllers) {
    326      GetEnabledDisabledCommandsForControllers(
    327          controllers, commandsHandled, aEnabledCommands, aDisabledCommands);
    328    }
    329 
    330    nsGlobalWindowOuter* win = nsGlobalWindowOuter::Cast(focusedWindow);
    331    focusedWindow = win->GetPrivateParent();
    332  }
    333 }
    334 
    335 already_AddRefed<nsINode> nsWindowRoot::GetPopupNode() {
    336  nsCOMPtr<nsINode> popupNode = do_QueryReferent(mPopupNode);
    337  return popupNode.forget();
    338 }
    339 
    340 void nsWindowRoot::SetPopupNode(nsINode* aNode) {
    341  mPopupNode = do_GetWeakReference(aNode);
    342 }
    343 
    344 nsIGlobalObject* nsWindowRoot::GetParentObject() {
    345  return xpc::NativeGlobal(xpc::PrivilegedJunkScope());
    346 }
    347 
    348 JSObject* nsWindowRoot::WrapObject(JSContext* aCx,
    349                                   JS::Handle<JSObject*> aGivenProto) {
    350  return mozilla::dom::WindowRoot_Binding::Wrap(aCx, this, aGivenProto);
    351 }
    352 
    353 void nsWindowRoot::AddBrowser(nsIRemoteTab* aBrowser) {
    354  nsWeakPtr weakBrowser = do_GetWeakReference(aBrowser);
    355  mWeakBrowsers.Insert(weakBrowser);
    356 }
    357 
    358 void nsWindowRoot::RemoveBrowser(nsIRemoteTab* aBrowser) {
    359  nsWeakPtr weakBrowser = do_GetWeakReference(aBrowser);
    360  mWeakBrowsers.Remove(weakBrowser);
    361 }
    362 
    363 void nsWindowRoot::EnumerateBrowsers(BrowserEnumerator aEnumFunc, void* aArg) {
    364  // Collect strong references to all browsers in a separate array in
    365  // case aEnumFunc alters mWeakBrowsers.
    366  nsTArray<nsCOMPtr<nsIRemoteTab>> remoteTabs;
    367  for (const auto& key : mWeakBrowsers) {
    368    nsCOMPtr<nsIRemoteTab> remoteTab(do_QueryReferent(key));
    369    if (remoteTab) {
    370      remoteTabs.AppendElement(remoteTab);
    371    }
    372  }
    373 
    374  for (uint32_t i = 0; i < remoteTabs.Length(); ++i) {
    375    aEnumFunc(remoteTabs[i], aArg);
    376  }
    377 }
    378 
    379 ///////////////////////////////////////////////////////////////////////////////////
    380 
    381 already_AddRefed<EventTarget> NS_NewWindowRoot(nsPIDOMWindowOuter* aWindow) {
    382  nsCOMPtr<EventTarget> result = new nsWindowRoot(aWindow);
    383 
    384  RefPtr<JSActorService> wasvc = JSActorService::GetSingleton();
    385  wasvc->RegisterChromeEventTarget(result);
    386 
    387  return result.forget();
    388 }