Bug 1025824 - Fix mHwcLayerMap handling r=sushil
[gecko.git] / dom / base / Navigator.cpp
blobb4909e26790ed1049ed6bd343647216d7fbcdaa1
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 ts=2 et tw=78: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 // Needs to be first.
8 #include "base/basictypes.h"
10 #include "Navigator.h"
11 #include "nsIXULAppInfo.h"
12 #include "nsPluginArray.h"
13 #include "nsMimeTypeArray.h"
14 #include "mozilla/MemoryReporting.h"
15 #include "mozilla/dom/DesktopNotification.h"
16 #include "nsGeolocation.h"
17 #include "nsIHttpProtocolHandler.h"
18 #include "nsIContentPolicy.h"
19 #include "nsIContentSecurityPolicy.h"
20 #include "nsContentPolicyUtils.h"
21 #include "nsCrossSiteListenerProxy.h"
22 #include "nsISupportsPriority.h"
23 #include "nsICachingChannel.h"
24 #include "nsIWebContentHandlerRegistrar.h"
25 #include "nsICookiePermission.h"
26 #include "nsIScriptSecurityManager.h"
27 #include "nsCharSeparatedTokenizer.h"
28 #include "nsContentUtils.h"
29 #include "nsUnicharUtils.h"
30 #include "mozilla/Preferences.h"
31 #include "mozilla/Telemetry.h"
32 #include "BatteryManager.h"
33 #include "mozilla/dom/PowerManager.h"
34 #include "mozilla/dom/WakeLock.h"
35 #include "mozilla/dom/power/PowerManagerService.h"
36 #include "mozilla/dom/MobileMessageManager.h"
37 #include "mozilla/dom/ServiceWorkerContainer.h"
38 #include "mozilla/dom/Telephony.h"
39 #include "mozilla/Hal.h"
40 #include "nsISiteSpecificUserAgent.h"
41 #include "mozilla/ClearOnShutdown.h"
42 #include "mozilla/StaticPtr.h"
43 #include "Connection.h"
44 #include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent()
45 #include "nsGlobalWindow.h"
46 #ifdef MOZ_B2G
47 #include "nsIMobileIdentityService.h"
48 #endif
49 #ifdef MOZ_B2G_RIL
50 #include "mozilla/dom/IccManager.h"
51 #include "mozilla/dom/CellBroadcast.h"
52 #include "mozilla/dom/MobileConnectionArray.h"
53 #include "mozilla/dom/Voicemail.h"
54 #endif
55 #include "nsIIdleObserver.h"
56 #include "nsIPermissionManager.h"
57 #include "nsMimeTypes.h"
58 #include "nsNetUtil.h"
59 #include "nsIHttpChannel.h"
60 #include "nsIHttpChannelInternal.h"
61 #include "TimeManager.h"
62 #include "DeviceStorage.h"
63 #include "nsIDOMNavigatorSystemMessages.h"
64 #include "nsStreamUtils.h"
65 #include "nsIAppsService.h"
66 #include "mozIApplication.h"
67 #include "WidgetUtils.h"
68 #include "mozIThirdPartyUtil.h"
69 #include "nsChannelPolicy.h"
71 #ifdef MOZ_MEDIA_NAVIGATOR
72 #include "MediaManager.h"
73 #endif
74 #ifdef MOZ_B2G_BT
75 #include "BluetoothManager.h"
76 #endif
77 #include "DOMCameraManager.h"
79 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
80 #include "AudioChannelManager.h"
81 #endif
83 #ifdef MOZ_B2G_FM
84 #include "mozilla/dom/FMRadio.h"
85 #endif
87 #include "nsIDOMGlobalPropertyInitializer.h"
88 #include "mozilla/dom/DataStoreService.h"
89 #include "nsJSUtils.h"
91 #include "nsScriptNameSpaceManager.h"
93 #include "mozilla/dom/NavigatorBinding.h"
94 #include "mozilla/dom/Promise.h"
96 #include "nsIUploadChannel2.h"
97 #include "nsFormData.h"
98 #include "nsIPrivateBrowsingChannel.h"
99 #include "nsIDocShell.h"
101 #include "WorkerPrivate.h"
102 #include "WorkerRunnable.h"
104 #if defined(XP_LINUX)
105 #include "mozilla/Hal.h"
106 #endif
107 #include "mozilla/dom/ContentChild.h"
109 namespace mozilla {
110 namespace dom {
112 static bool sDoNotTrackEnabled = false;
113 static uint32_t sDoNotTrackValue = 1;
114 static bool sVibratorEnabled = false;
115 static uint32_t sMaxVibrateMS = 0;
116 static uint32_t sMaxVibrateListLen = 0;
118 /* static */
119 void
120 Navigator::Init()
122 Preferences::AddBoolVarCache(&sDoNotTrackEnabled,
123 "privacy.donottrackheader.enabled",
124 false);
125 Preferences::AddUintVarCache(&sDoNotTrackValue,
126 "privacy.donottrackheader.value",
128 Preferences::AddBoolVarCache(&sVibratorEnabled,
129 "dom.vibrator.enabled", true);
130 Preferences::AddUintVarCache(&sMaxVibrateMS,
131 "dom.vibrator.max_vibrate_ms", 10000);
132 Preferences::AddUintVarCache(&sMaxVibrateListLen,
133 "dom.vibrator.max_vibrate_list_len", 128);
136 Navigator::Navigator(nsPIDOMWindow* aWindow)
137 : mWindow(aWindow)
139 MOZ_ASSERT(aWindow->IsInnerWindow(), "Navigator must get an inner window!");
140 SetIsDOMBinding();
143 Navigator::~Navigator()
145 Invalidate();
148 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Navigator)
149 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
150 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMNavigator)
151 NS_INTERFACE_MAP_ENTRY(nsIDOMNavigator)
152 NS_INTERFACE_MAP_ENTRY(nsIMozNavigatorNetwork)
153 NS_INTERFACE_MAP_END
155 NS_IMPL_CYCLE_COLLECTING_ADDREF(Navigator)
156 NS_IMPL_CYCLE_COLLECTING_RELEASE(Navigator)
158 NS_IMPL_CYCLE_COLLECTION_CLASS(Navigator)
160 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Navigator)
161 tmp->Invalidate();
162 NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
163 NS_IMPL_CYCLE_COLLECTION_UNLINK(mCachedResolveResults)
164 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
165 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
167 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator)
168 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPlugins)
169 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMimeTypes)
170 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGeolocation)
171 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNotification)
172 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryManager)
173 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPowerManager)
174 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMobileMessageManager)
175 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTelephony)
176 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConnection)
177 #ifdef MOZ_B2G_RIL
178 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMobileConnections)
179 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCellBroadcast)
180 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIccManager)
181 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVoicemail)
182 #endif
183 #ifdef MOZ_B2G_BT
184 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBluetooth)
185 #endif
186 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
187 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAudioChannelManager)
188 #endif
189 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCameraManager)
190 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessagesManager)
191 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDeviceStorageStores)
192 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTimeManager)
193 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServiceWorkerContainer)
195 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
196 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCachedResolveResults)
197 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
198 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
200 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(Navigator)
202 void
203 Navigator::Invalidate()
205 // Don't clear mWindow here so we know we've got a non-null mWindow
206 // until we're unlinked.
208 if (mPlugins) {
209 mPlugins->Invalidate();
210 mPlugins = nullptr;
213 mMimeTypes = nullptr;
215 // If there is a page transition, make sure delete the geolocation object.
216 if (mGeolocation) {
217 mGeolocation->Shutdown();
218 mGeolocation = nullptr;
221 if (mNotification) {
222 mNotification->Shutdown();
223 mNotification = nullptr;
226 if (mBatteryManager) {
227 mBatteryManager->Shutdown();
228 mBatteryManager = nullptr;
231 #ifdef MOZ_B2G_FM
232 if (mFMRadio) {
233 mFMRadio->Shutdown();
234 mFMRadio = nullptr;
236 #endif
238 if (mPowerManager) {
239 mPowerManager->Shutdown();
240 mPowerManager = nullptr;
243 if (mMobileMessageManager) {
244 mMobileMessageManager->Shutdown();
245 mMobileMessageManager = nullptr;
248 if (mTelephony) {
249 mTelephony = nullptr;
252 if (mConnection) {
253 mConnection->Shutdown();
254 mConnection = nullptr;
257 #ifdef MOZ_B2G_RIL
258 if (mMobileConnections) {
259 mMobileConnections = nullptr;
262 if (mCellBroadcast) {
263 mCellBroadcast = nullptr;
266 if (mIccManager) {
267 mIccManager->Shutdown();
268 mIccManager = nullptr;
271 if (mVoicemail) {
272 mVoicemail = nullptr;
274 #endif
276 #ifdef MOZ_B2G_BT
277 if (mBluetooth) {
278 mBluetooth = nullptr;
280 #endif
282 mCameraManager = nullptr;
284 if (mMessagesManager) {
285 mMessagesManager = nullptr;
288 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
289 if (mAudioChannelManager) {
290 mAudioChannelManager = nullptr;
292 #endif
294 uint32_t len = mDeviceStorageStores.Length();
295 for (uint32_t i = 0; i < len; ++i) {
296 mDeviceStorageStores[i]->Shutdown();
298 mDeviceStorageStores.Clear();
300 if (mTimeManager) {
301 mTimeManager = nullptr;
304 mServiceWorkerContainer = nullptr;
307 //*****************************************************************************
308 // Navigator::nsIDOMNavigator
309 //*****************************************************************************
311 NS_IMETHODIMP
312 Navigator::GetUserAgent(nsAString& aUserAgent)
314 nsresult rv = NS_GetNavigatorUserAgent(aUserAgent);
315 NS_ENSURE_SUCCESS(rv, rv);
317 if (!mWindow || !mWindow->GetDocShell()) {
318 return NS_OK;
321 nsIDocument* doc = mWindow->GetExtantDoc();
322 if (!doc) {
323 return NS_OK;
326 nsCOMPtr<nsIURI> codebaseURI;
327 doc->NodePrincipal()->GetURI(getter_AddRefs(codebaseURI));
328 if (!codebaseURI) {
329 return NS_OK;
332 nsCOMPtr<nsISiteSpecificUserAgent> siteSpecificUA =
333 do_GetService("@mozilla.org/dom/site-specific-user-agent;1");
334 NS_ENSURE_TRUE(siteSpecificUA, NS_OK);
336 return siteSpecificUA->GetUserAgentForURIAndWindow(codebaseURI, mWindow,
337 aUserAgent);
340 NS_IMETHODIMP
341 Navigator::GetAppCodeName(nsAString& aAppCodeName)
343 nsresult rv;
345 nsCOMPtr<nsIHttpProtocolHandler>
346 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
347 NS_ENSURE_SUCCESS(rv, rv);
349 nsAutoCString appName;
350 rv = service->GetAppName(appName);
351 CopyASCIItoUTF16(appName, aAppCodeName);
353 return rv;
356 NS_IMETHODIMP
357 Navigator::GetAppVersion(nsAString& aAppVersion)
359 return NS_GetNavigatorAppVersion(aAppVersion);
362 NS_IMETHODIMP
363 Navigator::GetAppName(nsAString& aAppName)
365 NS_GetNavigatorAppName(aAppName);
366 return NS_OK;
370 * Returns the value of Accept-Languages (HTTP header) as a nsTArray of
371 * languages. The value is set in the preference by the user ("Content
372 * Languages").
374 * "en", "en-US" and "i-cherokee" and "" are valid languages tokens.
376 * An empty array will be returned if there is no valid languages.
378 void
379 Navigator::GetAcceptLanguages(nsTArray<nsString>& aLanguages)
381 // E.g. "de-de, en-us,en".
382 const nsAdoptingString& acceptLang =
383 Preferences::GetLocalizedString("intl.accept_languages");
385 // Split values on commas.
386 nsCharSeparatedTokenizer langTokenizer(acceptLang, ',');
387 while (langTokenizer.hasMoreTokens()) {
388 nsDependentSubstring lang = langTokenizer.nextToken();
390 // Replace "_" with "-" to avoid POSIX/Windows "en_US" notation.
391 // NOTE: we should probably rely on the pref being set correctly.
392 if (lang.Length() > 2 && lang[2] == char16_t('_')) {
393 lang.Replace(2, 1, char16_t('-'));
396 // Use uppercase for country part, e.g. "en-US", not "en-us", see BCP47
397 // only uppercase 2-letter country codes, not "zh-Hant", "de-DE-x-goethe".
398 // NOTE: we should probably rely on the pref being set correctly.
399 if (lang.Length() > 2) {
400 nsCharSeparatedTokenizer localeTokenizer(lang, '-');
401 int32_t pos = 0;
402 bool first = true;
403 while (localeTokenizer.hasMoreTokens()) {
404 const nsSubstring& code = localeTokenizer.nextToken();
406 if (code.Length() == 2 && !first) {
407 nsAutoString upper(code);
408 ToUpperCase(upper);
409 lang.Replace(pos, code.Length(), upper);
412 pos += code.Length() + 1; // 1 is the separator
413 first = false;
417 aLanguages.AppendElement(lang);
422 * Do not use UI language (chosen app locale) here but the first value set in
423 * the Accept Languages header, see ::GetAcceptLanguages().
425 * See RFC 2616, Section 15.1.4 "Privacy Issues Connected to Accept Headers" for
426 * the reasons why.
428 NS_IMETHODIMP
429 Navigator::GetLanguage(nsAString& aLanguage)
431 nsTArray<nsString> languages;
432 GetLanguages(languages);
433 if (languages.Length() >= 1) {
434 aLanguage.Assign(languages[0]);
435 } else {
436 aLanguage.Truncate();
439 return NS_OK;
442 void
443 Navigator::GetLanguages(nsTArray<nsString>& aLanguages)
445 GetAcceptLanguages(aLanguages);
447 // The returned value is cached by the binding code. The window listen to the
448 // accept languages change and will clear the cache when needed. It has to
449 // take care of dispatching the DOM event already and the invalidation and the
450 // event has to be timed correctly.
453 NS_IMETHODIMP
454 Navigator::GetPlatform(nsAString& aPlatform)
456 return NS_GetNavigatorPlatform(aPlatform);
459 NS_IMETHODIMP
460 Navigator::GetOscpu(nsAString& aOSCPU)
462 if (!nsContentUtils::IsCallerChrome()) {
463 const nsAdoptingString& override =
464 Preferences::GetString("general.oscpu.override");
466 if (override) {
467 aOSCPU = override;
468 return NS_OK;
472 nsresult rv;
474 nsCOMPtr<nsIHttpProtocolHandler>
475 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
476 NS_ENSURE_SUCCESS(rv, rv);
478 nsAutoCString oscpu;
479 rv = service->GetOscpu(oscpu);
480 CopyASCIItoUTF16(oscpu, aOSCPU);
482 return rv;
485 NS_IMETHODIMP
486 Navigator::GetVendor(nsAString& aVendor)
488 aVendor.Truncate();
489 return NS_OK;
492 NS_IMETHODIMP
493 Navigator::GetVendorSub(nsAString& aVendorSub)
495 aVendorSub.Truncate();
496 return NS_OK;
499 NS_IMETHODIMP
500 Navigator::GetProduct(nsAString& aProduct)
502 aProduct.AssignLiteral("Gecko");
503 return NS_OK;
506 NS_IMETHODIMP
507 Navigator::GetProductSub(nsAString& aProductSub)
509 // Legacy build ID hardcoded for backward compatibility (bug 776376)
510 aProductSub.AssignLiteral("20100101");
511 return NS_OK;
514 nsMimeTypeArray*
515 Navigator::GetMimeTypes(ErrorResult& aRv)
517 if (!mMimeTypes) {
518 if (!mWindow) {
519 aRv.Throw(NS_ERROR_UNEXPECTED);
520 return nullptr;
522 mMimeTypes = new nsMimeTypeArray(mWindow);
525 return mMimeTypes;
528 nsPluginArray*
529 Navigator::GetPlugins(ErrorResult& aRv)
531 if (!mPlugins) {
532 if (!mWindow) {
533 aRv.Throw(NS_ERROR_UNEXPECTED);
534 return nullptr;
536 mPlugins = new nsPluginArray(mWindow);
537 mPlugins->Init();
540 return mPlugins;
543 // Values for the network.cookie.cookieBehavior pref are documented in
544 // nsCookieService.cpp.
545 #define COOKIE_BEHAVIOR_REJECT 2
547 bool
548 Navigator::CookieEnabled()
550 bool cookieEnabled =
551 (Preferences::GetInt("network.cookie.cookieBehavior",
552 COOKIE_BEHAVIOR_REJECT) != COOKIE_BEHAVIOR_REJECT);
554 // Check whether an exception overrides the global cookie behavior
555 // Note that the code for getting the URI here matches that in
556 // nsHTMLDocument::SetCookie.
557 if (!mWindow || !mWindow->GetDocShell()) {
558 return cookieEnabled;
561 nsCOMPtr<nsIDocument> doc = mWindow->GetExtantDoc();
562 if (!doc) {
563 return cookieEnabled;
566 nsCOMPtr<nsIURI> codebaseURI;
567 doc->NodePrincipal()->GetURI(getter_AddRefs(codebaseURI));
569 if (!codebaseURI) {
570 // Not a codebase, so technically can't set cookies, but let's
571 // just return the default value.
572 return cookieEnabled;
575 nsCOMPtr<nsICookiePermission> permMgr =
576 do_GetService(NS_COOKIEPERMISSION_CONTRACTID);
577 NS_ENSURE_TRUE(permMgr, cookieEnabled);
579 // Pass null for the channel, just like the cookie service does.
580 nsCookieAccess access;
581 nsresult rv = permMgr->CanAccess(codebaseURI, nullptr, &access);
582 NS_ENSURE_SUCCESS(rv, cookieEnabled);
584 if (access != nsICookiePermission::ACCESS_DEFAULT) {
585 cookieEnabled = access != nsICookiePermission::ACCESS_DENY;
588 return cookieEnabled;
591 bool
592 Navigator::OnLine()
594 return !NS_IsOffline();
597 NS_IMETHODIMP
598 Navigator::GetBuildID(nsAString& aBuildID)
600 if (!nsContentUtils::IsCallerChrome()) {
601 const nsAdoptingString& override =
602 Preferences::GetString("general.buildID.override");
604 if (override) {
605 aBuildID = override;
606 return NS_OK;
610 nsCOMPtr<nsIXULAppInfo> appInfo =
611 do_GetService("@mozilla.org/xre/app-info;1");
612 if (!appInfo) {
613 return NS_ERROR_NOT_IMPLEMENTED;
616 nsAutoCString buildID;
617 nsresult rv = appInfo->GetAppBuildID(buildID);
618 if (NS_FAILED(rv)) {
619 return rv;
622 aBuildID.Truncate();
623 AppendASCIItoUTF16(buildID, aBuildID);
624 return NS_OK;
627 NS_IMETHODIMP
628 Navigator::GetDoNotTrack(nsAString &aResult)
630 if (sDoNotTrackEnabled) {
631 if (sDoNotTrackValue == 0) {
632 aResult.AssignLiteral("0");
633 } else {
634 aResult.AssignLiteral("1");
636 } else {
637 aResult.AssignLiteral("unspecified");
640 return NS_OK;
643 bool
644 Navigator::JavaEnabled(ErrorResult& aRv)
646 Telemetry::AutoTimer<Telemetry::CHECK_JAVA_ENABLED> telemetryTimer;
648 // Return true if we have a handler for the java mime
649 nsAdoptingString javaMIME = Preferences::GetString("plugin.java.mime");
650 NS_ENSURE_TRUE(!javaMIME.IsEmpty(), false);
652 if (!mMimeTypes) {
653 if (!mWindow) {
654 aRv.Throw(NS_ERROR_UNEXPECTED);
655 return false;
657 mMimeTypes = new nsMimeTypeArray(mWindow);
660 RefreshMIMEArray();
662 nsMimeType *mimeType = mMimeTypes->NamedItem(javaMIME);
664 return mimeType && mimeType->GetEnabledPlugin();
667 void
668 Navigator::RefreshMIMEArray()
670 if (mMimeTypes) {
671 mMimeTypes->Refresh();
675 namespace {
677 class VibrateWindowListener : public nsIDOMEventListener
679 public:
680 VibrateWindowListener(nsIDOMWindow* aWindow, nsIDocument* aDocument)
682 mWindow = do_GetWeakReference(aWindow);
683 mDocument = do_GetWeakReference(aDocument);
685 NS_NAMED_LITERAL_STRING(visibilitychange, "visibilitychange");
686 aDocument->AddSystemEventListener(visibilitychange,
687 this, /* listener */
688 true, /* use capture */
689 false /* wants untrusted */);
692 virtual ~VibrateWindowListener()
696 void RemoveListener();
698 NS_DECL_ISUPPORTS
699 NS_DECL_NSIDOMEVENTLISTENER
701 private:
702 nsWeakPtr mWindow;
703 nsWeakPtr mDocument;
706 NS_IMPL_ISUPPORTS(VibrateWindowListener, nsIDOMEventListener)
708 StaticRefPtr<VibrateWindowListener> gVibrateWindowListener;
710 NS_IMETHODIMP
711 VibrateWindowListener::HandleEvent(nsIDOMEvent* aEvent)
713 nsCOMPtr<nsIDocument> doc =
714 do_QueryInterface(aEvent->InternalDOMEvent()->GetTarget());
716 if (!doc || doc->Hidden()) {
717 // It's important that we call CancelVibrate(), not Vibrate() with an
718 // empty list, because Vibrate() will fail if we're no longer focused, but
719 // CancelVibrate() will succeed, so long as nobody else has started a new
720 // vibration pattern.
721 nsCOMPtr<nsIDOMWindow> window = do_QueryReferent(mWindow);
722 hal::CancelVibrate(window);
723 RemoveListener();
724 gVibrateWindowListener = nullptr;
725 // Careful: The line above might have deleted |this|!
728 return NS_OK;
731 void
732 VibrateWindowListener::RemoveListener()
734 nsCOMPtr<EventTarget> target = do_QueryReferent(mDocument);
735 if (!target) {
736 return;
738 NS_NAMED_LITERAL_STRING(visibilitychange, "visibilitychange");
739 target->RemoveSystemEventListener(visibilitychange, this,
740 true /* use capture */);
743 } // anonymous namespace
745 void
746 Navigator::AddIdleObserver(MozIdleObserver& aIdleObserver, ErrorResult& aRv)
748 if (!mWindow) {
749 aRv.Throw(NS_ERROR_UNEXPECTED);
750 return;
752 CallbackObjectHolder<MozIdleObserver, nsIIdleObserver> holder(&aIdleObserver);
753 nsCOMPtr<nsIIdleObserver> obs = holder.ToXPCOMCallback();
754 if (NS_FAILED(mWindow->RegisterIdleObserver(obs))) {
755 NS_WARNING("Failed to add idle observer.");
759 void
760 Navigator::RemoveIdleObserver(MozIdleObserver& aIdleObserver, ErrorResult& aRv)
762 if (!mWindow) {
763 aRv.Throw(NS_ERROR_UNEXPECTED);
764 return;
766 CallbackObjectHolder<MozIdleObserver, nsIIdleObserver> holder(&aIdleObserver);
767 nsCOMPtr<nsIIdleObserver> obs = holder.ToXPCOMCallback();
768 if (NS_FAILED(mWindow->UnregisterIdleObserver(obs))) {
769 NS_WARNING("Failed to remove idle observer.");
773 bool
774 Navigator::Vibrate(uint32_t aDuration)
776 nsAutoTArray<uint32_t, 1> pattern;
777 pattern.AppendElement(aDuration);
778 return Vibrate(pattern);
781 bool
782 Navigator::Vibrate(const nsTArray<uint32_t>& aPattern)
784 if (!mWindow) {
785 return false;
788 nsCOMPtr<nsIDocument> doc = mWindow->GetExtantDoc();
789 if (!doc) {
790 return false;
793 if (doc->Hidden()) {
794 // Hidden documents cannot start or stop a vibration.
795 return false;
798 nsTArray<uint32_t> pattern(aPattern);
800 if (pattern.Length() > sMaxVibrateListLen) {
801 pattern.SetLength(sMaxVibrateListLen);
804 for (size_t i = 0; i < pattern.Length(); ++i) {
805 if (pattern[i] > sMaxVibrateMS) {
806 pattern[i] = sMaxVibrateMS;
810 // The spec says we check sVibratorEnabled after we've done the sanity
811 // checking on the pattern.
812 if (pattern.IsEmpty() || !sVibratorEnabled) {
813 return true;
816 // Add a listener to cancel the vibration if the document becomes hidden,
817 // and remove the old visibility listener, if there was one.
819 if (!gVibrateWindowListener) {
820 // If gVibrateWindowListener is null, this is the first time we've vibrated,
821 // and we need to register a listener to clear gVibrateWindowListener on
822 // shutdown.
823 ClearOnShutdown(&gVibrateWindowListener);
825 else {
826 gVibrateWindowListener->RemoveListener();
828 gVibrateWindowListener = new VibrateWindowListener(mWindow, doc);
830 hal::Vibrate(pattern, mWindow);
831 return true;
834 //*****************************************************************************
835 // Pointer Events interface
836 //*****************************************************************************
838 uint32_t
839 Navigator::MaxTouchPoints()
841 nsCOMPtr<nsIWidget> widget = widget::WidgetUtils::DOMWindowToWidget(mWindow);
843 NS_ENSURE_TRUE(widget, 0);
844 return widget->GetMaxTouchPoints();
847 //*****************************************************************************
848 // Navigator::nsIDOMClientInformation
849 //*****************************************************************************
851 void
852 Navigator::RegisterContentHandler(const nsAString& aMIMEType,
853 const nsAString& aURI,
854 const nsAString& aTitle,
855 ErrorResult& aRv)
857 if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell()) {
858 return;
861 nsCOMPtr<nsIWebContentHandlerRegistrar> registrar =
862 do_GetService(NS_WEBCONTENTHANDLERREGISTRAR_CONTRACTID);
863 if (!registrar) {
864 return;
867 aRv = registrar->RegisterContentHandler(aMIMEType, aURI, aTitle,
868 mWindow->GetOuterWindow());
871 void
872 Navigator::RegisterProtocolHandler(const nsAString& aProtocol,
873 const nsAString& aURI,
874 const nsAString& aTitle,
875 ErrorResult& aRv)
877 if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell()) {
878 return;
881 nsCOMPtr<nsIWebContentHandlerRegistrar> registrar =
882 do_GetService(NS_WEBCONTENTHANDLERREGISTRAR_CONTRACTID);
883 if (!registrar) {
884 return;
887 aRv = registrar->RegisterProtocolHandler(aProtocol, aURI, aTitle,
888 mWindow->GetOuterWindow());
891 bool
892 Navigator::MozIsLocallyAvailable(const nsAString &aURI,
893 bool aWhenOffline,
894 ErrorResult& aRv)
896 nsCOMPtr<nsIURI> uri;
897 nsresult rv = NS_NewURI(getter_AddRefs(uri), aURI);
898 if (NS_FAILED(rv)) {
899 aRv.Throw(rv);
900 return false;
903 // This method of checking the cache will only work for http/https urls.
904 bool match;
905 rv = uri->SchemeIs("http", &match);
906 if (NS_FAILED(rv)) {
907 aRv.Throw(rv);
908 return false;
911 if (!match) {
912 rv = uri->SchemeIs("https", &match);
913 if (NS_FAILED(rv)) {
914 aRv.Throw(rv);
915 return false;
917 if (!match) {
918 aRv.Throw(NS_ERROR_DOM_BAD_URI);
919 return false;
923 // Same origin check.
924 JSContext *cx = nsContentUtils::GetCurrentJSContext();
925 if (!cx) {
926 aRv.Throw(NS_ERROR_FAILURE);
927 return false;
930 rv = nsContentUtils::GetSecurityManager()->CheckSameOrigin(cx, uri);
931 if (NS_FAILED(rv)) {
932 aRv.Throw(rv);
933 return false;
936 // These load flags cause an error to be thrown if there is no
937 // valid cache entry, and skip the load if there is.
938 // If the cache is busy, assume that it is not yet available rather
939 // than waiting for it to become available.
940 uint32_t loadFlags = nsIChannel::INHIBIT_CACHING |
941 nsICachingChannel::LOAD_NO_NETWORK_IO |
942 nsICachingChannel::LOAD_ONLY_IF_MODIFIED |
943 nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY;
945 if (aWhenOffline) {
946 loadFlags |= nsICachingChannel::LOAD_CHECK_OFFLINE_CACHE |
947 nsICachingChannel::LOAD_ONLY_FROM_CACHE |
948 nsIRequest::LOAD_FROM_CACHE;
951 if (!mWindow) {
952 aRv.Throw(NS_ERROR_UNEXPECTED);
953 return false;
956 nsCOMPtr<nsILoadGroup> loadGroup;
957 nsCOMPtr<nsIDocument> doc = mWindow->GetDoc();
958 if (doc) {
959 loadGroup = doc->GetDocumentLoadGroup();
962 nsCOMPtr<nsIChannel> channel;
963 rv = NS_NewChannel(getter_AddRefs(channel), uri,
964 nullptr, loadGroup, nullptr, loadFlags);
965 if (NS_FAILED(rv)) {
966 aRv.Throw(rv);
967 return false;
970 nsCOMPtr<nsIInputStream> stream;
971 rv = channel->Open(getter_AddRefs(stream));
972 if (NS_FAILED(rv)) {
973 aRv.Throw(rv);
974 return false;
977 stream->Close();
979 nsresult status;
980 rv = channel->GetStatus(&status);
981 if (NS_FAILED(rv)) {
982 aRv.Throw(rv);
983 return false;
986 if (NS_FAILED(status)) {
987 return false;
990 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
991 bool isAvailable;
992 rv = httpChannel->GetRequestSucceeded(&isAvailable);
993 if (NS_FAILED(rv)) {
994 aRv.Throw(rv);
995 return false;
997 return isAvailable;
1000 nsDOMDeviceStorage*
1001 Navigator::GetDeviceStorage(const nsAString& aType, ErrorResult& aRv)
1003 if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell()) {
1004 aRv.Throw(NS_ERROR_FAILURE);
1005 return nullptr;
1008 nsRefPtr<nsDOMDeviceStorage> storage;
1009 nsDOMDeviceStorage::CreateDeviceStorageFor(mWindow, aType,
1010 getter_AddRefs(storage));
1012 if (!storage) {
1013 return nullptr;
1016 mDeviceStorageStores.AppendElement(storage);
1017 return storage;
1020 void
1021 Navigator::GetDeviceStorages(const nsAString& aType,
1022 nsTArray<nsRefPtr<nsDOMDeviceStorage> >& aStores,
1023 ErrorResult& aRv)
1025 if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell()) {
1026 aRv.Throw(NS_ERROR_FAILURE);
1027 return;
1030 nsDOMDeviceStorage::CreateDeviceStoragesFor(mWindow, aType, aStores);
1032 mDeviceStorageStores.AppendElements(aStores);
1035 Geolocation*
1036 Navigator::GetGeolocation(ErrorResult& aRv)
1038 if (mGeolocation) {
1039 return mGeolocation;
1042 if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell()) {
1043 aRv.Throw(NS_ERROR_FAILURE);
1044 return nullptr;
1047 mGeolocation = new Geolocation();
1048 if (NS_FAILED(mGeolocation->Init(mWindow->GetOuterWindow()))) {
1049 mGeolocation = nullptr;
1050 aRv.Throw(NS_ERROR_FAILURE);
1051 return nullptr;
1054 return mGeolocation;
1057 class BeaconStreamListener MOZ_FINAL : public nsIStreamListener
1059 public:
1060 BeaconStreamListener() {}
1062 NS_DECL_ISUPPORTS
1063 NS_DECL_NSISTREAMLISTENER
1064 NS_DECL_NSIREQUESTOBSERVER
1067 NS_IMPL_ISUPPORTS(BeaconStreamListener,
1068 nsIStreamListener,
1069 nsIRequestObserver)
1072 NS_IMETHODIMP
1073 BeaconStreamListener::OnStartRequest(nsIRequest *aRequest,
1074 nsISupports *aContext)
1076 aRequest->Cancel(NS_ERROR_NET_INTERRUPT);
1077 return NS_BINDING_ABORTED;
1080 NS_IMETHODIMP
1081 BeaconStreamListener::OnStopRequest(nsIRequest *aRequest,
1082 nsISupports *aContext,
1083 nsresult aStatus)
1085 return NS_OK;
1088 NS_IMETHODIMP
1089 BeaconStreamListener::OnDataAvailable(nsIRequest *aRequest,
1090 nsISupports *ctxt,
1091 nsIInputStream *inStr,
1092 uint64_t sourceOffset,
1093 uint32_t count)
1095 MOZ_ASSERT(false);
1096 return NS_OK;
1099 bool
1100 Navigator::SendBeacon(const nsAString& aUrl,
1101 const Nullable<ArrayBufferViewOrBlobOrStringOrFormData>& aData,
1102 ErrorResult& aRv)
1104 if (!mWindow) {
1105 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
1106 return false;
1109 nsCOMPtr<nsIDocument> doc = mWindow->GetDoc();
1110 if (!doc) {
1111 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
1112 return false;
1115 nsIURI* documentURI = doc->GetDocumentURI();
1116 if (!documentURI) {
1117 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
1118 return false;
1121 nsCOMPtr<nsIURI> uri;
1122 nsresult rv = nsContentUtils::NewURIWithDocumentCharset(
1123 getter_AddRefs(uri),
1124 aUrl,
1125 doc,
1126 doc->GetDocBaseURI());
1127 if (NS_FAILED(rv)) {
1128 aRv.Throw(NS_ERROR_DOM_URL_MISMATCH_ERR);
1129 return false;
1132 // Check whether this is a sane URI to load
1133 // Explicitly disallow things like chrome:, javascript:, and data: URIs
1134 nsCOMPtr<nsIPrincipal> principal = doc->NodePrincipal();
1135 nsCOMPtr<nsIScriptSecurityManager> secMan = nsContentUtils::GetSecurityManager();
1136 uint32_t flags = nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL
1137 & nsIScriptSecurityManager::DISALLOW_SCRIPT;
1138 rv = secMan->CheckLoadURIWithPrincipal(principal,
1139 uri,
1140 flags);
1141 if (NS_FAILED(rv)) {
1142 // Bad URI
1143 aRv.Throw(rv);
1144 return false;
1147 // Check whether the CSP allows us to load
1148 int16_t shouldLoad = nsIContentPolicy::ACCEPT;
1149 rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_BEACON,
1150 uri,
1151 principal,
1152 doc,
1153 EmptyCString(), //mime guess
1154 nullptr, //extra
1155 &shouldLoad,
1156 nsContentUtils::GetContentPolicy(),
1157 nsContentUtils::GetSecurityManager());
1158 if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
1159 // Disallowed by content policy
1160 aRv.Throw(NS_ERROR_CONTENT_BLOCKED);
1161 return false;
1164 nsCOMPtr<nsIChannel> channel;
1165 nsCOMPtr<nsIChannelPolicy> channelPolicy;
1166 nsCOMPtr<nsIContentSecurityPolicy> csp;
1167 rv = principal->GetCsp(getter_AddRefs(csp));
1168 if (NS_FAILED(rv)) {
1169 aRv.Throw(NS_ERROR_FAILURE);
1170 return false;
1173 if (csp) {
1174 channelPolicy = do_CreateInstance(NSCHANNELPOLICY_CONTRACTID);
1175 channelPolicy->SetContentSecurityPolicy(csp);
1176 channelPolicy->SetLoadType(nsIContentPolicy::TYPE_BEACON);
1178 rv = NS_NewChannel(getter_AddRefs(channel),
1179 uri,
1180 nullptr,
1181 nullptr,
1182 nullptr,
1183 nsIRequest::LOAD_NORMAL,
1184 channelPolicy);
1185 if (NS_FAILED(rv)) {
1186 aRv.Throw(rv);
1187 return false;
1190 nsCOMPtr<nsIPrivateBrowsingChannel> pbChannel = do_QueryInterface(channel);
1191 if (pbChannel) {
1192 nsIDocShell* docShell = mWindow->GetDocShell();
1193 nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
1194 if (loadContext) {
1195 rv = pbChannel->SetPrivate(loadContext->UsePrivateBrowsing());
1196 if (NS_FAILED(rv)) {
1197 NS_WARNING("Setting the privacy status on the beacon channel failed");
1202 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
1203 if (!httpChannel) {
1204 // Beacon spec only supports HTTP requests at this time
1205 aRv.Throw(NS_ERROR_DOM_BAD_URI);
1206 return false;
1208 httpChannel->SetReferrer(documentURI);
1210 // Anything that will need to refer to the window during the request
1211 // will need to be done now. For example, detection of whether any
1212 // cookies set by this request are foreign. Note that ThirdPartyUtil
1213 // (nsIThirdPartyUtil.isThirdPartyChannel) does a secondary check between
1214 // the channel URI and the cookie URI even when forceAllowThirdPartyCookie
1215 // is set, so this is safe with regard to redirects.
1216 nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal(do_QueryInterface(channel));
1217 nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil = do_GetService(THIRDPARTYUTIL_CONTRACTID);
1218 if (!httpChannelInternal) {
1219 aRv.Throw(NS_ERROR_DOM_BAD_URI);
1220 return false;
1222 bool isForeign = true;
1223 thirdPartyUtil->IsThirdPartyWindow(mWindow, uri, &isForeign);
1224 httpChannelInternal->SetForceAllowThirdPartyCookie(!isForeign);
1226 nsCString mimeType;
1227 if (!aData.IsNull()) {
1228 nsCOMPtr<nsIInputStream> in;
1230 if (aData.Value().IsString()) {
1231 nsCString stringData = NS_ConvertUTF16toUTF8(aData.Value().GetAsString());
1232 nsCOMPtr<nsIStringInputStream> strStream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
1233 if (NS_FAILED(rv)) {
1234 aRv.Throw(NS_ERROR_FAILURE);
1235 return false;
1237 rv = strStream->SetData(stringData.BeginReading(), stringData.Length());
1238 if (NS_FAILED(rv)) {
1239 aRv.Throw(NS_ERROR_FAILURE);
1240 return false;
1242 mimeType.AssignLiteral("text/plain;charset=UTF-8");
1243 in = strStream;
1245 } else if (aData.Value().IsArrayBufferView()) {
1247 nsCOMPtr<nsIStringInputStream> strStream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
1248 if (NS_FAILED(rv)) {
1249 aRv.Throw(NS_ERROR_FAILURE);
1250 return false;
1253 ArrayBufferView& view = aData.Value().GetAsArrayBufferView();
1254 view.ComputeLengthAndData();
1255 rv = strStream->SetData(reinterpret_cast<char*>(view.Data()),
1256 view.Length());
1258 if (NS_FAILED(rv)) {
1259 aRv.Throw(NS_ERROR_FAILURE);
1260 return false;
1262 mimeType.AssignLiteral("application/octet-stream");
1263 in = strStream;
1265 } else if (aData.Value().IsBlob()) {
1266 nsCOMPtr<nsIDOMBlob> blob = aData.Value().GetAsBlob();
1267 rv = blob->GetInternalStream(getter_AddRefs(in));
1268 if (NS_FAILED(rv)) {
1269 aRv.Throw(NS_ERROR_FAILURE);
1270 return false;
1272 nsAutoString type;
1273 rv = blob->GetType(type);
1274 if (NS_FAILED(rv)) {
1275 aRv.Throw(NS_ERROR_FAILURE);
1276 return false;
1278 mimeType = NS_ConvertUTF16toUTF8(type);
1280 } else if (aData.Value().IsFormData()) {
1281 nsFormData& form = aData.Value().GetAsFormData();
1282 uint64_t len;
1283 nsAutoCString charset;
1284 form.GetSendInfo(getter_AddRefs(in),
1285 &len,
1286 mimeType,
1287 charset);
1288 } else {
1289 MOZ_ASSERT(false, "switch statements not in sync");
1290 aRv.Throw(NS_ERROR_FAILURE);
1291 return false;
1294 nsCOMPtr<nsIUploadChannel2> uploadChannel = do_QueryInterface(channel);
1295 if (!uploadChannel) {
1296 aRv.Throw(NS_ERROR_FAILURE);
1297 return false;
1299 uploadChannel->ExplicitSetUploadStream(in, mimeType, -1,
1300 NS_LITERAL_CSTRING("POST"),
1301 false);
1302 } else {
1303 httpChannel->SetRequestMethod(NS_LITERAL_CSTRING("POST"));
1306 nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(channel);
1307 if (p) {
1308 p->SetPriority(nsISupportsPriority::PRIORITY_LOWEST);
1311 nsRefPtr<nsCORSListenerProxy> cors = new nsCORSListenerProxy(new BeaconStreamListener(),
1312 principal,
1313 true);
1315 // Start a preflight if cross-origin and content type is not whitelisted
1316 rv = secMan->CheckSameOriginURI(documentURI, uri, false);
1317 bool crossOrigin = NS_FAILED(rv);
1318 nsAutoCString contentType, parsedCharset;
1319 rv = NS_ParseContentType(mimeType, contentType, parsedCharset);
1320 if (crossOrigin &&
1321 contentType.Length() > 0 &&
1322 !contentType.Equals(APPLICATION_WWW_FORM_URLENCODED) &&
1323 !contentType.Equals(MULTIPART_FORM_DATA) &&
1324 !contentType.Equals(TEXT_PLAIN)) {
1325 nsCOMPtr<nsIChannel> preflightChannel;
1326 nsTArray<nsCString> unsafeHeaders;
1327 unsafeHeaders.AppendElement(NS_LITERAL_CSTRING("Content-Type"));
1328 rv = NS_StartCORSPreflight(channel,
1329 cors,
1330 principal,
1331 true,
1332 unsafeHeaders,
1333 getter_AddRefs(preflightChannel));
1334 } else {
1335 rv = channel->AsyncOpen(cors, nullptr);
1337 if (NS_FAILED(rv)) {
1338 aRv.Throw(rv);
1339 return false;
1341 return true;
1344 #ifdef MOZ_MEDIA_NAVIGATOR
1345 void
1346 Navigator::MozGetUserMedia(const MediaStreamConstraints& aConstraints,
1347 NavigatorUserMediaSuccessCallback& aOnSuccess,
1348 NavigatorUserMediaErrorCallback& aOnError,
1349 ErrorResult& aRv)
1351 CallbackObjectHolder<NavigatorUserMediaSuccessCallback,
1352 nsIDOMGetUserMediaSuccessCallback> holder1(&aOnSuccess);
1353 nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> onsuccess =
1354 holder1.ToXPCOMCallback();
1356 CallbackObjectHolder<NavigatorUserMediaErrorCallback,
1357 nsIDOMGetUserMediaErrorCallback> holder2(&aOnError);
1358 nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onerror = holder2.ToXPCOMCallback();
1360 if (!mWindow || !mWindow->GetOuterWindow() ||
1361 mWindow->GetOuterWindow()->GetCurrentInnerWindow() != mWindow) {
1362 aRv.Throw(NS_ERROR_NOT_AVAILABLE);
1363 return;
1366 bool privileged = nsContentUtils::IsChromeDoc(mWindow->GetExtantDoc());
1368 MediaManager* manager = MediaManager::Get();
1369 aRv = manager->GetUserMedia(privileged, mWindow, aConstraints,
1370 onsuccess, onerror);
1373 void
1374 Navigator::MozGetUserMediaDevices(const MediaStreamConstraints& aConstraints,
1375 MozGetUserMediaDevicesSuccessCallback& aOnSuccess,
1376 NavigatorUserMediaErrorCallback& aOnError,
1377 uint64_t aInnerWindowID,
1378 ErrorResult& aRv)
1380 CallbackObjectHolder<MozGetUserMediaDevicesSuccessCallback,
1381 nsIGetUserMediaDevicesSuccessCallback> holder1(&aOnSuccess);
1382 nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> onsuccess =
1383 holder1.ToXPCOMCallback();
1385 CallbackObjectHolder<NavigatorUserMediaErrorCallback,
1386 nsIDOMGetUserMediaErrorCallback> holder2(&aOnError);
1387 nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onerror = holder2.ToXPCOMCallback();
1389 if (!mWindow || !mWindow->GetOuterWindow() ||
1390 mWindow->GetOuterWindow()->GetCurrentInnerWindow() != mWindow) {
1391 aRv.Throw(NS_ERROR_NOT_AVAILABLE);
1392 return;
1395 MediaManager* manager = MediaManager::Get();
1396 aRv = manager->GetUserMediaDevices(mWindow, aConstraints, onsuccess, onerror,
1397 aInnerWindowID);
1399 #endif
1401 DesktopNotificationCenter*
1402 Navigator::GetMozNotification(ErrorResult& aRv)
1404 if (mNotification) {
1405 return mNotification;
1408 if (!mWindow || !mWindow->GetDocShell()) {
1409 aRv.Throw(NS_ERROR_FAILURE);
1410 return nullptr;
1413 mNotification = new DesktopNotificationCenter(mWindow);
1414 return mNotification;
1417 #ifdef MOZ_B2G_FM
1419 using mozilla::dom::FMRadio;
1421 FMRadio*
1422 Navigator::GetMozFMRadio(ErrorResult& aRv)
1424 if (!mFMRadio) {
1425 if (!mWindow) {
1426 aRv.Throw(NS_ERROR_UNEXPECTED);
1427 return nullptr;
1430 NS_ENSURE_TRUE(mWindow->GetDocShell(), nullptr);
1432 mFMRadio = new FMRadio();
1433 mFMRadio->Init(mWindow);
1436 return mFMRadio;
1439 #endif // MOZ_B2G_FM
1441 //*****************************************************************************
1442 // Navigator::nsINavigatorBattery
1443 //*****************************************************************************
1445 battery::BatteryManager*
1446 Navigator::GetBattery(ErrorResult& aRv)
1448 if (!mBatteryManager) {
1449 if (!mWindow) {
1450 aRv.Throw(NS_ERROR_UNEXPECTED);
1451 return nullptr;
1453 NS_ENSURE_TRUE(mWindow->GetDocShell(), nullptr);
1455 mBatteryManager = new battery::BatteryManager(mWindow);
1456 mBatteryManager->Init();
1459 return mBatteryManager;
1462 /* static */ already_AddRefed<Promise>
1463 Navigator::GetDataStores(nsPIDOMWindow* aWindow,
1464 const nsAString& aName,
1465 ErrorResult& aRv)
1467 if (!aWindow || !aWindow->GetDocShell()) {
1468 aRv.Throw(NS_ERROR_UNEXPECTED);
1469 return nullptr;
1472 nsRefPtr<DataStoreService> service = DataStoreService::GetOrCreate();
1473 if (!service) {
1474 aRv.Throw(NS_ERROR_FAILURE);
1475 return nullptr;
1478 nsCOMPtr<nsISupports> promise;
1479 aRv = service->GetDataStores(aWindow, aName, getter_AddRefs(promise));
1481 nsRefPtr<Promise> p = static_cast<Promise*>(promise.get());
1482 return p.forget();
1485 already_AddRefed<Promise>
1486 Navigator::GetDataStores(const nsAString& aName, ErrorResult& aRv)
1488 return GetDataStores(mWindow, aName, aRv);
1491 already_AddRefed<Promise>
1492 Navigator::GetFeature(const nsAString& aName)
1494 nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(mWindow);
1495 nsRefPtr<Promise> p = new Promise(go);
1497 #if defined(XP_LINUX)
1498 if (aName.EqualsLiteral("hardware.memory")) {
1499 // with seccomp enabled, fopen() should be in a non-sandboxed process
1500 if (XRE_GetProcessType() == GeckoProcessType_Default) {
1501 uint32_t memLevel = mozilla::hal::GetTotalSystemMemoryLevel();
1502 if (memLevel == 0) {
1503 p->MaybeReject(NS_ERROR_NOT_AVAILABLE);
1504 return p.forget();
1506 p->MaybeResolve((int)memLevel);
1507 } else {
1508 mozilla::dom::ContentChild* cc =
1509 mozilla::dom::ContentChild::GetSingleton();
1510 nsRefPtr<Promise> ipcRef(p);
1511 cc->SendGetSystemMemory(reinterpret_cast<uint64_t>(ipcRef.forget().take()));
1513 return p.forget();
1514 } // hardware.memory
1515 #endif
1516 // resolve with <undefined> because the feature name is not supported
1517 p->MaybeResolve(JS::UndefinedHandleValue);
1519 return p.forget();
1523 PowerManager*
1524 Navigator::GetMozPower(ErrorResult& aRv)
1526 if (!mPowerManager) {
1527 if (!mWindow) {
1528 aRv.Throw(NS_ERROR_UNEXPECTED);
1529 return nullptr;
1531 mPowerManager = PowerManager::CreateInstance(mWindow);
1532 if (!mPowerManager) {
1533 // We failed to get the power manager service?
1534 aRv.Throw(NS_ERROR_UNEXPECTED);
1538 return mPowerManager;
1541 already_AddRefed<WakeLock>
1542 Navigator::RequestWakeLock(const nsAString &aTopic, ErrorResult& aRv)
1544 if (!mWindow) {
1545 aRv.Throw(NS_ERROR_UNEXPECTED);
1546 return nullptr;
1549 nsRefPtr<power::PowerManagerService> pmService =
1550 power::PowerManagerService::GetInstance();
1551 // Maybe it went away for some reason... Or maybe we're just called
1552 // from our XPCOM method.
1553 if (!pmService) {
1554 aRv.Throw(NS_ERROR_UNEXPECTED);
1555 return nullptr;
1558 return pmService->NewWakeLock(aTopic, mWindow, aRv);
1561 nsIDOMMozMobileMessageManager*
1562 Navigator::GetMozMobileMessage()
1564 if (!mMobileMessageManager) {
1565 // Check that our window has not gone away
1566 NS_ENSURE_TRUE(mWindow, nullptr);
1567 NS_ENSURE_TRUE(mWindow->GetDocShell(), nullptr);
1569 mMobileMessageManager = new MobileMessageManager();
1570 mMobileMessageManager->Init(mWindow);
1573 return mMobileMessageManager;
1576 Telephony*
1577 Navigator::GetMozTelephony(ErrorResult& aRv)
1579 if (!mTelephony) {
1580 if (!mWindow) {
1581 aRv.Throw(NS_ERROR_UNEXPECTED);
1582 return nullptr;
1584 mTelephony = Telephony::Create(mWindow, aRv);
1587 return mTelephony;
1590 #ifdef MOZ_B2G
1591 already_AddRefed<Promise>
1592 Navigator::GetMobileIdAssertion(ErrorResult& aRv)
1594 if (!mWindow || !mWindow->GetDocShell()) {
1595 aRv.Throw(NS_ERROR_UNEXPECTED);
1596 return nullptr;
1599 nsCOMPtr<nsIMobileIdentityService> service =
1600 do_GetService("@mozilla.org/mobileidentity-service;1");
1601 if (!service) {
1602 aRv.Throw(NS_ERROR_FAILURE);
1603 return nullptr;
1606 nsCOMPtr<nsISupports> promise;
1607 aRv = service->GetMobileIdAssertion(mWindow, getter_AddRefs(promise));
1609 nsRefPtr<Promise> p = static_cast<Promise*>(promise.get());
1610 return p.forget();
1612 #endif // MOZ_B2G
1614 #ifdef MOZ_B2G_RIL
1616 MobileConnectionArray*
1617 Navigator::GetMozMobileConnections(ErrorResult& aRv)
1619 if (!mMobileConnections) {
1620 if (!mWindow) {
1621 aRv.Throw(NS_ERROR_UNEXPECTED);
1622 return nullptr;
1624 mMobileConnections = new MobileConnectionArray(mWindow);
1627 return mMobileConnections;
1630 CellBroadcast*
1631 Navigator::GetMozCellBroadcast(ErrorResult& aRv)
1633 if (!mCellBroadcast) {
1634 if (!mWindow) {
1635 aRv.Throw(NS_ERROR_UNEXPECTED);
1636 return nullptr;
1638 mCellBroadcast = CellBroadcast::Create(mWindow, aRv);
1641 return mCellBroadcast;
1644 Voicemail*
1645 Navigator::GetMozVoicemail(ErrorResult& aRv)
1647 if (!mVoicemail) {
1648 if (!mWindow) {
1649 aRv.Throw(NS_ERROR_UNEXPECTED);
1650 return nullptr;
1653 aRv = NS_NewVoicemail(mWindow, getter_AddRefs(mVoicemail));
1654 if (aRv.Failed()) {
1655 return nullptr;
1659 return mVoicemail;
1662 IccManager*
1663 Navigator::GetMozIccManager(ErrorResult& aRv)
1665 if (!mIccManager) {
1666 if (!mWindow) {
1667 aRv.Throw(NS_ERROR_UNEXPECTED);
1668 return nullptr;
1670 NS_ENSURE_TRUE(mWindow->GetDocShell(), nullptr);
1672 mIccManager = new IccManager(mWindow);
1675 return mIccManager;
1677 #endif // MOZ_B2G_RIL
1679 #ifdef MOZ_GAMEPAD
1680 void
1681 Navigator::GetGamepads(nsTArray<nsRefPtr<Gamepad> >& aGamepads,
1682 ErrorResult& aRv)
1684 if (!mWindow) {
1685 aRv.Throw(NS_ERROR_UNEXPECTED);
1686 return;
1688 NS_ENSURE_TRUE_VOID(mWindow->GetDocShell());
1689 nsGlobalWindow* win = static_cast<nsGlobalWindow*>(mWindow.get());
1690 win->SetHasGamepadEventListener(true);
1691 win->GetGamepads(aGamepads);
1693 #endif
1695 //*****************************************************************************
1696 // Navigator::nsIMozNavigatorNetwork
1697 //*****************************************************************************
1699 NS_IMETHODIMP
1700 Navigator::GetProperties(nsINetworkProperties** aProperties)
1702 ErrorResult rv;
1703 NS_IF_ADDREF(*aProperties = GetConnection(rv));
1704 return NS_OK;
1707 network::Connection*
1708 Navigator::GetConnection(ErrorResult& aRv)
1710 if (!mConnection) {
1711 if (!mWindow) {
1712 aRv.Throw(NS_ERROR_UNEXPECTED);
1713 return nullptr;
1715 mConnection = new network::Connection();
1716 mConnection->Init(mWindow);
1719 return mConnection;
1722 #ifdef MOZ_B2G_BT
1723 bluetooth::BluetoothManager*
1724 Navigator::GetMozBluetooth(ErrorResult& aRv)
1726 if (!mBluetooth) {
1727 if (!mWindow) {
1728 aRv.Throw(NS_ERROR_UNEXPECTED);
1729 return nullptr;
1731 mBluetooth = bluetooth::BluetoothManager::Create(mWindow);
1734 return mBluetooth;
1736 #endif //MOZ_B2G_BT
1738 nsresult
1739 Navigator::EnsureMessagesManager()
1741 if (mMessagesManager) {
1742 return NS_OK;
1745 NS_ENSURE_STATE(mWindow);
1747 nsresult rv;
1748 nsCOMPtr<nsIDOMNavigatorSystemMessages> messageManager =
1749 do_CreateInstance("@mozilla.org/system-message-manager;1", &rv);
1751 nsCOMPtr<nsIDOMGlobalPropertyInitializer> gpi =
1752 do_QueryInterface(messageManager);
1753 NS_ENSURE_TRUE(gpi, NS_ERROR_FAILURE);
1755 // We don't do anything with the return value.
1756 AutoJSContext cx;
1757 JS::Rooted<JS::Value> prop_val(cx);
1758 rv = gpi->Init(mWindow, &prop_val);
1759 NS_ENSURE_SUCCESS(rv, rv);
1761 mMessagesManager = messageManager.forget();
1763 return NS_OK;
1766 bool
1767 Navigator::MozHasPendingMessage(const nsAString& aType, ErrorResult& aRv)
1769 // The WebIDL binding is responsible for the pref check here.
1770 nsresult rv = EnsureMessagesManager();
1771 if (NS_FAILED(rv)) {
1772 aRv.Throw(rv);
1773 return false;
1776 bool result = false;
1777 rv = mMessagesManager->MozHasPendingMessage(aType, &result);
1778 if (NS_FAILED(rv)) {
1779 aRv.Throw(rv);
1780 return false;
1782 return result;
1785 void
1786 Navigator::MozSetMessageHandler(const nsAString& aType,
1787 systemMessageCallback* aCallback,
1788 ErrorResult& aRv)
1790 // The WebIDL binding is responsible for the pref check here.
1791 nsresult rv = EnsureMessagesManager();
1792 if (NS_FAILED(rv)) {
1793 aRv.Throw(rv);
1794 return;
1797 CallbackObjectHolder<systemMessageCallback, nsIDOMSystemMessageCallback>
1798 holder(aCallback);
1799 nsCOMPtr<nsIDOMSystemMessageCallback> callback = holder.ToXPCOMCallback();
1801 rv = mMessagesManager->MozSetMessageHandler(aType, callback);
1802 if (NS_FAILED(rv)) {
1803 aRv.Throw(rv);
1807 #ifdef MOZ_TIME_MANAGER
1808 time::TimeManager*
1809 Navigator::GetMozTime(ErrorResult& aRv)
1811 if (!mWindow) {
1812 aRv.Throw(NS_ERROR_UNEXPECTED);
1813 return nullptr;
1816 if (!mTimeManager) {
1817 mTimeManager = new time::TimeManager(mWindow);
1820 return mTimeManager;
1822 #endif
1824 nsDOMCameraManager*
1825 Navigator::GetMozCameras(ErrorResult& aRv)
1827 if (!mCameraManager) {
1828 if (!mWindow ||
1829 !mWindow->GetOuterWindow() ||
1830 mWindow->GetOuterWindow()->GetCurrentInnerWindow() != mWindow) {
1831 aRv.Throw(NS_ERROR_NOT_AVAILABLE);
1832 return nullptr;
1835 mCameraManager = nsDOMCameraManager::CreateInstance(mWindow);
1838 return mCameraManager;
1841 already_AddRefed<workers::ServiceWorkerContainer>
1842 Navigator::ServiceWorker()
1844 MOZ_ASSERT(mWindow);
1846 if (!mServiceWorkerContainer) {
1847 mServiceWorkerContainer = new workers::ServiceWorkerContainer(mWindow);
1850 nsRefPtr<workers::ServiceWorkerContainer> ref = mServiceWorkerContainer;
1851 return ref.forget();
1854 size_t
1855 Navigator::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
1857 size_t n = aMallocSizeOf(this);
1859 // TODO: add SizeOfIncludingThis() to nsMimeTypeArray, bug 674113.
1860 // TODO: add SizeOfIncludingThis() to nsPluginArray, bug 674114.
1861 // TODO: add SizeOfIncludingThis() to Geolocation, bug 674115.
1862 // TODO: add SizeOfIncludingThis() to DesktopNotificationCenter, bug 674116.
1864 return n;
1867 void
1868 Navigator::SetWindow(nsPIDOMWindow *aInnerWindow)
1870 NS_ASSERTION(aInnerWindow->IsInnerWindow(),
1871 "Navigator must get an inner window!");
1872 mWindow = aInnerWindow;
1875 void
1876 Navigator::OnNavigation()
1878 if (!mWindow) {
1879 return;
1882 #ifdef MOZ_MEDIA_NAVIGATOR
1883 // Inform MediaManager in case there are live streams or pending callbacks.
1884 MediaManager *manager = MediaManager::Get();
1885 if (manager) {
1886 manager->OnNavigation(mWindow->WindowID());
1888 #endif
1889 if (mCameraManager) {
1890 mCameraManager->OnNavigation(mWindow->WindowID());
1894 bool
1895 Navigator::CheckPermission(const char* type)
1897 return CheckPermission(mWindow, type);
1900 /* static */
1901 bool
1902 Navigator::CheckPermission(nsPIDOMWindow* aWindow, const char* aType)
1904 if (!aWindow) {
1905 return false;
1908 nsCOMPtr<nsIPermissionManager> permMgr =
1909 services::GetPermissionManager();
1910 NS_ENSURE_TRUE(permMgr, false);
1912 uint32_t permission = nsIPermissionManager::DENY_ACTION;
1913 permMgr->TestPermissionFromWindow(aWindow, aType, &permission);
1914 return permission == nsIPermissionManager::ALLOW_ACTION;
1917 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
1918 system::AudioChannelManager*
1919 Navigator::GetMozAudioChannelManager(ErrorResult& aRv)
1921 if (!mAudioChannelManager) {
1922 if (!mWindow) {
1923 aRv.Throw(NS_ERROR_UNEXPECTED);
1924 return nullptr;
1926 mAudioChannelManager = new system::AudioChannelManager();
1927 mAudioChannelManager->Init(mWindow);
1930 return mAudioChannelManager;
1932 #endif
1934 bool
1935 Navigator::DoNewResolve(JSContext* aCx, JS::Handle<JSObject*> aObject,
1936 JS::Handle<jsid> aId,
1937 JS::MutableHandle<JSPropertyDescriptor> aDesc)
1939 // Note: The infallibleInit call below depends on this check.
1940 if (!JSID_IS_STRING(aId)) {
1941 return true;
1944 nsScriptNameSpaceManager* nameSpaceManager = GetNameSpaceManager();
1945 if (!nameSpaceManager) {
1946 return Throw(aCx, NS_ERROR_NOT_INITIALIZED);
1949 nsDependentJSString name;
1950 name.infallibleInit(aId);
1952 const nsGlobalNameStruct* name_struct =
1953 nameSpaceManager->LookupNavigatorName(name);
1954 if (!name_struct) {
1955 return true;
1958 JS::Rooted<JSObject*> naviObj(aCx,
1959 js::CheckedUnwrap(aObject,
1960 /* stopAtOuter = */ false));
1961 if (!naviObj) {
1962 return Throw(aCx, NS_ERROR_DOM_SECURITY_ERR);
1965 if (name_struct->mType == nsGlobalNameStruct::eTypeNewDOMBinding) {
1966 ConstructNavigatorProperty construct = name_struct->mConstructNavigatorProperty;
1967 MOZ_ASSERT(construct);
1969 JS::Rooted<JSObject*> domObject(aCx);
1971 // Make sure to do the creation of our object in the compartment
1972 // of naviObj, especially since we plan to cache that object.
1973 JSAutoCompartment ac(aCx, naviObj);
1975 // Check whether our constructor is enabled after we unwrap Xrays, since
1976 // we don't want to define an interface on the Xray if it's disabled in
1977 // the target global, even if it's enabled in the Xray's global.
1978 if (name_struct->mConstructorEnabled &&
1979 !(*name_struct->mConstructorEnabled)(aCx, naviObj)) {
1980 return true;
1983 if (name.EqualsLiteral("mozSettings")) {
1984 bool hasPermission = CheckPermission("settings-read") ||
1985 CheckPermission("settings-write");
1986 if (!hasPermission) {
1987 FillPropertyDescriptor(aDesc, aObject, JS::NullValue(), false);
1988 return true;
1992 if (name.EqualsLiteral("mozDownloadManager")) {
1993 if (!CheckPermission("downloads")) {
1994 FillPropertyDescriptor(aDesc, aObject, JS::NullValue(), false);
1995 return true;
1999 nsISupports* existingObject = mCachedResolveResults.GetWeak(name);
2000 if (existingObject) {
2001 // We know all of our WebIDL objects here are wrappercached, so just go
2002 // ahead and WrapObject() them. We can't use WrapNewBindingObject,
2003 // because we don't have the concrete type.
2004 JS::Rooted<JS::Value> wrapped(aCx);
2005 if (!dom::WrapObject(aCx, existingObject, &wrapped)) {
2006 return false;
2008 domObject = &wrapped.toObject();
2009 } else {
2010 domObject = construct(aCx, naviObj);
2011 if (!domObject) {
2012 return Throw(aCx, NS_ERROR_FAILURE);
2015 // Store the value in our cache
2016 nsISupports* native = UnwrapDOMObjectToISupports(domObject);
2017 MOZ_ASSERT(native);
2018 mCachedResolveResults.Put(name, native);
2022 if (!JS_WrapObject(aCx, &domObject)) {
2023 return false;
2026 FillPropertyDescriptor(aDesc, aObject, JS::ObjectValue(*domObject), false);
2027 return true;
2030 NS_ASSERTION(name_struct->mType == nsGlobalNameStruct::eTypeNavigatorProperty,
2031 "unexpected type");
2033 nsresult rv = NS_OK;
2035 nsCOMPtr<nsISupports> native;
2036 bool hadCachedNative = mCachedResolveResults.Get(name, getter_AddRefs(native));
2037 bool okToUseNative;
2038 JS::Rooted<JS::Value> prop_val(aCx);
2039 if (hadCachedNative) {
2040 okToUseNative = true;
2041 } else {
2042 native = do_CreateInstance(name_struct->mCID, &rv);
2043 if (NS_FAILED(rv)) {
2044 return Throw(aCx, rv);
2047 nsCOMPtr<nsIDOMGlobalPropertyInitializer> gpi(do_QueryInterface(native));
2049 if (gpi) {
2050 if (!mWindow) {
2051 return Throw(aCx, NS_ERROR_UNEXPECTED);
2054 rv = gpi->Init(mWindow, &prop_val);
2055 if (NS_FAILED(rv)) {
2056 return Throw(aCx, rv);
2060 okToUseNative = !prop_val.isObjectOrNull();
2063 if (okToUseNative) {
2064 // Make sure to do the creation of our object in the compartment
2065 // of naviObj, especially since we plan to cache that object.
2066 JSAutoCompartment ac(aCx, naviObj);
2068 rv = nsContentUtils::WrapNative(aCx, native, &prop_val);
2070 if (NS_FAILED(rv)) {
2071 return Throw(aCx, rv);
2074 // Now that we know we managed to wrap this thing properly, go ahead and
2075 // cache it as needed.
2076 if (!hadCachedNative) {
2077 mCachedResolveResults.Put(name, native);
2081 if (!JS_WrapValue(aCx, &prop_val)) {
2082 return Throw(aCx, NS_ERROR_UNEXPECTED);
2085 FillPropertyDescriptor(aDesc, aObject, prop_val, false);
2086 return true;
2089 struct NavigatorNameEnumeratorClosure
2091 NavigatorNameEnumeratorClosure(JSContext* aCx, JSObject* aWrapper,
2092 nsTArray<nsString>& aNames)
2093 : mCx(aCx),
2094 mWrapper(aCx, aWrapper),
2095 mNames(aNames)
2099 JSContext* mCx;
2100 JS::Rooted<JSObject*> mWrapper;
2101 nsTArray<nsString>& mNames;
2104 static PLDHashOperator
2105 SaveNavigatorName(const nsAString& aName,
2106 const nsGlobalNameStruct& aNameStruct,
2107 void* aClosure)
2109 NavigatorNameEnumeratorClosure* closure =
2110 static_cast<NavigatorNameEnumeratorClosure*>(aClosure);
2111 if (!aNameStruct.mConstructorEnabled ||
2112 aNameStruct.mConstructorEnabled(closure->mCx, closure->mWrapper)) {
2113 closure->mNames.AppendElement(aName);
2115 return PL_DHASH_NEXT;
2118 void
2119 Navigator::GetOwnPropertyNames(JSContext* aCx, nsTArray<nsString>& aNames,
2120 ErrorResult& aRv)
2122 nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager();
2123 if (!nameSpaceManager) {
2124 NS_ERROR("Can't get namespace manager.");
2125 aRv.Throw(NS_ERROR_UNEXPECTED);
2126 return;
2129 NavigatorNameEnumeratorClosure closure(aCx, GetWrapper(), aNames);
2130 nameSpaceManager->EnumerateNavigatorNames(SaveNavigatorName, &closure);
2133 JSObject*
2134 Navigator::WrapObject(JSContext* cx)
2136 return NavigatorBinding::Wrap(cx, this);
2139 /* static */
2140 bool
2141 Navigator::HasWakeLockSupport(JSContext* /* unused*/, JSObject* /*unused */)
2143 nsCOMPtr<nsIPowerManagerService> pmService =
2144 do_GetService(POWERMANAGERSERVICE_CONTRACTID);
2145 // No service means no wake lock support
2146 return !!pmService;
2149 /* static */
2150 bool
2151 Navigator::HasMobileMessageSupport(JSContext* /* unused */, JSObject* aGlobal)
2153 nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
2155 #ifndef MOZ_WEBSMS_BACKEND
2156 return false;
2157 #endif
2159 // First of all, the general pref has to be turned on.
2160 bool enabled = false;
2161 Preferences::GetBool("dom.sms.enabled", &enabled);
2162 if (!enabled) {
2163 return false;
2166 NS_ENSURE_TRUE(win, false);
2167 NS_ENSURE_TRUE(win->GetDocShell(), false);
2169 if (!CheckPermission(win, "sms")) {
2170 return false;
2173 return true;
2176 /* static */
2177 bool
2178 Navigator::HasCameraSupport(JSContext* /* unused */, JSObject* aGlobal)
2180 nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
2181 return win && nsDOMCameraManager::CheckPermission(win);
2184 /* static */
2185 bool
2186 Navigator::HasWifiManagerSupport(JSContext* /* unused */,
2187 JSObject* aGlobal)
2189 // On XBL scope, the global object is NOT |window|. So we have
2190 // to use nsContentUtils::GetObjectPrincipal to get the principal
2191 // and test directly with permission manager.
2193 nsIPrincipal* principal = nsContentUtils::ObjectPrincipal(aGlobal);
2195 nsCOMPtr<nsIPermissionManager> permMgr =
2196 services::GetPermissionManager();
2197 NS_ENSURE_TRUE(permMgr, false);
2199 uint32_t permission = nsIPermissionManager::DENY_ACTION;
2200 permMgr->TestPermissionFromPrincipal(principal, "wifi-manage", &permission);
2201 return nsIPermissionManager::ALLOW_ACTION == permission;
2204 #ifdef MOZ_NFC
2205 /* static */
2206 bool
2207 Navigator::HasNFCSupport(JSContext* /* unused */, JSObject* aGlobal)
2209 // Do not support NFC if NFC content helper does not exist.
2210 nsCOMPtr<nsISupports> contentHelper = do_GetService("@mozilla.org/nfc/content-helper;1");
2211 if (!contentHelper) {
2212 return false;
2215 nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
2216 return win && (CheckPermission(win, "nfc-read") ||
2217 CheckPermission(win, "nfc-write"));
2219 #endif // MOZ_NFC
2221 #ifdef MOZ_TIME_MANAGER
2222 /* static */
2223 bool
2224 Navigator::HasTimeSupport(JSContext* /* unused */, JSObject* aGlobal)
2226 nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
2227 return win && CheckPermission(win, "time");
2229 #endif // MOZ_TIME_MANAGER
2231 #ifdef MOZ_MEDIA_NAVIGATOR
2232 /* static */
2233 bool
2234 Navigator::HasUserMediaSupport(JSContext* /* unused */,
2235 JSObject* /* unused */)
2237 // Make enabling peerconnection enable getUserMedia() as well
2238 return Preferences::GetBool("media.navigator.enabled", false) ||
2239 Preferences::GetBool("media.peerconnection.enabled", false);
2241 #endif // MOZ_MEDIA_NAVIGATOR
2243 /* static */
2244 bool
2245 Navigator::HasInputMethodSupport(JSContext* /* unused */,
2246 JSObject* aGlobal)
2248 nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
2249 if (!win || !Preferences::GetBool("dom.mozInputMethod.enabled", false)) {
2250 return false;
2253 if (Preferences::GetBool("dom.mozInputMethod.testing", false)) {
2254 return true;
2257 return CheckPermission(win, "input") ||
2258 CheckPermission(win, "input-manage");
2261 /* static */
2262 bool
2263 Navigator::HasDataStoreSupport(nsIPrincipal* aPrincipal)
2265 workers::AssertIsOnMainThread();
2267 // First of all, the general pref has to be turned on.
2268 bool enabled = false;
2269 Preferences::GetBool("dom.datastore.enabled", &enabled);
2270 if (!enabled) {
2271 return false;
2274 // Just for testing, we can enable DataStore for any kind of app.
2275 if (Preferences::GetBool("dom.testing.datastore_enabled_for_hosted_apps", false)) {
2276 return true;
2279 uint16_t status;
2280 if (NS_FAILED(aPrincipal->GetAppStatus(&status))) {
2281 return false;
2284 // Only support DataStore API for certified apps for now.
2285 return status == nsIPrincipal::APP_STATUS_CERTIFIED;
2288 // A WorkerMainThreadRunnable to synchronously dispatch the call of
2289 // HasDataStoreSupport() from the worker thread to the main thread.
2290 class HasDataStoreSupportRunnable MOZ_FINAL
2291 : public workers::WorkerMainThreadRunnable
2293 public:
2294 bool mResult;
2296 HasDataStoreSupportRunnable(workers::WorkerPrivate* aWorkerPrivate)
2297 : workers::WorkerMainThreadRunnable(aWorkerPrivate)
2298 , mResult(false)
2300 MOZ_ASSERT(aWorkerPrivate);
2301 aWorkerPrivate->AssertIsOnWorkerThread();
2304 protected:
2305 virtual bool
2306 MainThreadRun() MOZ_OVERRIDE
2308 workers::AssertIsOnMainThread();
2310 mResult = Navigator::HasDataStoreSupport(mWorkerPrivate->GetPrincipal());
2312 return true;
2316 /* static */
2317 bool
2318 Navigator::HasDataStoreSupport(JSContext* aCx, JSObject* aGlobal)
2320 // If the caller is on the worker thread, dispatch this to the main thread.
2321 if (!NS_IsMainThread()) {
2322 workers::WorkerPrivate* workerPrivate =
2323 workers::GetWorkerPrivateFromContext(aCx);
2324 workerPrivate->AssertIsOnWorkerThread();
2326 nsRefPtr<HasDataStoreSupportRunnable> runnable =
2327 new HasDataStoreSupportRunnable(workerPrivate);
2328 runnable->Dispatch(aCx);
2330 return runnable->mResult;
2333 workers::AssertIsOnMainThread();
2335 JS::Rooted<JSObject*> global(aCx, aGlobal);
2337 nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(global);
2338 if (!win) {
2339 return false;
2342 nsIDocument* doc = win->GetExtantDoc();
2343 if (!doc || !doc->NodePrincipal()) {
2344 return false;
2347 return HasDataStoreSupport(doc->NodePrincipal());
2350 /* static */
2351 bool
2352 Navigator::HasNetworkStatsSupport(JSContext* /* unused */, JSObject* aGlobal)
2354 nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
2355 return CheckPermission(win, "networkstats-manage");
2358 /* static */
2359 bool
2360 Navigator::HasFeatureDetectionSupport(JSContext* /* unused */, JSObject* aGlobal)
2362 nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
2363 return CheckPermission(win, "feature-detection");
2367 /* static */
2368 already_AddRefed<nsPIDOMWindow>
2369 Navigator::GetWindowFromGlobal(JSObject* aGlobal)
2371 nsCOMPtr<nsPIDOMWindow> win =
2372 do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(aGlobal));
2373 MOZ_ASSERT(!win || win->IsInnerWindow());
2374 return win.forget();
2377 } // namespace dom
2378 } // namespace mozilla
2380 nsresult
2381 NS_GetNavigatorUserAgent(nsAString& aUserAgent)
2383 nsresult rv;
2385 nsCOMPtr<nsIHttpProtocolHandler>
2386 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
2387 NS_ENSURE_SUCCESS(rv, rv);
2389 nsAutoCString ua;
2390 rv = service->GetUserAgent(ua);
2391 CopyASCIItoUTF16(ua, aUserAgent);
2393 return rv;
2396 nsresult
2397 NS_GetNavigatorPlatform(nsAString& aPlatform)
2399 if (!nsContentUtils::IsCallerChrome()) {
2400 const nsAdoptingString& override =
2401 mozilla::Preferences::GetString("general.platform.override");
2403 if (override) {
2404 aPlatform = override;
2405 return NS_OK;
2409 nsresult rv;
2411 nsCOMPtr<nsIHttpProtocolHandler>
2412 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
2413 NS_ENSURE_SUCCESS(rv, rv);
2415 // Sorry for the #if platform ugliness, but Communicator is likewise
2416 // hardcoded and we are seeking backward compatibility here (bug 47080).
2417 #if defined(_WIN64)
2418 aPlatform.AssignLiteral("Win64");
2419 #elif defined(WIN32)
2420 aPlatform.AssignLiteral("Win32");
2421 #elif defined(XP_MACOSX) && defined(__ppc__)
2422 aPlatform.AssignLiteral("MacPPC");
2423 #elif defined(XP_MACOSX) && defined(__i386__)
2424 aPlatform.AssignLiteral("MacIntel");
2425 #elif defined(XP_MACOSX) && defined(__x86_64__)
2426 aPlatform.AssignLiteral("MacIntel");
2427 #else
2428 // XXX Communicator uses compiled-in build-time string defines
2429 // to indicate the platform it was compiled *for*, not what it is
2430 // currently running *on* which is what this does.
2431 nsAutoCString plat;
2432 rv = service->GetOscpu(plat);
2433 CopyASCIItoUTF16(plat, aPlatform);
2434 #endif
2436 return rv;
2438 nsresult
2439 NS_GetNavigatorAppVersion(nsAString& aAppVersion)
2441 if (!nsContentUtils::IsCallerChrome()) {
2442 const nsAdoptingString& override =
2443 mozilla::Preferences::GetString("general.appversion.override");
2445 if (override) {
2446 aAppVersion = override;
2447 return NS_OK;
2451 nsresult rv;
2453 nsCOMPtr<nsIHttpProtocolHandler>
2454 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
2455 NS_ENSURE_SUCCESS(rv, rv);
2457 nsAutoCString str;
2458 rv = service->GetAppVersion(str);
2459 CopyASCIItoUTF16(str, aAppVersion);
2460 NS_ENSURE_SUCCESS(rv, rv);
2462 aAppVersion.AppendLiteral(" (");
2464 rv = service->GetPlatform(str);
2465 NS_ENSURE_SUCCESS(rv, rv);
2467 AppendASCIItoUTF16(str, aAppVersion);
2468 aAppVersion.Append(char16_t(')'));
2470 return rv;
2473 void
2474 NS_GetNavigatorAppName(nsAString& aAppName)
2476 if (!nsContentUtils::IsCallerChrome()) {
2477 const nsAdoptingString& override =
2478 mozilla::Preferences::GetString("general.appname.override");
2480 if (override) {
2481 aAppName = override;
2482 return;
2486 aAppName.AssignLiteral("Netscape");