Bug 850442 - Part 3 - Convert callbacks, Geolocation and Position. r=bz
authorGuilherme Gonçalves <ggoncalves@mozilla.com>
Fri, 12 Apr 2013 11:46:36 -0700
changeset 139603 37b472c847b1137a81e0081c058ee87fd8b28ce4
parent 139602 394ca10bb287fd6d21fa92ded56a2b94d78d6e9f
child 139604 23e907c7c1068a8ec48a8e60d68adc5af4113e74
push id2579
push userakeybl@mozilla.com
push dateMon, 24 Jun 2013 18:52:47 +0000
treeherdermozilla-beta@b69b7de8a05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs850442
milestone23.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 850442 - Part 3 - Convert callbacks, Geolocation and Position. r=bz
dom/base/Navigator.h
dom/bindings/Bindings.conf
dom/interfaces/geolocation/moz.build
dom/interfaces/geolocation/nsIDOMGeoGeolocation.idl
dom/interfaces/geolocation/nsIGeolocation.idl
dom/ipc/ContentParent.cpp
dom/src/geolocation/nsGeoPosition.h
dom/src/geolocation/nsGeolocation.cpp
dom/src/geolocation/nsGeolocation.h
dom/tests/mochitest/geolocation/Makefile.in
dom/tests/mochitest/geolocation/test_cachedPosition.html
dom/tests/mochitest/geolocation/test_optional_api_params.html
dom/webidl/Geolocation.webidl
dom/webidl/WebIDL.mk
testing/mochitest/android.json
testing/mochitest/b2g.json
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -26,20 +26,25 @@
 #endif
 #include "nsAutoPtr.h"
 #include "nsIDOMNavigatorTime.h"
 #include "nsWeakReference.h"
 #include "DeviceStorage.h"
 
 class nsPluginArray;
 class nsMimeTypeArray;
-class nsGeolocation;
 class nsPIDOMWindow;
 class nsIDOMMozConnection;
 
+namespace mozilla {
+namespace dom {
+class nsGeolocation;
+}
+}
+
 #ifdef MOZ_MEDIA_NAVIGATOR
 #include "nsIDOMNavigatorUserMedia.h"
 #endif
 
 #ifdef MOZ_B2G_RIL
 #include "nsIDOMNavigatorTelephony.h"
 class nsIDOMTelephony;
 #endif
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -343,16 +343,21 @@ DOMInterfaces = {
     'headerFile': 'nsDOMFile.h',
     'resultNotAddRefed': [ 'item' ]
 },
 
 'FileReaderSync': {
     'workers': True,
 },
 
+'Geolocation': {
+    'nativeType': 'mozilla::dom::nsGeolocation',
+    'headerFile': 'nsGeolocation.h'
+},
+
 'UndoManager': [
 {
     'implicitJSContext' : [ 'undo', 'redo', 'transact' ]
 }],
 
 'FileRequest': {
     'nativeType': 'mozilla::dom::file::DOMFileRequest',
 },
--- a/dom/interfaces/geolocation/moz.build
+++ b/dom/interfaces/geolocation/moz.build
@@ -7,17 +7,16 @@
 XPIDL_SOURCES += [
     'nsIDOMGeoGeolocation.idl',
     'nsIDOMGeoPosition.idl',
     'nsIDOMGeoPositionCallback.idl',
     'nsIDOMGeoPositionCoords.idl',
     'nsIDOMGeoPositionError.idl',
     'nsIDOMGeoPositionErrorCallback.idl',
     'nsIDOMNavigatorGeolocation.idl',
-    'nsIGeolocation.idl',
 ]
 
 XPIDL_MODULE = 'dom_geolocation'
 
 XPIDL_FLAGS += [
     '-I$(topsrcdir)/dom/interfaces/base',
 ]
 
--- a/dom/interfaces/geolocation/nsIDOMGeoGeolocation.idl
+++ b/dom/interfaces/geolocation/nsIDOMGeoGeolocation.idl
@@ -1,35 +1,33 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "domstubs.idl"
 
-interface nsIDOMGeoPosition;
-interface nsIDOMGeoPositionOptions;
 interface nsIDOMGeoPositionCallback;
 interface nsIDOMGeoPositionErrorCallback;
 
+%{C++
+#include "DictionaryHelpers.h"
+%}
+
 dictionary GeoPositionOptions
 {
   boolean enableHighAccuracy;
   long timeout;
   long maximumAge;
 };
 
-[scriptable, uuid(b9a301f7-285b-4be9-b739-fb869019c77a)]
+[ptr] native NamespacedGeoPositionOptions(mozilla::idl::GeoPositionOptions);
+
+[scriptable, builtinclass, uuid(1bc7d103-c7ae-4467-881c-21a8dfa17938)]
 interface nsIDOMGeoGeolocation : nsISupports
 {
-  [implicit_jscontext]
-  void getCurrentPosition(in nsIDOMGeoPositionCallback successCallback,
-                          [optional] in nsIDOMGeoPositionErrorCallback errorCallback,
-                          /* GeoPositionOptions */
-                          [optional] in jsval options);
-
-  [implicit_jscontext]
-  long watchPosition(in nsIDOMGeoPositionCallback successCallback,
-                     [optional] in nsIDOMGeoPositionErrorCallback errorCallback,
-                     /* GeoPositionOptions */
-                     [optional] in jsval options);
-
+  int32_t watchPosition(in nsIDOMGeoPositionCallback callback,
+                        in nsIDOMGeoPositionErrorCallback errorCallback,
+                        in NamespacedGeoPositionOptions options);
+  void getCurrentPosition(in nsIDOMGeoPositionCallback callback,
+                          in nsIDOMGeoPositionErrorCallback errorCallback,
+                          in NamespacedGeoPositionOptions options);
   void clearWatch(in long watchId);
 };
