LCOV - code coverage report
Current view: top level - layout/xul - nsXULTooltipListener.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 15 319 4.7 %
Date: 2018-08-07 16:42:27 Functions: 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 "nsXULTooltipListener.h"
       8             : 
       9             : #include "nsXULElement.h"
      10             : #include "nsIDocument.h"
      11             : #include "nsGkAtoms.h"
      12             : #include "nsMenuPopupFrame.h"
      13             : #include "nsIServiceManager.h"
      14             : #include "nsIDragService.h"
      15             : #include "nsIDragSession.h"
      16             : #ifdef MOZ_XUL
      17             : #include "nsITreeView.h"
      18             : #endif
      19             : #include "nsIScriptContext.h"
      20             : #include "nsPIDOMWindow.h"
      21             : #ifdef MOZ_XUL
      22             : #include "nsXULPopupManager.h"
      23             : #endif
      24             : #include "nsIRootBox.h"
      25             : #include "nsIBoxObject.h"
      26             : #include "nsTreeColumns.h"
      27             : #include "mozilla/ErrorResult.h"
      28             : #include "mozilla/Preferences.h"
      29             : #include "mozilla/LookAndFeel.h"
      30             : #include "mozilla/dom/Element.h"
      31             : #include "mozilla/dom/Event.h" // for Event
      32             : #include "mozilla/dom/BoxObject.h"
      33             : #include "mozilla/dom/MouseEvent.h"
      34             : #include "mozilla/dom/TreeColumnBinding.h"
      35             : #include "mozilla/TextEvents.h"
      36             : 
      37             : using namespace mozilla;
      38             : using namespace mozilla::dom;
      39             : 
      40             : nsXULTooltipListener* nsXULTooltipListener::sInstance = nullptr;
      41             : 
      42             : //////////////////////////////////////////////////////////////////////////
      43             : //// nsISupports
      44             : 
      45           1 : nsXULTooltipListener::nsXULTooltipListener()
      46             :   : mMouseScreenX(0)
      47             :   , mMouseScreenY(0)
      48             :   , mTooltipShownOnce(false)
      49             : #ifdef MOZ_XUL
      50             :   , mIsSourceTree(false)
      51             :   , mNeedTitletip(false)
      52           8 :   , mLastTreeRow(-1)
      53             : #endif
      54             : {
      55             :   // FIXME(emilio): This can be faster, this should use BoolVarCache.
      56             :   //
      57             :   // register the callback so we get notified of updates
      58             :   Preferences::RegisterCallback(ToolbarTipsPrefChanged,
      59           1 :                                 "browser.chrome.toolbar_tips");
      60             : 
      61             :   // Call the pref callback to initialize our state.
      62           1 :   ToolbarTipsPrefChanged("browser.chrome.toolbar_tips", nullptr);
      63           0 : }
      64             : 
      65           0 : nsXULTooltipListener::~nsXULTooltipListener()
      66             : {
      67           0 :   MOZ_ASSERT(sInstance == this);
      68           0 :   sInstance = nullptr;
      69             : 
      70           0 :   HideTooltip();
      71             : 
      72             :   // Unregister our pref observer
      73             :   Preferences::UnregisterCallback(ToolbarTipsPrefChanged,
      74           0 :                                   "browser.chrome.toolbar_tips");
      75           0 : }
      76             : 
      77        2944 : NS_IMPL_ISUPPORTS(nsXULTooltipListener, nsIDOMEventListener)
      78             : 
      79             : void
      80           0 : nsXULTooltipListener::MouseOut(Event* aEvent)
      81             : {
      82             :   // reset flag so that tooltip will display on the next MouseMove
      83           0 :   mTooltipShownOnce = false;
      84             : 
      85             :   // if the timer is running and no tooltip is shown, we
      86             :   // have to cancel the timer here so that it doesn't
      87             :   // show the tooltip if we move the mouse out of the window
      88           0 :   nsCOMPtr<nsIContent> currentTooltip = do_QueryReferent(mCurrentTooltip);
      89           0 :   if (mTooltipTimer && !currentTooltip) {
      90           0 :     mTooltipTimer->Cancel();
      91           0 :     mTooltipTimer = nullptr;
      92           0 :     return;
      93             :   }
      94             : 
      95             : #ifdef DEBUG_crap
      96             :   if (mNeedTitletip)
      97             :     return;
      98             : #endif
      99             : 
     100             : #ifdef MOZ_XUL
     101             :   // check to see if the mouse left the targetNode, and if so,
     102             :   // hide the tooltip
     103           0 :   if (currentTooltip) {
     104             :     // which node did the mouse leave?
     105           0 :     nsCOMPtr<nsINode> targetNode = do_QueryInterface(aEvent->GetTarget());
     106             : 
     107           0 :     nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
     108           0 :     if (pm) {
     109             :       nsCOMPtr<nsINode> tooltipNode =
     110           0 :         pm->GetLastTriggerTooltipNode(currentTooltip->GetUncomposedDoc());
     111           0 :       if (tooltipNode == targetNode) {
     112             :         // if the target node is the current tooltip target node, the mouse
     113             :         // left the node the tooltip appeared on, so close the tooltip.
     114           0 :         HideTooltip();
     115             :         // reset special tree tracking
     116           0 :         if (mIsSourceTree) {
     117           0 :           mLastTreeRow = -1;
     118           0 :           mLastTreeCol = nullptr;
     119             :         }
     120             :       }
     121             :     }
     122             :   }
     123             : #endif
     124             : }
     125             : 
     126             : void
     127           0 : nsXULTooltipListener::MouseMove(Event* aEvent)
     128             : {
     129           0 :   if (!sShowTooltips)
     130           0 :     return;
     131             : 
     132             :   // stash the coordinates of the event so that we can still get back to it from within the
     133             :   // timer callback. On win32, we'll get a MouseMove event even when a popup goes away --
     134             :   // even when the mouse doesn't change position! To get around this, we make sure the
     135             :   // mouse has really moved before proceeding.
     136           0 :   MouseEvent* mouseEvent = aEvent->AsMouseEvent();
     137           0 :   if (!mouseEvent) {
     138             :     return;
     139             :   }
     140           0 :   int32_t newMouseX = mouseEvent->ScreenX(CallerType::System);
     141           0 :   int32_t newMouseY = mouseEvent->ScreenY(CallerType::System);
     142             : 
     143             :   // filter out false win32 MouseMove event
     144           0 :   if (mMouseScreenX == newMouseX && mMouseScreenY == newMouseY)
     145             :     return;
     146             : 
     147             :   // filter out minor movements due to crappy optical mice and shaky hands
     148             :   // to prevent tooltips from hiding prematurely.
     149           0 :   nsCOMPtr<nsIContent> currentTooltip = do_QueryReferent(mCurrentTooltip);
     150             : 
     151           0 :   if ((currentTooltip) &&
     152           0 :       (abs(mMouseScreenX - newMouseX) <= kTooltipMouseMoveTolerance) &&
     153           0 :       (abs(mMouseScreenY - newMouseY) <= kTooltipMouseMoveTolerance))
     154           0 :     return;
     155           0 :   mMouseScreenX = newMouseX;
     156           0 :   mMouseScreenY = newMouseY;
     157             : 
     158             :   nsCOMPtr<nsIContent> sourceContent =
     159           0 :     do_QueryInterface(aEvent->GetCurrentTarget());
     160           0 :   mSourceNode = do_GetWeakReference(sourceContent);
     161             : #ifdef MOZ_XUL
     162           0 :   mIsSourceTree = sourceContent->IsXULElement(nsGkAtoms::treechildren);
     163           0 :   if (mIsSourceTree)
     164           0 :     CheckTreeBodyMove(mouseEvent);
     165             : #endif
     166             : 
     167             :   // as the mouse moves, we want to make sure we reset the timer to show it,
     168             :   // so that the delay is from when the mouse stops moving, not when it enters
     169             :   // the node.
     170           0 :   KillTooltipTimer();
     171             : 
     172             :   // If the mouse moves while the tooltip is up, hide it. If nothing is
     173             :   // showing and the tooltip hasn't been displayed since the mouse entered
     174             :   // the node, then start the timer to show the tooltip.
     175           0 :   if (!currentTooltip && !mTooltipShownOnce) {
     176           0 :     nsCOMPtr<EventTarget> eventTarget = aEvent->GetTarget();
     177             : 
     178             :     // don't show tooltips attached to elements outside of a menu popup
     179             :     // when hovering over an element inside it. The popupsinherittooltip
     180             :     // attribute may be used to disable this behaviour, which is useful for
     181             :     // large menu hierarchies such as bookmarks.
     182           0 :     if (!sourceContent->IsElement() ||
     183           0 :         !sourceContent->AsElement()->AttrValueIs(kNameSpaceID_None,
     184             :                                                  nsGkAtoms::popupsinherittooltip,
     185             :                                                  nsGkAtoms::_true, eCaseMatters)) {
     186           0 :       nsCOMPtr<nsIContent> targetContent = do_QueryInterface(eventTarget);
     187           0 :       while (targetContent && targetContent != sourceContent) {
     188           0 :         if (targetContent->IsAnyOfXULElements(nsGkAtoms::menupopup,
     189             :                                               nsGkAtoms::panel,
     190             :                                               nsGkAtoms::tooltip)) {
     191           0 :           mSourceNode = nullptr;
     192           0 :           return;
     193             :         }
     194             : 
     195           0 :         targetContent = targetContent->GetParent();
     196             :       }
     197             :     }
     198             : 
     199           0 :     mTargetNode = do_GetWeakReference(eventTarget);
     200           0 :     if (mTargetNode) {
     201           0 :       nsresult rv = NS_NewTimerWithFuncCallback(
     202           0 :         getter_AddRefs(mTooltipTimer),
     203             :         sTooltipCallback, this,
     204           0 :         LookAndFeel::GetInt(LookAndFeel::eIntID_TooltipDelay, 500),
     205             :         nsITimer::TYPE_ONE_SHOT,
     206             :         "sTooltipCallback",
     207           0 :         sourceContent->OwnerDoc()->EventTargetFor(TaskCategory::Other));
     208           0 :       if (NS_FAILED(rv)) {
     209           0 :         mTargetNode = nullptr;
     210           0 :         mSourceNode = nullptr;
     211             :       }
     212             :     }
     213             :     return;
     214             :   }
     215             : 
     216             : #ifdef MOZ_XUL
     217           0 :   if (mIsSourceTree)
     218             :     return;
     219             : #endif
     220             : 
     221           0 :   HideTooltip();
     222             :   // set a flag so that the tooltip is only displayed once until the mouse
     223             :   // leaves the node
     224           0 :   mTooltipShownOnce = true;
     225             : }
     226             : 
     227             : NS_IMETHODIMP
     228           0 : nsXULTooltipListener::HandleEvent(Event* aEvent)
     229             : {
     230           0 :   nsAutoString type;
     231           0 :   aEvent->GetType(type);
     232           0 :   if (type.EqualsLiteral("DOMMouseScroll") ||
     233           0 :       type.EqualsLiteral("mousedown") ||
     234           0 :       type.EqualsLiteral("mouseup") ||
     235           0 :       type.EqualsLiteral("dragstart")) {
     236           0 :     HideTooltip();
     237           0 :     return NS_OK;
     238             :   }
     239             : 
     240           0 :   if (type.EqualsLiteral("keydown")) {
     241             :     // Hide the tooltip if a non-modifier key is pressed.
     242           0 :     WidgetKeyboardEvent* keyEvent = aEvent->WidgetEventPtr()->AsKeyboardEvent();
     243           0 :     if (!keyEvent->IsModifierKeyEvent()) {
     244           0 :       HideTooltip();
     245             :     }
     246             : 
     247             :     return NS_OK;
     248             :   }
     249             : 
     250           0 :   if (type.EqualsLiteral("popuphiding")) {
     251           0 :     DestroyTooltip();
     252           0 :     return NS_OK;
     253             :   }
     254             : 
     255             :   // Note that mousemove, mouseover and mouseout might be
     256             :   // fired even during dragging due to widget's bug.
     257             :   nsCOMPtr<nsIDragService> dragService =
     258           0 :     do_GetService("@mozilla.org/widget/dragservice;1");
     259           0 :   NS_ENSURE_TRUE(dragService, NS_OK);
     260           0 :   nsCOMPtr<nsIDragSession> dragSession;
     261           0 :   dragService->GetCurrentSession(getter_AddRefs(dragSession));
     262           0 :   if (dragSession) {
     263             :     return NS_OK;
     264             :   }
     265             : 
     266             :   // Not dragging.
     267             : 
     268           0 :   if (type.EqualsLiteral("mousemove")) {
     269           0 :     MouseMove(aEvent);
     270           0 :     return NS_OK;
     271             :   }
     272             : 
     273           0 :   if (type.EqualsLiteral("mouseout")) {
     274           0 :     MouseOut(aEvent);
     275           0 :     return NS_OK;
     276             :   }
     277             : 
     278             :   return NS_OK;
     279             : }
     280             : 
     281             : //////////////////////////////////////////////////////////////////////////
     282             : //// nsXULTooltipListener
     283             : 
     284             : // static
     285             : void
     286           1 : nsXULTooltipListener::ToolbarTipsPrefChanged(const char *aPref,
     287             :                                              void *aClosure)
     288             : {
     289           0 :   sShowTooltips =
     290           1 :     Preferences::GetBool("browser.chrome.toolbar_tips", sShowTooltips);
     291           1 : }
     292             : 
     293             : //////////////////////////////////////////////////////////////////////////
     294             : //// nsXULTooltipListener
     295             : 
     296             : bool nsXULTooltipListener::sShowTooltips = false;
     297             : 
     298             : void
     299           0 : nsXULTooltipListener::AddTooltipSupport(nsIContent* aNode)
     300             : {
     301         112 :   MOZ_ASSERT(aNode);
     302           0 :   MOZ_ASSERT(this == sInstance);
     303             : 
     304           0 :   aNode->AddSystemEventListener(NS_LITERAL_STRING("mouseout"), this,
     305           0 :                                 false, false);
     306           0 :   aNode->AddSystemEventListener(NS_LITERAL_STRING("mousemove"), this,
     307           0 :                                 false, false);
     308           0 :   aNode->AddSystemEventListener(NS_LITERAL_STRING("mousedown"), this,
     309           0 :                                 false, false);
     310           0 :   aNode->AddSystemEventListener(NS_LITERAL_STRING("mouseup"), this,
     311           0 :                                 false, false);
     312           0 :   aNode->AddSystemEventListener(NS_LITERAL_STRING("dragstart"), this,
     313         224 :                                 true, false);
     314         112 : }
     315             : 
     316             : void
     317           0 : nsXULTooltipListener::RemoveTooltipSupport(nsIContent* aNode)
     318             : {
     319          18 :   MOZ_ASSERT(aNode);
     320          18 :   MOZ_ASSERT(this == sInstance);
     321             : 
     322             :   // The last reference to us can go after some of these calls.
     323           0 :   RefPtr<nsXULTooltipListener> instance = this;
     324             : 
     325           0 :   aNode->RemoveSystemEventListener(NS_LITERAL_STRING("mouseout"), this, false);
     326           0 :   aNode->RemoveSystemEventListener(NS_LITERAL_STRING("mousemove"), this, false);
     327           0 :   aNode->RemoveSystemEventListener(NS_LITERAL_STRING("mousedown"), this, false);
     328           0 :   aNode->RemoveSystemEventListener(NS_LITERAL_STRING("mouseup"), this, false);
     329          54 :   aNode->RemoveSystemEventListener(NS_LITERAL_STRING("dragstart"), this, true);
     330          18 : }
     331             : 
     332             : #ifdef MOZ_XUL
     333             : void
     334           0 : nsXULTooltipListener::CheckTreeBodyMove(MouseEvent* aMouseEvent)
     335             : {
     336           0 :   nsCOMPtr<nsIContent> sourceNode = do_QueryReferent(mSourceNode);
     337           0 :   if (!sourceNode)
     338           0 :     return;
     339             : 
     340             :   // get the boxObject of the documentElement of the document the tree is in
     341           0 :   nsCOMPtr<nsIBoxObject> bx;
     342           0 :   nsIDocument* doc = sourceNode->GetComposedDoc();
     343           0 :   if (doc) {
     344           0 :     ErrorResult ignored;
     345           0 :     bx = doc->GetBoxObjectFor(doc->GetRootElement(), ignored);
     346             :   }
     347             : 
     348           0 :   nsCOMPtr<nsITreeBoxObject> obx;
     349           0 :   GetSourceTreeBoxObject(getter_AddRefs(obx));
     350           0 :   if (bx && obx) {
     351           0 :     int32_t x = aMouseEvent->ScreenX(CallerType::System);
     352           0 :     int32_t y = aMouseEvent->ScreenY(CallerType::System);
     353             : 
     354             :     int32_t row;
     355           0 :     RefPtr<nsTreeColumn> col;
     356           0 :     nsAutoString obj;
     357             : 
     358             :     // subtract off the documentElement's boxObject
     359             :     int32_t boxX, boxY;
     360           0 :     bx->GetScreenX(&boxX);
     361           0 :     bx->GetScreenY(&boxY);
     362           0 :     x -= boxX;
     363           0 :     y -= boxY;
     364             : 
     365           0 :     obx->GetCellAt(x, y, &row, getter_AddRefs(col), obj);
     366             : 
     367             :     // determine if we are going to need a titletip
     368             :     // XXX check the disabletitletips attribute on the tree content
     369           0 :     mNeedTitletip = false;
     370           0 :     int16_t colType = -1;
     371           0 :     if (col) {
     372           0 :       colType = col->Type();
     373             :     }
     374           0 :     if (row >= 0 && obj.EqualsLiteral("text") &&
     375             :         colType != TreeColumnBinding::TYPE_PASSWORD) {
     376           0 :       obx->IsCellCropped(row, col, &mNeedTitletip);
     377             :     }
     378             : 
     379           0 :     nsCOMPtr<nsIContent> currentTooltip = do_QueryReferent(mCurrentTooltip);
     380           0 :     if (currentTooltip && (row != mLastTreeRow || col != mLastTreeCol)) {
     381           0 :       HideTooltip();
     382             :     }
     383             : 
     384           0 :     mLastTreeRow = row;
     385           0 :     mLastTreeCol = col;
     386             :   }
     387             : }
     388             : #endif
     389             : 
     390             : nsresult
     391           0 : nsXULTooltipListener::ShowTooltip()
     392             : {
     393           0 :   nsCOMPtr<nsIContent> sourceNode = do_QueryReferent(mSourceNode);
     394             : 
     395             :   // get the tooltip content designated for the target node
     396           0 :   nsCOMPtr<nsIContent> tooltipNode;
     397           0 :   GetTooltipFor(sourceNode, getter_AddRefs(tooltipNode));
     398           0 :   if (!tooltipNode || sourceNode == tooltipNode)
     399             :     return NS_ERROR_FAILURE; // the target node doesn't need a tooltip
     400             : 
     401             :   // set the node in the document that triggered the tooltip and show it
     402           0 :   if (tooltipNode->GetComposedDoc() &&
     403           0 :       tooltipNode->GetComposedDoc()->IsXULDocument()) {
     404             :     // Make sure the target node is still attached to some document.
     405             :     // It might have been deleted.
     406           0 :     if (sourceNode->IsInComposedDoc()) {
     407             : #ifdef MOZ_XUL
     408           0 :       if (!mIsSourceTree) {
     409           0 :         mLastTreeRow = -1;
     410           0 :         mLastTreeCol = nullptr;
     411             :       }
     412             : #endif
     413             : 
     414           0 :       mCurrentTooltip = do_GetWeakReference(tooltipNode);
     415           0 :       LaunchTooltip();
     416           0 :       mTargetNode = nullptr;
     417             : 
     418           0 :       nsCOMPtr<nsIContent> currentTooltip = do_QueryReferent(mCurrentTooltip);
     419           0 :       if (!currentTooltip)
     420           0 :         return NS_OK;
     421             : 
     422             :       // listen for popuphidden on the tooltip node, so that we can
     423             :       // be sure DestroyPopup is called even if someone else closes the tooltip
     424           0 :       currentTooltip->AddSystemEventListener(NS_LITERAL_STRING("popuphiding"),
     425           0 :                                              this, false, false);
     426             : 
     427             :       // listen for mousedown, mouseup, keydown, and DOMMouseScroll events at document level
     428           0 :       nsIDocument* doc = sourceNode->GetComposedDoc();
     429           0 :       if (doc) {
     430             :         // Probably, we should listen to untrusted events for hiding tooltips
     431             :         // on content since tooltips might disturb something of web
     432             :         // applications.  If we don't specify the aWantsUntrusted of
     433             :         // AddSystemEventListener(), the event target sets it to TRUE if the
     434             :         // target is in content.
     435           0 :         doc->AddSystemEventListener(NS_LITERAL_STRING("DOMMouseScroll"),
     436           0 :                                     this, true);
     437           0 :         doc->AddSystemEventListener(NS_LITERAL_STRING("mousedown"),
     438           0 :                                     this, true);
     439           0 :         doc->AddSystemEventListener(NS_LITERAL_STRING("mouseup"),
     440           0 :                                     this, true);
     441             : #ifndef XP_WIN
     442             :         // On Windows, key events don't close tooltips.
     443           0 :         doc->AddSystemEventListener(NS_LITERAL_STRING("keydown"),
     444           0 :                                     this, true);
     445             : #endif
     446             :       }
     447           0 :       mSourceNode = nullptr;
     448             :     }
     449             :   }
     450             : 
     451             :   return NS_OK;
     452             : }
     453             : 
     454             : #ifdef MOZ_XUL
     455             : // XXX: "This stuff inside DEBUG_crap could be used to make tree tooltips work
     456             : //       in the future."
     457             : #ifdef DEBUG_crap
     458             : static void
     459             : GetTreeCellCoords(nsITreeBoxObject* aTreeBox, nsIContent* aSourceNode,
     460             :                   int32_t aRow, nsTreeColumn* aCol, int32_t* aX, int32_t* aY)
     461             : {
     462             :   int32_t junk;
     463             :   aTreeBox->GetCoordsForCellItem(aRow, aCol, EmptyCString(), aX, aY, &junk, &junk);
     464             :   RefPtr<nsXULElement> xulEl = nsXULElement::FromNode(aSourceNode);
     465             :   nsCOMPtr<nsIBoxObject> bx = xulEl->GetBoxObject(IgnoreErrors());
     466             :   int32_t myX, myY;
     467             :   bx->GetX(&myX);
     468             :   bx->GetY(&myY);
     469             :   *aX += myX;
     470             :   *aY += myY;
     471             : }
     472             : #endif
     473             : 
     474             : static void
     475           0 : SetTitletipLabel(nsITreeBoxObject* aTreeBox, Element* aTooltip,
     476             :                  int32_t aRow, nsTreeColumn* aCol)
     477             : {
     478           0 :   nsCOMPtr<nsITreeView> view;
     479           0 :   aTreeBox->GetView(getter_AddRefs(view));
     480           0 :   if (view) {
     481           0 :     nsAutoString label;
     482             : #ifdef DEBUG
     483             :     nsresult rv =
     484             : #endif
     485           0 :       view->GetCellText(aRow, aCol, label);
     486           0 :     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get the cell text!");
     487           0 :     aTooltip->SetAttr(kNameSpaceID_None, nsGkAtoms::label, label, true);
     488             :   }
     489           0 : }
     490             : #endif
     491             : 
     492             : void
     493           0 : nsXULTooltipListener::LaunchTooltip()
     494             : {
     495           0 :   nsCOMPtr<Element> currentTooltip = do_QueryReferent(mCurrentTooltip);
     496           0 :   if (!currentTooltip)
     497           0 :     return;
     498             : 
     499             : #ifdef MOZ_XUL
     500           0 :   if (mIsSourceTree && mNeedTitletip) {
     501           0 :     nsCOMPtr<nsITreeBoxObject> obx;
     502           0 :     GetSourceTreeBoxObject(getter_AddRefs(obx));
     503             : 
     504           0 :     SetTitletipLabel(obx, currentTooltip, mLastTreeRow, mLastTreeCol);
     505           0 :     if (!(currentTooltip = do_QueryReferent(mCurrentTooltip))) {
     506             :       // Because of mutation events, currentTooltip can be null.
     507           0 :       return;
     508             :     }
     509           0 :     currentTooltip->SetAttr(kNameSpaceID_None, nsGkAtoms::titletip, NS_LITERAL_STRING("true"), true);
     510             :   } else {
     511           0 :     currentTooltip->UnsetAttr(kNameSpaceID_None, nsGkAtoms::titletip, true);
     512             :   }
     513           0 :   if (!(currentTooltip = do_QueryReferent(mCurrentTooltip))) {
     514             :     // Because of mutation events, currentTooltip can be null.
     515             :     return;
     516             :   }
     517             : 
     518           0 :   nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
     519           0 :   if (pm) {
     520           0 :     nsCOMPtr<nsIContent> target = do_QueryReferent(mTargetNode);
     521           0 :     pm->ShowTooltipAtScreen(currentTooltip, target, mMouseScreenX, mMouseScreenY);
     522             : 
     523             :     // Clear the current tooltip if the popup was not opened successfully.
     524           0 :     if (!pm->IsPopupOpen(currentTooltip))
     525           0 :       mCurrentTooltip = nullptr;
     526             :   }
     527             : #endif
     528             : 
     529             : }
     530             : 
     531             : nsresult
     532           0 : nsXULTooltipListener::HideTooltip()
     533             : {
     534             : #ifdef MOZ_XUL
     535           0 :   nsCOMPtr<nsIContent> currentTooltip = do_QueryReferent(mCurrentTooltip);
     536           0 :   if (currentTooltip) {
     537           0 :     nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
     538           0 :     if (pm)
     539           0 :       pm->HidePopup(currentTooltip, false, false, false, false);
     540             :   }
     541             : #endif
     542             : 
     543           0 :   DestroyTooltip();
     544           0 :   return NS_OK;
     545             : }
     546             : 
     547             : static void
     548           0 : GetImmediateChild(nsIContent* aContent, nsAtom *aTag, nsIContent** aResult)
     549             : {
     550           0 :   *aResult = nullptr;
     551           0 :   for (nsCOMPtr<nsIContent> childContent = aContent->GetFirstChild();
     552           0 :        childContent; childContent = childContent->GetNextSibling()) {
     553           0 :     if (childContent->IsXULElement(aTag)) {
     554           0 :       childContent.forget(aResult);
     555           0 :       return;
     556             :     }
     557             :   }
     558             : }
     559             : 
     560             : nsresult
     561           0 : nsXULTooltipListener::FindTooltip(nsIContent* aTarget, nsIContent** aTooltip)
     562             : {
     563           0 :   if (!aTarget)
     564             :     return NS_ERROR_NULL_POINTER;
     565             : 
     566             :   // before we go on, make sure that target node still has a window
     567           0 :   nsIDocument *document = aTarget->GetComposedDoc();
     568           0 :   if (!document) {
     569           0 :     NS_WARNING("Unable to retrieve the tooltip node document.");
     570           0 :     return NS_ERROR_FAILURE;
     571             :   }
     572           0 :   nsPIDOMWindowOuter *window = document->GetWindow();
     573           0 :   if (!window) {
     574             :     return NS_OK;
     575             :   }
     576             : 
     577           0 :   if (window->Closed()) {
     578             :     return NS_OK;
     579             :   }
     580             : 
     581           0 :   nsAutoString tooltipText;
     582           0 :   if (aTarget->IsElement()) {
     583           0 :     aTarget->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::tooltiptext, tooltipText);
     584             :   }
     585           0 :   if (!tooltipText.IsEmpty()) {
     586             :     // specifying tooltiptext means we will always use the default tooltip
     587           0 :     nsIRootBox* rootBox = nsIRootBox::GetRootBox(document->GetShell());
     588           0 :     NS_ENSURE_STATE(rootBox);
     589           0 :     if (RefPtr<Element> tooltip = rootBox->GetDefaultTooltip()) {
     590           0 :       tooltip->SetAttr(kNameSpaceID_None, nsGkAtoms::label, tooltipText, true);
     591           0 :       tooltip.forget(aTooltip);
     592             :     }
     593           0 :     return NS_OK;
     594             :   }
     595             : 
     596           0 :   nsAutoString tooltipId;
     597           0 :   if (aTarget->IsElement()) {
     598           0 :     aTarget->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::tooltip, tooltipId);
     599             :   }
     600             : 
     601             :   // if tooltip == _child, look for first <tooltip> child
     602           0 :   if (tooltipId.EqualsLiteral("_child")) {
     603           0 :     GetImmediateChild(aTarget, nsGkAtoms::tooltip, aTooltip);
     604           0 :     return NS_OK;
     605             :   }
     606             : 
     607           0 :   if (!tooltipId.IsEmpty() && aTarget->IsInUncomposedDoc()) {
     608             :     // tooltip must be an id, use getElementById to find it
     609             :     //XXXsmaug If aTarget is in shadow dom, should we use
     610             :     //         ShadowRoot::GetElementById()?
     611           0 :     nsCOMPtr<nsIContent> tooltipEl = document->GetElementById(tooltipId);
     612             : 
     613           0 :     if (tooltipEl) {
     614             : #ifdef MOZ_XUL
     615           0 :       mNeedTitletip = false;
     616             : #endif
     617           0 :       tooltipEl.forget(aTooltip);
     618           0 :       return NS_OK;
     619             :     }
     620             :   }
     621             : 
     622             : #ifdef MOZ_XUL
     623             :   // titletips should just use the default tooltip
     624           0 :   if (mIsSourceTree && mNeedTitletip) {
     625           0 :     nsIRootBox* rootBox = nsIRootBox::GetRootBox(document->GetShell());
     626           0 :     NS_ENSURE_STATE(rootBox);
     627           0 :     NS_IF_ADDREF(*aTooltip = rootBox->GetDefaultTooltip());
     628             :   }
     629             : #endif
     630             : 
     631             :   return NS_OK;
     632             : }
     633             : 
     634             : 
     635             : nsresult
     636           0 : nsXULTooltipListener::GetTooltipFor(nsIContent* aTarget, nsIContent** aTooltip)
     637             : {
     638           0 :   *aTooltip = nullptr;
     639           0 :   nsCOMPtr<nsIContent> tooltip;
     640           0 :   nsresult rv = FindTooltip(aTarget, getter_AddRefs(tooltip));
     641           0 :   if (NS_FAILED(rv) || !tooltip) {
     642             :     return rv;
     643             :   }
     644             : 
     645             : #ifdef MOZ_XUL
     646             :   // Submenus can't be used as tooltips, see bug 288763.
     647           0 :   nsIContent* parent = tooltip->GetParent();
     648           0 :   if (parent) {
     649           0 :     nsMenuFrame* menu = do_QueryFrame(parent->GetPrimaryFrame());
     650           0 :     if (menu) {
     651           0 :       NS_WARNING("Menu cannot be used as a tooltip");
     652           0 :       return NS_ERROR_FAILURE;
     653             :     }
     654             :   }
     655             : #endif
     656             : 
     657           0 :   tooltip.swap(*aTooltip);
     658           0 :   return rv;
     659             : }
     660             : 
     661             : nsresult
     662           0 : nsXULTooltipListener::DestroyTooltip()
     663             : {
     664           0 :   nsCOMPtr<nsIDOMEventListener> kungFuDeathGrip(this);
     665           0 :   nsCOMPtr<nsIContent> currentTooltip = do_QueryReferent(mCurrentTooltip);
     666           0 :   if (currentTooltip) {
     667             :     // release tooltip before removing listener to prevent our destructor from
     668             :     // being called recursively (bug 120863)
     669           0 :     mCurrentTooltip = nullptr;
     670             : 
     671             :     // clear out the tooltip node on the document
     672           0 :     nsCOMPtr<nsIDocument> doc = currentTooltip->GetComposedDoc();
     673           0 :     if (doc) {
     674             :       // remove the mousedown and keydown listener from document
     675           0 :       doc->RemoveSystemEventListener(NS_LITERAL_STRING("DOMMouseScroll"), this,
     676           0 :                                      true);
     677           0 :       doc->RemoveSystemEventListener(NS_LITERAL_STRING("mousedown"), this,
     678           0 :                                      true);
     679           0 :       doc->RemoveSystemEventListener(NS_LITERAL_STRING("mouseup"), this, true);
     680             : #ifndef XP_WIN
     681           0 :       doc->RemoveSystemEventListener(NS_LITERAL_STRING("keydown"), this, true);
     682             : #endif
     683             :     }
     684             : 
     685             :     // remove the popuphidden listener from tooltip
     686           0 :     currentTooltip->RemoveSystemEventListener(NS_LITERAL_STRING("popuphiding"), this, false);
     687             :   }
     688             : 
     689             :   // kill any ongoing timers
     690           0 :   KillTooltipTimer();
     691           0 :   mSourceNode = nullptr;
     692             : #ifdef MOZ_XUL
     693           0 :   mLastTreeCol = nullptr;
     694             : #endif
     695             : 
     696           0 :   return NS_OK;
     697             : }
     698             : 
     699             : void
     700           0 : nsXULTooltipListener::KillTooltipTimer()
     701             : {
     702           0 :   if (mTooltipTimer) {
     703           0 :     mTooltipTimer->Cancel();
     704           0 :     mTooltipTimer = nullptr;
     705           0 :     mTargetNode = nullptr;
     706             :   }
     707           0 : }
     708             : 
     709             : void
     710           0 : nsXULTooltipListener::sTooltipCallback(nsITimer *aTimer, void *aListener)
     711             : {
     712           0 :   RefPtr<nsXULTooltipListener> instance = sInstance;
     713           0 :   if (instance)
     714           0 :     instance->ShowTooltip();
     715           0 : }
     716             : 
     717             : #ifdef MOZ_XUL
     718             : nsresult
     719           0 : nsXULTooltipListener::GetSourceTreeBoxObject(nsITreeBoxObject** aBoxObject)
     720             : {
     721           0 :   *aBoxObject = nullptr;
     722             : 
     723           0 :   nsCOMPtr<nsIContent> sourceNode = do_QueryReferent(mSourceNode);
     724           0 :   if (mIsSourceTree && sourceNode) {
     725             :     RefPtr<nsXULElement> xulEl =
     726           0 :       nsXULElement::FromNodeOrNull(sourceNode->GetParent());
     727           0 :     if (xulEl) {
     728           0 :       nsCOMPtr<nsIBoxObject> bx = xulEl->GetBoxObject(IgnoreErrors());
     729           0 :       nsCOMPtr<nsITreeBoxObject> obx(do_QueryInterface(bx));
     730           0 :       if (obx) {
     731           0 :         *aBoxObject = obx;
     732             :         NS_ADDREF(*aBoxObject);
     733             :         return NS_OK;
     734             :       }
     735             :     }
     736             :   }
     737             :   return NS_ERROR_FAILURE;
     738             : }
     739             : #endif

Generated by: LCOV version 1.13-14-ga5dd952