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
)
36 nsCOMPtr
<nsIObserverService
> obsService
=
37 mozilla::services::GetObserverService();
39 obsService
->AddObserver(this, "plugin-info-updated", true);
43 nsPluginArray::~nsPluginArray()
48 nsPluginArray::GetParentObject() const
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
)
69 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsPluginArray
,
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());
85 nsPluginArray::GetMimeTypes(nsTArray
<nsRefPtr
<nsMimeType
> >& aMimeTypes
,
86 nsTArray
<nsRefPtr
<nsMimeType
> >& aHiddenMimeTypes
)
89 aHiddenMimeTypes
.Clear();
91 if (!AllowPlugins()) {
97 GetPluginMimeTypes(mPlugins
, aMimeTypes
);
98 GetPluginMimeTypes(mHiddenPlugins
, aHiddenMimeTypes
);
102 nsPluginArray::Item(uint32_t aIndex
)
105 return IndexedGetter(aIndex
, unused
);
109 nsPluginArray::NamedItem(const nsAString
& aName
)
112 return NamedGetter(aName
, unused
);
116 nsPluginArray::Refresh(bool aReloadDocuments
)
118 nsRefPtr
<nsPluginHost
> pluginHost
= nsPluginHost::GetInst();
120 if(!AllowPlugins() || !pluginHost
) {
124 // NS_ERROR_PLUGINS_PLUGINSNOTCHANGED on reloading plugins indicates
125 // that plugins did not change and was not reloaded
126 if (pluginHost
->ReloadPlugins() ==
127 NS_ERROR_PLUGINS_PLUGINSNOTCHANGED
) {
128 nsTArray
<nsRefPtr
<nsPluginTag
> > newPluginTags
;
129 pluginHost
->GetPlugins(newPluginTags
);
131 // Check if the number of plugins we know about are different from
132 // the number of plugin tags the plugin host knows about. If the
133 // lengths are different, we refresh. This is safe because we're
134 // notified for every plugin enabling/disabling event that
135 // happens, and therefore the lengths will be in sync only when
136 // the both arrays contain the same plugin tags (though as
138 uint32_t pluginCount
= mPlugins
.Length() + mHiddenPlugins
.Length();
139 if (newPluginTags
.Length() == pluginCount
) {
145 mHiddenPlugins
.Clear();
147 nsCOMPtr
<nsIDOMNavigator
> navigator
;
148 mWindow
->GetNavigator(getter_AddRefs(navigator
));
154 static_cast<mozilla::dom::Navigator
*>(navigator
.get())->RefreshMIMEArray();
156 nsCOMPtr
<nsIWebNavigation
> webNav
= do_GetInterface(mWindow
);
157 if (aReloadDocuments
&& webNav
) {
158 webNav
->Reload(nsIWebNavigation::LOAD_FLAGS_NONE
);
163 nsPluginArray::IndexedGetter(uint32_t aIndex
, bool &aFound
)
167 if (!AllowPlugins()) {
173 aFound
= aIndex
< mPlugins
.Length();
175 return aFound
? mPlugins
[aIndex
] : nullptr;
179 nsPluginArray::Invalidate()
181 nsCOMPtr
<nsIObserverService
> obsService
=
182 mozilla::services::GetObserverService();
184 obsService
->RemoveObserver(this, "plugin-info-updated");
188 static nsPluginElement
*
189 FindPlugin(const nsTArray
<nsRefPtr
<nsPluginElement
> >& aPlugins
,
190 const nsAString
& aName
)
192 for (uint32_t i
= 0; i
< aPlugins
.Length(); ++i
) {
193 nsAutoString pluginName
;
194 nsPluginElement
* plugin
= aPlugins
[i
];
195 plugin
->GetName(pluginName
);
197 if (pluginName
.Equals(aName
)) {
206 nsPluginArray::NamedGetter(const nsAString
& aName
, bool &aFound
)
210 if (!AllowPlugins()) {
216 nsPluginElement
* plugin
= FindPlugin(mPlugins
, aName
);
218 plugin
= FindPlugin(mHiddenPlugins
, aName
);
221 aFound
= (plugin
!= nullptr);
226 nsPluginArray::NameIsEnumerable(const nsAString
& aName
)
232 nsPluginArray::Length()
234 if (!AllowPlugins()) {
240 return mPlugins
.Length();
244 nsPluginArray::GetSupportedNames(unsigned, nsTArray
<nsString
>& aRetval
)
248 if (!AllowPlugins()) {
252 for (uint32_t i
= 0; i
< mPlugins
.Length(); ++i
) {
253 nsAutoString pluginName
;
254 mPlugins
[i
]->GetName(pluginName
);
256 aRetval
.AppendElement(pluginName
);
261 nsPluginArray::Observe(nsISupports
*aSubject
, const char *aTopic
,
262 const char16_t
*aData
) {
263 if (!nsCRT::strcmp(aTopic
, "plugin-info-updated")) {
271 nsPluginArray::AllowPlugins() const
273 nsCOMPtr
<nsIDocShell
> docShell
= mWindow
? mWindow
->GetDocShell() : nullptr;
275 return docShell
&& docShell
->PluginsAllowedInCurrentDoc();
279 HasStringPrefix(const nsCString
& str
, const nsACString
& prefix
) {
280 return str
.Compare(prefix
.BeginReading(), false, prefix
.Length()) == 0;
284 IsPluginEnumerable(const nsTArray
<nsCString
>& enumerableNames
,
285 const nsPluginTag
* pluginTag
)
287 const nsCString
& pluginName
= pluginTag
->mName
;
289 const uint32_t length
= enumerableNames
.Length();
290 for (uint32_t i
= 0; i
< length
; i
++) {
291 const nsCString
& name
= enumerableNames
[i
];
292 if (HasStringPrefix(pluginName
, name
)) {
293 return true; // don't hide plugin
297 return false; // hide plugin!
301 nsPluginArray::EnsurePlugins()
303 if (!mPlugins
.IsEmpty() || !mHiddenPlugins
.IsEmpty()) {
304 // We already have an array of plugin elements.
308 nsRefPtr
<nsPluginHost
> pluginHost
= nsPluginHost::GetInst();
310 // We have no plugin host.
314 nsTArray
<nsRefPtr
<nsPluginTag
> > pluginTags
;
315 pluginHost
->GetPlugins(pluginTags
);
317 nsTArray
<nsCString
> enumerableNames
;
319 const nsAdoptingCString
& enumerableNamesPref
=
320 Preferences::GetCString("plugins.enumerable_names");
322 bool disablePluginHiding
= !enumerableNamesPref
||
323 enumerableNamesPref
.EqualsLiteral("*");
325 if (!disablePluginHiding
) {
326 nsCCharSeparatedTokenizer
tokens(enumerableNamesPref
, ',');
327 while (tokens
.hasMoreTokens()) {
328 const nsCSubstring
& token
= tokens
.nextToken();
329 if (!token
.IsEmpty()) {
330 enumerableNames
.AppendElement(token
);
335 // need to wrap each of these with a nsPluginElement, which is
337 for (uint32_t i
= 0; i
< pluginTags
.Length(); ++i
) {
338 nsPluginTag
* pluginTag
= pluginTags
[i
];
340 // Add the plugin to the list of hidden plugins or non-hidden plugins?
341 nsTArray
<nsRefPtr
<nsPluginElement
> >& pluginArray
=
342 (disablePluginHiding
|| IsPluginEnumerable(enumerableNames
, pluginTag
))
346 pluginArray
.AppendElement(new nsPluginElement(mWindow
, pluginTag
));
350 // nsPluginElement implementation.
352 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPluginElement
)
353 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPluginElement
)
354 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPluginElement
)
355 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
356 NS_INTERFACE_MAP_ENTRY(nsISupports
)
359 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsPluginElement
, mWindow
, mMimeTypes
)
361 nsPluginElement::nsPluginElement(nsPIDOMWindow
* aWindow
,
362 nsPluginTag
* aPluginTag
)
364 mPluginTag(aPluginTag
)
370 nsPluginElement::GetParentObject() const
377 nsPluginElement::WrapObject(JSContext
* aCx
)
379 return PluginBinding::Wrap(aCx
, this);
383 nsPluginElement::GetDescription(nsString
& retval
) const
385 CopyUTF8toUTF16(mPluginTag
->mDescription
, retval
);
389 nsPluginElement::GetFilename(nsString
& retval
) const
391 CopyUTF8toUTF16(mPluginTag
->mFileName
, retval
);
395 nsPluginElement::GetVersion(nsString
& retval
) const
397 CopyUTF8toUTF16(mPluginTag
->mVersion
, retval
);
401 nsPluginElement::GetName(nsString
& retval
) const
403 CopyUTF8toUTF16(mPluginTag
->mName
, retval
);
407 nsPluginElement::Item(uint32_t aIndex
)
409 EnsurePluginMimeTypes();
411 return mMimeTypes
.SafeElementAt(aIndex
);
415 nsPluginElement::NamedItem(const nsAString
& aName
)
418 return NamedGetter(aName
, unused
);
422 nsPluginElement::IndexedGetter(uint32_t aIndex
, bool &aFound
)
424 EnsurePluginMimeTypes();
426 aFound
= aIndex
< mMimeTypes
.Length();
428 return aFound
? mMimeTypes
[aIndex
] : nullptr;
432 nsPluginElement::NamedGetter(const nsAString
& aName
, bool &aFound
)
434 EnsurePluginMimeTypes();
438 for (uint32_t i
= 0; i
< mMimeTypes
.Length(); ++i
) {
439 if (mMimeTypes
[i
]->Type().Equals(aName
)) {
442 return mMimeTypes
[i
];
450 nsPluginElement::NameIsEnumerable(const nsAString
& aName
)
456 nsPluginElement::Length()
458 EnsurePluginMimeTypes();
460 return mMimeTypes
.Length();
464 nsPluginElement::GetSupportedNames(unsigned, nsTArray
<nsString
>& retval
)
466 EnsurePluginMimeTypes();
468 for (uint32_t i
= 0; i
< mMimeTypes
.Length(); ++i
) {
469 retval
.AppendElement(mMimeTypes
[i
]->Type());
473 nsTArray
<nsRefPtr
<nsMimeType
> >&
474 nsPluginElement::MimeTypes()
476 EnsurePluginMimeTypes();
482 nsPluginElement::EnsurePluginMimeTypes()
484 if (!mMimeTypes
.IsEmpty()) {
488 for (uint32_t i
= 0; i
< mPluginTag
->mMimeTypes
.Length(); ++i
) {
489 NS_ConvertUTF8toUTF16
type(mPluginTag
->mMimeTypes
[i
]);
490 mMimeTypes
.AppendElement(new nsMimeType(mWindow
, this, i
, type
));