Bug 838146 part 1. Implement WebIDL API on Navigator for the parts that are specified or are in nsIDOMNavigator. r=smaug, sr=sicking
☠☠ backed out by 33fb417caccf ☠ ☠
authorBoris Zbarsky <bzbarsky@mit.edu>
Fri, 12 Jul 2013 10:35:35 -0400
changeset 151522 483fbc6878a8ecd493006eba4ef7ecfedc6a8e2a
parent 151521 e6de1128c616bb5179ca36602f38cfc7cd89f909
child 151523 1bc7f216750320b2cfa936e9de6166f6dcc62d10
push id382
push userakeybl@mozilla.com
push dateMon, 21 Oct 2013 21:47:13 +0000
treeherdermozilla-release@5f1868ee45cb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, sicking
bugs838146
milestone25.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 838146 part 1. Implement WebIDL API on Navigator for the parts that are specified or are in nsIDOMNavigator. r=smaug, sr=sicking
dom/base/Navigator.cpp
dom/base/Navigator.h
dom/bindings/Bindings.conf
dom/bindings/Codegen.py
dom/power/PowerManager.cpp
dom/power/PowerManager.h
dom/webidl/Navigator.webidl
dom/webidl/WebIDL.mk
dom/workers/RuntimeService.cpp
dom/workers/test/test_navigator.html
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -67,16 +67,19 @@
 #include "nsIDOMCameraManager.h"
 #include "DOMCameraManager.h"
 
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
 #include "AudioChannelManager.h"
 #endif
 
 #include "nsIDOMGlobalPropertyInitializer.h"
