LCOV - code coverage report
Current view: top level - gfx/layers/apz/src - FocusTarget.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 3 69 4.3 %
Date: 2017-07-14 16:53:18 Functions: 1 6 16.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "mozilla/layers/FocusTarget.h"
       7             : 
       8             : #include "mozilla/dom/EventTarget.h" // for EventTarget
       9             : #include "mozilla/dom/TabParent.h"   // for TabParent
      10             : #include "mozilla/EventDispatcher.h" // for EventDispatcher
      11             : #include "mozilla/layout/RenderFrameParent.h" // For RenderFrameParent
      12             : #include "nsIPresShell.h"  // for nsIPresShell
      13             : #include "nsLayoutUtils.h" // for nsLayoutUtils
      14             : 
      15             : #define ENABLE_FT_LOGGING 0
      16             : // #define ENABLE_FT_LOGGING 1
      17             : 
      18             : #if ENABLE_FT_LOGGING
      19             : #  define FT_LOG(FMT, ...) printf_stderr("FT (%s): " FMT, \
      20             :                                          XRE_IsParentProcess() ? "chrome" : "content", \
      21             :                                          __VA_ARGS__)
      22             : #else
      23             : #  define FT_LOG(...)
      24             : #endif
      25             : 
      26             : using namespace mozilla::dom;
      27             : using namespace mozilla::layout;
      28             : 
      29             : namespace mozilla {
      30             : namespace layers {
      31             : 
      32             : static already_AddRefed<nsIPresShell>
      33           0 : GetRetargetEventPresShell(nsIPresShell* aRootPresShell)
      34             : {
      35           0 :   MOZ_ASSERT(aRootPresShell);
      36             : 
      37             :   // Use the last focused window in this PresShell and its
      38             :   // associated PresShell
      39             :   nsCOMPtr<nsPIDOMWindowOuter> window =
      40           0 :     aRootPresShell->GetFocusedDOMWindowInOurWindow();
      41           0 :   if (!window) {
      42           0 :     return nullptr;
      43             :   }
      44             : 
      45           0 :   nsCOMPtr<nsIDocument> retargetEventDoc = window->GetExtantDoc();
      46           0 :   if (!retargetEventDoc) {
      47           0 :     return nullptr;
      48             :   }
      49             : 
      50           0 :   nsCOMPtr<nsIPresShell> presShell = retargetEventDoc->GetShell();
      51           0 :   return presShell.forget();
      52             : }
      53             : 
      54             : static bool
      55           0 : HasListenersForKeyEvents(nsIContent* aContent)
      56             : {
      57           0 :   if (!aContent) {
      58           0 :     return false;
      59             :   }
      60             : 
      61           0 :   WidgetEvent event(true, eVoidEvent);
      62           0 :   nsTArray<EventTarget*> targets;
      63             :   nsresult rv = EventDispatcher::Dispatch(aContent, nullptr, &event, nullptr,
      64           0 :       nullptr, nullptr, &targets);
      65           0 :   NS_ENSURE_SUCCESS(rv, false);
      66           0 :   for (size_t i = 0; i < targets.Length(); i++) {
      67           0 :     if (targets[i]->HasUntrustedOrNonSystemGroupKeyEventListeners()) {
      68           0 :       return true;
      69             :     }
      70             :   }
      71           0 :   return false;
      72             : }
      73             : 
      74             : static bool
      75           0 : IsEditableNode(nsINode* aNode)
      76             : {
      77           0 :   return aNode && aNode->IsEditable();
      78             : }
      79             : 
      80         115 : FocusTarget::FocusTarget()
      81             :   : mSequenceNumber(0)
      82             :   , mFocusHasKeyEventListeners(false)
      83         115 :   , mType(FocusTarget::eNone)
      84             : {
      85         115 : }
      86             : 
      87           0 : FocusTarget::FocusTarget(nsIPresShell* aRootPresShell,
      88           0 :                          uint64_t aFocusSequenceNumber)
      89             :   : mSequenceNumber(aFocusSequenceNumber)
      90           0 :   , mFocusHasKeyEventListeners(false)
      91             : {
      92           0 :   MOZ_ASSERT(aRootPresShell);
      93           0 :   MOZ_ASSERT(NS_IsMainThread());
      94             : 
      95             :   // Key events can be retargeted to a child PresShell when there is an iframe
      96           0 :   nsCOMPtr<nsIPresShell> presShell = GetRetargetEventPresShell(aRootPresShell);
      97             : 
      98           0 :   if (!presShell) {
      99             :     FT_LOG("Creating nil target with seq=%" PRIu64 " (can't find retargeted presshell)\n",
     100             :            aFocusSequenceNumber);
     101             : 
     102           0 :     mType = FocusTarget::eNone;
     103           0 :     return;
     104             :   }
     105             : 
     106             :   // Get the content that should be scrolled for this PresShell, which is
     107             :   // the current focused element or the current DOM selection
     108           0 :   nsCOMPtr<nsIContent> scrollTarget = presShell->GetContentForScrolling();
     109             : 
     110             :   // Collect event listener information so we can track what is potentially focus
     111             :   // changing
     112           0 :   mFocusHasKeyEventListeners = HasListenersForKeyEvents(scrollTarget);
     113             : 
     114             :   // Check if the scroll target is a remote browser
     115           0 :   if (TabParent* browserParent = TabParent::GetFrom(scrollTarget)) {
     116           0 :     RenderFrameParent* rfp = browserParent->GetRenderFrame();
     117             : 
     118             :     // The globally focused element for scrolling is in a remote layer tree
     119           0 :     if (rfp) {
     120             :       FT_LOG("Creating reflayer target with seq=%" PRIu64 ", lt=%" PRIu64 "\n",
     121             :              aFocusSequenceNumber,
     122             :              rfp->GetLayersId());
     123             : 
     124           0 :       mType = FocusTarget::eRefLayer;
     125           0 :       mData.mRefLayerId = rfp->GetLayersId();
     126           0 :       return;
     127             :     }
     128             : 
     129             :     FT_LOG("Creating nil target with seq=%" PRIu64 " (remote browser missing layers id)\n",
     130             :            aFocusSequenceNumber);
     131             : 
     132           0 :     mType = FocusTarget::eNone;
     133           0 :     return;
     134             :   }
     135             : 
     136             :   // If the focus isn't on a remote browser then check for scrollable targets
     137           0 :   if (IsEditableNode(scrollTarget) ||
     138           0 :       IsEditableNode(presShell->GetDocument())) {
     139             :     FT_LOG("Creating nil target with seq=%" PRIu64 " (disabling for editable node)\n",
     140             :            aFocusSequenceNumber);
     141             : 
     142           0 :     mType = FocusTarget::eNone;
     143           0 :     return;
     144             :   }
     145             : 
     146             :   // Gather the scrollable frames that would be scrolled in each direction
     147             :   // for this scroll target
     148             :   nsIScrollableFrame* horizontal =
     149           0 :     presShell->GetScrollableFrameToScrollForContent(scrollTarget.get(),
     150           0 :                                                     nsIPresShell::eHorizontal);
     151             :   nsIScrollableFrame* vertical =
     152           0 :     presShell->GetScrollableFrameToScrollForContent(scrollTarget.get(),
     153           0 :                                                     nsIPresShell::eVertical);
     154             : 
     155             :   // We might have the globally focused element for scrolling. Gather a ViewID for
     156             :   // the horizontal and vertical scroll targets of this element.
     157           0 :   mType = FocusTarget::eScrollLayer;
     158           0 :   mData.mScrollTargets.mHorizontal =
     159           0 :     nsLayoutUtils::FindIDForScrollableFrame(horizontal);
     160           0 :   mData.mScrollTargets.mVertical =
     161           0 :     nsLayoutUtils::FindIDForScrollableFrame(vertical);
     162             : 
     163             :   FT_LOG("Creating scroll target with seq=%" PRIu64 ", h=%" PRIu64 ", v=%" PRIu64 "\n",
     164             :          aFocusSequenceNumber,
     165             :          mData.mScrollTargets.mHorizontal,
     166             :          mData.mScrollTargets.mVertical);
     167             : }
     168             : 
     169             : bool
     170           0 : FocusTarget::operator==(const FocusTarget& aRhs) const
     171             : {
     172           0 :   if (mSequenceNumber != aRhs.mSequenceNumber ||
     173           0 :       mFocusHasKeyEventListeners != aRhs.mFocusHasKeyEventListeners ||
     174           0 :       mType != aRhs.mType) {
     175           0 :     return false;
     176             :   }
     177             : 
     178           0 :   if (mType == FocusTarget::eRefLayer) {
     179           0 :       return mData.mRefLayerId == aRhs.mData.mRefLayerId;
     180           0 :   } else if (mType == FocusTarget::eScrollLayer) {
     181           0 :       return mData.mScrollTargets.mHorizontal == aRhs.mData.mScrollTargets.mHorizontal &&
     182           0 :              mData.mScrollTargets.mVertical == aRhs.mData.mScrollTargets.mVertical;
     183             :   }
     184           0 :   return true;
     185             : }
     186             : 
     187             : } // namespace layers
     188             : } // namespace mozilla

Generated by: LCOV version 1.13