Bug 1025824 - Fix mHwcLayerMap handling r=sushil
[gecko.git] / dom / base / nsPluginArray.cpp
blob931d5141fb08491cfbf181855361e18f80d22941
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 void
85 nsPluginArray::GetMimeTypes(nsTArray<nsRefPtr<nsMimeType> >& aMimeTypes,
86 nsTArray<nsRefPtr<nsMimeType> >& aHiddenMimeTypes)
88 aMimeTypes.Clear();
89 aHiddenMimeTypes.Clear();
91 if (!AllowPlugins()) {
92 return;
95 EnsurePlugins();
97 GetPluginMimeTypes(mPlugins, aMimeTypes);
98 GetPluginMimeTypes(mHiddenPlugins, aHiddenMimeTypes);
101 nsPluginElement*
102 nsPluginArray::Item(uint32_t aIndex)
104 bool unused;
105 return IndexedGetter(aIndex, unused);
108 nsPluginElement*
109 nsPluginArray::NamedItem(const nsAString& aName)
111 bool unused;
112 return NamedGetter(aName, unused);
115 void
116 nsPluginArray::Refresh(bool aReloadDocuments)
118 nsRefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
120 if(!AllowPlugins() || !pluginHost) {
121 return;
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
137 // different types).
138 uint32_t pluginCount = mPlugins.Length() + mHiddenPlugins.Length();
139 if (newPluginTags.Length() == pluginCount) {
140 return;
144 mPlugins.Clear();
145 mHiddenPlugins.Clear();
147 nsCOMPtr<nsIDOMNavigator> navigator;
148 mWindow->GetNavigator(getter_AddRefs(navigator));
150 if (!navigator) {
151 return;
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);
162 nsPluginElement*
163 nsPluginArray::IndexedGetter(uint32_t aIndex, bool &aFound)
165 aFound = false;
167 if (!AllowPlugins()) {
168 return nullptr;
171 EnsurePlugins();
173 aFound = aIndex < mPlugins.Length();
175 return aFound ? mPlugins[aIndex] : nullptr;
178 void
179 nsPluginArray::Invalidate()
181 nsCOMPtr<nsIObserverService> obsService =
182 mozilla::services::GetObserverService();
183 if (obsService) {
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)) {
198 return plugin;
202 return nullptr;
205 nsPluginElement*
206 nsPluginArray::NamedGetter(const nsAString& aName, bool &aFound)
208 aFound = false;
210 if (!AllowPlugins()) {
211 return nullptr;
214 EnsurePlugins();
216 nsPluginElement* plugin = FindPlugin(mPlugins, aName);
217 if (!plugin) {
218 plugin = FindPlugin(mHiddenPlugins, aName);
221 aFound = (plugin != nullptr);
222 return plugin;
225 bool
226 nsPluginArray::NameIsEnumerable(const nsAString& aName)
228 return true;
231 uint32_t
232 nsPluginArray::Length()
234 if (!AllowPlugins()) {
235 return 0;
238 EnsurePlugins();
240 return mPlugins.Length();
243 void
244 nsPluginArray::GetSupportedNames(unsigned, nsTArray<nsString>& aRetval)
246 aRetval.Clear();
248 if (!AllowPlugins()) {
249 return;
252 for (uint32_t i = 0; i < mPlugins.Length(); ++i) {
253 nsAutoString pluginName;
254 mPlugins[i]->GetName(pluginName);
256 aRetval.AppendElement(pluginName);
260 NS_IMETHODIMP
261 nsPluginArray::Observe(nsISupports *aSubject, const char *aTopic,
262 const char16_t *aData) {
263 if (!nsCRT::strcmp(aTopic, "plugin-info-updated")) {
264 Refresh(false);
267 return NS_OK;
270 bool
271 nsPluginArray::AllowPlugins() const
273 nsCOMPtr<nsIDocShell> docShell = mWindow ? mWindow->GetDocShell() : nullptr;
275 return docShell && docShell->PluginsAllowedInCurrentDoc();
278 static bool
279 HasStringPrefix(const nsCString& str, const nsACString& prefix) {
280 return str.Compare(prefix.BeginReading(), false, prefix.Length()) == 0;
283 static bool
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!
300 void
301 nsPluginArray::EnsurePlugins()
303 if (!mPlugins.IsEmpty() || !mHiddenPlugins.IsEmpty()) {
304 // We already have an array of plugin elements.
305 return;
308 nsRefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
309 if (!pluginHost) {
310 // We have no plugin host.
311 return;
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
336 // scriptable.
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))
343 ? mPlugins
344 : mHiddenPlugins;
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)
357 NS_INTERFACE_MAP_END
359 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsPluginElement, mWindow, mMimeTypes)
361 nsPluginElement::nsPluginElement(nsPIDOMWindow* aWindow,
362 nsPluginTag* aPluginTag)
363 : mWindow(aWindow),
364 mPluginTag(aPluginTag)
366 SetIsDOMBinding();
369 nsPIDOMWindow*
370 nsPluginElement::GetParentObject() const
372 MOZ_ASSERT(mWindow);
373 return mWindow;
376 JSObject*
377 nsPluginElement::WrapObject(JSContext* aCx)
379 return PluginBinding::Wrap(aCx, this);
382 void
383 nsPluginElement::GetDescription(nsString& retval) const
385 CopyUTF8toUTF16(mPluginTag->mDescription, retval);
388 void
389 nsPluginElement::GetFilename(nsString& retval) const
391 CopyUTF8toUTF16(mPluginTag->mFileName, retval);
394 void
395 nsPluginElement::GetVersion(nsString& retval) const
397 CopyUTF8toUTF16(mPluginTag->mVersion, retval);
400 void
401 nsPluginElement::GetName(nsString& retval) const
403 CopyUTF8toUTF16(mPluginTag->mName, retval);
406 nsMimeType*
407 nsPluginElement::Item(uint32_t aIndex)
409 EnsurePluginMimeTypes();
411 return mMimeTypes.SafeElementAt(aIndex);
414 nsMimeType*
415 nsPluginElement::NamedItem(const nsAString& aName)
417 bool unused;
418 return NamedGetter(aName, unused);
421 nsMimeType*
422 nsPluginElement::IndexedGetter(uint32_t aIndex, bool &aFound)
424 EnsurePluginMimeTypes();
426 aFound = aIndex < mMimeTypes.Length();
428 return aFound ? mMimeTypes[aIndex] : nullptr;
431 nsMimeType*
432 nsPluginElement::NamedGetter(const nsAString& aName, bool &aFound)
434 EnsurePluginMimeTypes();
436 aFound = false;
438 for (uint32_t i = 0; i < mMimeTypes.Length(); ++i) {
439 if (mMimeTypes[i]->Type().Equals(aName)) {
440 aFound = true;
442 return mMimeTypes[i];
446 return nullptr;
449 bool
450 nsPluginElement::NameIsEnumerable(const nsAString& aName)
452 return true;
455 uint32_t
456 nsPluginElement::Length()
458 EnsurePluginMimeTypes();
460 return mMimeTypes.Length();
463 void
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();
478 return mMimeTypes;
481 void
482 nsPluginElement::EnsurePluginMimeTypes()
484 if (!mMimeTypes.IsEmpty()) {
485 return;
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));