deleted file mode 100644
--- a/dom/interfaces/geolocation/nsIGeolocation.idl
+++ /dev/null
@@ -1,29 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "domstubs.idl"
-
-interface nsIDOMGeoPositionCallback;
-interface nsIDOMGeoPositionErrorCallback;
-[ptr] native GeoPositionOptions(mozilla::idl::GeoPositionOptions);
-
-%{C++
-namespace mozilla {
-namespace idl {
-class GeoPositionOptions;
-}
-}
-%}
-
-[scriptable, builtinclass, uuid(d8e6449f-92c8-4c6a-aa9f-fef70157ec29)]
-interface nsIGeolocation : nsISupports
-{
-  // Versions of the DOM APIs that don't require JS option values
-  int32_t watchPosition(in nsIDOMGeoPositionCallback callback,
-                        in nsIDOMGeoPositionErrorCallback errorCallback,
-                        in GeoPositionOptions options);
-  void getCurrentPosition(in nsIDOMGeoPositionCallback callback,
-                          in nsIDOMGeoPositionErrorCallback errorCallback,
-                          in GeoPositionOptions options);
-};
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -79,17 +79,16 @@
 #include "nsSystemInfo.h"
 #include "nsThreadUtils.h"
 #include "nsToolkitCompsCID.h"
 #include "nsWidgetsCID.h"
 #include "SandboxHal.h"
 #include "StructuredCloneUtils.h"
 #include "TabParent.h"
 #include "URIUtils.h"
-#include "nsGeolocation.h"
 
 #ifdef ANDROID
 # include "gfxAndroidPlatform.h"
 #endif
 
 #ifdef MOZ_CRASHREPORTER
 # include "nsExceptionHandler.h"
 # include "nsICrashReporter.h"
@@ -2365,17 +2364,17 @@ ContentParent::RecvFilePathUpdateNotify(
     }
     obs->NotifyObservers(dsf, "file-watcher-update", NS_ConvertASCIItoUTF16(aReason).get());
     return true;
 }
 
 static int32_t
 AddGeolocationListener(nsIDOMGeoPositionCallback* watcher, bool highAccuracy)
 {
-  nsCOMPtr<nsIGeolocation> geo = do_GetService("@mozilla.org/geolocation;1");
+  nsCOMPtr<nsIDOMGeoGeolocation> geo = do_GetService("@mozilla.org/geolocation;1");
   if (!geo) {
     return -1;
   }
 
   GeoPositionOptions* options = new GeoPositionOptions();
   options->enableHighAccuracy = highAccuracy;
   int32_t retval = 1;
   geo->WatchPosition(watcher, nullptr, options, &retval);
--- a/dom/src/geolocation/nsGeoPosition.h
+++ b/dom/src/geolocation/nsGeoPosition.h
@@ -92,16 +92,18 @@ public:
   nsISupports* GetParentObject() const;
 
   virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope) MOZ_OVERRIDE;
 
   Coordinates* Coords();
 
   uint64_t Timestamp() const;
 
+  nsIDOMGeoPosition* GetWrappedGeoPosition() { return mGeoPosition; }
+
 private:
   nsRefPtr<Coordinates> mCoordinates;
   nsCOMPtr<nsISupports> mParent;
   nsCOMPtr<nsIDOMGeoPosition> mGeoPosition;
 };
 
 class Coordinates MOZ_FINAL : public nsISupports,
                               public nsWrapperCache
--- a/dom/src/geolocation/nsGeolocation.cpp
+++ b/dom/src/geolocation/nsGeolocation.cpp
@@ -41,16 +41,17 @@
 #include "mozilla/Services.h"
 #include "mozilla/unused.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/ClearOnShutdown.h"
 
 #include <math.h>
 #include <algorithm>
+#include <limits>
 
 #ifdef MOZ_MAEMO_LIBLOCATION
 #include "MaemoLocationProvider.h"
 #endif
 
 #ifdef MOZ_ENABLE_QTMOBILITY
 #include "QTMLocationProvider.h"
 #endif
@@ -72,16 +73,29 @@
 
 // The settings key.
 #define GEO_SETINGS_ENABLED          "geolocation.enabled"
 
 using mozilla::unused;          // <snicker>
 using namespace mozilla;
 using namespace mozilla::dom;
 