+#include "nsJSUtils.h"
+
+#include "mozilla/dom/NavigatorBinding.h"
 
 using namespace mozilla::dom::power;
 
 // This should not be in the namespace.
 DOMCI_DATA(Navigator, mozilla::dom::Navigator)
 
 namespace mozilla {
 namespace dom {
@@ -357,17 +360,18 @@ NS_IMETHODIMP
 Navigator::GetAppVersion(nsAString& aAppVersion)
 {
   return NS_GetNavigatorAppVersion(aAppVersion);
 }
 
 NS_IMETHODIMP
 Navigator::GetAppName(nsAString& aAppName)
 {
-  return NS_GetNavigatorAppName(aAppName);
+  NS_GetNavigatorAppName(aAppName);
+  return NS_OK;
 }
 
 /**
  * JS property navigator.language, exposed to web content.
  * Take first value from Accept-Languages (HTTP header), which is
  * the "content language" freely set by the user in the Pref window.
  *
  * Do not use UI language (chosen app locale) here.
@@ -480,99 +484,130 @@ Navigator::GetProductSub(nsAString& aPro
   // Legacy build ID hardcoded for backward compatibility (bug 776376)
   aProductSub.AssignLiteral("20100101");
   return NS_OK;
 }
 
 NS_IMETHODIMP
 Navigator::GetMimeTypes(nsISupports** aMimeTypes)
 {
+  ErrorResult rv;
+  NS_IF_ADDREF(*aMimeTypes = GetMimeTypes(rv));
+  return rv.ErrorCode();
+}
+
+nsMimeTypeArray*
+Navigator::GetMimeTypes(ErrorResult& aRv)
+{
   if (!mMimeTypes) {
-    NS_ENSURE_STATE(mWindow);
+    if (!mWindow) {
+      aRv.Throw(NS_ERROR_UNEXPECTED);
+      return nullptr;
+    }
     nsWeakPtr win = do_GetWeakReference(mWindow);
     mMimeTypes = new nsMimeTypeArray(win);
   }
 
-  NS_ADDREF(*aMimeTypes = mMimeTypes);
-
-  return NS_OK;
+  return mMimeTypes;
 }
 
 NS_IMETHODIMP
 Navigator::GetPlugins(nsISupports** aPlugins)
 {
+  ErrorResult rv;
+  NS_IF_ADDREF(*aPlugins = static_cast<nsIObserver*>(GetPlugins(rv)));
+  return rv.ErrorCode();
+}
+
+nsPluginArray*
+Navigator::GetPlugins(ErrorResult& aRv)
+{
   if (!mPlugins) {
-    NS_ENSURE_STATE(mWindow);
+    if (!mWindow) {
+      aRv.Throw(NS_ERROR_UNEXPECTED);
+      return nullptr;
+    }
     nsWeakPtr win = do_GetWeakReference(mWindow);
     mPlugins = new nsPluginArray(win);
     mPlugins->Init();
   }
 
-  NS_ADDREF(*aPlugins = static_cast<nsIObserver*>(mPlugins.get()));
-
-  return NS_OK;
+  return mPlugins;
 }
 
 // Values for the network.cookie.cookieBehavior pref are documented in
 // nsCookieService.cpp.
 #define COOKIE_BEHAVIOR_REJECT 2
 
 NS_IMETHODIMP
 Navigator::GetCookieEnabled(bool* aCookieEnabled)
 {
-  *aCookieEnabled =
+  *aCookieEnabled = CookieEnabled();
+  return NS_OK;
+}
+
+bool
+Navigator::CookieEnabled()
+{
+  bool cookieEnabled =
     (Preferences::GetInt("network.cookie.cookieBehavior",
                          COOKIE_BEHAVIOR_REJECT) != COOKIE_BEHAVIOR_REJECT);
 
   // Check whether an exception overrides the global cookie behavior
   // Note that the code for getting the URI here matches that in
   // nsHTMLDocument::SetCookie.
   if (!mWindow || !mWindow->GetDocShell()) {
-    return NS_OK;
+    return cookieEnabled;
   }
 
   nsCOMPtr<nsIDocument> doc = mWindow->GetExtantDoc();
   if (!doc) {
-    return NS_OK;
+    return cookieEnabled;
   }
 
   nsCOMPtr<nsIURI> codebaseURI;
   doc->NodePrincipal()->GetURI(getter_AddRefs(codebaseURI));
 
   if (!codebaseURI) {
     // Not a codebase, so technically can't set cookies, but let's
     // just return the default value.
-    return NS_OK;
+    return cookieEnabled;
   }
 
   nsCOMPtr<nsICookiePermission> permMgr =
     do_GetService(NS_COOKIEPERMISSION_CONTRACTID);
-  NS_ENSURE_TRUE(permMgr, NS_OK);
+  NS_ENSURE_TRUE(permMgr, cookieEnabled);
 
   // Pass null for the channel, just like the cookie service does.
   nsCookieAccess access;
   nsresult rv = permMgr->CanAccess(codebaseURI, nullptr, &access);
-  NS_ENSURE_SUCCESS(rv, NS_OK);
+  NS_ENSURE_SUCCESS(rv, cookieEnabled);
 
   if (access != nsICookiePermission::ACCESS_DEFAULT) {
-    *aCookieEnabled = access != nsICookiePermission::ACCESS_DENY;
+    cookieEnabled = access != nsICookiePermission::ACCESS_DENY;
   }
 
-  return NS_OK;
+  return cookieEnabled;
 }
 
 NS_IMETHODIMP
 Navigator::GetOnLine(bool* aOnline)
 {
   NS_PRECONDITION(aOnline, "Null out param");
 
-  *aOnline = !NS_IsOffline();
+  *aOnline = OnLine();
   return NS_OK;
 }
 
+bool
+Navigator::OnLine()
+{
+  return !NS_IsOffline();
+}
+
 NS_IMETHODIMP
 Navigator::GetBuildID(nsAString& aBuildID)
 {
   if (!nsContentUtils::IsCallerChrome()) {
     const nsAdoptingString& override =
       Preferences::GetString("general.buildID.override");
 
     if (override) {
@@ -608,41 +643,48 @@ Navigator::GetDoNotTrack(nsAString &aRes
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 Navigator::JavaEnabled(bool* aReturn)
 {
+  ErrorResult rv;
+  *aReturn = JavaEnabled(rv);
+  return rv.ErrorCode();
+}
+
+bool
+Navigator::JavaEnabled(ErrorResult& aRv)
+{
   Telemetry::AutoTimer<Telemetry::CHECK_JAVA_ENABLED> telemetryTimer;
   // Return true if we have a handler for "application/x-java-vm",
   // otherwise return false.
-  *aReturn = false;
-
   if (!mMimeTypes) {
-    NS_ENSURE_STATE(mWindow);
+    if (!mWindow) {
+      aRv.Throw(NS_ERROR_UNEXPECTED);
+      return false;
+    }
     nsWeakPtr win = do_GetWeakReference(mWindow);
     mMimeTypes = new nsMimeTypeArray(win);
   }
 
   RefreshMIMEArray();
 
   nsMimeType *mimeType =
     mMimeTypes->NamedItem(NS_LITERAL_STRING("application/x-java-vm"));
 
-  *aReturn = mimeType && mimeType->GetEnabledPlugin();
-
-  return NS_OK;
+  return mimeType && mimeType->GetEnabledPlugin();
 }
 
 NS_IMETHODIMP
 Navigator::TaintEnabled(bool *aReturn)
 {
-  *aReturn = false;
+  *aReturn = TaintEnabled();
   return NS_OK;
 }
 
 void
 Navigator::RefreshMIMEArray()
 {
   if (mMimeTypes) {
     mMimeTypes->Refresh();
@@ -750,53 +792,83 @@ Navigator::AddIdleObserver(nsIIdleObserv
   }
 
   NS_ENSURE_ARG_POINTER(aIdleObserver);
 
   if (!CheckPermission("idle")) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
-  if (NS_FAILED(mWindow->RegisterIdleObserver(aIdleObserver))) {
+  AddIdleObserver(*aIdleObserver);
+  return NS_OK;
+}
+
+void
+Navigator::AddIdleObserver(nsIIdleObserver& aIdleObserver)
+{
+  // Callers (either the XPCOM method or the WebIDL binding) are responsible for
+  // the permission check here.
+  if (NS_FAILED(mWindow->RegisterIdleObserver(&aIdleObserver))) {
     NS_WARNING("Failed to add idle observer.");
   }
+}
 
-  return NS_OK;
+void
+Navigator::AddIdleObserver(MozIdleObserver& aIdleObserver, ErrorResult& aRv)
+{
+  if (!mWindow) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return;
+  }
+  CallbackObjectHolder<MozIdleObserver, nsIIdleObserver> holder(&aIdleObserver);
+  nsCOMPtr<nsIIdleObserver> obs = holder.ToXPCOMCallback();
+  return AddIdleObserver(*obs);
 }
 
 NS_IMETHODIMP
 Navigator::RemoveIdleObserver(nsIIdleObserver* aIdleObserver)
 {
   NS_ENSURE_STATE(mWindow);
 
   if (!nsContentUtils::IsIdleObserverAPIEnabled()) {
     NS_WARNING("The IdleObserver API has been disabled");
     return NS_OK;
   }
 
   NS_ENSURE_ARG_POINTER(aIdleObserver);
 
-  if (NS_FAILED(mWindow->UnregisterIdleObserver(aIdleObserver))) {
+  RemoveIdleObserver(*aIdleObserver);
+  return NS_OK;
+}
+
+void
+Navigator::RemoveIdleObserver(nsIIdleObserver& aIdleObserver)
+{
+  // Callers (either the XPCOM method or the WebIDL binding) are responsible for
+  // the permission check here.
+  if (NS_FAILED(mWindow->UnregisterIdleObserver(&aIdleObserver))) {
     NS_WARNING("Failed to remove idle observer.");
   }
-  return NS_OK;
+}
+
+void
+Navigator::RemoveIdleObserver(MozIdleObserver& aIdleObserver, ErrorResult& aRv)
+{
+  if (!mWindow) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return;
+  }
+  CallbackObjectHolder<MozIdleObserver, nsIIdleObserver> holder(&aIdleObserver);
+  nsCOMPtr<nsIIdleObserver> obs = holder.ToXPCOMCallback();
+  return RemoveIdleObserver(*obs);
 }
 
 NS_IMETHODIMP
 Navigator::Vibrate(const JS::Value& aPattern, JSContext* cx)
 {
-  NS_ENSURE_STATE(mWindow);
-
-  nsCOMPtr<nsIDocument> doc = mWindow->GetExtantDoc();
-  NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
-  if (doc->Hidden()) {
-    // Hidden documents cannot start or stop a vibration.
-    return NS_OK;
-  }
-
   nsAutoTArray<uint32_t, 8> pattern;
 
   // null or undefined pattern is an error.
   if (JSVAL_IS_NULL(aPattern) || JSVAL_IS_VOID(aPattern)) {
     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
   }
 
   if (JSVAL_IS_PRIMITIVE(aPattern)) {
@@ -824,38 +896,81 @@ Navigator::Vibrate(const JS::Value& aPat
         pattern[i] = pv;
       }
       else {
         return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
       }
     }
   }
 
+  ErrorResult rv;
+  Vibrate(pattern, rv);
+  return rv.ErrorCode();
+}
+
+void
+Navigator::Vibrate(uint32_t aDuration, ErrorResult& aRv)
+{
+  nsAutoTArray<uint32_t, 1> pattern;
+  pattern.AppendElement(aDuration);
+  Vibrate(pattern, aRv);
+}
+
+void
+Navigator::Vibrate(const nsTArray<uint32_t>& aPattern, ErrorResult& aRv)
+{
+  if (!mWindow) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return;
+  }
+  nsCOMPtr<nsIDocument> doc = mWindow->GetExtantDoc();
+  if (!doc) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return;
+  }
+  if (doc->Hidden()) {
+    // Hidden documents cannot start or stop a vibration.
+    return;
+  }
+
+  if (aPattern.Length() > sMaxVibrateListLen) {
+    // XXXbz this should be returning false instead
+    aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+    return;
+  }
+
+  for (size_t i = 0; i < aPattern.Length(); ++i) {
+    if (aPattern[i] > sMaxVibrateMS) {
+      // XXXbz this should be returning false instead
+      aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+      return;
+    }
+  }
+
   // The spec says we check sVibratorEnabled after we've done the sanity
   // checking on the pattern.
   if (!sVibratorEnabled) {
-    return NS_OK;
+    return;
   }
 
   // Add a listener to cancel the vibration if the document becomes hidden,
   // and remove the old visibility listener, if there was one.
 
   if (!gVibrateWindowListener) {
     // If gVibrateWindowListener is null, this is the first time we've vibrated,
     // and we need to register a listener to clear gVibrateWindowListener on
     // shutdown.
     ClearOnShutdown(&gVibrateWindowListener);
   }
   else {
     gVibrateWindowListener->RemoveListener();
   }
   gVibrateWindowListener = new VibrateWindowListener(mWindow, doc);
 
-  hal::Vibrate(pattern, mWindow);
-  return NS_OK;
+  hal::Vibrate(aPattern, mWindow);
 }
 
 //*****************************************************************************
 //    Navigator::nsIDOMClientInformation
 //*****************************************************************************
 
 NS_IMETHODIMP
 Navigator::RegisterContentHandler(const nsAString& aMIMEType,
@@ -1035,44 +1150,45 @@ NS_IMETHODIMP Navigator::GetDeviceStorag
 }
 
 //*****************************************************************************
 //    Navigator::nsIDOMNavigatorGeolocation
 //*****************************************************************************
 
 NS_IMETHODIMP Navigator::GetGeolocation(nsIDOMGeoGeolocation** _retval)
 {
-  NS_ENSURE_ARG_POINTER(_retval);
-  *_retval = nullptr;
+  ErrorResult rv;
+  NS_IF_ADDREF(*_retval = GetGeolocation(rv));
+  return rv.ErrorCode();
+}
 
+Geolocation*
+Navigator::GetGeolocation(ErrorResult& aRv)
+{
   if (!Preferences::GetBool("geo.enabled", true)) {
-    return NS_OK;
+    return nullptr;
   }
 
   if (mGeolocation) {
-    NS_ADDREF(*_retval = mGeolocation);
-    return NS_OK;
+    return mGeolocation;
   }
 
   if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell()) {
-    return NS_ERROR_FAILURE;
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
   }
 
   mGeolocation = new Geolocation();
-  if (!mGeolocation) {
-    return NS_ERROR_FAILURE;
-  }
-
   if (NS_FAILED(mGeolocation->Init(mWindow->GetOuterWindow()))) {
     mGeolocation = nullptr;
-    return NS_ERROR_FAILURE;
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
   }
 
-  NS_ADDREF(*_retval = mGeolocation);
-  return NS_OK;
+  return mGeolocation;
 }
 
 //*****************************************************************************
 //    Navigator::nsIDOMNavigatorUserMedia (mozGetUserMedia)
 //*****************************************************************************
 #ifdef MOZ_MEDIA_NAVIGATOR
 NS_IMETHODIMP
 Navigator::MozGetUserMedia(nsIMediaStreamOptions* aParams,
@@ -1143,60 +1259,95 @@ NS_IMETHODIMP Navigator::GetMozNotificat
 
 //*****************************************************************************
 //    Navigator::nsINavigatorBattery
 //*****************************************************************************
 
 NS_IMETHODIMP
 Navigator::GetBattery(nsISupports** aBattery)
 {
-  if (!mBatteryManager) {
-    *aBattery = nullptr;
+  ErrorResult rv;
+  NS_IF_ADDREF(*aBattery = GetBattery(rv));
+  return rv.ErrorCode();
+}
 
-    NS_ENSURE_STATE(mWindow);
-    NS_ENSURE_TRUE(mWindow->GetDocShell(), NS_OK);
+battery::BatteryManager*
+Navigator::GetBattery(ErrorResult& aRv)
+{
+  if (!mBatteryManager) {
+    if (!mWindow) {
+      aRv.Throw(NS_ERROR_UNEXPECTED);
+      return nullptr;
+    }
+    NS_ENSURE_TRUE(mWindow->GetDocShell(), nullptr);
 
     mBatteryManager = new battery::BatteryManager();
     mBatteryManager->Init(mWindow);
   }
 
-  NS_ADDREF(*aBattery = mBatteryManager);
-
-  return NS_OK;
+  return mBatteryManager;
 }
 
 NS_IMETHODIMP
 Navigator::GetMozPower(nsIDOMMozPowerManager** aPower)
 {
-  *aPower = nullptr;
+  if (!PowerManager::CheckPermission(mWindow)) {
+    *aPower = nullptr;
+    return NS_OK;
+  }
+  ErrorResult rv;
+  NS_IF_ADDREF(*aPower = GetMozPower(rv));
+  return rv.ErrorCode();
+}
 
+nsIDOMMozPowerManager*
+Navigator::GetMozPower(ErrorResult& aRv)
+{
+  // Callers (either the XPCOM method or the WebIDL binding) are responsible for
+  // the permission check here.
   if (!mPowerManager) {
-    NS_ENSURE_STATE(mWindow);
-    mPowerManager = PowerManager::CheckPermissionAndCreateInstance(mWindow);
-    NS_ENSURE_TRUE(mPowerManager, NS_OK);
+    if (!mWindow) {
+      aRv.Throw(NS_ERROR_UNEXPECTED);
+      return nullptr;
+    }
+    mPowerManager = PowerManager::CreateInstance(mWindow);
+    if (!mPowerManager) {
+      // We failed to get the power manager service?
+      aRv.Throw(NS_ERROR_UNEXPECTED);
+    }
   }
 
-  nsCOMPtr<nsIDOMMozPowerManager> power(mPowerManager);
-  power.forget(aPower);
-
-  return NS_OK;
+  return mPowerManager;
 }
 
 NS_IMETHODIMP
 Navigator::RequestWakeLock(const nsAString &aTopic, nsIDOMMozWakeLock **aWakeLock)
 {
-  NS_ENSURE_STATE(mWindow);
+  ErrorResult rv;
+  *aWakeLock = RequestWakeLock(aTopic, rv).get();
+  return rv.ErrorCode();
+}
 
-  *aWakeLock = nullptr;
+already_AddRefed<nsIDOMMozWakeLock>
+Navigator::RequestWakeLock(const nsAString &aTopic, ErrorResult& aRv)
+{
+  if (!mWindow) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return nullptr;
+  }
 
   nsCOMPtr<nsIPowerManagerService> pmService =
     do_GetService(POWERMANAGERSERVICE_CONTRACTID);
-  NS_ENSURE_TRUE(pmService, NS_OK);
+  // Maybe it went away for some reason... Or maybe we're just called
+  // from our XPCOM method.
+  NS_ENSURE_TRUE(pmService, nullptr);
 
-  return pmService->NewWakeLock(aTopic, mWindow, aWakeLock);
+  nsCOMPtr<nsIDOMMozWakeLock> wakelock;
+  aRv = pmService->NewWakeLock(aTopic, mWindow, getter_AddRefs(wakelock));
+  return wakelock.forget();
 }
 
 //*****************************************************************************
 //    Navigator::nsIDOMNavigatorSms
 //*****************************************************************************
 
 NS_IMETHODIMP
 Navigator::GetMozSms(nsIDOMMozSmsManager** aSmsManager)
@@ -1599,26 +1750,33 @@ Navigator::OnNavigation()
   if (mCameraManager) {
     mCameraManager->OnNavigation(mWindow->WindowID());
   }
 }
 
 bool
 Navigator::CheckPermission(const char* type)
 {
-  if (!mWindow) {
+  return CheckPermission(mWindow, type);
+}
+
+/* static */
+bool
+Navigator::CheckPermission(nsPIDOMWindow* aWindow, const char* aType)
+{
+  if (!aWindow) {
     return false;
   }
 
   nsCOMPtr<nsIPermissionManager> permMgr =
     do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
   NS_ENSURE_TRUE(permMgr, false);
 
   uint32_t permission = nsIPermissionManager::DENY_ACTION;
-  permMgr->TestPermissionFromWindow(mWindow, type, &permission);
+  permMgr->TestPermissionFromWindow(aWindow, aType, &permission);
   return permission == nsIPermissionManager::ALLOW_ACTION;
 }
 
 //*****************************************************************************
 //    Navigator::nsINavigatorAudioChannelManager
 //*****************************************************************************
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
 NS_IMETHODIMP
@@ -1632,16 +1790,63 @@ Navigator::GetMozAudioChannelManager(nsI
     mAudioChannelManager->Init(mWindow);
   }
 
   NS_ADDREF(*aAudioChannelManager = mAudioChannelManager);
   return NS_OK;
 }
 #endif
 
+/* static */
+bool
+Navigator::HasBatterySupport(JSContext* /* unused*/, JSObject* /*unused */)
+{
+  return battery::BatteryManager::HasSupport();
+}
+
+/* static */
+bool
+Navigator::HasPowerSupport(JSContext* /* unused */, JSObject* aGlobal)
+{
+  nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
+  return win && PowerManager::CheckPermission(win);
+}
+
+/* static */
+bool
+Navigator::HasIdleSupport(JSContext*  /* unused */, JSObject* aGlobal)
+{
+  if (!nsContentUtils::IsIdleObserverAPIEnabled()) {
+    return false;
+  }
+
+  nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
+  return CheckPermission(win, "idle");
+}
+
+/* static */
+bool
+Navigator::HasWakeLockSupport(JSContext* /* unused*/, JSObject* /*unused */)
+{
+  nsCOMPtr<nsIPowerManagerService> pmService =
+    do_GetService(POWERMANAGERSERVICE_CONTRACTID);
+  // No service means no wake lock support
+  return !!pmService;
+}
+
+/* static */
+already_AddRefed<nsPIDOMWindow>
+Navigator::GetWindowFromGlobal(JSObject* aGlobal)
+{
+  nsCOMPtr<nsPIDOMWindow> win =
+    do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(aGlobal));
+  MOZ_ASSERT(!win || win->IsInnerWindow());
+  return win.forget();
+}
+
 } // namespace dom
 } // namespace mozilla
 
 nsresult
 NS_GetNavigatorUserAgent(nsAString& aUserAgent)
 {
   nsresult rv;
 
@@ -1730,24 +1935,22 @@ NS_GetNavigatorAppVersion(nsAString& aAp
   NS_ENSURE_SUCCESS(rv, rv);
 
   AppendASCIItoUTF16(str, aAppVersion);
   aAppVersion.Append(PRUnichar(')'));
 
   return rv;
 }
 
-nsresult
+void
 NS_GetNavigatorAppName(nsAString& aAppName)
 {
   if (!nsContentUtils::IsCallerChrome()) {
     const nsAdoptingString& override =
       mozilla::Preferences::GetString("general.appname.override");
 
     if (override) {
       aAppName = override;
-      return NS_OK;
     }
   }
 
   aAppName.AssignLiteral("Netscape");
-  return NS_OK;
 }
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -64,26 +64,29 @@ class nsIDOMTelephony;
 #ifdef MOZ_GAMEPAD
 #include "nsINavigatorGamepads.h"
 #endif
 
 //*****************************************************************************
 // Navigator: Script "navigator" object
 //*****************************************************************************
 
+void NS_GetNavigatorAppName(nsAString& aAppName);
+
 namespace mozilla {
 namespace dom {
 
 namespace battery {
 class BatteryManager;
 } // namespace battery
 
 class DesktopNotificationCenter;
 class SmsManager;
 class MobileMessageManager;
+class MozIdleObserver;
 
 namespace icc {
 #ifdef MOZ_B2G_RIL
 class IccManager;
 #endif
 }
 
 namespace network {
@@ -187,17 +190,17 @@ public:
 #endif
 
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
   NS_DECL_NSIMOZNAVIGATORAUDIOCHANNELMANAGER
 #endif
   static void Init();
 
   void Invalidate();
-  nsPIDOMWindow *GetWindow()
+  nsPIDOMWindow *GetWindow() const
   {
     return mWindow;
   }
 
   void RefreshMIMEArray();
 
   static bool HasDesktopNotificationSupport();
 
@@ -213,18 +216,101 @@ public:
    */
   void OnNavigation();
 
   // Helper to initialize mMessagesManager.
   nsresult EnsureMessagesManager();
 
   NS_DECL_NSIDOMNAVIGATORCAMERA
 
+  // WebIDL API
+  void GetAppName(nsString& aAppName)
+  {
+    NS_GetNavigatorAppName(aAppName);
+  }
+  void GetAppVersion(nsString& aAppVersion, ErrorResult& aRv)
+  {
+    aRv = GetAppVersion(aAppVersion);
+  }
+  void GetPlatform(nsString& aPlatform, ErrorResult& aRv)
+  {
+    aRv = GetPlatform(aPlatform);
+  }
+  void GetUserAgent(nsString& aUserAgent, ErrorResult& aRv)
+  {
+    aRv = GetUserAgent(aUserAgent);
+  }
+  // The XPCOM GetProduct is OK
+  // The XPCOM GetLanguage is OK
+  bool OnLine();
+  void RegisterProtocolHandler(const nsAString& aScheme, const nsAString& aURL,
+                               const nsAString& aTitle, ErrorResult& rv)
+  {
+    rv = RegisterProtocolHandler(aScheme, aURL, aTitle);
+  }
+  void RegisterContentHandler(const nsAString& aMIMEType, const nsAString& aURL,
+                              const nsAString& aTitle, ErrorResult& rv)
+  {
+    rv = RegisterContentHandler(aMIMEType, aURL, aTitle);
+  }
+  nsMimeTypeArray* GetMimeTypes(ErrorResult& aRv);
+  nsPluginArray* GetPlugins(ErrorResult& aRv);
+  // The XPCOM GetDoNotTrack is ok
+  Geolocation* GetGeolocation(ErrorResult& aRv);
+  battery::BatteryManager* GetBattery(ErrorResult& aRv);
+  void Vibrate(uint32_t aDuration, ErrorResult& aRv);
+  void Vibrate(const nsTArray<uint32_t>& aDuration, ErrorResult& aRv);
+  void GetAppCodeName(nsString& aAppCodeName, ErrorResult& aRv)
+  {
+    aRv = GetAppCodeName(aAppCodeName);
+  }
+  void GetOscpu(nsString& aOscpu, ErrorResult& aRv)
+  {
+    aRv = GetOscpu(aOscpu);
+  }
+  // The XPCOM GetVendor is OK
+  // The XPCOM GetVendorSub is OK
+  // The XPCOM GetProductSub is OK
+  bool CookieEnabled();
+  void GetBuildID(nsString& aBuildID, ErrorResult& aRv)
+  {
+    aRv = GetBuildID(aBuildID);
+  }
+  nsIDOMMozPowerManager* GetMozPower(ErrorResult& aRv);
+  bool JavaEnabled(ErrorResult& aRv);
+  bool TaintEnabled()
+  {
+    return false;
+  }
+  void AddIdleObserver(MozIdleObserver& aObserver, ErrorResult& aRv);
+  void RemoveIdleObserver(MozIdleObserver& aObserver, ErrorResult& aRv);
+  already_AddRefed<nsIDOMMozWakeLock> RequestWakeLock(const nsAString &aTopic,
+                                                      ErrorResult& aRv);
+
+  // WebIDL helper methods
+  static bool HasBatterySupport(JSContext* /* unused*/, JSObject* /*unused */);
+  static bool HasPowerSupport(JSContext* /* unused */, JSObject* aGlobal);
+  static bool HasIdleSupport(JSContext* /* unused */, JSObject* aGlobal);
+  static bool HasWakeLockSupport(JSContext* /* unused*/, JSObject* /*unused */);
+  nsPIDOMWindow* GetParentObject() const
+  {
+    return GetWindow();
+  }
+
 private:
   bool CheckPermission(const char* type);
+  static bool CheckPermission(nsPIDOMWindow* aWindow, const char* aType);
+  // GetWindowFromGlobal returns the inner window for this global, if
+  // any, else null.
+  static already_AddRefed<nsPIDOMWindow> GetWindowFromGlobal(JSObject* aGlobal);
+
+  // Methods to common up the XPCOM and WebIDL implementations of
+  // Add/RemoveIdleObserver.
+  void AddIdleObserver(nsIIdleObserver& aIdleObserver);
+  void RemoveIdleObserver(nsIIdleObserver& aIdleObserver);
 
   nsRefPtr<nsMimeTypeArray> mMimeTypes;
   nsRefPtr<nsPluginArray> mPlugins;
   nsRefPtr<Geolocation> mGeolocation;
   nsRefPtr<DesktopNotificationCenter> mNotification;
   nsRefPtr<battery::BatteryManager> mBatteryManager;
   nsRefPtr<power::PowerManager> mPowerManager;
   nsRefPtr<SmsManager> mSmsManager;
@@ -253,11 +339,10 @@ private:
 };
 
 } // namespace dom
 } // namespace mozilla
 
 nsresult NS_GetNavigatorUserAgent(nsAString& aUserAgent);
 nsresult NS_GetNavigatorPlatform(nsAString& aPlatform);
 nsresult NS_GetNavigatorAppVersion(nsAString& aAppVersion);
-nsresult NS_GetNavigatorAppName(nsAString& aAppName);
 
 #endif // mozilla_dom_Navigator_h
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -706,16 +706,20 @@ DOMInterfaces = {
 
 'MutationRecord': {
     'nativeType': 'nsDOMMutationRecord',
     'headerFile': 'nsDOMMutationObserver.h',
     'resultNotAddRefed': [ 'target', 'addedNodes', 'removedNodes',
                            'previousSibling', 'nextSibling' ]
 },
 
+'Navigator': {
+    'register': False,
+},
+
 'Node': {
     'nativeType': 'nsINode',
     'concrete': False,
     'resultNotAddRefed': [ 'ownerDocument', 'parentNode', 'parentElement',
                            'childNodes', 'firstChild', 'lastChild',
                            'previousSibling', 'nextSibling', 'insertBefore',
                            'appendChild', 'replaceChild', 'removeChild',
                            'attributes' ]
@@ -1701,23 +1705,25 @@ addExternalIface('imgINotificationObserv
 addExternalIface('imgIRequest', nativeType='imgIRequest', notflattened=True)
 addExternalIface('LockedFile')
 addExternalIface('MediaList')
 addExternalIface('MenuBuilder', nativeType='nsIMenuBuilder', notflattened=True)
 addExternalIface('MozBoxObject', nativeType='nsIBoxObject')
 addExternalIface('MozControllers', nativeType='nsIControllers')
 addExternalIface('MozFrameLoader', nativeType='nsIFrameLoader', notflattened=True)
 addExternalIface('MozObserver', nativeType='nsIObserver', notflattened=True)
+addExternalIface('MozPowerManager', headerFile='nsIDOMPowerManager.h')
 addExternalIface('MozRDFCompositeDataSource', nativeType='nsIRDFCompositeDataSource',
                  notflattened=True)
 addExternalIface('MozRDFResource', nativeType='nsIRDFResource', notflattened=True)
 addExternalIface('MozTreeBoxObject', nativeType='nsITreeBoxObject',
                  notflattened=True)
 addExternalIface('MozTreeColumn', nativeType='nsITreeColumn',
                  headerFile='nsITreeColumns.h')
+addExternalIface('MozWakeLock', headerFile='nsIDOMWakeLock.h')
 addExternalIface('MozXULTemplateBuilder', nativeType='nsIXULTemplateBuilder')
 addExternalIface('nsIControllers', nativeType='nsIControllers')
 addExternalIface('nsIInputStreamCallback', nativeType='nsIInputStreamCallback',
                  headerFile='nsIAsyncInputStream.h')
 addExternalIface('nsIStreamListener', nativeType='nsIStreamListener', notflattened=True)
 addExternalIface('nsISupports', nativeType='nsISupports')
 addExternalIface('nsIEditor', nativeType='nsIEditor', notflattened=True)
 addExternalIface('nsIVariant', nativeType='nsIVariant', notflattened=True)
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -3727,17 +3727,17 @@ def convertConstIDLValueToJSVal(value):
     if tag == IDLType.Tags.uint32:
         return "UINT_TO_JSVAL(%sU)" % (value.value)
     if tag in [IDLType.Tags.int64, IDLType.Tags.uint64]:
         return "DOUBLE_TO_JSVAL(%s)" % numericValue(tag, value.value)
     if tag == IDLType.Tags.bool:
         return "JSVAL_TRUE" if value.value else "JSVAL_FALSE"
     if tag in [IDLType.Tags.float, IDLType.Tags.double]:
         return "DOUBLE_TO_JSVAL(%s)" % (value.value)
-    raise TypeError("Const value of unhandled type: " + value.type)
+    raise TypeError("Const value of unhandled type: %s" % value.type)
 
 class CGArgumentConverter(CGThing):
     """
     A class that takes an IDL argument object and its index in the
     argument list and generates code to unwrap the argument to the
     right native type.
 
     argDescription is a description of the argument for error-reporting
--- a/dom/power/PowerManager.cpp
+++ b/dom/power/PowerManager.cpp
@@ -174,31 +174,35 @@ PowerManager::GetCpuSleepAllowed(bool *a
 
 NS_IMETHODIMP
 PowerManager::SetCpuSleepAllowed(bool aAllowed)
 {
   hal::SetCpuSleepAllowed(aAllowed);
   return NS_OK;
 }
 
-already_AddRefed<PowerManager>
-PowerManager::CheckPermissionAndCreateInstance(nsPIDOMWindow* aWindow)
+bool
+PowerManager::CheckPermission(nsPIDOMWindow* aWindow)
 {
   nsCOMPtr<nsIPermissionManager> permMgr =
     do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
-  NS_ENSURE_TRUE(permMgr, nullptr);
+  NS_ENSURE_TRUE(permMgr, false);
 
   uint32_t permission = nsIPermissionManager::DENY_ACTION;
   permMgr->TestPermissionFromWindow(aWindow, "power", &permission);
 
-  if (permission != nsIPermissionManager::ALLOW_ACTION) {
-    return nullptr;
+  return permission == nsIPermissionManager::ALLOW_ACTION;
+}
+
+already_AddRefed<PowerManager>
+PowerManager::CreateInstance(nsPIDOMWindow* aWindow)
+{
+  nsRefPtr<PowerManager> powerManager = new PowerManager();
+  if (NS_FAILED(powerManager->Init(aWindow))) {
+    powerManager = nullptr;
   }
 
-  nsRefPtr<PowerManager> powerManager = new PowerManager();
-  powerManager->Init(aWindow);
-
   return powerManager.forget();
 }
 
 } // power
 } // dom
 } // mozilla
--- a/dom/power/PowerManager.h
+++ b/dom/power/PowerManager.h
@@ -28,18 +28,19 @@ public:
   NS_DECL_NSIDOMMOZWAKELOCKLISTENER
 
   PowerManager() {};
   virtual ~PowerManager() {};
 
   nsresult Init(nsIDOMWindow *aWindow);
   nsresult Shutdown();
 
-  static already_AddRefed<PowerManager>
-  CheckPermissionAndCreateInstance(nsPIDOMWindow*);
+  static bool CheckPermission(nsPIDOMWindow*);
+
+  static already_AddRefed<PowerManager> CreateInstance(nsPIDOMWindow*);
 
 private:
 
   nsWeakPtr mWindow;
   nsTArray<nsCOMPtr<nsIDOMMozWakeLockListener> > mListeners;
 };
 
 } // namespace power
new file mode 100644
--- /dev/null
+++ b/dom/webidl/Navigator.webidl
@@ -0,0 +1,204 @@
+/* -*- 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.whatwg.org/specs/web-apps/current-work/#the-navigator-object
+ * http://www.w3.org/TR/tracking-dnt/
+ * http://www.w3.org/TR/geolocation-API/#geolocation_interface
+ * http://www.w3.org/TR/battery-status/#navigatorbattery-interface
+ * http://www.w3.org/TR/vibration/#vibration-interface
+ *
+ * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
+ * Opera Software ASA. You are granted a license to use, reproduce
+ * and create derivative works of this document.
+ */
+
+interface MozPowerManager;
+interface MozWakeLock;
+
+// http://www.whatwg.org/specs/web-apps/current-work/#the-navigator-object
+[HeaderFile="Navigator.h"]
+interface Navigator {
+  // objects implementing this interface also implement the interfaces given below
+};
+Navigator implements NavigatorID;
+Navigator implements NavigatorLanguage;
+Navigator implements NavigatorOnLine;
+Navigator implements NavigatorContentUtils;
+Navigator implements NavigatorStorageUtils;
+
+[NoInterfaceObject]
+interface NavigatorID {
+  readonly attribute DOMString appName;
+  [Throws]
+  readonly attribute DOMString appVersion;
+  [Throws]
+  readonly attribute DOMString platform;
+  [Throws]
+  readonly attribute DOMString userAgent;
+
+  // Spec has this as a const, but that's wrong because it should not
+  // be on the interface object.
+  //const DOMString product = "Gecko"; // for historical reasons
+  readonly attribute DOMString product;
+};
+
+[NoInterfaceObject]
+interface NavigatorLanguage {
+  readonly attribute DOMString? language;
+};
+
+[NoInterfaceObject]
+interface NavigatorOnLine {
+  readonly attribute boolean onLine;
+};
+
+[NoInterfaceObject]
+interface NavigatorContentUtils {
+  // content handler registration
+  [Throws]
+  void registerProtocolHandler(DOMString scheme, DOMString url, DOMString title);
+  [Throws]
+  void registerContentHandler(DOMString mimeType, DOMString url, DOMString title);
+  // NOT IMPLEMENTED
+  //DOMString isProtocolHandlerRegistered(DOMString scheme, DOMString url);
+  //DOMString isContentHandlerRegistered(DOMString mimeType, DOMString url);
+  //void unregisterProtocolHandler(DOMString scheme, DOMString url);
+  //void unregisterContentHandler(DOMString mimeType, DOMString url);
+};
+
+[NoInterfaceObject]
+interface NavigatorStorageUtils {
+  // NOT IMPLEMENTED
+  //void yieldForStorageUpdates();
+};
+
+// Things that definitely need to be in the spec and and are not for some
+// reason.  See https://www.w3.org/Bugs/Public/show_bug.cgi?id=22406
+partial interface Navigator {
+  [Throws]
+  readonly attribute MimeTypeArray mimeTypes;
+  [Throws]
+  readonly attribute PluginArray plugins;
+};
+
+// http://www.w3.org/TR/tracking-dnt/ sort of
+partial interface Navigator {
+  readonly attribute DOMString doNotTrack;
+};
+
+// http://www.w3.org/TR/geolocation-API/#geolocation_interface
+[NoInterfaceObject]
+interface NavigatorGeolocation {
+  // XXXbz This should perhaps be controleld by the "geo.enabled" pref, instead
+  // of checking it in the C++.  Let's not for now to reduce risk.
+  // Also, we violate the spec as a result, since we can return null.  See bug
+  // 884921.
+  [Throws]
+  readonly attribute Geolocation? geolocation;
+};
+Navigator implements NavigatorGeolocation;
+
+// http://www.w3.org/TR/battery-status/#navigatorbattery-interface
+[NoInterfaceObject]
+interface NavigatorBattery {
+    // XXXbz Per spec this should be non-nullable, but we return null in
+    // torn-down windows.  See bug 884925.
+    [Throws, Func="Navigator::HasBatterySupport"]
+    readonly attribute BatteryManager? battery;
+};
+Navigator implements NavigatorBattery;
+
+// http://www.w3.org/TR/vibration/#vibration-interface
+partial interface Navigator {
+    // We don't support sequences in unions yet
+    //boolean vibrate ((unsigned long or sequence<unsigned long>) pattern);
+    // XXXbz also, per spec we should be returning a boolean, and we just don't.
+    // See bug 884935.
+    [Throws]
+    void vibrate(unsigned long duration);
+    [Throws]
+    void vibrate(sequence<unsigned long> pattern);
+};
+
+// Mozilla-specific extensions
+
+callback interface MozIdleObserver {
+  // Time is in seconds and is read only when idle observers are added
+  // and removed.
+  readonly attribute unsigned long time;
+  void onidle();
+  void onactive();
+};
+
+// nsIDOMNavigator
+partial interface Navigator {
+  // WebKit/Blink/Trident/Presto support this (hardcoded "Mozilla").
+  [Throws]
+  readonly attribute DOMString appCodeName;
+  [Throws]
+  readonly attribute DOMString oscpu;
+  // WebKit/Blink support this; Trident/Presto do not.
+  readonly attribute DOMString vendor;
+  // WebKit/Blink supports this (hardcoded ""); Trident/Presto do not.
+  readonly attribute DOMString vendorSub;
+  // WebKit/Blink supports this (hardcoded "20030107"); Trident/Presto don't
+  readonly attribute DOMString productSub;
+  // WebKit/Blink/Trident/Presto support this.
+  readonly attribute boolean cookieEnabled;
+  [Throws]
+  readonly attribute DOMString buildID;
+  [Throws, Func="Navigator::HasPowerSupport"]
+  readonly attribute MozPowerManager mozPower;
+
+  // WebKit/Blink/Trident/Presto support this.
+  [Throws]
+  boolean javaEnabled();
+  // Everyone but WebKit/Blink supports this.  See bug 679971.
+  boolean taintEnabled();
+
+  /**
+   * Navigator requests to add an idle observer to the existing window.
+   */
+  [Throws, Func="Navigator::HasIdleSupport"]
+  void addIdleObserver(MozIdleObserver aIdleObserver);
+
+  /**
+   * Navigator requests to remove an idle observer from the existing window.
+   */
+  [Throws, Func="Navigator::HasIdleSupport"]
+  void removeIdleObserver(MozIdleObserver aIdleObserver);
+
+  /**
+   * Request a wake lock for a resource.
+   *
+   * A page holds a wake lock to request that a resource not be turned
+   * off (or otherwise made unavailable).
+   *
+   * The topic is the name of a resource that might be made unavailable for
+   * various reasons. For example, on a mobile device the power manager might
+   * decide to turn off the screen after a period of idle time to save power.
+   *
+   * The resource manager checks the lock state of a topic before turning off
+   * the associated resource. For example, a page could hold a lock on the
+   * "screen" topic to prevent the screensaver from appearing or the screen
+   * from turning off.
+   *
+   * The resource manager defines what each topic means and sets policy.  For
+   * example, the resource manager might decide to ignore 'screen' wake locks
+   * held by pages which are not visible.
+   *
+   * One topic can be locked multiple times; it is considered released only when
+   * all locks on the topic have been released.
+   *
+   * The returned nsIDOMMozWakeLock object is a token of the lock.  You can
+   * unlock the lock via the object's |unlock| method.  The lock is released
+   * automatically when its associated window is unloaded.
+   *
+   * @param aTopic resource name
+   */
+  [Throws, Func="Navigator::HasWakeLockSupport"]
+  MozWakeLock requestWakeLock(DOMString aTopic);
+};
--- a/dom/webidl/WebIDL.mk
+++ b/dom/webidl/WebIDL.mk
@@ -186,16 +186,17 @@ webidl_files = \
   MouseEvent.webidl \
   MouseScrollEvent.webidl \
   MozActivity.webidl \
   MozMmsMessage.webidl \
   MozNamedAttrMap.webidl \
   MozTimeManager.webidl \
   MutationEvent.webidl \
   MutationObserver.webidl \
+  Navigator.webidl \
   NetDashboard.webidl \
   Node.webidl \
   NodeFilter.webidl \
   NodeIterator.webidl \
   NodeList.webidl \
   Notification.webidl \
   NotifyAudioAvailableEvent.webidl \
   NotifyPaintEvent.webidl \
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -1153,18 +1153,18 @@ RuntimeService::RegisterWorker(JSContext
   if (parent) {
     if (!parent->AddChildWorker(aCx, aWorkerPrivate)) {
       UnregisterWorker(aCx, aWorkerPrivate);
       return false;
     }
   }
   else {
     if (!mNavigatorStringsLoaded) {
-      if (NS_FAILED(NS_GetNavigatorAppName(mNavigatorStrings.mAppName)) ||
-          NS_FAILED(NS_GetNavigatorAppVersion(mNavigatorStrings.mAppVersion)) ||
+      NS_GetNavigatorAppName(mNavigatorStrings.mAppName);
+      if (NS_FAILED(NS_GetNavigatorAppVersion(mNavigatorStrings.mAppVersion)) ||
           NS_FAILED(NS_GetNavigatorPlatform(mNavigatorStrings.mPlatform)) ||
           NS_FAILED(NS_GetNavigatorUserAgent(mNavigatorStrings.mUserAgent))) {
         JS_ReportError(aCx, "Failed to load navigator strings!");
         UnregisterWorker(aCx, aWorkerPrivate);
         return false;
       }
 
       mNavigatorStringsLoaded = true;
--- a/dom/workers/test/test_navigator.html
+++ b/dom/workers/test/test_navigator.html
@@ -30,17 +30,18 @@ Tests of DOM Worker Navigator
       return;
     }
 
     if (typeof navigator[args.name] == "undefined") {
       ok(false, "Navigator has no '" + args.name + "' property!");
       return;
     }
 
-    is(navigator[args.name], args.value, "Mismatched navigator string!");
+    is(navigator[args.name], args.value,
+       "Mismatched navigator string for " + args.name + "!");
   };
 
   worker.onerror = function(event) {
     ok(false, "Worker had an error: " + event.message);
     SimpleTest.finish();
   }
 
   SimpleTest.waitForExplicitFinish();