LCOV - code coverage report
Current view: top level - layout/xul - nsXULTooltipListener.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 91 344 26.5 %
Date: 2017-07-14 16:53:18 Functions: 10 23 43.5 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13