+static mozilla::idl::GeoPositionOptions*
+GeoPositionOptionsFromPositionOptions(const PositionOptions& aOptions)
+{
+  nsAutoPtr<mozilla::idl::GeoPositionOptions> geoOptions(
+    new mozilla::idl::GeoPositionOptions());
+
+  geoOptions->enableHighAccuracy = aOptions.mEnableHighAccuracy;
+  geoOptions->maximumAge = aOptions.mMaximumAge;
+  geoOptions->timeout = aOptions.mTimeout;
+
+  return geoOptions.forget();
+}
+
 class GeolocationSettingsCallback : public nsISettingsServiceCallback
 {
 public:
   NS_DECL_ISUPPORTS
 
   GeolocationSettingsCallback() {
     MOZ_COUNT_CTOR(GeolocationSettingsCallback);
   }
@@ -169,34 +183,37 @@ private:
 
 class RequestSendLocationEvent : public nsRunnable
 {
 public:
   // a bit funky.  if locator is passed, that means this
   // event should remove the request from it.  If we ever
   // have to do more, then we can change this around.
   RequestSendLocationEvent(nsIDOMGeoPosition* aPosition,
+                           bool aCachePosition,
                            nsGeolocationRequest* aRequest,
                            nsGeolocation* aLocator)
     : mPosition(aPosition),
+      mCachePosition(aCachePosition),
       mRequest(aRequest),
       mLocator(aLocator)
   {
   }
 
   NS_IMETHOD Run() {
-    mRequest->SendLocation(mPosition);
+    mRequest->SendLocation(mPosition, mCachePosition);
     if (mLocator) {
       mLocator->RemoveRequest(mRequest);
     }
     return NS_OK;
   }
 
 private:
-  nsCOMPtr<nsIDOMGeoPosition>    mPosition;
+  nsCOMPtr<nsIDOMGeoPosition> mPosition;
+  bool mCachePosition;
   nsRefPtr<nsGeolocationRequest> mRequest;
 
   nsRefPtr<nsGeolocation>        mLocator;
 };
 
 class RequestRestartTimerEvent : public nsRunnable
 {
 public:
@@ -257,42 +274,50 @@ PositionError::GetParentObject() const
 
 JSObject*
 PositionError::WrapObject(JSContext* aCx, JSObject* aScope)
 {
   return PositionErrorBinding::Wrap(aCx, aScope, this);
 }
 
 void
-PositionError::NotifyCallback(nsIDOMGeoPositionErrorCallback* aCallback)
+PositionError::NotifyCallback(const GeoPositionErrorCallback& aCallback)
 {
-  if (!aCallback) {
-    return;
-  }
-
   // Ensure that the proper context is on the stack (bug 452762)
   nsCOMPtr<nsIJSContextStack> stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1"));
   if (!stack || NS_FAILED(stack->Push(nullptr))) {
     return;
   }
 
   nsAutoMicroTask mt;
-  aCallback->HandleEvent(this);
+  if (aCallback.HasWebIDLCallback()) {
+    PositionErrorCallback* callback = aCallback.GetWebIDLCallback();
+
+    if (callback) {
+      ErrorResult err;
+      callback->Call(*this, err);
+    }
+  } else {
+    nsIDOMGeoPositionErrorCallback* callback = aCallback.GetXPCOMCallback();
+    if (callback) {
+      callback->HandleEvent(this);
+    }
+  }
 
   // remove the stack
   JSContext* cx;
   stack->Pop(&cx);
 }
 ////////////////////////////////////////////////////
 // nsGeolocationRequest
 ////////////////////////////////////////////////////
 
 nsGeolocationRequest::nsGeolocationRequest(nsGeolocation* aLocator,
-                                           nsIDOMGeoPositionCallback* aCallback,
-                                           nsIDOMGeoPositionErrorCallback* aErrorCallback,
+                                           const GeoPositionCallback& aCallback,
+                                           const GeoPositionErrorCallback& aErrorCallback,
                                            mozilla::idl::GeoPositionOptions* aOptions,
                                            bool aWatchPositionRequest,
                                            int32_t aWatchId)
   : mAllowed(false),
     mCleared(false),
     mIsFirstUpdate(true),
     mIsWatchPositionRequest(aWatchPositionRequest),
     mCallback(aCallback),
@@ -302,33 +327,16 @@ nsGeolocationRequest::nsGeolocationReque
     mWatchId(aWatchId)
 {
 }
 
 nsGeolocationRequest::~nsGeolocationRequest()
 {
 }
 
-
-static mozilla::idl::GeoPositionOptions*
-OptionsFromJSOptions(JSContext* aCx, const JS::Value& aOptions, nsresult* aRv)
-{
-  *aRv = NS_OK;
-  nsAutoPtr<mozilla::idl::GeoPositionOptions> options(nullptr);
-  if (aCx && !JSVAL_IS_VOID(aOptions) && !JSVAL_IS_NULL(aOptions)) {
-    options = new mozilla::idl::GeoPositionOptions();
-    nsresult rv = options->Init(aCx, &aOptions);
-    if (NS_FAILED(rv)) {
-      *aRv = rv;
-      return nullptr;
-    }
-  }
-  return options.forget();
-}
-
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGeolocationRequest)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentPermissionRequest)
   NS_INTERFACE_MAP_ENTRY(nsIContentPermissionRequest)
   NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGeolocationRequest)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGeolocationRequest)
@@ -467,19 +475,20 @@ nsGeolocationRequest::Allow()
   gs->SetHigherAccuracy(mOptions && mOptions->enableHighAccuracy);
 
   if (lastPosition && maximumAge > 0 &&
       ( PRTime(PR_Now() / PR_USEC_PER_MSEC) - maximumAge <=
         PRTime(cachedPositionTime) )) {
     // okay, we can return a cached position
     mAllowed = true;
 
-    nsCOMPtr<nsIRunnable> ev = new RequestSendLocationEvent(lastPosition,
-							    this,
-							    mIsWatchPositionRequest ? nullptr : mLocator);
+    nsCOMPtr<nsIRunnable> ev =
+      new RequestSendLocationEvent(
+        lastPosition, true, this, mIsWatchPositionRequest ? nullptr : mLocator);
+
     NS_DispatchToMainThread(ev);
   }
 
   SetTimeoutTimer();
 
   mAllowed = true;
   return NS_OK;
 }
@@ -512,48 +521,66 @@ nsGeolocationRequest::MarkCleared()
   if (mTimeoutTimer) {
     mTimeoutTimer->Cancel();
     mTimeoutTimer = nullptr;
   }
   mCleared = true;
 }
 
 void
