Bumping gaia.json for 8 gaia revision(s) a=gaia-bump
[gecko.git] / dom / base / nsPluginArray.cpp
blob1dcd55182e57362e510b4d60aa4d2babff4789b8
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)
32 void
33 nsPluginArray::Init()
35 nsCOMPtr<nsIObserverService> obsService =
36 mozilla::services::GetObserverService();
37 if (obsService) {
38 obsService->AddObserver(this, "plugin-info-updated", true);
42 nsPluginArray::~nsPluginArray()
46 nsPIDOMWindow*
47 nsPluginArray::GetParentObject() const
49 MOZ_ASSERT(mWindow);
50 return mWindow;
53 JSObject*
54 nsPluginArray::WrapObject(JSContext* aCx)
56 return PluginArrayBinding::Wrap(aCx, this);
59 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPluginArray)
60 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPluginArray)
61 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPluginArray)
62 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
63 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
64 NS_INTERFACE_MAP_ENTRY(nsIObserver)
65 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
66 NS_INTERFACE_MAP_END
68 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsPluginArray,
69 mWindow,
70 mPlugins,
71 mHiddenPlugins)
73 static void
74 GetPluginMimeTypes(const nsTArray<nsRefPtr<nsPluginElement> >& aPlugins,
75 nsTArray<nsRefPtr<nsMimeType> >& aMimeTypes)
77 for (uint32_t i = 0; i < aPlugins.Length(); ++i) {
78 nsPluginElement *plugin = aPlugins[i];
79 aMimeTypes.AppendElements(plugin->MimeTypes());
83 static bool
84 operator<(const nsRefPtr<nsMimeType>& lhs, const nsRefPtr<nsMimeType>& rhs)
86 // Sort MIME types alphabetically by type name.
87 return lhs->Type() < rhs->Type();
90 void
91 nsPluginArray::GetMimeTypes(nsTArray<nsRefPtr<nsMimeType> >& aMimeTypes,
92 nsTArray<nsRefPtr<nsMimeType> >& aHiddenMimeTypes)
94 aMimeTypes.Clear();
95 aHiddenMimeTypes.Clear();
97 if (!AllowPlugins()) {
98 return;
101 EnsurePlugins();
103 GetPluginMimeTypes(mPlugins, aMimeTypes);
104 GetPluginMimeTypes(mHiddenPlugins, aHiddenMimeTypes);
106 // Alphabetize the enumeration order of non-hidden MIME types to reduce
107 // fingerprintable entropy based on plugins' installation file times.
108 aMimeTypes.Sort();
111 nsPluginElement*
112 nsPluginArray::Item(uint32_t aIndex)
114 bool unused;
115 return IndexedGetter(aIndex, unused);
118 nsPluginElement*
119 nsPluginArray::NamedItem(const nsAString& aName)
121 bool unused;
122 return NamedGetter(aName, unused);
125 void
126 nsPluginArray::Refresh(bool aReloadDocuments)
128 nsRefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
130 if(!AllowPlugins() || !pluginHost) {
131 return;
134 // NS_ERROR_PLUGINS_PLUGINSNOTCHANGED on reloading plugins indicates
135 // that plugins did not change and was not reloaded
136 if (pluginHost->ReloadPlugins() ==
137 NS_ERROR_PLUGINS_PLUGINSNOTCHANGED) {
138 nsTArray<nsRefPtr<nsPluginTag> > newPluginTags;
139 pluginHost->GetPlugins(newPluginTags);
141 // Check if the number of plugins we know about are different from
142 // the number of plugin tags the plugin host knows about. If the
143 // lengths are different, we refresh. This is safe because we're
144 // notified for every plugin enabling/disabling event that
145 // happens, and therefore the lengths will be in sync only when
146 // the both arrays contain the same plugin tags (though as
147 // different types).
148 uint32_t pluginCount = mPlugins.Length() + mHiddenPlugins.Length();
149 if (newPluginTags.Length() == pluginCount) {
150 return;
154 mPlugins.Clear();
155 mHiddenPlugins.Clear();
157 nsCOMPtr<nsIDOMNavigator> navigator;
158 mWindow->GetNavigator(getter_AddRefs(navigator));
160 if (!navigator) {
161 return;
164 static_cast<mozilla::dom::Navigator*>(navigator.get())->RefreshMIMEArray();
166 nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(mWindow);
167 if (aReloadDocuments && webNav) {
168 webNav->Reload(nsIWebNavigation::LOAD_FLAGS_NONE);
172 nsPluginElement*
173 nsPluginArray::IndexedGetter(uint32_t aIndex, bool &aFound)
175 aFound = false;
177 if (!AllowPlugins()) {
178 return nullptr;
181 EnsurePlugins();
183 aFound = aIndex < mPlugins.Length();
185 return aFound ? mPlugins[aIndex] : nullptr;
188 void
189 nsPluginArray::Invalidate()
191 nsCOMPtr<nsIObserverService> obsService =
192 mozilla::services::GetObserverService();
193 if (obsService) {
194 obsService->RemoveObserver(this, "plugin-info-updated");
198 static nsPluginElement*
199 FindPlugin(const nsTArray<nsRefPtr<nsPluginElement> >& aPlugins,
200 const nsAString& aName)
202 for (uint32_t i = 0; i < aPlugins.Length(); ++i) {
203 nsAutoString pluginName;
204 nsPluginElement* plugin = aPlugins[i];
205 plugin->GetName(pluginName);
207 if (pluginName.Equals(aName)) {
208 return plugin;
212 return nullptr;
215 nsPluginElement*
216 nsPluginArray::NamedGetter(const nsAString& aName, bool &aFound)
218 aFound = false;
220 if (!AllowPlugins()) {
221 return nullptr;
224 EnsurePlugins();
226 nsPluginElement* plugin = FindPlugin(mPlugins, aName);
227 if (!plugin) {
228 plugin = FindPlugin(mHiddenPlugins, aName);
231 aFound = (plugin != nullptr);
232 return plugin;
235 bool
236 nsPluginArray::NameIsEnumerable(const nsAString& aName)
238 return true;
241 uint32_t
242 nsPluginArray::Length()
244 if (!AllowPlugins()) {
245 return 0;
248 EnsurePlugins();
250 return mPlugins.Length();
253 void
254 nsPluginArray::GetSupportedNames(unsigned, nsTArray<nsString>& aRetval)
256 aRetval.Clear();
258 if (!AllowPlugins()) {
259 return;
262 for (uint32_t i = 0; i < mPlugins.Length(); ++i) {
263 nsAutoString pluginName;
264 mPlugins[i]->GetName(pluginName);
266 aRetval.AppendElement(pluginName);
270 NS_IMETHODIMP
271 nsPluginArray::Observe(nsISupports *aSubject, const char *aTopic,
272 const char16_t *aData) {
273 if (!nsCRT::strcmp(aTopic, "plugin-info-updated")) {
274 Refresh(false);
277 return NS_OK;
280 bool
281 nsPluginArray::AllowPlugins() const
283 nsCOMPtr<nsIDocShell> docShell = mWindow ? mWindow->GetDocShell() : nullptr;
285 return docShell && docShell->PluginsAllowedInCurrentDoc();
288 static bool
289 HasStringPrefix(const nsCString& str, const nsACString& prefix) {
290 return str.Compare(prefix.BeginReading(), false, prefix.Length()) == 0;
293 static bool
294 IsPluginEnumerable(const nsTArray<nsCString>& enumerableNames,
295 const nsPluginTag* pluginTag)
297 const nsCString& pluginName = pluginTag->mName;
299 const uint32_t length = enumerableNames.Length();
300 for (uint32_t i = 0; i < length; i++) {
301 const nsCString& name = enumerableNames[i];
302 if (HasStringPrefix(pluginName, name)) {
303 return true; // don't hide plugin
307 return false; // hide plugin!
310 static bool
311 operator<(const nsRefPtr<nsPluginElement>& lhs,
312 const nsRefPtr<nsPluginElement>& rhs)
314 // Sort plugins alphabetically by name.
315 return lhs->PluginTag()->mName < rhs->PluginTag()->mName;
318 void
319 nsPluginArray::EnsurePlugins()
321 if (!mPlugins.IsEmpty() || !mHiddenPlugins.IsEmpty()) {
322 // We already have an array of plugin elements.
323 return;
326 nsRefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
327 if (!pluginHost) {
328 // We have no plugin host.
329 return;
332 nsTArray<nsRefPtr<nsPluginTag> > pluginTags;
333 pluginHost->GetPlugins(pluginTags);
335 nsTArray<nsCString> enumerableNames;
337 const nsAdoptingCString& enumerableNamesPref =
338 Preferences::GetCString("plugins.enumerable_names");
340 bool disablePluginHiding = !enumerableNamesPref ||
341 enumerableNamesPref.EqualsLiteral("*");
343 if (!disablePluginHiding) {
344 nsCCharSeparatedTokenizer tokens(enumerableNamesPref, ',');
345 while (tokens.hasMoreTokens()) {
346 const nsCSubstring& token = tokens.nextToken();
347 if (!token.IsEmpty()) {
348 enumerableNames.AppendElement(token);
353 // need to wrap each of these with a nsPluginElement, which is
354 // scriptable.
355 for (uint32_t i = 0; i < pluginTags.Length(); ++i) {
356 nsPluginTag* pluginTag = pluginTags[i];
358 // Add the plugin to the list of hidden plugins or non-hidden plugins?
359 nsTArray<nsRefPtr<nsPluginElement> >& pluginArray =
360 (disablePluginHiding || IsPluginEnumerable(enumerableNames, pluginTag))
361 ? mPlugins
362 : mHiddenPlugins;
364 pluginArray.AppendElement(new nsPluginElement(mWindow, pluginTag));
367 // Alphabetize the enumeration order of non-hidden plugins to reduce
368 // fingerprintable entropy based on plugins' installation file times.
369 mPlugins.Sort();
372 // nsPluginElement implementation.
374 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPluginElement)
375 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPluginElement)
376 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPluginElement)
377 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
378 NS_INTERFACE_MAP_ENTRY(nsISupports)
379 NS_INTERFACE_MAP_END
381 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsPluginElement, mWindow, mMimeTypes)
383 nsPluginElement::nsPluginElement(nsPIDOMWindow* aWindow,
384 nsPluginTag* aPluginTag)
385 : mWindow(aWindow),
386 mPluginTag(aPluginTag)
390 nsPluginElement::~nsPluginElement()
394 nsPIDOMWindow*
395 nsPluginElement::GetParentObject() const
397 MOZ_ASSERT(mWindow);
398 return mWindow;
401 JSObject*
402 nsPluginElement::WrapObject(JSContext* aCx)
404 return PluginBinding::Wrap(aCx, this);
407 void
408 nsPluginElement::GetDescription(nsString& retval) const
410 CopyUTF8toUTF16(mPluginTag->mDescription, retval);
413 void
414 nsPluginElement::GetFilename(nsString& retval) const
416 CopyUTF8toUTF16(mPluginTag->mFileName, retval);
419 void
420 nsPluginElement::GetVersion(nsString& retval) const
422 CopyUTF8toUTF16(mPluginTag->mVersion, retval);
425 void
426 nsPluginElement::GetName(nsString& retval) const
428 CopyUTF8toUTF16(mPluginTag->mName, retval);
431 nsMimeType*
432 nsPluginElement::Item(uint32_t aIndex)
434 EnsurePluginMimeTypes();
436 return mMimeTypes.SafeElementAt(aIndex);
439 nsMimeType*
440 nsPluginElement::NamedItem(const nsAString& aName)
442 bool unused;
443 return NamedGetter(aName, unused);
446 nsMimeType*
447 nsPluginElement::IndexedGetter(uint32_t aIndex, bool &aFound)
449 EnsurePluginMimeTypes();
451 aFound = aIndex < mMimeTypes.Length();
453 return aFound ? mMimeTypes[aIndex] : nullptr;
456 nsMimeType*
457 nsPluginElement::NamedGetter(const nsAString& aName, bool &aFound)
459 EnsurePluginMimeTypes();
461 aFound = false;
463 for (uint32_t i = 0; i < mMimeTypes.Length(); ++i) {
464 if (mMimeTypes[i]->Type().Equals(aName)) {
465 aFound = true;
467 return mMimeTypes[i];
471 return nullptr;
474 bool
475 nsPluginElement::NameIsEnumerable(const nsAString& aName)
477 return true;
480 uint32_t
481 nsPluginElement::Length()
483 EnsurePluginMimeTypes();
485 return mMimeTypes.Length();
488 void
489 nsPluginElement::GetSupportedNames(unsigned, nsTArray<nsString>& retval)
491 EnsurePluginMimeTypes();
493 for (uint32_t i = 0; i < mMimeTypes.Length(); ++i) {
494 retval.AppendElement(mMimeTypes[i]->Type());
498 nsTArray<nsRefPtr<nsMimeType> >&
499 nsPluginElement::MimeTypes()
501 EnsurePluginMimeTypes();
503 return mMimeTypes;
506 void
507 nsPluginElement::EnsurePluginMimeTypes()
509 if (!mMimeTypes.IsEmpty()) {
510 return;
513 for (uint32_t i = 0; i < mPluginTag->mMimeTypes.Length(); ++i) {
514 NS_ConvertUTF8toUTF16 type(mPluginTag->mMimeTypes[i]);
515 mMimeTypes.AppendElement(new nsMimeType(mWindow, this, i, type));