LCOV - code coverage report
Current view: top level - toolkit/components/alerts - nsXULAlerts.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 2 209 1.0 %
Date: 2017-07-14 16:53:18 Functions: 2 21 9.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 "nsXULAlerts.h"
       7             : 
       8             : #include "nsArray.h"
       9             : #include "nsComponentManagerUtils.h"
      10             : #include "nsCOMPtr.h"
      11             : #include "mozilla/ClearOnShutdown.h"
      12             : #include "mozilla/LookAndFeel.h"
      13             : #include "mozilla/dom/Notification.h"
      14             : #include "mozilla/Unused.h"
      15             : #include "nsIServiceManager.h"
      16             : #include "nsISupportsPrimitives.h"
      17             : #include "nsPIDOMWindow.h"
      18             : #include "nsIWindowWatcher.h"
      19             : 
      20             : using namespace mozilla;
      21             : using mozilla::dom::NotificationTelemetryService;
      22             : 
      23             : #define ALERT_CHROME_URL "chrome://global/content/alerts/alert.xul"
      24             : 
      25             : namespace {
      26           3 : StaticRefPtr<nsXULAlerts> gXULAlerts;
      27             : } // anonymous namespace
      28             : 
      29           0 : NS_IMPL_CYCLE_COLLECTION(nsXULAlertObserver, mAlertWindow)
      30             : 
      31           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXULAlertObserver)
      32           0 :   NS_INTERFACE_MAP_ENTRY(nsIObserver)
      33           0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
      34           0 : NS_INTERFACE_MAP_END
      35             : 
      36           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXULAlertObserver)
      37           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXULAlertObserver)
      38             : 
      39             : NS_IMETHODIMP
      40           0 : nsXULAlertObserver::Observe(nsISupports* aSubject, const char* aTopic,
      41             :                             const char16_t* aData)
      42             : {
      43           0 :   if (!strcmp("alertfinished", aTopic)) {
      44           0 :     mozIDOMWindowProxy* currentAlert = mXULAlerts->mNamedWindows.GetWeak(mAlertName);
      45             :     // The window in mNamedWindows might be a replacement, thus it should only
      46             :     // be removed if it is the same window that is associated with this listener.
      47           0 :     if (currentAlert == mAlertWindow) {
      48           0 :       mXULAlerts->mNamedWindows.Remove(mAlertName);
      49             : 
      50           0 :       if (mIsPersistent) {
      51           0 :         mXULAlerts->PersistentAlertFinished();
      52             :       }
      53             :     }
      54             :   }
      55             : 
      56           0 :   nsresult rv = NS_OK;
      57           0 :   if (mObserver) {
      58           0 :     rv = mObserver->Observe(aSubject, aTopic, aData);
      59             :   }
      60           0 :   return rv;
      61             : }
      62             : 
      63             : // We don't cycle collect nsXULAlerts since gXULAlerts will keep the instance
      64             : // alive till shutdown anyway.
      65           0 : NS_IMPL_ISUPPORTS(nsXULAlerts, nsIAlertsService, nsIAlertsDoNotDisturb, nsIAlertsIconURI)
      66             : 
      67             : /* static */ already_AddRefed<nsXULAlerts>
      68           0 : nsXULAlerts::GetInstance()
      69             : {
      70             :   // Gecko on Android does not fully support XUL windows.
      71             : #ifndef MOZ_WIDGET_ANDROID
      72           0 :   if (!gXULAlerts) {
      73           0 :     gXULAlerts = new nsXULAlerts();
      74           0 :     ClearOnShutdown(&gXULAlerts);
      75             :   }
      76             : #endif // MOZ_WIDGET_ANDROID
      77           0 :   RefPtr<nsXULAlerts> instance = gXULAlerts.get();
      78           0 :   return instance.forget();
      79             : }
      80             : 
      81             : void
      82           0 : nsXULAlerts::PersistentAlertFinished()
      83             : {
      84           0 :   MOZ_ASSERT(mPersistentAlertCount);
      85           0 :   mPersistentAlertCount--;
      86             : 
      87             :   // Show next pending persistent alert if any.
      88           0 :   if (!mPendingPersistentAlerts.IsEmpty()) {
      89           0 :     ShowAlertWithIconURI(mPendingPersistentAlerts[0].mAlert,
      90           0 :                          mPendingPersistentAlerts[0].mListener,
      91           0 :                          nullptr);
      92           0 :     mPendingPersistentAlerts.RemoveElementAt(0);
      93             :   }
      94           0 : }
      95             : 
      96             : NS_IMETHODIMP
      97           0 : nsXULAlerts::ShowAlertNotification(const nsAString& aImageUrl, const nsAString& aAlertTitle,
      98             :                                    const nsAString& aAlertText, bool aAlertTextClickable,
      99             :                                    const nsAString& aAlertCookie, nsIObserver* aAlertListener,
     100             :                                    const nsAString& aAlertName, const nsAString& aBidi,
     101             :                                    const nsAString& aLang, const nsAString& aData,
     102             :                                    nsIPrincipal* aPrincipal, bool aInPrivateBrowsing,
     103             :                                    bool aRequireInteraction)
     104             : {
     105             :   nsCOMPtr<nsIAlertNotification> alert =
     106           0 :     do_CreateInstance(ALERT_NOTIFICATION_CONTRACTID);
     107           0 :   NS_ENSURE_TRUE(alert, NS_ERROR_FAILURE);
     108           0 :   nsresult rv = alert->Init(aAlertName, aImageUrl, aAlertTitle,
     109             :                             aAlertText, aAlertTextClickable,
     110             :                             aAlertCookie, aBidi, aLang, aData,
     111             :                             aPrincipal, aInPrivateBrowsing,
     112           0 :                             aRequireInteraction);
     113           0 :   NS_ENSURE_SUCCESS(rv, rv);
     114           0 :   return ShowAlert(alert, aAlertListener);
     115             : }
     116             : 
     117             : NS_IMETHODIMP
     118           0 : nsXULAlerts::ShowPersistentNotification(const nsAString& aPersistentData,
     119             :                                         nsIAlertNotification* aAlert,
     120             :                                         nsIObserver* aAlertListener)
     121             : {
     122           0 :   return ShowAlert(aAlert, aAlertListener);
     123             : }
     124             : 
     125             : NS_IMETHODIMP
     126           0 : nsXULAlerts::ShowAlert(nsIAlertNotification* aAlert,
     127             :                        nsIObserver* aAlertListener)
     128             : {
     129           0 :   nsAutoString name;
     130           0 :   nsresult rv = aAlert->GetName(name);
     131           0 :   NS_ENSURE_SUCCESS(rv, rv);
     132             : 
     133             :   // If there is a pending alert with the same name in the list of
     134             :   // pending alerts, replace it.
     135           0 :   if (!mPendingPersistentAlerts.IsEmpty()) {
     136           0 :     for (uint32_t i = 0; i < mPendingPersistentAlerts.Length(); i++) {
     137           0 :       nsAutoString pendingAlertName;
     138           0 :       nsCOMPtr<nsIAlertNotification> pendingAlert = mPendingPersistentAlerts[i].mAlert;
     139           0 :       rv = pendingAlert->GetName(pendingAlertName);
     140           0 :       NS_ENSURE_SUCCESS(rv, rv);
     141             : 
     142           0 :       if (pendingAlertName.Equals(name)) {
     143           0 :         nsAutoString cookie;
     144           0 :         rv = pendingAlert->GetCookie(cookie);
     145           0 :         NS_ENSURE_SUCCESS(rv, rv);
     146             : 
     147           0 :         if (mPendingPersistentAlerts[i].mListener) {
     148           0 :           rv = mPendingPersistentAlerts[i].mListener->Observe(nullptr, "alertfinished", cookie.get());
     149           0 :           NS_ENSURE_SUCCESS(rv, rv);
     150             :         }
     151             : 
     152           0 :         mPendingPersistentAlerts[i].Init(aAlert, aAlertListener);
     153           0 :         return NS_OK;
     154             :       }
     155             :     }
     156             :   }
     157             : 
     158             :   bool requireInteraction;
     159           0 :   rv = aAlert->GetRequireInteraction(&requireInteraction);
     160           0 :   NS_ENSURE_SUCCESS(rv, rv);
     161             : 
     162           0 :   if (requireInteraction &&
     163           0 :       !mNamedWindows.Contains(name) &&
     164           0 :       static_cast<int32_t>(mPersistentAlertCount) >=
     165           0 :         Preferences::GetInt("dom.webnotifications.requireinteraction.count", 0)) {
     166           0 :     PendingAlert* pa = mPendingPersistentAlerts.AppendElement();
     167           0 :     pa->Init(aAlert, aAlertListener);
     168           0 :     return NS_OK;
     169             :   } else {
     170           0 :     return ShowAlertWithIconURI(aAlert, aAlertListener, nullptr);
     171             :   }
     172             : }
     173             : 
     174             : NS_IMETHODIMP
     175           0 : nsXULAlerts::ShowAlertWithIconURI(nsIAlertNotification* aAlert,
     176             :                                   nsIObserver* aAlertListener,
     177             :                                   nsIURI* aIconURI)
     178             : {
     179             :   bool inPrivateBrowsing;
     180           0 :   nsresult rv = aAlert->GetInPrivateBrowsing(&inPrivateBrowsing);
     181           0 :   NS_ENSURE_SUCCESS(rv, rv);
     182             : 
     183           0 :   nsAutoString cookie;
     184           0 :   rv = aAlert->GetCookie(cookie);
     185           0 :   NS_ENSURE_SUCCESS(rv, rv);
     186             : 
     187           0 :   if (mDoNotDisturb) {
     188           0 :     if (aAlertListener)
     189           0 :       aAlertListener->Observe(nullptr, "alertfinished", cookie.get());
     190           0 :     return NS_OK;
     191             :   }
     192             : 
     193           0 :   nsAutoString name;
     194           0 :   rv = aAlert->GetName(name);
     195           0 :   NS_ENSURE_SUCCESS(rv, rv);
     196             : 
     197           0 :   nsAutoString imageUrl;
     198           0 :   rv = aAlert->GetImageURL(imageUrl);
     199           0 :   NS_ENSURE_SUCCESS(rv, rv);
     200             : 
     201           0 :   nsAutoString title;
     202           0 :   rv = aAlert->GetTitle(title);
     203           0 :   NS_ENSURE_SUCCESS(rv, rv);
     204             : 
     205           0 :   nsAutoString text;
     206           0 :   rv = aAlert->GetText(text);
     207           0 :   NS_ENSURE_SUCCESS(rv, rv);
     208             : 
     209             :   bool textClickable;
     210           0 :   rv = aAlert->GetTextClickable(&textClickable);
     211           0 :   NS_ENSURE_SUCCESS(rv, rv);
     212             : 
     213           0 :   nsAutoString bidi;
     214           0 :   rv = aAlert->GetDir(bidi);
     215           0 :   NS_ENSURE_SUCCESS(rv, rv);
     216             : 
     217           0 :   nsAutoString lang;
     218           0 :   rv = aAlert->GetLang(lang);
     219           0 :   NS_ENSURE_SUCCESS(rv, rv);
     220             : 
     221           0 :   nsAutoString source;
     222           0 :   rv = aAlert->GetSource(source);
     223           0 :   NS_ENSURE_SUCCESS(rv, rv);
     224             : 
     225             :   bool requireInteraction;
     226           0 :   rv = aAlert->GetRequireInteraction(&requireInteraction);
     227           0 :   NS_ENSURE_SUCCESS(rv, rv);
     228             : 
     229           0 :   nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
     230             : 
     231           0 :   nsCOMPtr<nsIMutableArray> argsArray = nsArray::Create();
     232             : 
     233             :   // create scriptable versions of our strings that we can store in our nsIMutableArray....
     234           0 :   nsCOMPtr<nsISupportsString> scriptableImageUrl (do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID));
     235           0 :   NS_ENSURE_TRUE(scriptableImageUrl, NS_ERROR_FAILURE);
     236             : 
     237           0 :   scriptableImageUrl->SetData(imageUrl);
     238           0 :   rv = argsArray->AppendElement(scriptableImageUrl, /*weak =*/ false);
     239           0 :   NS_ENSURE_SUCCESS(rv, rv);
     240             : 
     241           0 :   nsCOMPtr<nsISupportsString> scriptableAlertTitle (do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID));
     242           0 :   NS_ENSURE_TRUE(scriptableAlertTitle, NS_ERROR_FAILURE);
     243             : 
     244           0 :   scriptableAlertTitle->SetData(title);
     245           0 :   rv = argsArray->AppendElement(scriptableAlertTitle, /*weak =*/ false);
     246           0 :   NS_ENSURE_SUCCESS(rv, rv);
     247             : 
     248           0 :   nsCOMPtr<nsISupportsString> scriptableAlertText (do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID));
     249           0 :   NS_ENSURE_TRUE(scriptableAlertText, NS_ERROR_FAILURE);
     250             : 
     251           0 :   scriptableAlertText->SetData(text);
     252           0 :   rv = argsArray->AppendElement(scriptableAlertText, /*weak =*/ false);
     253           0 :   NS_ENSURE_SUCCESS(rv, rv);
     254             : 
     255           0 :   nsCOMPtr<nsISupportsPRBool> scriptableIsClickable (do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID));
     256           0 :   NS_ENSURE_TRUE(scriptableIsClickable, NS_ERROR_FAILURE);
     257             : 
     258           0 :   scriptableIsClickable->SetData(textClickable);
     259           0 :   rv = argsArray->AppendElement(scriptableIsClickable, /*weak =*/ false);
     260           0 :   NS_ENSURE_SUCCESS(rv, rv);
     261             : 
     262           0 :   nsCOMPtr<nsISupportsString> scriptableAlertCookie (do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID));
     263           0 :   NS_ENSURE_TRUE(scriptableAlertCookie, NS_ERROR_FAILURE);
     264             : 
     265           0 :   scriptableAlertCookie->SetData(cookie);
     266           0 :   rv = argsArray->AppendElement(scriptableAlertCookie, /*weak =*/ false);
     267           0 :   NS_ENSURE_SUCCESS(rv, rv);
     268             : 
     269           0 :   nsCOMPtr<nsISupportsPRInt32> scriptableOrigin (do_CreateInstance(NS_SUPPORTS_PRINT32_CONTRACTID));
     270           0 :   NS_ENSURE_TRUE(scriptableOrigin, NS_ERROR_FAILURE);
     271             : 
     272             :   int32_t origin =
     273           0 :     LookAndFeel::GetInt(LookAndFeel::eIntID_AlertNotificationOrigin);
     274           0 :   scriptableOrigin->SetData(origin);
     275             : 
     276           0 :   rv = argsArray->AppendElement(scriptableOrigin, /*weak =*/ false);
     277           0 :   NS_ENSURE_SUCCESS(rv, rv);
     278             : 
     279           0 :   nsCOMPtr<nsISupportsString> scriptableBidi (do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID));
     280           0 :   NS_ENSURE_TRUE(scriptableBidi, NS_ERROR_FAILURE);
     281             : 
     282           0 :   scriptableBidi->SetData(bidi);
     283           0 :   rv = argsArray->AppendElement(scriptableBidi, /*weak =*/ false);
     284           0 :   NS_ENSURE_SUCCESS(rv, rv);
     285             : 
     286           0 :   nsCOMPtr<nsISupportsString> scriptableLang (do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID));
     287           0 :   NS_ENSURE_TRUE(scriptableLang, NS_ERROR_FAILURE);
     288             : 
     289           0 :   scriptableLang->SetData(lang);
     290           0 :   rv = argsArray->AppendElement(scriptableLang, /*weak =*/ false);
     291           0 :   NS_ENSURE_SUCCESS(rv, rv);
     292             : 
     293           0 :   nsCOMPtr<nsISupportsPRBool> scriptableRequireInteraction (do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID));
     294           0 :   NS_ENSURE_TRUE(scriptableRequireInteraction, NS_ERROR_FAILURE);
     295             : 
     296           0 :   scriptableRequireInteraction->SetData(requireInteraction);
     297           0 :   rv = argsArray->AppendElement(scriptableRequireInteraction, /*weak =*/ false);
     298           0 :   NS_ENSURE_SUCCESS(rv, rv);
     299             : 
     300             :   // Alerts with the same name should replace the old alert in the same position.
     301             :   // Provide the new alert window with a pointer to the replaced window so that
     302             :   // it may take the same position.
     303           0 :   nsCOMPtr<nsISupportsInterfacePointer> replacedWindow = do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID, &rv);
     304           0 :   NS_ENSURE_TRUE(replacedWindow, NS_ERROR_FAILURE);
     305           0 :   mozIDOMWindowProxy* previousAlert = mNamedWindows.GetWeak(name);
     306           0 :   replacedWindow->SetData(previousAlert);
     307           0 :   replacedWindow->SetDataIID(&NS_GET_IID(mozIDOMWindowProxy));
     308           0 :   rv = argsArray->AppendElement(replacedWindow, /*weak =*/ false);
     309           0 :   NS_ENSURE_SUCCESS(rv, rv);
     310             : 
     311           0 :   if (requireInteraction) {
     312           0 :     mPersistentAlertCount++;
     313             :   }
     314             : 
     315             :   // Add an observer (that wraps aAlertListener) to remove the window from
     316             :   // mNamedWindows when it is closed.
     317           0 :   nsCOMPtr<nsISupportsInterfacePointer> ifptr = do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID, &rv);
     318           0 :   NS_ENSURE_SUCCESS(rv, rv);
     319           0 :   RefPtr<nsXULAlertObserver> alertObserver = new nsXULAlertObserver(this, name, aAlertListener, requireInteraction);
     320           0 :   nsCOMPtr<nsISupports> iSupports(do_QueryInterface(alertObserver));
     321           0 :   ifptr->SetData(iSupports);
     322           0 :   ifptr->SetDataIID(&NS_GET_IID(nsIObserver));
     323           0 :   rv = argsArray->AppendElement(ifptr, /*weak =*/ false);
     324           0 :   NS_ENSURE_SUCCESS(rv, rv);
     325             : 
     326             :   // The source contains the host and port of the site that sent the
     327             :   // notification. It is empty for system alerts.
     328           0 :   nsCOMPtr<nsISupportsString> scriptableAlertSource (do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID));
     329           0 :   NS_ENSURE_TRUE(scriptableAlertSource, NS_ERROR_FAILURE);
     330           0 :   scriptableAlertSource->SetData(source);
     331           0 :   rv = argsArray->AppendElement(scriptableAlertSource, /*weak =*/ false);
     332           0 :   NS_ENSURE_SUCCESS(rv, rv);
     333             : 
     334           0 :   nsCOMPtr<nsISupportsCString> scriptableIconURL (do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID));
     335           0 :   NS_ENSURE_TRUE(scriptableIconURL, NS_ERROR_FAILURE);
     336           0 :   if (aIconURI) {
     337           0 :     nsAutoCString iconURL;
     338           0 :     rv = aIconURI->GetSpec(iconURL);
     339           0 :     NS_ENSURE_SUCCESS(rv, rv);
     340           0 :     scriptableIconURL->SetData(iconURL);
     341             :   }
     342           0 :   rv = argsArray->AppendElement(scriptableIconURL, /*weak =*/ false);
     343           0 :   NS_ENSURE_SUCCESS(rv, rv);
     344             : 
     345           0 :   nsCOMPtr<mozIDOMWindowProxy> newWindow;
     346           0 :   nsAutoCString features("chrome,dialog=yes,titlebar=no,popup=yes");
     347           0 :   if (inPrivateBrowsing) {
     348           0 :     features.AppendLiteral(",private");
     349             :   }
     350           0 :   rv = wwatch->OpenWindow(nullptr, ALERT_CHROME_URL, "_blank", features.get(),
     351           0 :                           argsArray, getter_AddRefs(newWindow));
     352           0 :   NS_ENSURE_SUCCESS(rv, rv);
     353             : 
     354           0 :   mNamedWindows.Put(name, newWindow);
     355           0 :   alertObserver->SetAlertWindow(newWindow);
     356             : 
     357           0 :   return NS_OK;
     358             : }
     359             : 
     360             : NS_IMETHODIMP
     361           0 : nsXULAlerts::SetManualDoNotDisturb(bool aDoNotDisturb)
     362             : {
     363           0 :   mDoNotDisturb = aDoNotDisturb;
     364           0 :   return NS_OK;
     365             : }
     366             : 
     367             : NS_IMETHODIMP
     368           0 : nsXULAlerts::GetManualDoNotDisturb(bool* aRetVal)
     369             : {
     370           0 :   *aRetVal = mDoNotDisturb;
     371           0 :   return NS_OK;
     372             : }
     373             : 
     374             : NS_IMETHODIMP
     375           0 : nsXULAlerts::CloseAlert(const nsAString& aAlertName,
     376             :                         nsIPrincipal* aPrincipal)
     377             : {
     378           0 :   mozIDOMWindowProxy* alert = mNamedWindows.GetWeak(aAlertName);
     379           0 :   if (nsCOMPtr<nsPIDOMWindowOuter> domWindow = nsPIDOMWindowOuter::From(alert)) {
     380           0 :     domWindow->DispatchCustomEvent(NS_LITERAL_STRING("XULAlertClose"));
     381             :   }
     382           0 :   return NS_OK;
     383           9 : }
     384             : 

Generated by: LCOV version 1.13