-nsGeolocationRequest::SendLocation(nsIDOMGeoPosition* aPosition)
+nsGeolocationRequest::SendLocation(nsIDOMGeoPosition* aPosition, bool aCachePosition)
 {
   if (mCleared || !mAllowed) {
     return;
   }
 
   if (mTimeoutTimer) {
     mTimeoutTimer->Cancel();
     mTimeoutTimer = nullptr;
   }
 
-  // we should not pass null back to the DOM.
-  if (!aPosition) {
+  nsRefPtr<Position> wrapped, cachedWrapper = mLocator->GetCachedPosition();
+  if (cachedWrapper && aPosition == cachedWrapper->GetWrappedGeoPosition()) {
+    wrapped = cachedWrapper;
+  } else if (aPosition) {
+    nsCOMPtr<nsIDOMGeoPositionCoords> coords;
+    aPosition->GetCoords(getter_AddRefs(coords));
+    if (coords) {
+      wrapped = new Position(mLocator, aPosition);
+    }
+  }
+
+  if (!wrapped) {
     NotifyError(nsIDOMGeoPositionError::POSITION_UNAVAILABLE);
     return;
   }
 
-  nsCOMPtr<nsIDOMGeoPositionCoords> coords;
-  aPosition->GetCoords(getter_AddRefs(coords));
-  if (!coords) {
-    NotifyError(nsIDOMGeoPositionError::POSITION_UNAVAILABLE);
-    return;
+  if (aCachePosition) {
+    mLocator->SetCachedPosition(wrapped);
   }
 
   // Ensure that the proper context is on the stack (bug 452762)
   nsCOMPtr<nsIJSContextStack> stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1"));
   if (!stack || NS_FAILED(stack->Push(nullptr))) {
     return; // silently fail
   }
 
   nsAutoMicroTask mt;
-  mCallback->HandleEvent(aPosition);
+  if (mCallback.HasWebIDLCallback()) {
+    ErrorResult err;
+    PositionCallback* callback = mCallback.GetWebIDLCallback();
+
+    MOZ_ASSERT(callback);
+    callback->Call(*wrapped, err);
+  } else {
+    nsIDOMGeoPositionCallback* callback = mCallback.GetXPCOMCallback();
+
+    MOZ_ASSERT(callback);
+    callback->HandleEvent(aPosition);
+  }
 
   // remove the stack
   JSContext* cx;
   stack->Pop(&cx);
 
   if (mIsWatchPositionRequest) {
     SetTimeoutTimer();
   }
@@ -580,35 +607,34 @@ nsGeolocationRequest::Update(nsIDOMGeoPo
   // This ensures that all listeners get at least one position callback, particularly
   // in the case when newly detected positions are all less accurate than the cached one.
   //
   // Fixes bug 596481
   nsCOMPtr<nsIRunnable> ev;
   if (mIsFirstUpdate || aIsBetter) {
     mIsFirstUpdate = false;
     ev  = new RequestSendLocationEvent(aPosition,
+                                       aIsBetter,
                                        this,
-                                       mIsWatchPositionRequest ? nullptr : mLocator);
+                                       mIsWatchPositionRequest ? nullptr :  mLocator);
   } else {
     ev = new RequestRestartTimerEvent(this);
   }
   NS_DispatchToMainThread(ev);
   return true;
 }
 
 void
 nsGeolocationRequest::Shutdown()
 {
   if (mTimeoutTimer) {
     mTimeoutTimer->Cancel();
     mTimeoutTimer = nullptr;
   }
   mCleared = true;
-  mCallback = nullptr;
-  mErrorCallback = nullptr;
 
   // This should happen last, to ensure that this request isn't taken into consideration
   // when deciding whether existing requests still require high accuracy.
   if (mOptions && mOptions->enableHighAccuracy) {
     nsRefPtr<nsGeolocationService> gs = nsGeolocationService::GetGeolocationService();
     if (gs) {
       gs->SetHigherAccuracy(false);
     }
@@ -1124,42 +1150,48 @@ nsGeolocationService::RemoveLocator(nsGe
 
 ////////////////////////////////////////////////////
 // nsGeolocation
 ////////////////////////////////////////////////////
 
 DOMCI_DATA(GeoGeolocation, nsGeolocation)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGeolocation)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMGeoGeolocation)
   NS_INTERFACE_MAP_ENTRY(nsIDOMGeoGeolocation)
-  NS_INTERFACE_MAP_ENTRY(nsIGeolocation)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(GeoGeolocation)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGeolocation)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGeolocation)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGeolocation)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mCachedPosition)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
   tmp->mPendingRequests.Clear();
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingCallbacks)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mWatchingCallbacks)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsGeolocation)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCachedPosition)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
   for (uint32_t i = 0; i < tmp->mPendingRequests.Length(); ++i)
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingRequests[i].request)
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingCallbacks)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWatchingCallbacks)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(nsGeolocation)
 
 nsGeolocation::nsGeolocation()
 : mLastWatchId(0)
 {
+  SetIsDOMBinding();
 }
 
 nsGeolocation::~nsGeolocation()
 {
   if (mService) {
     Shutdown();
   }
 }
@@ -1215,16 +1247,22 @@ nsGeolocation::Shutdown()
   if (mService) {
     mService->RemoveLocator(this);
   }
 
   mService = nullptr;
   mPrincipal = nullptr;
 }
 
+nsIDOMWindow*
+nsGeolocation::GetParentObject() const {
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mOwner);
+  return window.get();
+}
+
 bool
 nsGeolocation::HasActiveCallbacks()
 {
   for (uint32_t i = 0; i < mWatchingCallbacks.Length(); i++) {
     if (mWatchingCallbacks[i]->IsActive()) {
       return true;
     }
   }
@@ -1280,36 +1318,66 @@ nsGeolocation::Update(nsIDOMGeoPosition 
   }
 
   // notify everyone that is watching
   for (uint32_t i = 0; i< mWatchingCallbacks.Length(); i++) {
     mWatchingCallbacks[i]->Update(aSomewhere, aIsBetter);
   }
 }
 
-NS_IMETHODIMP
-nsGeolocation::GetCurrentPosition(nsIDOMGeoPositionCallback *callback,
-                                  nsIDOMGeoPositionErrorCallback *errorCallback,
-                                  const JS::Value& jsoptions,
-                                  JSContext* cx)
+void
+nsGeolocation::SetCachedPosition(Position* aPosition)
+{
+  mCachedPosition = aPosition;
+}
+
+Position*
+nsGeolocation::GetCachedPosition()
 {
-  nsresult rv;
-  nsAutoPtr<mozilla::idl::GeoPositionOptions> options(
-      OptionsFromJSOptions(cx, jsoptions, &rv));
-  NS_ENSURE_SUCCESS(rv, rv);
-  return GetCurrentPosition(callback, errorCallback, options.forget());
+  return mCachedPosition;
+}
+
+void
+nsGeolocation::GetCurrentPosition(PositionCallback& aCallback,
+                                  PositionErrorCallback* aErrorCallback,
+                                  const PositionOptions& aOptions,
+                                  ErrorResult& aRv)
+{
+  GeoPositionCallback successCallback(&aCallback);
+  GeoPositionErrorCallback errorCallback(aErrorCallback);
+
+  nsresult rv =
+    GetCurrentPosition(successCallback, errorCallback,
+                       GeoPositionOptionsFromPositionOptions(aOptions));
+
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+  }
+
+  return;
 }
 
 NS_IMETHODIMP
