Bumping gaia.json for 2 gaia revision(s) a=gaia-bump
[gecko.git] / dom / base / nsPluginArray.cpp
blob15e73868b8bee2a7e85fcc5a95dda4c68874d2ca
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsPluginArray.h"
8 #include "mozilla/Preferences.h"
9 #include "mozilla/dom/PluginArrayBinding.h"
10 #include "mozilla/dom/PluginBinding.h"
12 #include "nsCharSeparatedTokenizer.h"
13 #include "nsMimeTypeArray.h"
14 #include "Navigator.h"
15 #include "nsIDocShell.h"
16 #include "nsIWebNavigation.h"
17 #include "nsPluginHost.h"
18 #include "nsPluginTags.h"
19 #include "nsIObserverService.h"
20 #include "nsIWeakReference.h"
21 #include "mozilla/Services.h"
22 #include "nsIInterfaceRequestorUtils.h"
24 using namespace mozilla;
25 using namespace mozilla::dom;
27 nsPluginArray::nsPluginArray(nsPIDOMWindow* aWindow)
28 : mWindow(aWindow)
30 SetIsDOMBinding();
33 void
34 nsPluginArray::Init()
36 nsCOMPtr<nsIObserverService> obsService =
37 mozilla::services::GetObserverService();
38 if (obsService) {
39 obsService->AddObserver(this, "plugin-info-updated", true);
43 nsPluginArray::~nsPluginArray()
47 nsPIDOMWindow*
48 nsPluginArray::GetParentObject() const
50 MOZ_ASSERT(mWindow);
51 return mWindow;
54 JSObject*
55 nsPluginArray::WrapObject(JSContext* aCx)
57 return PluginArrayBinding::Wrap(aCx, this);
60 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPluginArray)
61 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPluginArray)
62 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPluginArray)
63 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
64 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
65 NS_INTERFACE_MAP_ENTRY(nsIObserver)
66 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
67 NS_INTERFACE_MAP_END
69 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsPluginArray,
70 mWindow,
71 mPlugins,
72 mHiddenPlugins)
74 static void
75 GetPluginMimeTypes(const nsTArray<nsRefPtr<nsPluginElement> >& aPlugins,
76 nsTArray<nsRefPtr<nsMimeType> >& aMimeTypes)
78 for (uint32_t i = 0; i < aPlugins.Length(); ++i) {
79 nsPluginElement *plugin = aPlugins[i];
80 aMimeTypes.AppendElements(plugin->MimeTypes());
84 static bool
85 operator<(const nsRefPtr<nsMimeType>& lhs, const nsRefPtr<nsMimeType>& rhs)
87 // Sort MIME types alphabetically by type name.
88 return lhs->Type() < rhs->Type();
91 void
92 nsPluginArray::GetMimeTypes(nsTArray<nsRefPtr<nsMimeType> >& aMimeTypes,
93 nsTArray<nsRefPtr<nsMimeType> >& aHiddenMimeTypes)
95 aMimeTypes.Clear();
96 aHiddenMimeTypes.Clear();
98 if (!AllowPlugins()) {
99 return;
102 EnsurePlugins();
104 GetPluginMimeTypes(mPlugins, aMimeTypes);
105 GetPluginMimeTypes(mHiddenPlugins, aHiddenMimeTypes);
107 // Alphabetize the enumeration order of non-hidden MIME types to reduce
108 // fingerprintable entropy based on plugins' installation file times.
109 aMimeTypes.Sort();
112 nsPluginElement*
113 nsPluginArray::Item(uint32_t aIndex)
115 bool unused;
116 return IndexedGetter(aIndex, unused);
119 nsPluginElement*
120 nsPluginArray::NamedItem(const nsAString& aName)
122 bool unused;
123 return NamedGetter(aName, unused);
126 void
127 nsPluginArray::Refresh(bool aReloadDocuments)
129 nsRefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
131 if(!AllowPlugins() || !pluginHost) {
132 return;
135 // NS_ERROR_PLUGINS_PLUGINSNOTCHANGED on reloading plugins indicates
136 // that plugins did not change and was not reloaded
137 if (pluginHost->ReloadPlugins() ==
138 NS_ERROR_PLUGINS_PLUGINSNOTCHANGED) {
139 nsTArray<nsRefPtr<nsPluginTag> > newPluginTags;
140 pluginHost->GetPlugins(newPluginTags);
142 // Check if the number of plugins we know about are different from
143 // the number of plugin tags the plugin host knows about. If the
144 // lengths are different, we refresh. This is safe because we're
145 // notified for every plugin enabling/disabling event that
146 // happens, and therefore the lengths will be in sync only when
147 // the both arrays contain the same plugin tags (though as
148 // different types).
149 uint32_t pluginCount = mPlugins.Length() + mHiddenPlugins.Length();
150 if (newPluginTags.Length() == pluginCount) {
151 return;
155 mPlugins.Clear();
156 mHiddenPlugins.Clear();
158 nsCOMPtr<nsIDOMNavigator> navigator;
159 mWindow->GetNavigator(getter_AddRefs(navigator));
161 if (!navigator) {
162 return;
165 static_cast<mozilla::dom::Navigator*>(navigator.get())->RefreshMIMEArray();
167 nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(mWindow);
168 if (aReloadDocuments && webNav) {
169 webNav->Reload(nsIWebNavigation::LOAD_FLAGS_NONE);
173 nsPluginElement*
174 nsPluginArray::IndexedGetter(uint32_t aIndex, bool &aFound)
176 aFound = false;
178 if (!AllowPlugins()) {
179 return nullptr;
182 EnsurePlugins();
184 aFound = aIndex < mPlugins.Length();
186 return aFound ? mPlugins[aIndex] : nullptr;
189 void
190 nsPluginArray::Invalidate()
192 nsCOMPtr<nsIObserverService> obsService =
193 mozilla::services::GetObserverService();
194 if (obsService) {
195 obsService->RemoveObserver(this, "plugin-info-updated");
199 static nsPluginElement*
200 FindPlugin(const nsTArray<nsRefPtr<nsPluginElement> >& aPlugins,
201 const nsAString& aName)
203 for (uint32_t i = 0; i < aPlugins.Length(); ++i) {
204 nsAutoString pluginName;
205 nsPluginElement* plugin = aPlugins[i];
206 plugin->GetName(pluginName);
208 if (pluginName.Equals(aName)) {
209 return plugin;
213 return nullptr;
216 nsPluginElement*
217 nsPluginArray::NamedGetter(const nsAString& aName, bool &aFound)
219 aFound = false;
221 if (!AllowPlugins()) {
222 return nullptr;
225 EnsurePlugins();
227 nsPluginElement* plugin = FindPlugin(mPlugins, aName);
228 if (!plugin) {
229 plugin = FindPlugin(mHiddenPlugins, aName);
232 aFound = (plugin != nullptr);
233 return plugin;
236 bool
237 nsPluginArray::NameIsEnumerable(const nsAString& aName)
239 return true;
242 uint32_t
243 nsPluginArray::Length()
245 if (!AllowPlugins()) {
246 return 0;
249 EnsurePlugins();
251 return mPlugins.Length();
254 void
255 nsPluginArray::GetSupportedNames(unsigned, nsTArray<nsString>& aRetval)
257 aRetval.Clear();
259 if (!AllowPlugins()) {
260 return;
263 for (uint32_t i = 0; i < mPlugins.Length(); ++i) {
264 nsAutoString pluginName;
265 mPlugins[i]->GetName(pluginName);
267 aRetval.AppendElement(pluginName);
271 NS_IMETHODIMP
272 nsPluginArray::Observe(nsISupports *aSubject, const char *aTopic,
273 const char16_t *aData) {
274 if (!nsCRT::strcmp(aTopic, "plugin-info-updated")) {
275 Refresh(false);
278 return NS_OK;
281 bool
282 nsPluginArray::AllowPlugins() const
284 nsCOMPtr<nsIDocShell> docShell = mWindow ? mWindow->GetDocShell() : nullptr;
286 return docShell && docShell->PluginsAllowedInCurrentDoc();
289 static bool
290 HasStringPrefix(const nsCString& str, const nsACString& prefix) {
291 return str.Compare(prefix.BeginReading(), false, prefix.Length()) == 0;
294 static bool
295 IsPluginEnumerable(const nsTArray<nsCString>& enumerableNames,
296 const nsPluginTag* pluginTag)
298 const nsCString& pluginName = pluginTag->mName;
300 const uint32_t length = enumerableNames.Length();
301 for (uint32_t i = 0; i < length; i++) {
302 const nsCString& name = enumerableNames[i];
303 if (HasStringPrefix(pluginName, name)) {
304 return true; // don't hide plugin
308 return false; // hide plugin!
311 static bool
312 operator<(const nsRefPtr<nsPluginElement>& lhs,
313 const nsRefPtr<nsPluginElement>& rhs)
315 // Sort plugins alphabetically by name.
316 return lhs->PluginTag()->mName < rhs->PluginTag()->mName;
319 void
320 nsPluginArray::EnsurePlugins()
322 if (!mPlugins.IsEmpty() || !mHiddenPlugins.IsEmpty()) {
323 // We already have an array of plugin elements.
324 return;
327 nsRefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
328 if (!pluginHost) {
329 // We have no plugin host.
330 return;
333 nsTArray<nsRefPtr<nsPluginTag> > pluginTags;
334 pluginHost->GetPlugins(pluginTags);
336 nsTArray<nsCString> enumerableNames;
338 const nsAdoptingCString& enumerableNamesPref =
339 Preferences::GetCString("plugins.enumerable_names");
341 bool disablePluginHiding = !enumerableNamesPref ||
342 enumerableNamesPref.EqualsLiteral("*");
344 if (!disablePluginHiding) {
345 nsCCharSeparatedTokenizer tokens(enumerableNamesPref, ',');
346 while (tokens.hasMoreTokens()) {
347 const nsCSubstring& token = tokens.nextToken();
348 if (!token.IsEmpty()) {
349 enumerableNames.AppendElement(token);
354 // need to wrap each of these with a nsPluginElement, which is
355 // scriptable.
356 for (uint32_t i = 0; i < pluginTags.Length(); ++i) {
357 nsPluginTag* pluginTag = pluginTags[i];
359 // Add the plugin to the list of hidden plugins or non-hidden plugins?
360 nsTArray<nsRefPtr<nsPluginElement> >& pluginArray =
361 (disablePluginHiding || IsPluginEnumerable(enumerableNames, pluginTag))
362 ? mPlugins
363 : mHiddenPlugins;
365 pluginArray.AppendElement(new nsPluginElement(mWindow, pluginTag));
368 // Alphabetize the enumeration order of non-hidden plugins to reduce
369 // fingerprintable entropy based on plugins' installation file times.
370 mPlugins.Sort();
373 // nsPluginElement implementation.
375 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPluginElement)
376 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPluginElement)
377 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPluginElement)
378 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
379 NS_INTERFACE_MAP_ENTRY(nsISupports)
380 NS_INTERFACE_MAP_END
382 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsPluginElement, mWindow, mMimeTypes)
384 nsPluginElement::nsPluginElement(nsPIDOMWindow* aWindow,
385 nsPluginTag* aPluginTag)
386 : mWindow(aWindow),
387 mPluginTag(aPluginTag)
389 SetIsDOMBinding();
392 nsPluginElement::~nsPluginElement()
396 nsPIDOMWindow*
397 nsPluginElement::GetParentObject() const
399 MOZ_ASSERT(mWindow);
400 return mWindow;
403 JSObject*
404 nsPluginElement::WrapObject(JSContext* aCx)
406 return PluginBinding::Wrap(aCx, this);
409 void
410 nsPluginElement::GetDescription(nsString& retval) const
412 CopyUTF8toUTF16(mPluginTag->mDescription, retval);
415 void
416 nsPluginElement::GetFilename(nsString& retval) const
418 CopyUTF8toUTF16(mPluginTag->mFileName, retval);
421 void
422 nsPluginElement::GetVersion(nsString& retval) const
424 CopyUTF8toUTF16(mPluginTag->mVersion, retval);
427 void
428 nsPluginElement::GetName(nsString& retval) const
430 CopyUTF8toUTF16(mPluginTag->mName, retval);
433 nsMimeType*
434 nsPluginElement::Item(uint32_t aIndex)
436 EnsurePluginMimeTypes();
438 return mMimeTypes.SafeElementAt(aIndex);
441 nsMimeType*
442 nsPluginElement::NamedItem(const nsAString& aName)
444 bool unused;
445 return NamedGetter(aName, unused);
448 nsMimeType*
449 nsPluginElement::IndexedGetter(uint32_t aIndex, bool &aFound)
451 EnsurePluginMimeTypes();
453 aFound = aIndex < mMimeTypes.Length();
455 return aFound ? mMimeTypes[aIndex] : nullptr;
458 nsMimeType*
459 nsPluginElement::NamedGetter(const nsAString& aName, bool &aFound)
461 EnsurePluginMimeTypes();
463 aFound = false;
465 for (uint32_t i = 0; i < mMimeTypes.Length(); ++i) {
466 if (mMimeTypes[i]->Type().Equals(aName)) {
467 aFound = true;
469 return mMimeTypes[i];
473 return nullptr;
476 bool
477 nsPluginElement::NameIsEnumerable(const nsAString& aName)
479 return true;
482 uint32_t
483 nsPluginElement::Length()
485 EnsurePluginMimeTypes();
487 return mMimeTypes.Length();
490 void
491 nsPluginElement::GetSupportedNames(unsigned, nsTArray<nsString>& retval)
493 EnsurePluginMimeTypes();
495 for (uint32_t i = 0; i < mMimeTypes.Length(); ++i) {
496 retval.AppendElement(mMimeTypes[i]->Type());
500 nsTArray<nsRefPtr<nsMimeType> >&
501 nsPluginElement::MimeTypes()
503 EnsurePluginMimeTypes();
505 return mMimeTypes;
508 void
509 nsPluginElement::EnsurePluginMimeTypes()
511 if (!mMimeTypes.IsEmpty()) {
512 return;
515 for (uint32_t i = 0; i < mPluginTag->mMimeTypes.Length(); ++i) {
516 NS_ConvertUTF8toUTF16 type(mPluginTag->mMimeTypes[i]);
517 mMimeTypes.AppendElement(new nsMimeType(mWindow, this, i, type));