LCOV - code coverage report
Current view: top level - dom/presentation - PresentationServiceBase.h (source / functions) Hit Total Coverage
Test: output.info Lines: 9 163 5.5 %
Date: 2017-07-14 16:53:18 Functions: 3 51 5.9 %
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 sw=2 ts=8 et ft=cpp : */
       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 file,
       5             :  * You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #ifndef mozilla_dom_PresentationServiceBase_h
       8             : #define mozilla_dom_PresentationServiceBase_h
       9             : 
      10             : #include "mozilla/Unused.h"
      11             : #include "nsClassHashtable.h"
      12             : #include "nsCOMArray.h"
      13             : #include "nsIPresentationListener.h"
      14             : #include "nsIPresentationService.h"
      15             : #include "nsRefPtrHashtable.h"
      16             : #include "nsString.h"
      17             : #include "nsTArray.h"
      18             : 
      19             : namespace mozilla {
      20             : namespace dom {
      21             : 
      22             : template<class T>
      23             : class PresentationServiceBase
      24             : {
      25             : public:
      26           1 :   PresentationServiceBase() = default;
      27             : 
      28             :   already_AddRefed<T>
      29           0 :   GetSessionInfo(const nsAString& aSessionId, const uint8_t aRole)
      30             :   {
      31           0 :     MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
      32             :                aRole == nsIPresentationService::ROLE_RECEIVER);
      33             : 
      34           0 :     RefPtr<T> info;
      35           0 :     if (aRole == nsIPresentationService::ROLE_CONTROLLER) {
      36           0 :       return mSessionInfoAtController.Get(aSessionId, getter_AddRefs(info)) ?
      37           0 :              info.forget() : nullptr;
      38             :     } else {
      39           0 :       return mSessionInfoAtReceiver.Get(aSessionId, getter_AddRefs(info)) ?
      40           0 :              info.forget() : nullptr;
      41             :     }
      42             :   }
      43             : 
      44             : protected:
      45             :   class SessionIdManager final
      46             :   {
      47             :   public:
      48           2 :     explicit SessionIdManager()
      49           2 :     {
      50           2 :       MOZ_COUNT_CTOR(SessionIdManager);
      51           2 :     }
      52             : 
      53           0 :     ~SessionIdManager()
      54             :     {
      55           0 :       MOZ_COUNT_DTOR(SessionIdManager);
      56           0 :     }
      57             : 
      58           0 :     nsresult GetWindowId(const nsAString& aSessionId, uint64_t* aWindowId)
      59             :     {
      60           0 :       MOZ_ASSERT(NS_IsMainThread());
      61             : 
      62           0 :       if (mRespondingWindowIds.Get(aSessionId, aWindowId)) {
      63           0 :         return NS_OK;
      64             :       }
      65           0 :       return NS_ERROR_NOT_AVAILABLE;
      66             :     }
      67             : 
      68           0 :     nsresult GetSessionIds(uint64_t aWindowId, nsTArray<nsString>& aSessionIds)
      69             :     {
      70           0 :       MOZ_ASSERT(NS_IsMainThread());
      71             : 
      72             :       nsTArray<nsString>* sessionIdArray;
      73           0 :       if (!mRespondingSessionIds.Get(aWindowId, &sessionIdArray)) {
      74           0 :         return NS_ERROR_INVALID_ARG;
      75             :       }
      76             : 
      77           0 :       aSessionIds.Assign(*sessionIdArray);
      78           0 :       return NS_OK;
      79             :     }
      80             : 
      81           0 :     void AddSessionId(uint64_t aWindowId, const nsAString& aSessionId)
      82             :     {
      83           0 :       MOZ_ASSERT(NS_IsMainThread());
      84             : 
      85           0 :       if (NS_WARN_IF(aWindowId == 0)) {
      86           0 :         return;
      87             :       }
      88             : 
      89             :       nsTArray<nsString>* sessionIdArray;
      90           0 :       if (!mRespondingSessionIds.Get(aWindowId, &sessionIdArray)) {
      91           0 :         sessionIdArray = new nsTArray<nsString>();
      92           0 :         mRespondingSessionIds.Put(aWindowId, sessionIdArray);
      93             :       }
      94             : 
      95           0 :       sessionIdArray->AppendElement(nsString(aSessionId));
      96           0 :       mRespondingWindowIds.Put(aSessionId, aWindowId);
      97             :     }
      98             : 
      99           0 :     void RemoveSessionId(const nsAString& aSessionId)
     100             :     {
     101           0 :       MOZ_ASSERT(NS_IsMainThread());
     102             : 
     103           0 :       uint64_t windowId = 0;
     104           0 :       if (mRespondingWindowIds.Get(aSessionId, &windowId)) {
     105           0 :         mRespondingWindowIds.Remove(aSessionId);
     106             :         nsTArray<nsString>* sessionIdArray;
     107           0 :         if (mRespondingSessionIds.Get(windowId, &sessionIdArray)) {
     108           0 :           sessionIdArray->RemoveElement(nsString(aSessionId));
     109           0 :           if (sessionIdArray->IsEmpty()) {
     110           0 :             mRespondingSessionIds.Remove(windowId);
     111             :           }
     112             :         }
     113             :       }
     114           0 :     }
     115             : 
     116           0 :     nsresult UpdateWindowId(const nsAString& aSessionId, const uint64_t aWindowId)
     117             :     {
     118           0 :       MOZ_ASSERT(NS_IsMainThread());
     119             : 
     120           0 :       RemoveSessionId(aSessionId);
     121           0 :       AddSessionId(aWindowId, aSessionId);
     122           0 :       return NS_OK;
     123             :     }
     124             : 
     125           0 :     void Clear()
     126             :     {
     127           0 :       mRespondingSessionIds.Clear();
     128           0 :       mRespondingWindowIds.Clear();
     129           0 :     }
     130             : 
     131             :   private:
     132             :     nsClassHashtable<nsUint64HashKey, nsTArray<nsString>> mRespondingSessionIds;
     133             :     nsDataHashtable<nsStringHashKey, uint64_t> mRespondingWindowIds;
     134             :   };
     135             : 
     136             :   class AvailabilityManager final
     137             :   {
     138             :   public:
     139           1 :     explicit AvailabilityManager()
     140           1 :     {
     141           1 :       MOZ_COUNT_CTOR(AvailabilityManager);
     142           1 :     }
     143             : 
     144           0 :     ~AvailabilityManager()
     145             :     {
     146           0 :       MOZ_COUNT_DTOR(AvailabilityManager);
     147           0 :     }
     148             : 
     149           0 :     void AddAvailabilityListener(
     150             :                                const nsTArray<nsString>& aAvailabilityUrls,
     151             :                                nsIPresentationAvailabilityListener* aListener)
     152             :     {
     153           0 :       nsTArray<nsString> dummy;
     154           0 :       AddAvailabilityListener(aAvailabilityUrls, aListener, dummy);
     155           0 :     }
     156             : 
     157           0 :     void AddAvailabilityListener(
     158             :                                const nsTArray<nsString>& aAvailabilityUrls,
     159             :                                nsIPresentationAvailabilityListener* aListener,
     160             :                                nsTArray<nsString>& aAddedUrls)
     161             :     {
     162           0 :       if (!aListener) {
     163           0 :         MOZ_ASSERT(false, "aListener should not be null.");
     164             :         return;
     165             :       }
     166             : 
     167           0 :       if (aAvailabilityUrls.IsEmpty()) {
     168           0 :         MOZ_ASSERT(false, "aAvailabilityUrls should not be empty.");
     169             :         return;
     170             :       }
     171             : 
     172           0 :       aAddedUrls.Clear();
     173           0 :       nsTArray<nsString> knownAvailableUrls;
     174           0 :       for (const auto& url : aAvailabilityUrls) {
     175             :         AvailabilityEntry* entry;
     176           0 :         if (!mAvailabilityUrlTable.Get(url, &entry)) {
     177           0 :           entry = new AvailabilityEntry();
     178           0 :           mAvailabilityUrlTable.Put(url, entry);
     179           0 :           aAddedUrls.AppendElement(url);
     180             :         }
     181           0 :         if (!entry->mListeners.Contains(aListener)) {
     182           0 :           entry->mListeners.AppendElement(aListener);
     183             :         }
     184           0 :         if (entry->mAvailable) {
     185           0 :           knownAvailableUrls.AppendElement(url);
     186             :         }
     187             :       }
     188             : 
     189           0 :       if (!knownAvailableUrls.IsEmpty()) {
     190             :         Unused <<
     191           0 :           NS_WARN_IF(
     192             :             NS_FAILED(aListener->NotifyAvailableChange(knownAvailableUrls,
     193             :                                                        true)));
     194             :       } else {
     195             :         // If we can't find any known available url and there is no newly
     196             :         // added url, we still need to notify the listener of the result.
     197             :         // So, the promise returned by |getAvailability| can be resolved.
     198           0 :         if (aAddedUrls.IsEmpty()) {
     199             :           Unused <<
     200           0 :             NS_WARN_IF(
     201             :               NS_FAILED(aListener->NotifyAvailableChange(aAvailabilityUrls,
     202             :                                                          false)));
     203             :         }
     204             :       }
     205           0 :     }
     206             : 
     207           0 :     void RemoveAvailabilityListener(
     208             :                                const nsTArray<nsString>& aAvailabilityUrls,
     209             :                                nsIPresentationAvailabilityListener* aListener)
     210             :     {
     211           0 :       nsTArray<nsString> dummy;
     212           0 :       RemoveAvailabilityListener(aAvailabilityUrls, aListener, dummy);
     213           0 :     }
     214             : 
     215           0 :     void RemoveAvailabilityListener(
     216             :                                const nsTArray<nsString>& aAvailabilityUrls,
     217             :                                nsIPresentationAvailabilityListener* aListener,
     218             :                                nsTArray<nsString>& aRemovedUrls)
     219             :     {
     220           0 :       if (!aListener) {
     221           0 :         MOZ_ASSERT(false, "aListener should not be null.");
     222             :         return;
     223             :       }
     224             : 
     225           0 :       if (aAvailabilityUrls.IsEmpty()) {
     226           0 :         MOZ_ASSERT(false, "aAvailabilityUrls should not be empty.");
     227             :         return;
     228             :       }
     229             : 
     230           0 :       aRemovedUrls.Clear();
     231           0 :       for (const auto& url : aAvailabilityUrls) {
     232             :         AvailabilityEntry* entry;
     233           0 :         if (mAvailabilityUrlTable.Get(url, &entry)) {
     234           0 :           entry->mListeners.RemoveElement(aListener);
     235           0 :           if (entry->mListeners.IsEmpty()) {
     236           0 :             mAvailabilityUrlTable.Remove(url);
     237           0 :             aRemovedUrls.AppendElement(url);
     238             :           }
     239             :         }
     240             :       }
     241           0 :     }
     242             : 
     243           0 :     nsresult DoNotifyAvailableChange(const nsTArray<nsString>& aAvailabilityUrls,
     244             :                                      bool aAvailable)
     245             :     {
     246             :       typedef nsClassHashtable<nsISupportsHashKey,
     247             :                                nsTArray<nsString>> ListenerToUrlsMap;
     248           0 :       ListenerToUrlsMap availabilityListenerTable;
     249             :       // Create a mapping from nsIPresentationAvailabilityListener to
     250             :       // availabilityUrls.
     251           0 :       for (auto it = mAvailabilityUrlTable.ConstIter(); !it.Done(); it.Next()) {
     252           0 :         if (aAvailabilityUrls.Contains(it.Key())) {
     253           0 :           AvailabilityEntry* entry = it.UserData();
     254           0 :           entry->mAvailable = aAvailable;
     255             : 
     256           0 :           for (uint32_t i = 0; i < entry->mListeners.Length(); ++i) {
     257             :             nsIPresentationAvailabilityListener* listener =
     258           0 :               entry->mListeners.ObjectAt(i);
     259             :             nsTArray<nsString>* urlArray;
     260           0 :             if (!availabilityListenerTable.Get(listener, &urlArray)) {
     261           0 :               urlArray = new nsTArray<nsString>();
     262           0 :               availabilityListenerTable.Put(listener, urlArray);
     263             :             }
     264           0 :             urlArray->AppendElement(it.Key());
     265             :           }
     266             :         }
     267             :       }
     268             : 
     269           0 :       for (auto it = availabilityListenerTable.Iter(); !it.Done(); it.Next()) {
     270             :         auto listener =
     271           0 :           static_cast<nsIPresentationAvailabilityListener*>(it.Key());
     272             : 
     273             :         Unused <<
     274           0 :           NS_WARN_IF(NS_FAILED(listener->NotifyAvailableChange(*it.UserData(),
     275             :                                                                aAvailable)));
     276             :       }
     277           0 :       return NS_OK;
     278             :     }
     279             : 
     280           0 :     void GetAvailbilityUrlByAvailability(nsTArray<nsString>& aOutArray,
     281             :                                          bool aAvailable)
     282             :     {
     283           0 :       aOutArray.Clear();
     284             : 
     285           0 :       for (auto it = mAvailabilityUrlTable.ConstIter(); !it.Done(); it.Next()) {
     286           0 :         if (it.UserData()->mAvailable == aAvailable) {
     287           0 :           aOutArray.AppendElement(it.Key());
     288             :         }
     289             :       }
     290           0 :     }
     291             : 
     292           0 :     void Clear()
     293             :     {
     294           0 :       mAvailabilityUrlTable.Clear();
     295           0 :     }
     296             : 
     297             :   private:
     298           0 :     struct AvailabilityEntry
     299             :     {
     300           0 :       explicit AvailabilityEntry()
     301           0 :         : mAvailable(false)
     302           0 :       {}
     303             : 
     304             :       bool mAvailable;
     305             :       nsCOMArray<nsIPresentationAvailabilityListener> mListeners;
     306             :     };
     307             : 
     308             :     nsClassHashtable<nsStringHashKey, AvailabilityEntry> mAvailabilityUrlTable;
     309             :   };
     310             : 
     311           0 :   virtual ~PresentationServiceBase() = default;
     312             : 
     313           0 :   void Shutdown()
     314             :   {
     315           0 :     mRespondingListeners.Clear();
     316           0 :     mControllerSessionIdManager.Clear();
     317           0 :     mReceiverSessionIdManager.Clear();
     318           0 :   }
     319             : 
     320           0 :   nsresult GetWindowIdBySessionIdInternal(const nsAString& aSessionId,
     321             :                                           uint8_t aRole,
     322             :                                           uint64_t* aWindowId)
     323             :   {
     324           0 :     MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
     325             :                aRole == nsIPresentationService::ROLE_RECEIVER);
     326             : 
     327           0 :     if (NS_WARN_IF(!aWindowId)) {
     328           0 :       return NS_ERROR_INVALID_POINTER;
     329             :     }
     330             : 
     331           0 :     if (aRole == nsIPresentationService::ROLE_CONTROLLER) {
     332           0 :       return mControllerSessionIdManager.GetWindowId(aSessionId, aWindowId);
     333             :     }
     334             : 
     335           0 :     return mReceiverSessionIdManager.GetWindowId(aSessionId, aWindowId);
     336             :   }
     337             : 
     338           0 :   void AddRespondingSessionId(uint64_t aWindowId,
     339             :                               const nsAString& aSessionId,
     340             :                               uint8_t aRole)
     341             :   {
     342           0 :     MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
     343             :                aRole == nsIPresentationService::ROLE_RECEIVER);
     344             : 
     345           0 :     if (aRole == nsIPresentationService::ROLE_CONTROLLER) {
     346           0 :       mControllerSessionIdManager.AddSessionId(aWindowId, aSessionId);
     347             :     } else {
     348           0 :       mReceiverSessionIdManager.AddSessionId(aWindowId, aSessionId);
     349             :     }
     350           0 :   }
     351             : 
     352           0 :   void RemoveRespondingSessionId(const nsAString& aSessionId,
     353             :                                  uint8_t aRole)
     354             :   {
     355           0 :     MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
     356             :                aRole == nsIPresentationService::ROLE_RECEIVER);
     357             : 
     358           0 :     if (aRole == nsIPresentationService::ROLE_CONTROLLER) {
     359           0 :       mControllerSessionIdManager.RemoveSessionId(aSessionId);
     360             :     } else {
     361           0 :       mReceiverSessionIdManager.RemoveSessionId(aSessionId);
     362             :     }
     363           0 :   }
     364             : 
     365           0 :   nsresult UpdateWindowIdBySessionIdInternal(const nsAString& aSessionId,
     366             :                                              uint8_t aRole,
     367             :                                              const uint64_t aWindowId)
     368             :   {
     369           0 :     MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
     370             :                aRole == nsIPresentationService::ROLE_RECEIVER);
     371             : 
     372           0 :     if (aRole == nsIPresentationService::ROLE_CONTROLLER) {
     373           0 :       return mControllerSessionIdManager.UpdateWindowId(aSessionId, aWindowId);
     374             :     }
     375             : 
     376           0 :     return mReceiverSessionIdManager.UpdateWindowId(aSessionId, aWindowId);
     377             :   }
     378             : 
     379             :   // Store the responding listener based on the window ID of the (in-process or
     380             :   // OOP) receiver page.
     381             :   nsRefPtrHashtable<nsUint64HashKey, nsIPresentationRespondingListener>
     382             :   mRespondingListeners;
     383             : 
     384             :   // Store the mapping between the window ID of the in-process and OOP page and the ID
     385             :   // of the responding session. It's used for both controller and receiver page
     386             :   // to retrieve the correspondent session ID. Besides, also keep the mapping
     387             :   // between the responding session ID and the window ID to help look up the
     388             :   // window ID.
     389             :   SessionIdManager mControllerSessionIdManager;
     390             :   SessionIdManager mReceiverSessionIdManager;
     391             : 
     392             :   nsRefPtrHashtable<nsStringHashKey, T> mSessionInfoAtController;
     393             :   nsRefPtrHashtable<nsStringHashKey, T> mSessionInfoAtReceiver;
     394             : 
     395             :   AvailabilityManager mAvailabilityManager;
     396             : };
     397             : 
     398             : } // namespace dom
     399             : } // namespace mozilla
     400             : 
     401             : #endif // mozilla_dom_PresentationServiceBase_h

Generated by: LCOV version 1.13