-nsGeolocation::GetCurrentPosition(nsIDOMGeoPositionCallback *callback,
-                                  nsIDOMGeoPositionErrorCallback *errorCallback,
+nsGeolocation::GetCurrentPosition(nsIDOMGeoPositionCallback* aCallback,
+                                  nsIDOMGeoPositionErrorCallback* aErrorCallback,
+                                  mozilla::idl::GeoPositionOptions* aOptions)
+{
+  NS_ENSURE_ARG_POINTER(aCallback);
+
+  GeoPositionCallback successCallback(aCallback);
+  GeoPositionErrorCallback errorCallback(aErrorCallback);
+
+  return GetCurrentPosition(successCallback, errorCallback, aOptions);
+}
+
+nsresult
+nsGeolocation::GetCurrentPosition(GeoPositionCallback& callback,
+                                  GeoPositionErrorCallback& errorCallback,
                                   mozilla::idl::GeoPositionOptions *options)
 {
-  NS_ENSURE_ARG_POINTER(callback);
-
   if (mPendingCallbacks.Length() > MAX_GEO_REQUESTS_PER_WINDOW) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   nsRefPtr<nsGeolocationRequest> request = new nsGeolocationRequest(this,
                                                                     callback,
                                                                     errorCallback,
                                                                     options,
@@ -1352,51 +1420,70 @@ nsGeolocation::GetCurrentPositionReady(n
   }
 
   nsCOMPtr<nsIRunnable> ev = new RequestAllowEvent(true, aRequest);
   NS_DispatchToMainThread(ev);
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsGeolocation::WatchPosition(nsIDOMGeoPositionCallback *callback,
-                             nsIDOMGeoPositionErrorCallback *errorCallback,
-                             const JS::Value& jsoptions,
-                             JSContext* cx,
-                             int32_t *_retval)
+int32_t
+nsGeolocation::WatchPosition(PositionCallback& aCallback,
+                             PositionErrorCallback* aErrorCallback,
+                             const PositionOptions& aOptions,
+                             ErrorResult& aRv)
 {
-  nsresult rv;
-  nsAutoPtr<mozilla::idl::GeoPositionOptions> options(
-      OptionsFromJSOptions(cx, jsoptions, &rv));
-  NS_ENSURE_SUCCESS(rv, rv);
-  return WatchPosition(callback, errorCallback, options.forget(), _retval);
+  int32_t ret;
+  GeoPositionCallback successCallback(&aCallback);
+  GeoPositionErrorCallback errorCallback(aErrorCallback);
+
+  nsresult rv =
+    WatchPosition(successCallback, errorCallback,
+                  GeoPositionOptionsFromPositionOptions(aOptions), &ret);
+
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+  }
+
+  return ret;
 }
 
 NS_IMETHODIMP
-nsGeolocation::WatchPosition(nsIDOMGeoPositionCallback *callback,
-                             nsIDOMGeoPositionErrorCallback *errorCallback,
-                             mozilla::idl::GeoPositionOptions *options,
-                             int32_t *_retval)
+nsGeolocation::WatchPosition(nsIDOMGeoPositionCallback *aCallback,
+                             nsIDOMGeoPositionErrorCallback *aErrorCallback,
+                             mozilla::idl::GeoPositionOptions *aOptions,
+                             int32_t* aRv)
 {
-  NS_ENSURE_ARG_POINTER(callback);
+  NS_ENSURE_ARG_POINTER(aCallback);
+
+  GeoPositionCallback successCallback(aCallback);
+  GeoPositionErrorCallback errorCallback(aErrorCallback);
 
+  return WatchPosition(successCallback, errorCallback, aOptions, aRv);
+}
+
+nsresult
+nsGeolocation::WatchPosition(GeoPositionCallback& aCallback,
+                             GeoPositionErrorCallback& aErrorCallback,
+                             mozilla::idl::GeoPositionOptions* aOptions,
+                             int32_t* aRv)
+{
   if (mWatchingCallbacks.Length() > MAX_GEO_REQUESTS_PER_WINDOW) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   // The watch ID:
-  *_retval = mLastWatchId++;
+  *aRv = mLastWatchId++;
 
   nsRefPtr<nsGeolocationRequest> request = new nsGeolocationRequest(this,
-                                                                    callback,
-                                                                    errorCallback,
-                                                                    options,
+                                                                    aCallback,
+                                                                    aErrorCallback,
+                                                                    aOptions,
                                                                     true,
-                                                                    *_retval);
+                                                                    *aRv);
 
   if (!sGeoEnabled) {
     nsCOMPtr<nsIRunnable> ev = new RequestAllowEvent(false, request);
 
     // need to hand back an index/reference.
     mWatchingCallbacks.AppendElement(request);
 
     NS_DispatchToMainThread(ev);
@@ -1535,8 +1622,14 @@ nsGeolocation::RegisterRequestWithPrompt
     request->Sendprompt();
     return true;
   }
 
   nsCOMPtr<nsIRunnable> ev  = new RequestPromptEvent(request);
   NS_DispatchToMainThread(ev);
   return true;
 }
+
+JSObject*
+nsGeolocation::WrapObject(JSContext *aCtx, JSObject *aScope)
+{
+  return mozilla::dom::GeolocationBinding::Wrap(aCtx, aScope, this);
+}
--- a/dom/src/geolocation/nsGeolocation.h
+++ b/dom/src/geolocation/nsGeolocation.h
@@ -16,61 +16,70 @@
 #include "nsITimer.h"
 #include "nsIObserver.h"
 #include "nsIURI.h"
 #include "nsWrapperCache.h"
 
 #include "nsWeakPtr.h"
 #include "nsCycleCollectionParticipant.h"
 
+#include "nsGeoPosition.h"
 #include "nsIDOMGeoGeolocation.h"
 #include "nsIDOMGeoPosition.h"
 #include "nsIDOMGeoPositionError.h"
 #include "nsIDOMGeoPositionCallback.h"
 #include "nsIDOMGeoPositionErrorCallback.h"
 #include "nsIDOMNavigatorGeolocation.h"
-#include "nsIGeolocation.h"
+#include "mozilla/dom/GeolocationBinding.h"
 #include "mozilla/dom/PositionErrorBinding.h"
+#include "mozilla/dom/CallbackObject.h"
 
 #include "nsPIDOMWindow.h"
 
 #include "nsIGeolocationProvider.h"
 #include "nsIContentPermissionPrompt.h"
 #include "DictionaryHelpers.h"
 #include "PCOMContentPermissionRequestChild.h"
 #include "mozilla/Attributes.h"
 
 class nsGeolocationService;
+
+namespace mozilla {
+namespace dom {
 class nsGeolocation;
+typedef CallbackObjectHolder<PositionCallback, nsIDOMGeoPositionCallback> GeoPositionCallback;
+typedef CallbackObjectHolder<PositionErrorCallback, nsIDOMGeoPositionErrorCallback> GeoPositionErrorCallback;
+}
+}
 
 class nsGeolocationRequest
  : public nsIContentPermissionRequest
  , public nsITimerCallback
  , public PCOMContentPermissionRequestChild
 {
  public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_NSICONTENTPERMISSIONREQUEST
   NS_DECL_NSITIMERCALLBACK
 
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsGeolocationRequest, nsIContentPermissionRequest)
 
-  nsGeolocationRequest(nsGeolocation* locator,
-                       nsIDOMGeoPositionCallback* callback,
-                       nsIDOMGeoPositionErrorCallback* errorCallback,
+  nsGeolocationRequest(mozilla::dom::nsGeolocation* locator,
+                       const mozilla::dom::GeoPositionCallback& callback,
+                       const mozilla::dom::GeoPositionErrorCallback& errorCallback,
                        mozilla::idl::GeoPositionOptions* aOptions,
                        bool watchPositionRequest = false,
                        int32_t watchId = 0);
   void Shutdown();
 
   // Called by the geolocation device to notify that a location has changed.
   // isBetter: the accuracy is as good or better than the previous position. 
   bool Update(nsIDOMGeoPosition* aPosition, bool aIsBetter);
 
-  void SendLocation(nsIDOMGeoPosition* location);
+  void SendLocation(nsIDOMGeoPosition* location, bool aCachePosition);
   void MarkCleared();
   bool WantsHighAccuracy() {return mOptions && mOptions->enableHighAccuracy;}
   bool IsActive() {return !mCleared;}
   bool Allowed() {return mAllowed;}
   void SetTimeoutTimer();
   nsIPrincipal* GetPrincipal();
 
   ~nsGeolocationRequest();
@@ -83,21 +92,21 @@ class nsGeolocationRequest
 
   void NotifyError(int16_t errorCode);
   bool mAllowed;
   bool mCleared;
   bool mIsFirstUpdate;
   bool mIsWatchPositionRequest;
 
   nsCOMPtr<nsITimer> mTimeoutTimer;
-  nsCOMPtr<nsIDOMGeoPositionCallback> mCallback;
-  nsCOMPtr<nsIDOMGeoPositionErrorCallback> mErrorCallback;
+  mozilla::dom::GeoPositionCallback mCallback;
+  mozilla::dom::GeoPositionErrorCallback mErrorCallback;
   nsAutoPtr<mozilla::idl::GeoPositionOptions> mOptions;
 
-  nsRefPtr<nsGeolocation> mLocator;
+  nsRefPtr<mozilla::dom::nsGeolocation> mLocator;
 
   int32_t mWatchId;
 };
 
 /**
  * Singleton that manages the geolocation provider
  */
 class nsGeolocationService MOZ_FINAL : public nsIGeolocationUpdate, public nsIObserver
@@ -116,18 +125,18 @@ public:
   }
 
   nsresult Init();
 
   void HandleMozsettingChanged(const PRUnichar* aData);
   void HandleMozsettingValue(const bool aValue);
 
   // Management of the nsGeolocation objects
