LCOV - code coverage report
Current view: directory - dom/src/geolocation - nsGeolocation.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 450 226 50.2 %
Date: 2012-06-02 Functions: 78 50 64.1 %

       1                 : /* ***** BEGIN LICENSE BLOCK *****
       2                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       3                 :  *
       4                 :  * The contents of this file are subject to the Mozilla Public License Version
       5                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       6                 :  * the License. You may obtain a copy of the License at
       7                 :  * http://www.mozilla.org/MPL/
       8                 :  *
       9                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      10                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      11                 :  * for the specific language governing rights and limitations under the
      12                 :  * License.
      13                 :  *
      14                 :  * The Original Code is Geolocation.
      15                 :  *
      16                 :  * The Initial Developer of the Original Code is Mozilla Foundation
      17                 :  * Portions created by the Initial Developer are Copyright (C) 2008
      18                 :  * the Initial Developer. All Rights Reserved.
      19                 :  *
      20                 :  * Contributor(s):
      21                 :  *  Doug Turner <dougt@meer.net>  (Original Author)
      22                 :  *
      23                 :  * Alternatively, the contents of this file may be used under the terms of
      24                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      25                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      26                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      27                 :  * of those above. If you wish to allow use of your version of this file only
      28                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      29                 :  * use your version of this file under the terms of the MPL, indicate your
      30                 :  * decision by deleting the provisions above and replace them with the notice
      31                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      32                 :  * the provisions above, a recipient may use your version of this file under
      33                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      34                 :  *
      35                 :  * ***** END LICENSE BLOCK ***** */
      36                 : 
      37                 : #include "nsContentPermissionHelper.h"
      38                 : #include "nsXULAppAPI.h"
      39                 : 
      40                 : #include "mozilla/dom/PBrowserChild.h"
      41                 : #include "mozilla/dom/PBrowserParent.h"
      42                 : #include "mozilla/dom/ContentChild.h"
      43                 : #include "nsNetUtil.h"
      44                 : 
      45                 : #include "nsFrameManager.h"
      46                 : #include "nsFrameLoader.h"
      47                 : #include "nsIFrameLoader.h"
      48                 : 
      49                 : #include "nsIDocShellTreeOwner.h"
      50                 : #include "nsIDocShellTreeItem.h"
      51                 : #include "nsIWebProgressListener2.h"
      52                 : 
      53                 : #include "nsDOMEventTargetHelper.h"
      54                 : #include "TabChild.h"
      55                 : 
      56                 : #include "nsGeolocation.h"
      57                 : #include "nsAutoPtr.h"
      58                 : #include "nsCOMPtr.h"
      59                 : #include "nsIDOMWindow.h"
      60                 : #include "nsDOMClassInfoID.h"
      61                 : #include "nsComponentManagerUtils.h"
      62                 : #include "nsICategoryManager.h"
      63                 : #include "nsISupportsPrimitives.h"
      64                 : #include "nsServiceManagerUtils.h"
      65                 : #include "nsContentUtils.h"
      66                 : #include "nsIURI.h"
      67                 : #include "nsIPermissionManager.h"
      68                 : #include "nsIObserverService.h"
      69                 : #include "nsIPrefService.h"
      70                 : #include "nsIPrefBranch.h"
      71                 : #include "nsIJSContextStack.h"
      72                 : #include "nsThreadUtils.h"
      73                 : #include "mozilla/Services.h"
      74                 : #include "mozilla/unused.h"
      75                 : #include "mozilla/Preferences.h"
      76                 : 
      77                 : #include <math.h>
      78                 : 
      79                 : #ifdef MOZ_MAEMO_LIBLOCATION
      80                 : #include "MaemoLocationProvider.h"
      81                 : #endif
      82                 : 
      83                 : #ifdef MOZ_ENABLE_QTMOBILITY
      84                 : #include "QTMLocationProvider.h"
      85                 : #endif
      86                 : 
      87                 : #ifdef MOZ_WIDGET_ANDROID
      88                 : #include "AndroidLocationProvider.h"
      89                 : #endif
      90                 : 
      91                 : #ifdef MOZ_WIDGET_GONK
      92                 : #include "GonkGPSGeolocationProvider.h"
      93                 : #endif
      94                 : 
      95                 : #include "nsIDOMDocument.h"
      96                 : #include "nsIDocument.h"
      97                 : 
      98                 : // Some limit to the number of get or watch geolocation requests
      99                 : // that a window can make.
     100                 : #define MAX_GEO_REQUESTS_PER_WINDOW  1500
     101                 : 
     102                 : using mozilla::unused;          // <snicker>
     103                 : using namespace mozilla;
     104                 : using namespace mozilla::dom;
     105                 : 
     106                 : class RequestPromptEvent : public nsRunnable
     107               0 : {
     108                 : public:
     109               0 :   RequestPromptEvent(nsGeolocationRequest* request)
     110               0 :     : mRequest(request)
     111                 :   {
     112               0 :   }
     113                 : 
     114               0 :   NS_IMETHOD Run() {
     115               0 :     nsCOMPtr<nsIContentPermissionPrompt> prompt = do_GetService(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID);
     116               0 :     if (prompt) {
     117               0 :       prompt->Prompt(mRequest);
     118                 :     }
     119               0 :     return NS_OK;
     120                 :   }
     121                 : 
     122                 : private:
     123                 :   nsRefPtr<nsGeolocationRequest> mRequest;
     124                 : };
     125                 : 
     126                 : class RequestAllowEvent : public nsRunnable
     127               0 : {
     128                 : public:
     129               0 :   RequestAllowEvent(int allow, nsGeolocationRequest* request)
     130                 :     : mAllow(allow),
     131               0 :       mRequest(request)
     132                 :   {
     133               0 :   }
     134                 : 
     135               0 :   NS_IMETHOD Run() {
     136               0 :     if (mAllow)
     137               0 :       mRequest->Allow();
     138                 :     else
     139               0 :       mRequest->Cancel();
     140               0 :     return NS_OK;
     141                 :   }
     142                 : 
     143                 : private:
     144                 :   bool mAllow;
     145                 :   nsRefPtr<nsGeolocationRequest> mRequest;
     146                 : };
     147                 : 
     148                 : class RequestSendLocationEvent : public nsRunnable
     149               8 : {
     150                 : public:
     151                 :   // a bit funky.  if locator is passed, that means this
     152                 :   // event should remove the request from it.  If we ever
     153                 :   // have to do more, then we can change this around.
     154               2 :   RequestSendLocationEvent(nsIDOMGeoPosition* aPosition,
     155                 :                            nsGeolocationRequest* aRequest,
     156                 :                            nsGeolocation* aLocator)
     157                 :     : mPosition(aPosition),
     158                 :       mRequest(aRequest),
     159               2 :       mLocator(aLocator)
     160                 :   {
     161               2 :   }
     162                 : 
     163               2 :   NS_IMETHOD Run() {
     164               2 :     mRequest->SendLocation(mPosition);
     165               2 :     if (mLocator)
     166               0 :       mLocator->RemoveRequest(mRequest);
     167               2 :     return NS_OK;
     168                 :   }
     169                 : 
     170                 : private:
     171                 :   nsCOMPtr<nsIDOMGeoPosition>    mPosition;
     172                 :   nsRefPtr<nsGeolocationRequest> mRequest;
     173                 : 
     174                 :   nsRefPtr<nsGeolocation>        mLocator;
     175                 : };
     176                 : 
     177                 : ////////////////////////////////////////////////////
     178                 : // nsDOMGeoPositionError
     179                 : ////////////////////////////////////////////////////
     180                 : 
     181                 : class nsDOMGeoPositionError : public nsIDOMGeoPositionError
     182                 : {
     183                 : public:
     184                 :   NS_DECL_ISUPPORTS
     185                 :   NS_DECL_NSIDOMGEOPOSITIONERROR
     186                 : 
     187                 :   nsDOMGeoPositionError(PRInt16 aCode);
     188                 :   void NotifyCallback(nsIDOMGeoPositionErrorCallback* callback);
     189                 : 
     190                 : private:
     191                 :   ~nsDOMGeoPositionError();
     192                 :   PRInt16 mCode;
     193                 : };
     194                 : 
     195                 : DOMCI_DATA(GeoPositionError, nsDOMGeoPositionError)
     196                 : 
     197               0 : NS_INTERFACE_MAP_BEGIN(nsDOMGeoPositionError)
     198               0 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMGeoPositionError)
     199               0 :   NS_INTERFACE_MAP_ENTRY(nsIDOMGeoPositionError)
     200               0 :   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(GeoPositionError)
     201               0 : NS_INTERFACE_MAP_END
     202                 : 
     203               0 : NS_IMPL_THREADSAFE_ADDREF(nsDOMGeoPositionError)
     204               0 : NS_IMPL_THREADSAFE_RELEASE(nsDOMGeoPositionError)
     205                 : 
     206               0 : nsDOMGeoPositionError::nsDOMGeoPositionError(PRInt16 aCode)
     207               0 :   : mCode(aCode)
     208                 : {
     209               0 : }
     210                 : 
     211               0 : nsDOMGeoPositionError::~nsDOMGeoPositionError(){}
     212                 : 
     213                 : 
     214                 : NS_IMETHODIMP
     215               0 : nsDOMGeoPositionError::GetCode(PRInt16 *aCode)
     216                 : {
     217               0 :   NS_ENSURE_ARG_POINTER(aCode);
     218               0 :   *aCode = mCode;
     219               0 :   return NS_OK;
     220                 : }
     221                 : 
     222                 : void
     223               0 : nsDOMGeoPositionError::NotifyCallback(nsIDOMGeoPositionErrorCallback* aCallback)
     224                 : {
     225               0 :   if (!aCallback)
     226               0 :     return;
     227                 :   
     228                 :   // Ensure that the proper context is on the stack (bug 452762)
     229               0 :   nsCOMPtr<nsIJSContextStack> stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1"));
     230               0 :   if (!stack || NS_FAILED(stack->Push(nsnull)))
     231                 :     return;
     232                 :   
     233               0 :   aCallback->HandleEvent(this);
     234                 :   
     235                 :   // remove the stack
     236                 :   JSContext* cx;
     237               0 :   stack->Pop(&cx);
     238                 : }
     239                 : ////////////////////////////////////////////////////
     240                 : // nsGeolocationRequest
     241                 : ////////////////////////////////////////////////////
     242                 : 
     243               1 : nsGeolocationRequest::nsGeolocationRequest(nsGeolocation* aLocator,
     244                 :                                            nsIDOMGeoPositionCallback* aCallback,
     245                 :                                            nsIDOMGeoPositionErrorCallback* aErrorCallback,
     246                 :                                            nsIDOMGeoPositionOptions* aOptions,
     247                 :                                            bool aWatchPositionRequest)
     248                 :   : mAllowed(false),
     249                 :     mCleared(false),
     250                 :     mIsWatchPositionRequest(aWatchPositionRequest),
     251                 :     mCallback(aCallback),
     252                 :     mErrorCallback(aErrorCallback),
     253                 :     mOptions(aOptions),
     254               1 :     mLocator(aLocator)
     255                 : {
     256               1 : }
     257                 : 
     258               2 : nsGeolocationRequest::~nsGeolocationRequest()
     259                 : {
     260               4 : }
     261                 : 
     262                 : nsresult
     263               1 : nsGeolocationRequest::Init()
     264                 : {
     265                 :   // This method is called before the user has given permission for this request.
     266               1 :   return NS_OK;
     267                 : }
     268                 : 
     269              16 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGeolocationRequest)
     270               0 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentPermissionRequest)
     271               0 :   NS_INTERFACE_MAP_ENTRY(nsIContentPermissionRequest)
     272               0 :   NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
     273               0 : NS_INTERFACE_MAP_END
     274                 : 
     275               5 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGeolocationRequest)
     276               5 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGeolocationRequest)
     277                 : 
     278            1468 : NS_IMPL_CYCLE_COLLECTION_4(nsGeolocationRequest, mCallback, mErrorCallback, mOptions, mLocator)
     279                 : 
     280                 : 
     281                 : void
     282               0 : nsGeolocationRequest::NotifyError(PRInt16 errorCode)
     283                 : {
     284               0 :   nsRefPtr<nsDOMGeoPositionError> positionError = new nsDOMGeoPositionError(errorCode);
     285               0 :   if (!positionError)
     286                 :     return;
     287                 :   
     288               0 :   positionError->NotifyCallback(mErrorCallback);
     289                 : }
     290                 : 
     291                 : 
     292                 : NS_IMETHODIMP
     293               0 : nsGeolocationRequest::Notify(nsITimer* aTimer)
     294                 : {
     295                 :   // If we haven't gotten an answer from the geolocation
     296                 :   // provider yet, cancel the request.  Same logic as
     297                 :   // ::Cancel, just a different error
     298                 :   
     299                 :   // remove ourselves from the locator's callback lists.
     300               0 :   mLocator->RemoveRequest(this);
     301               0 :   NotifyError(nsIDOMGeoPositionError::TIMEOUT);
     302                 : 
     303               0 :   mTimeoutTimer = nsnull;
     304               0 :   return NS_OK;
     305                 : }
     306                 :  
     307                 : NS_IMETHODIMP
     308               0 : nsGeolocationRequest::GetUri(nsIURI * *aRequestingURI)
     309                 : {
     310               0 :   NS_ENSURE_ARG_POINTER(aRequestingURI);
     311                 : 
     312               0 :   nsCOMPtr<nsIURI> uri = mLocator->GetURI();
     313               0 :   uri.forget(aRequestingURI);
     314                 : 
     315               0 :   return NS_OK;
     316                 : }
     317                 : 
     318                 : NS_IMETHODIMP
     319               0 : nsGeolocationRequest::GetType(nsACString & aType)
     320                 : {
     321               0 :   aType = "geolocation";
     322               0 :   return NS_OK;
     323                 : }
     324                 : 
     325                 : NS_IMETHODIMP
     326               0 : nsGeolocationRequest::GetWindow(nsIDOMWindow * *aRequestingWindow)
     327                 : {
     328               0 :   NS_ENSURE_ARG_POINTER(aRequestingWindow);
     329                 : 
     330               0 :   nsCOMPtr<nsIDOMWindow> window = do_QueryReferent(mLocator->GetOwner());
     331               0 :   window.forget(aRequestingWindow);
     332                 : 
     333               0 :   return NS_OK;
     334                 : }
     335                 : 
     336                 : NS_IMETHODIMP
     337               0 : nsGeolocationRequest::GetElement(nsIDOMElement * *aRequestingElement)
     338                 : {
     339               0 :   NS_ENSURE_ARG_POINTER(aRequestingElement);
     340               0 :   *aRequestingElement = nsnull;
     341               0 :   return NS_OK;
     342                 : }
     343                 : 
     344                 : NS_IMETHODIMP
     345               0 : nsGeolocationRequest::Cancel()
     346                 : {
     347                 :   // remove ourselves from the locators callback lists.
     348               0 :   mLocator->RemoveRequest(this);
     349                 : 
     350               0 :   NotifyError(nsIDOMGeoPositionError::PERMISSION_DENIED);
     351               0 :   return NS_OK;
     352                 : }
     353                 : 
     354                 : NS_IMETHODIMP
     355               1 : nsGeolocationRequest::Allow()
     356                 : {
     357               2 :   nsRefPtr<nsGeolocationService> geoService = nsGeolocationService::GetInstance();
     358                 : 
     359                 :   // Kick off the geo device, if it isn't already running
     360               1 :   nsresult rv = geoService->StartDevice();
     361                 :   
     362               1 :   if (NS_FAILED(rv)) {
     363                 :     // Location provider error
     364               0 :     NotifyError(nsIDOMGeoPositionError::POSITION_UNAVAILABLE);
     365               0 :     return NS_OK;
     366                 :   }
     367                 :   
     368               2 :   nsCOMPtr<nsIDOMGeoPosition> lastPosition = geoService->GetCachedPosition();
     369                 :   DOMTimeStamp cachedPositionTime;
     370               1 :   if (lastPosition)
     371               0 :     lastPosition->GetTimestamp(&cachedPositionTime);
     372                 : 
     373                 :   // check to see if we can use a cached value
     374                 :   //
     375                 :   // either:
     376                 :   // a) the user has specified a maximumAge which allows us to return a cached value,
     377                 :   // -or-
     378                 :   // b) the cached position time is some reasonable value to return to the user (<30s)
     379                 :   
     380               1 :   PRUint32 maximumAge = 30 * PR_MSEC_PER_SEC;
     381               1 :   if (mOptions) {
     382                 :     PRInt32 tempAge;
     383               0 :     nsresult rv = mOptions->GetMaximumAge(&tempAge);
     384               0 :     if (NS_SUCCEEDED(rv)) {
     385               0 :       if (tempAge >= 0)
     386               0 :         maximumAge = tempAge;
     387                 :     }
     388                 :   }
     389                 : 
     390               1 :   if (lastPosition && maximumAge > 0 &&
     391               0 :       ( PRTime(PR_Now() / PR_USEC_PER_MSEC) - maximumAge <=
     392                 :         PRTime(cachedPositionTime) )) {
     393                 :     // okay, we can return a cached position
     394               0 :     mAllowed = true;
     395                 :     
     396                 :      nsCOMPtr<nsIRunnable> ev =
     397                 :          new RequestSendLocationEvent(lastPosition, this,
     398               0 :                                       mIsWatchPositionRequest ? nsnull : mLocator);
     399               0 :     NS_DispatchToMainThread(ev);
     400                 :   }
     401                 : 
     402               1 :   SetTimeoutTimer();
     403                 : 
     404               1 :   mAllowed = true;
     405               1 :   return NS_OK;
     406                 : }
     407                 : 
     408                 : void
     409               2 : nsGeolocationRequest::SetTimeoutTimer()
     410                 : {
     411               2 :   if (mTimeoutTimer) {
     412               0 :     mTimeoutTimer->Cancel();
     413               0 :     mTimeoutTimer = nsnull;
     414                 :   }
     415                 :   PRInt32 timeout;
     416               2 :   if (mOptions && NS_SUCCEEDED(mOptions->GetTimeout(&timeout)) && timeout > 0) {
     417                 :     
     418               0 :     if (timeout < 10)
     419               0 :       timeout = 10;
     420                 : 
     421               0 :     mTimeoutTimer = do_CreateInstance("@mozilla.org/timer;1");
     422               0 :     mTimeoutTimer->InitWithCallback(this, timeout, nsITimer::TYPE_ONE_SHOT);
     423                 :   }
     424               2 : }
     425                 : 
     426                 : void
     427               1 : nsGeolocationRequest::MarkCleared()
     428                 : {
     429               1 :   if (mTimeoutTimer) {
     430               0 :     mTimeoutTimer->Cancel();
     431               0 :     mTimeoutTimer = nsnull;
     432                 :   }
     433               1 :   mCleared = true;
     434               1 : }
     435                 : 
     436                 : void
     437               2 : nsGeolocationRequest::SendLocation(nsIDOMGeoPosition* aPosition)
     438                 : {
     439               2 :   if (mCleared || !mAllowed)
     440               1 :     return;
     441                 : 
     442               1 :   if (mTimeoutTimer) {
     443               0 :     mTimeoutTimer->Cancel();
     444               0 :     mTimeoutTimer = nsnull;
     445                 :   }
     446                 : 
     447                 :   // we should not pass null back to the DOM.
     448               1 :   if (!aPosition) {
     449               0 :     NotifyError(nsIDOMGeoPositionError::POSITION_UNAVAILABLE);
     450               0 :     return;
     451                 :   }
     452                 : 
     453                 :   // Ensure that the proper context is on the stack (bug 452762)
     454               2 :   nsCOMPtr<nsIJSContextStack> stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1"));
     455               1 :   if (!stack || NS_FAILED(stack->Push(nsnull)))
     456                 :     return; // silently fail
     457                 :   
     458               1 :   mCallback->HandleEvent(aPosition);
     459                 : 
     460                 :   // remove the stack
     461                 :   JSContext* cx;
     462               1 :   stack->Pop(&cx);
     463                 : 
     464               1 :   if (mIsWatchPositionRequest)
     465               1 :     SetTimeoutTimer();
     466                 : }
     467                 : 
     468                 : bool
     469               2 : nsGeolocationRequest::Update(nsIDOMGeoPosition* aPosition)
     470                 : {
     471               2 :   if (!mAllowed)
     472               0 :     return false;
     473                 :   nsCOMPtr<nsIRunnable> ev  =
     474                 :       new RequestSendLocationEvent(aPosition, this,
     475               6 :                                    mIsWatchPositionRequest ? nsnull : mLocator);
     476               2 :   NS_DispatchToMainThread(ev);
     477               2 :   return true;
     478                 : }
     479                 : 
     480                 : void
     481               0 : nsGeolocationRequest::Shutdown()
     482                 : {
     483               0 :   if (mTimeoutTimer) {
     484               0 :     mTimeoutTimer->Cancel();
     485               0 :     mTimeoutTimer = nsnull;
     486                 :   }
     487               0 :   mCleared = true;
     488               0 :   mCallback = nsnull;
     489               0 :   mErrorCallback = nsnull;
     490               0 : }
     491                 : 
     492               0 : bool nsGeolocationRequest::Recv__delete__(const bool& allow)
     493                 : {
     494               0 :   if (allow)
     495               0 :     (void) Allow();
     496                 :   else
     497               0 :     (void) Cancel();
     498               0 :   return true;
     499                 : }
     500                 : ////////////////////////////////////////////////////
     501                 : // nsGeolocationService
     502                 : ////////////////////////////////////////////////////
     503              19 : NS_INTERFACE_MAP_BEGIN(nsGeolocationService)
     504              19 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIGeolocationUpdate)
     505              16 :   NS_INTERFACE_MAP_ENTRY(nsIGeolocationUpdate)
     506              13 :   NS_INTERFACE_MAP_ENTRY(nsIObserver)
     507              13 : NS_INTERFACE_MAP_END
     508                 : 
     509              14 : NS_IMPL_THREADSAFE_ADDREF(nsGeolocationService)
     510              15 : NS_IMPL_THREADSAFE_RELEASE(nsGeolocationService)
     511                 : 
     512                 : 
     513                 : static bool sGeoEnabled = true;
     514                 : static bool sGeoIgnoreLocationFilter = false;
     515                 : static PRInt32 sProviderTimeout = 6000; // Time, in milliseconds, to wait for the location provider to spin up.
     516                 : 
     517               1 : nsresult nsGeolocationService::Init()
     518                 : {
     519               1 :   Preferences::AddIntVarCache(&sProviderTimeout, "geo.timeout", sProviderTimeout);
     520               1 :   Preferences::AddBoolVarCache(&sGeoEnabled, "geo.enabled", sGeoEnabled);
     521               1 :   Preferences::AddBoolVarCache(&sGeoIgnoreLocationFilter, "geo.ignore.location_filter", sGeoIgnoreLocationFilter);
     522                 : 
     523               1 :   if (!sGeoEnabled)
     524               0 :     return NS_ERROR_FAILURE;
     525                 : 
     526               2 :   nsCOMPtr<nsIGeolocationProvider> provider = do_GetService(NS_GEOLOCATION_PROVIDER_CONTRACTID);
     527               1 :   if (provider)
     528               1 :     mProviders.AppendObject(provider);
     529                 : 
     530                 :   // look up any providers that were registered via the category manager
     531               2 :   nsCOMPtr<nsICategoryManager> catMan(do_GetService("@mozilla.org/categorymanager;1"));
     532               1 :   if (!catMan)
     533               0 :     return NS_ERROR_FAILURE;
     534                 : 
     535                 :   // geolocation service can be enabled -> now register observer
     536               2 :   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     537               1 :   if (!obs)
     538               0 :     return NS_ERROR_FAILURE;
     539                 : 
     540               1 :   obs->AddObserver(this, "quit-application", false);
     541                 : 
     542               2 :   nsCOMPtr<nsISimpleEnumerator> geoproviders;
     543               1 :   catMan->EnumerateCategory("geolocation-provider", getter_AddRefs(geoproviders));
     544               1 :   if (geoproviders) {
     545                 : 
     546                 :     bool hasMore;
     547               3 :     while (NS_SUCCEEDED(geoproviders->HasMoreElements(&hasMore)) && hasMore) {
     548               2 :       nsCOMPtr<nsISupports> elem;
     549               1 :       geoproviders->GetNext(getter_AddRefs(elem));
     550                 : 
     551               2 :       nsCOMPtr<nsISupportsCString> elemString = do_QueryInterface(elem);
     552                 :       
     553               2 :       nsCAutoString name;
     554               1 :       elemString->GetData(name);
     555                 : 
     556               2 :       nsXPIDLCString spec;
     557               1 :       catMan->GetCategoryEntry("geolocation-provider", name.get(), getter_Copies(spec));
     558                 : 
     559               1 :       provider = do_GetService(spec);
     560               1 :       if (provider)
     561               1 :         mProviders.AppendObject(provider);
     562                 :     }
     563                 :   }
     564                 : 
     565                 :   // we should move these providers outside of this file! dft
     566                 : 
     567                 : #ifdef MOZ_MAEMO_LIBLOCATION
     568                 :   provider = new MaemoLocationProvider();
     569                 :   if (provider)
     570                 :     mProviders.AppendObject(provider);
     571                 : #endif
     572                 : 
     573                 : #ifdef MOZ_ENABLE_QTMOBILITY
     574                 :   provider = new QTMLocationProvider();
     575                 :   if (provider)
     576                 :     mProviders.AppendObject(provider);
     577                 : #endif
     578                 : 
     579                 : #ifdef MOZ_WIDGET_ANDROID
     580                 :   provider = new AndroidLocationProvider();
     581                 :   if (provider)
     582                 :     mProviders.AppendObject(provider);
     583                 : #endif
     584                 : 
     585                 : #ifdef MOZ_WIDGET_GONK
     586                 :   provider = GonkGPSGeolocationProvider::GetSingleton();
     587                 :   if (provider)
     588                 :     mProviders.AppendObject(provider);
     589                 : #endif
     590                 : 
     591               1 :   return NS_OK;
     592                 : }
     593                 : 
     594               1 : nsGeolocationService::~nsGeolocationService()
     595                 : {
     596               1 : }
     597                 : 
     598                 : NS_IMETHODIMP
     599               1 : nsGeolocationService::Observe(nsISupports* aSubject,
     600                 :                               const char* aTopic,
     601                 :                               const PRUnichar* aData)
     602                 : {
     603               1 :   if (!strcmp("quit-application", aTopic))
     604                 :   {
     605               0 :     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     606               0 :     if (obs) {
     607               0 :       obs->RemoveObserver(this, "quit-application");
     608                 :     }
     609                 : 
     610               0 :     for (PRUint32 i = 0; i< mGeolocators.Length(); i++)
     611               0 :       mGeolocators[i]->Shutdown();
     612                 : 
     613               0 :     StopDevice();
     614                 : 
     615               0 :     return NS_OK;
     616                 :   }
     617                 :   
     618               1 :   if (!strcmp("timer-callback", aTopic))
     619                 :   {
     620                 :     // decide if we can close down the service.
     621               2 :     for (PRUint32 i = 0; i< mGeolocators.Length(); i++)
     622               1 :       if (mGeolocators[i]->HasActiveCallbacks())
     623                 :       {
     624               0 :         SetDisconnectTimer();
     625               0 :         return NS_OK;
     626                 :       }
     627                 :     
     628                 :     // okay to close up.
     629               1 :     StopDevice();
     630               1 :     Update(nsnull);
     631               1 :     return NS_OK;
     632                 :   }
     633                 : 
     634               0 :   return NS_ERROR_FAILURE;
     635                 : }
     636                 : 
     637                 : NS_IMETHODIMP
     638               2 : nsGeolocationService::Update(nsIDOMGeoPosition *aSomewhere)
     639                 : {
     640               2 :   SetCachedPosition(aSomewhere);
     641                 : 
     642               4 :   for (PRUint32 i = 0; i< mGeolocators.Length(); i++)
     643               2 :     mGeolocators[i]->Update(aSomewhere);
     644               2 :   return NS_OK;
     645                 : }
     646                 : 
     647                 : void
     648               2 : nsGeolocationService::SetCachedPosition(nsIDOMGeoPosition* aPosition)
     649                 : {
     650               2 :   mLastPosition = aPosition;
     651               2 : }
     652                 : 
     653                 : nsIDOMGeoPosition*
     654               1 : nsGeolocationService::GetCachedPosition()
     655                 : {
     656               1 :   return mLastPosition;
     657                 : }
     658                 : 
     659                 : nsresult
     660               1 : nsGeolocationService::StartDevice()
     661                 : {
     662               1 :   if (!sGeoEnabled)
     663               0 :     return NS_ERROR_NOT_AVAILABLE;
     664                 : 
     665                 :   // we do not want to keep the geolocation devices online
     666                 :   // indefinitely.  Close them down after a reasonable period of
     667                 :   // inactivivity
     668               1 :   SetDisconnectTimer();
     669                 : 
     670               1 :   if (XRE_GetProcessType() == GeckoProcessType_Content) {
     671               0 :     ContentChild* cpc = ContentChild::GetSingleton();
     672               0 :     cpc->SendAddGeolocationListener();
     673               0 :     return NS_OK;
     674                 :   }
     675                 : 
     676                 :   // Start them up!
     677               2 :   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     678               1 :   if (!obs)
     679               0 :     return NS_ERROR_FAILURE;
     680                 : 
     681               3 :   for (PRInt32 i = 0; i < mProviders.Count(); i++) {
     682               2 :     mProviders[i]->Startup();
     683               2 :     mProviders[i]->Watch(this);
     684               4 :     obs->NotifyObservers(mProviders[i],
     685                 :                          "geolocation-device-events",
     686               4 :                          NS_LITERAL_STRING("starting").get());
     687                 :   }
     688                 : 
     689               1 :   return NS_OK;
     690                 : }
     691                 : 
     692                 : void
     693               1 : nsGeolocationService::SetDisconnectTimer()
     694                 : {
     695               1 :   if (!mDisconnectTimer)
     696               1 :     mDisconnectTimer = do_CreateInstance("@mozilla.org/timer;1");
     697                 :   else
     698               0 :     mDisconnectTimer->Cancel();
     699                 : 
     700               1 :   mDisconnectTimer->Init(this,
     701                 :                          sProviderTimeout,
     702               1 :                          nsITimer::TYPE_ONE_SHOT);
     703               1 : }
     704                 : 
     705                 : void 
     706               1 : nsGeolocationService::StopDevice()
     707                 : {
     708               1 :   if(mDisconnectTimer) {
     709               1 :     mDisconnectTimer->Cancel();
     710               1 :     mDisconnectTimer = nsnull;
     711                 :   }
     712                 : 
     713               1 :   if (XRE_GetProcessType() == GeckoProcessType_Content) {
     714               0 :     ContentChild* cpc = ContentChild::GetSingleton();
     715               0 :     cpc->SendRemoveGeolocationListener();
     716               0 :     return; // bail early
     717                 :   }
     718                 : 
     719               2 :   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     720               1 :   if (!obs)
     721                 :     return;
     722                 : 
     723               3 :   for (PRInt32 i = 0; i < mProviders.Count(); i++) {
     724               2 :     mProviders[i]->Shutdown();
     725               4 :     obs->NotifyObservers(mProviders[i],
     726                 :                          "geolocation-device-events",
     727               4 :                          NS_LITERAL_STRING("shutdown").get());
     728                 :   }
     729                 : }
     730                 : 
     731                 : nsGeolocationService* nsGeolocationService::gService = nsnull;
     732                 : 
     733                 : nsGeolocationService*
     734               3 : nsGeolocationService::GetInstance()
     735                 : {
     736               3 :   if (!nsGeolocationService::gService) {
     737               1 :     nsGeolocationService::gService = new nsGeolocationService();
     738               1 :     NS_ASSERTION(nsGeolocationService::gService, "null nsGeolocationService.");
     739                 : 
     740               1 :     if (nsGeolocationService::gService) {
     741               1 :       if (NS_FAILED(nsGeolocationService::gService->Init())) {
     742               0 :         delete nsGeolocationService::gService;
     743               0 :         nsGeolocationService::gService = nsnull;
     744                 :       }        
     745                 :     }
     746                 :   }
     747               3 :   return nsGeolocationService::gService;
     748                 : }
     749                 : 
     750                 : nsGeolocationService*
     751               1 : nsGeolocationService::GetGeolocationService()
     752                 : {
     753               1 :   nsGeolocationService* inst = nsGeolocationService::GetInstance();
     754               1 :   NS_IF_ADDREF(inst);
     755               1 :   return inst;
     756                 : }
     757                 : 
     758                 : void
     759               1 : nsGeolocationService::AddLocator(nsGeolocation* aLocator)
     760                 : {
     761               1 :   mGeolocators.AppendElement(aLocator);
     762               1 : }
     763                 : 
     764                 : void
     765               1 : nsGeolocationService::RemoveLocator(nsGeolocation* aLocator)
     766                 : {
     767               1 :   mGeolocators.RemoveElement(aLocator);
     768               1 : }
     769                 : 
     770                 : ////////////////////////////////////////////////////
     771                 : // nsGeolocation
     772                 : ////////////////////////////////////////////////////
     773                 : 
     774                 : DOMCI_DATA(GeoGeolocation, nsGeolocation)
     775                 : 
     776              29 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGeolocation)
     777               9 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMGeoGeolocation)
     778               8 :   NS_INTERFACE_MAP_ENTRY(nsIDOMGeoGeolocation)
     779               5 :   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(GeoGeolocation)
     780               4 : NS_INTERFACE_MAP_END
     781                 : 
     782               9 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGeolocation)
     783              10 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGeolocation)
     784            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsGeolocation)
     785                 : 
     786               1 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGeolocation)
     787               1 :   tmp->mPendingCallbacks.Clear();
     788               1 :   tmp->mWatchingCallbacks.Clear();
     789               1 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     790                 : 
     791               2 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsGeolocation)
     792                 :   PRUint32 i; 
     793               2 :   for (i = 0; i < tmp->mPendingCallbacks.Length(); ++i)
     794               0 :     NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mPendingCallbacks[i], nsIContentPermissionRequest)
     795                 : 
     796               4 :   for (i = 0; i < tmp->mWatchingCallbacks.Length(); ++i)
     797               2 :     NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mWatchingCallbacks[i], nsIContentPermissionRequest)
     798               2 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     799                 : 
     800               1 : nsGeolocation::nsGeolocation() 
     801                 : {
     802               1 : }
     803                 : 
     804               2 : nsGeolocation::~nsGeolocation()
     805                 : {
     806               1 :   if (mService)
     807               1 :     Shutdown();
     808               1 : }
     809                 : 
     810                 : nsresult
     811               1 : nsGeolocation::Init(nsIDOMWindow* aContentDom)
     812                 : {
     813                 :   // Remember the window
     814               1 :   if (aContentDom) {
     815               0 :     nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aContentDom);
     816               0 :     if (!window)
     817               0 :       return NS_ERROR_FAILURE;
     818                 : 
     819               0 :     mOwner = do_GetWeakReference(window->GetCurrentInnerWindow());
     820               0 :     if (!mOwner)
     821               0 :       return NS_ERROR_FAILURE;
     822                 : 
     823                 :     // Grab the uri of the document
     824               0 :     nsCOMPtr<nsIDOMDocument> domdoc;
     825               0 :     aContentDom->GetDocument(getter_AddRefs(domdoc));
     826               0 :     nsCOMPtr<nsIDocument> doc = do_QueryInterface(domdoc);
     827               0 :     if (!doc)
     828               0 :       return NS_ERROR_FAILURE;
     829                 : 
     830               0 :     doc->NodePrincipal()->GetURI(getter_AddRefs(mURI));
     831                 :     
     832               0 :     if (!mURI)
     833               0 :       return NS_ERROR_FAILURE;
     834                 :   }
     835                 : 
     836                 :   // If no aContentDom was passed into us, we are being used
     837                 :   // by chrome/c++ and have no mOwner, no mURI, and no need
     838                 :   // to prompt.
     839               1 :   mService = nsGeolocationService::GetInstance();
     840               1 :   if (mService)
     841               1 :     mService->AddLocator(this);
     842                 : 
     843               1 :   return NS_OK;
     844                 : }
     845                 : 
     846                 : void
     847               1 : nsGeolocation::Shutdown()
     848                 : {
     849                 :   // Shutdown and release all callbacks
     850               1 :   for (PRUint32 i = 0; i< mPendingCallbacks.Length(); i++)
     851               0 :     mPendingCallbacks[i]->Shutdown();
     852               1 :   mPendingCallbacks.Clear();
     853                 : 
     854               1 :   for (PRUint32 i = 0; i< mWatchingCallbacks.Length(); i++)
     855               0 :     mWatchingCallbacks[i]->Shutdown();
     856               1 :   mWatchingCallbacks.Clear();
     857                 : 
     858               1 :   if (mService)
     859               1 :     mService->RemoveLocator(this);
     860                 : 
     861               1 :   mService = nsnull;
     862               1 :   mURI = nsnull;
     863               1 : }
     864                 : 
     865                 : bool
     866               1 : nsGeolocation::HasActiveCallbacks()
     867                 : {
     868               2 :   for (PRUint32 i = 0; i < mWatchingCallbacks.Length(); i++)
     869               1 :     if (mWatchingCallbacks[i]->IsActive())
     870               0 :       return true;
     871                 : 
     872               1 :   return mPendingCallbacks.Length() != 0;
     873                 : }
     874                 : 
     875                 : void
     876               0 : nsGeolocation::RemoveRequest(nsGeolocationRequest* aRequest)
     877                 : {
     878               0 :   mPendingCallbacks.RemoveElement(aRequest);
     879                 : 
     880                 :   // if it is in the mWatchingCallbacks, we can't do much
     881                 :   // since we passed back the position in the array to who
     882                 :   // ever called WatchPosition() and we do not want to mess
     883                 :   // around with the ordering of the array.  Instead, just
     884                 :   // mark the request as "cleared".
     885                 : 
     886               0 :   aRequest->MarkCleared();
     887               0 : }
     888                 : 
     889                 : void
     890               2 : nsGeolocation::Update(nsIDOMGeoPosition *aSomewhere)
     891                 : {
     892               2 :   if (!WindowOwnerStillExists())
     893               0 :     return Shutdown();
     894                 : 
     895               2 :   for (PRUint32 i = mPendingCallbacks.Length(); i> 0; i--) {
     896               0 :     if (mPendingCallbacks[i-1]->Update(aSomewhere))
     897               0 :       mPendingCallbacks.RemoveElementAt(i-1);
     898                 :   }
     899                 : 
     900                 :   // notify everyone that is watching
     901               4 :   for (PRUint32 i = 0; i< mWatchingCallbacks.Length(); i++) {
     902               2 :     mWatchingCallbacks[i]->Update(aSomewhere);
     903                 :   }
     904                 : }
     905                 : 
     906                 : NS_IMETHODIMP
     907               0 : nsGeolocation::GetCurrentPosition(nsIDOMGeoPositionCallback *callback,
     908                 :                                   nsIDOMGeoPositionErrorCallback *errorCallback,
     909                 :                                   nsIDOMGeoPositionOptions *options)
     910                 : {
     911               0 :   NS_ENSURE_ARG_POINTER(callback);
     912                 : 
     913               0 :   if (!sGeoEnabled)
     914               0 :     return NS_ERROR_NOT_AVAILABLE;
     915                 : 
     916               0 :   if (mPendingCallbacks.Length() > MAX_GEO_REQUESTS_PER_WINDOW)
     917               0 :     return NS_ERROR_NOT_AVAILABLE;
     918                 : 
     919                 :   nsRefPtr<nsGeolocationRequest> request = new nsGeolocationRequest(this,
     920                 :                                                                     callback,
     921                 :                                                                     errorCallback,
     922                 :                                                                     options,
     923               0 :                                                                     false);
     924               0 :   if (!request)
     925               0 :     return NS_ERROR_OUT_OF_MEMORY;
     926                 : 
     927               0 :   if (NS_FAILED(request->Init()))
     928               0 :     return NS_ERROR_FAILURE; // this as OKAY.  not sure why we wouldn't throw. xxx dft
     929                 : 
     930               0 :   if (mOwner) {
     931               0 :     if (!RegisterRequestWithPrompt(request))
     932               0 :       return NS_ERROR_NOT_AVAILABLE;
     933                 :     
     934               0 :     mPendingCallbacks.AppendElement(request);
     935               0 :     return NS_OK;
     936                 :   }
     937                 : 
     938               0 :   if (!nsContentUtils::IsCallerChrome())
     939               0 :     return NS_ERROR_FAILURE;
     940                 : 
     941               0 :   mPendingCallbacks.AppendElement(request);
     942                 : 
     943               0 :   nsCOMPtr<nsIRunnable> ev = new RequestAllowEvent(true, request);
     944               0 :   NS_DispatchToMainThread(ev);
     945                 : 
     946               0 :   return NS_OK;
     947                 : }
     948                 : 
     949                 : NS_IMETHODIMP
     950               1 : nsGeolocation::WatchPosition(nsIDOMGeoPositionCallback *callback,
     951                 :                              nsIDOMGeoPositionErrorCallback *errorCallback,
     952                 :                              nsIDOMGeoPositionOptions *options,
     953                 :                              PRInt32 *_retval NS_OUTPARAM)
     954                 : {
     955                 : 
     956               1 :   NS_ENSURE_ARG_POINTER(callback);
     957                 : 
     958               1 :   if (!sGeoEnabled)
     959               0 :     return NS_ERROR_NOT_AVAILABLE;
     960                 : 
     961               1 :   if (mPendingCallbacks.Length() > MAX_GEO_REQUESTS_PER_WINDOW)
     962               0 :     return NS_ERROR_NOT_AVAILABLE;
     963                 : 
     964                 :   nsRefPtr<nsGeolocationRequest> request = new nsGeolocationRequest(this,
     965                 :                                                                     callback,
     966                 :                                                                     errorCallback,
     967                 :                                                                     options,
     968               2 :                                                                     true);
     969               1 :   if (!request)
     970               0 :     return NS_ERROR_OUT_OF_MEMORY;
     971                 : 
     972               1 :   if (NS_FAILED(request->Init()))
     973               0 :     return NS_ERROR_FAILURE; // this as OKAY.  not sure why we wouldn't throw. xxx dft
     974                 : 
     975               1 :   if (mOwner) {
     976               0 :     if (!RegisterRequestWithPrompt(request))
     977               0 :       return NS_ERROR_NOT_AVAILABLE;
     978                 : 
     979                 :     // need to hand back an index/reference.
     980               0 :     mWatchingCallbacks.AppendElement(request);
     981               0 :     *_retval = mWatchingCallbacks.Length() - 1;
     982                 : 
     983               0 :     return NS_OK;
     984                 :   }
     985                 : 
     986               1 :   if (!nsContentUtils::IsCallerChrome())
     987               0 :     return NS_ERROR_FAILURE;
     988                 : 
     989               1 :   request->Allow();
     990                 : 
     991                 :   // need to hand back an index/reference.
     992               1 :   mWatchingCallbacks.AppendElement(request);
     993               1 :   *_retval = mWatchingCallbacks.Length() - 1;
     994                 : 
     995               1 :   return NS_OK;
     996                 : }
     997                 : 
     998                 : NS_IMETHODIMP
     999               1 : nsGeolocation::ClearWatch(PRInt32 aWatchId)
    1000                 : {
    1001               1 :   PRUint32 count = mWatchingCallbacks.Length();
    1002               1 :   if (aWatchId < 0 || count == 0 || PRUint32(aWatchId) >= count)
    1003               0 :     return NS_OK;
    1004                 : 
    1005               1 :   mWatchingCallbacks[aWatchId]->MarkCleared();
    1006               1 :   return NS_OK;
    1007                 : }
    1008                 : 
    1009                 : bool
    1010               2 : nsGeolocation::WindowOwnerStillExists()
    1011                 : {
    1012                 :   // an owner was never set when nsGeolocation
    1013                 :   // was created, which means that this object
    1014                 :   // is being used without a window.
    1015               2 :   if (mOwner == nsnull)
    1016               2 :     return true;
    1017                 : 
    1018               0 :   nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mOwner);
    1019                 : 
    1020               0 :   if (window)
    1021                 :   {
    1022               0 :     bool closed = false;
    1023               0 :     window->GetClosed(&closed);
    1024               0 :     if (closed)
    1025               0 :       return false;
    1026                 : 
    1027               0 :     nsPIDOMWindow* outer = window->GetOuterWindow();
    1028               0 :     if (!outer || outer->GetCurrentInnerWindow() != window)
    1029               0 :       return false;
    1030                 :   }
    1031                 : 
    1032               0 :   return true;
    1033                 : }
    1034                 : 
    1035                 : bool
    1036               0 : nsGeolocation::RegisterRequestWithPrompt(nsGeolocationRequest* request)
    1037                 : {
    1038               0 :   if (Preferences::GetBool("geo.prompt.testing", false)) {
    1039                 :     nsCOMPtr<nsIRunnable> ev =
    1040                 :         new RequestAllowEvent(Preferences::GetBool("geo.prompt.testing.allow",
    1041               0 :                                                    false), request);
    1042               0 :     NS_DispatchToMainThread(ev);
    1043               0 :     return true;
    1044                 :   }
    1045                 : 
    1046               0 :   if (XRE_GetProcessType() == GeckoProcessType_Content) {
    1047               0 :     nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mOwner);
    1048               0 :     if (!window)
    1049               0 :       return true;
    1050                 : 
    1051                 :     // because owner implements nsITabChild, we can assume that it is
    1052                 :     // the one and only TabChild.
    1053               0 :     TabChild* child = GetTabChildFrom(window->GetDocShell());
    1054               0 :     if (!child)
    1055               0 :       return false;
    1056                 :     
    1057                 :     // Retain a reference so the object isn't deleted without IPDL's knowledge.
    1058                 :     // Corresponding release occurs in DeallocPContentPermissionRequest.
    1059               0 :     request->AddRef();
    1060                 : 
    1061               0 :     nsCString type = NS_LITERAL_CSTRING("geolocation");
    1062               0 :     child->SendPContentPermissionRequestConstructor(request, type, IPC::URI(mURI));
    1063                 :     
    1064               0 :     request->Sendprompt();
    1065               0 :     return true;
    1066                 :   }
    1067                 : 
    1068               0 :   nsCOMPtr<nsIRunnable> ev  = new RequestPromptEvent(request);
    1069               0 :   NS_DispatchToMainThread(ev);
    1070               0 :   return true;
    1071            4392 : }
    1072                 : 

Generated by: LCOV version 1.7