-  void AddLocator(nsGeolocation* locator);
-  void RemoveLocator(nsGeolocation* locator);
+  void AddLocator(mozilla::dom::nsGeolocation* locator);
+  void RemoveLocator(mozilla::dom::nsGeolocation* locator);
 
   void SetCachedPosition(nsIDOMGeoPosition* aPosition);
   nsIDOMGeoPosition* GetCachedPosition();
   bool IsBetterPosition(nsIDOMGeoPosition *aSomewhere);
 
   // Find and startup a geolocation device (gps, nmea, etc.)
   nsresult StartDevice(nsIPrincipal* aPrincipal, bool aRequestPrivate);
 
@@ -151,47 +160,57 @@ private:
   nsCOMPtr<nsITimer> mDisconnectTimer;
 
   // The object providing geo location information to us.
   nsCOMArray<nsIGeolocationProvider> mProviders;
 
   // mGeolocators are not owned here.  Their constructor
   // adds them to this list, and their destructor removes
   // them from this list.
-  nsTArray<nsGeolocation*> mGeolocators;
+  nsTArray<mozilla::dom::nsGeolocation*> mGeolocators;
 
   // This is the last geo position that we have seen.
   nsCOMPtr<nsIDOMGeoPosition> mLastPosition;
 
   // Current state of requests for higher accuracy
   bool mHigherAccuracy;
 };
 
+namespace mozilla {
+namespace dom {
 
 /**
  * Can return a geolocation info
  */
 class nsGeolocation MOZ_FINAL : public nsIDOMGeoGeolocation,
-                                public nsIGeolocation
+                                public nsWrapperCache
 {
 public:
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsGeolocation)
+
   NS_DECL_NSIDOMGEOGEOLOCATION
-  NS_DECL_NSIGEOLOCATION
-
-  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsGeolocation, nsIDOMGeoGeolocation)
 
   nsGeolocation();
 
   nsresult Init(nsIDOMWindow* contentDom=nullptr);
 
+  nsIDOMWindow* GetParentObject() const;
+  virtual JSObject* WrapObject(JSContext *aCtx, JSObject *aScope) MOZ_OVERRIDE;
+
+  int32_t WatchPosition(PositionCallback& aCallback, PositionErrorCallback* aErrorCallback, const PositionOptions& aOptions, ErrorResult& aRv);
+  void GetCurrentPosition(PositionCallback& aCallback, PositionErrorCallback* aErrorCallback, const PositionOptions& aOptions, ErrorResult& aRv);
+
   // Called by the geolocation device to notify that a location has changed.
   void Update(nsIDOMGeoPosition* aPosition, bool aIsBetter);
 
+  void SetCachedPosition(Position* aPosition);
+  Position* GetCachedPosition();
+
   // Returns true if any of the callbacks are repeating
   bool HasActiveCallbacks();
 
   // Remove request from all callbacks arrays
   void RemoveRequest(nsGeolocationRequest* request);
 
   // Shutting down.
   void Shutdown();
@@ -210,16 +229,19 @@ public:
 
   // Notification from the service:
   void ServiceReady();
 
 private:
 
   ~nsGeolocation();
 
+  nsresult GetCurrentPosition(GeoPositionCallback& aCallback, GeoPositionErrorCallback& aErrorCallback, mozilla::idl::GeoPositionOptions* aOptions);
+  nsresult WatchPosition(GeoPositionCallback& aCallback, GeoPositionErrorCallback& aErrorCallback, mozilla::idl::GeoPositionOptions* aOptions, int32_t* aRv);
+
   bool RegisterRequestWithPrompt(nsGeolocationRequest* request);
 
   // Methods for the service when it's ready to process requests:
   nsresult GetCurrentPositionReady(nsGeolocationRequest* aRequest);
   nsresult WatchPositionReady(nsGeolocationRequest* aRequest);
 
   // Two callback arrays.  The first |mPendingCallbacks| holds objects for only
   // one callback and then they are released/removed from the array.  The second
@@ -233,16 +255,19 @@ private:
   nsWeakPtr mOwner;
 
   // where the content was loaded from
   nsCOMPtr<nsIPrincipal> mPrincipal;
 
   // owning back pointer.
   nsRefPtr<nsGeolocationService> mService;
 
+  // cached Position wrapper
+  nsRefPtr<Position> mCachedPosition;
+
   // Watch ID
   uint32_t mLastWatchId;
 
   // Pending requests are used when the service is not ready:
   class PendingRequest
   {
   public:
     nsRefPtr<nsGeolocationRequest> request;
@@ -250,19 +275,16 @@ private:
       GetCurrentPosition,
       WatchPosition
     } type;
   };
 
   nsTArray<PendingRequest> mPendingRequests;
 };
 
-namespace mozilla {
-namespace dom {
-
 class PositionError MOZ_FINAL : public nsIDOMGeoPositionError,
                                 public nsWrapperCache
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(PositionError)
 
   NS_DECL_NSIDOMGEOPOSITIONERROR
@@ -276,17 +298,17 @@ public:
   int16_t Code() const {
     return mCode;
   }
 
   void GetMessage(nsString& aRetVal) const {
     aRetVal.Truncate();
   }
 
-  void NotifyCallback(nsIDOMGeoPositionErrorCallback* callback);
+  void NotifyCallback(const GeoPositionErrorCallback& callback);
 private:
   ~PositionError();
   int16_t mCode;
   nsRefPtr<nsGeolocation> mParent;
 };
 
 }
 }
--- a/dom/tests/mochitest/geolocation/Makefile.in
+++ b/dom/tests/mochitest/geolocation/Makefile.in
@@ -8,16 +8,17 @@ srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir	= @relativesrcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MOCHITEST_FILES	= \
 		test_allowCurrent.html \
 		test_allowWatch.html \
+		test_cachedPosition.html \
 		test_cancelCurrent.html \
 		test_cancelWatch.html \
 		test_clearWatch.html \
 		test_clearWatch_invalid.html \
 		test_manyCurrentConcurrent.html \
 		test_manyCurrentSerial.html \
 		test_manyWatchConcurrent.html \
 		test_manyWatchSerial.html \
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/geolocation/test_cachedPosition.html
@@ -0,0 +1,81 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=850442
+-->
+<head>
+  <title>Test for getCurrentPosition </title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="geolocation_common.js"></script>
+
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=850442">Mozilla Bug 850442</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+resume_geolocationProvider();
+force_prompt(true);
+
+function done() {
+  reset_prompt();
+  resume_geolocationProvider();
+  SimpleTest.finish();
+}
+
+function errorCallback(err) {
+  ok(false, "error callback should not have been called");
+  done();
+}
+
+function testCachedPosition() {
+  var cached = null;
+  navigator.geolocation.getCurrentPosition(function(pos) {
+    // get cached position
+    cached = pos;
+
+    navigator.geolocation.getCurrentPosition(function(pos) {
+      // force use of cached position, make sure
+      // it's equal to what we have
+      is(pos, cached, "position should be equal to cached position");
+      resume_geolocationProvider();
+
+      navigator.geolocation.getCurrentPosition(function(pos) {
+        // force new position, can't be the one we have
+        isnot(pos, cached, "new position should be different from the cached");
+        done();
+      }, errorCallback, {maximumAge: 0});
+    }, errorCallback, {maximumAge: 21600000});
+  }, errorCallback, {maximumAge: 21600000});
+}
+
+// ensure we have a position in cache,
+// and stop receiving new positions once we do so the
+// cache doesn't change
+var watchID;
+watchID = navigator.geolocation.watchPosition(
+  function(pos) {
+    info("Stopping geolocation provider");
+    stop_geolocationProvider();
+  }, function(err) {
+    is(err.code, err.TIMEOUT, "got TIMEOUT for watchPosition");
+
+    // no new positions in a while,
+    // the cache should be stable now.
+    navigator.geolocation.clearWatch(watchID);
+    testCachedPosition();
+  }, {maximumAge: 0, timeout: 1000}
+);
+
+</script>
+</pre>
+</body>
+</html>
+
--- a/dom/tests/mochitest/geolocation/test_optional_api_params.html
+++ b/dom/tests/mochitest/geolocation/test_optional_api_params.html
@@ -19,97 +19,79 @@ https://bugzilla.mozilla.org/show_bug.cg
 <script class="testbody" type="text/javascript">
 
 // ensure we are using the right testing provider
 resume_geolocationProvider();
 force_prompt(true)
 
 /** Test for Bug 452566 **/
 
-const NOT_ENOUGH_ARGS = 2153185281;
-
 ok(navigator.geolocation, "Should have geolocation");
 
 var exception = null;
 try {
   navigator.geolocation.getCurrentPosition();
-} catch(ex) {
-  if (ex.result == NOT_ENOUGH_ARGS) {
-    exception = ex;
-  }
+} catch(ex if ex instanceof TypeError) {
+  exception = ex;
 }
 ok(exception, "Should have got an exception");
 
 exception = null;
 try {
   navigator.geolocation.getCurrentPosition(function() {});
-} catch(ex) {
-  if (ex.result == NOT_ENOUGH_ARGS) {
-    exception = ex;
-  }
+} catch(ex if ex instanceof TypeError) {
+  exception = ex;
 }
 ok(!exception, exception);
 
 exception = null;
 try {
   navigator.geolocation.getCurrentPosition(function() {}, function() {});
-} catch(ex) {
-  if (ex.result == NOT_ENOUGH_ARGS) {
-    exception = ex;
-  }
+} catch(ex if ex instanceof TypeError) {
+  exception = ex;
 }
 ok(!exception, exception);
 
 exception = null;
 try {
   navigator.geolocation.getCurrentPosition(function() {}, function() {}, {});
-} catch(ex) {
-  if (ex.result == NOT_ENOUGH_ARGS) {
-    exception = ex;
-  }
+} catch(ex if ex instanceof TypeError) {
+  exception = ex;
 }
 ok(!exception, exception);
 
 exception = null;
 try {
   navigator.geolocation.watchPosition();
-} catch(ex) {
-  if (ex.result == NOT_ENOUGH_ARGS) {
-    exception = ex;
-  }
+} catch(ex if ex instanceof TypeError) {
+  exception = ex;
 }
 ok(exception, "Should have got an exception");
 
 exception = null;
 try {
   navigator.geolocation.watchPosition(function() {});
-} catch(ex) {
-  if (ex.result == NOT_ENOUGH_ARGS) {
-    exception = ex;
-  }
+} catch(ex if ex instanceof TypeError) {
+  exception = ex;
 }
 ok(!exception, exception);
 
 exception = null;
 try {
   navigator.geolocation.watchPosition(function() {}, function() {});
-} catch(ex) {
-  if (ex.result == NOT_ENOUGH_ARGS) {
-    exception = ex;
-  }
+} catch(ex if ex instanceof TypeError) {
+  exception = ex;
 }
 ok(!exception, exception);
 
 exception = null;
 try {
   navigator.geolocation.watchPosition(function() {}, function() {}, {});
-} catch(ex) {
-  if (ex.result == NOT_ENOUGH_ARGS) {
-    exception = ex;
-  }
+} catch(ex if ex instanceof TypeError) {
+  exception = ex;
 }
 ok(!exception, exception);
 
 // so clean up ready for the next test.
 reset_prompt();
 
 </script>
 </pre>
new file mode 100644
--- /dev/null
+++ b/dom/webidl/Geolocation.webidl
@@ -0,0 +1,36 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * http://www.w3.org/TR/geolocation-API
+ *
+ * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
+ * liability, trademark and document use rules apply.
+ */
+
+dictionary PositionOptions {
+  boolean enableHighAccuracy = false;
+  long timeout = 0x7fffffff;
+  long maximumAge = 30000; /* non-conformant, should be 0 */
+};
+
+[NoInterfaceObject]
+interface Geolocation {
+  [Throws]
+  void getCurrentPosition(PositionCallback successCallback,
+                          optional PositionErrorCallback? errorCallback = null,
+                          optional PositionOptions options);
+
+  [Throws]
+  long watchPosition(PositionCallback successCallback,
+                     optional PositionErrorCallback? errorCallback = null,
+                     optional PositionOptions options);
+
+  void clearWatch(long watchId);
+};
+
+callback PositionCallback = void (Position position);
+
+callback PositionErrorCallback = void (PositionError positionError);
--- a/dom/webidl/WebIDL.mk
+++ b/dom/webidl/WebIDL.mk
@@ -67,16 +67,17 @@ webidl_files = \
   File.webidl \
   FileHandle.webidl \
   FileList.webidl \
   FileReaderSync.webidl \
   FileRequest.webidl \
   FormData.webidl \
   Function.webidl \
   GainNode.webidl \
+  Geolocation.webidl \
   HTMLAnchorElement.webidl \
   HTMLAppletElement.webidl \
   HTMLAreaElement.webidl \
   HTMLAudioElement.webidl \
   HTMLBaseElement.webidl \
   HTMLBodyElement.webidl \
   HTMLBRElement.webidl \
   HTMLButtonElement.webidl \
--- a/testing/mochitest/android.json
+++ b/testing/mochitest/android.json
@@ -191,16 +191,17 @@
  "dom/tests/mochitest/dom-level2-core/test_documentimportnode04.html": "",
  "dom/tests/mochitest/dom-level2-core/test_documentimportnode21.html": "",
  "dom/tests/mochitest/general/test_497898.html": "",
  "dom/tests/mochitest/general/test_focusrings.xul": "TIMED_OUT",
  "dom/tests/mochitest/general/test_vibrator.html": "CRASH_SUTAGENT",
  "dom/tests/mochitest/general/test_windowProperties.html": "",
  "dom/tests/mochitest/geolocation/test_allowCurrent.html": "TIMED_OUT",
  "dom/tests/mochitest/geolocation/test_allowWatch.html": "TIMED_OUT",
+ "dom/tests/mochitest/geolocation/test_cachedPosition.html": "TIMED_OUT",
  "dom/tests/mochitest/geolocation/test_clearWatch.html": "TIMED_OUT",
  "dom/tests/mochitest/geolocation/test_manyCurrentConcurrent.html": "TIMED_OUT",
  "dom/tests/mochitest/geolocation/test_manyCurrentSerial.html": "TIMED_OUT",
  "dom/tests/mochitest/geolocation/test_manyWatchConcurrent.html": "TIMED_OUT",
  "dom/tests/mochitest/geolocation/test_manyWatchSerial.html": "TIMED_OUT",
  "dom/tests/mochitest/geolocation/test_mozsettings.html": "mozSettings is undefined",
  "dom/tests/mochitest/geolocation/test_mozsettingsWatch.html": "mozSettings is undefined",
  "dom/tests/mochitest/geolocation/test_shutdown.html": "TIMED_OUT",
--- a/testing/mochitest/b2g.json
+++ b/testing/mochitest/b2g.json
@@ -374,16 +374,17 @@
 	"dom/tests/mochitest/general/test_clipboard_events.html":"",
 	"dom/tests/mochitest/general/test_focus_legend_noparent.html":"",
 	"dom/tests/mochitest/general/test_focusrings.xul" : "",
 	"dom/tests/mochitest/general/test_windowedhistoryframes.html" : "",
 	"dom/tests/mochitest/general/test_idleapi_permissions.html":"",
 	"dom/tests/mochitest/general/test_interfaces.html":"",
 	"dom/tests/mochitest/geolocation/test_allowCurrent.html":"",
 	"dom/tests/mochitest/geolocation/test_allowWatch.html":"",
+	"dom/tests/mochitest/geolocation/test_cachedPosition.html":"",
 	"dom/tests/mochitest/geolocation/test_cancelCurrent.html":"",
 	"dom/tests/mochitest/geolocation/test_cancelWatch.html":"",
 	"dom/tests/mochitest/geolocation/test_clearWatch.html":"",
 	"dom/tests/mochitest/geolocation/test_clearWatch_invalid.html":"",
 	"dom/tests/mochitest/geolocation/test_manyCurrentConcurrent.html":"",
 	"dom/tests/mochitest/geolocation/test_manyCurrentSerial.html":"",
 	"dom/tests/mochitest/geolocation/test_manyWatchConcurrent.html":"",
 	"dom/tests/mochitest/geolocation/test_manyWatchSerial.html":"",