Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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)
29 {
30 SetIsDOMBinding();
31 }
33 void
34 nsPluginArray::Init()
35 {
36 nsCOMPtr<nsIObserverService> obsService =
37 mozilla::services::GetObserverService();
38 if (obsService) {
39 obsService->AddObserver(this, "plugin-info-updated", true);
40 }
41 }
43 nsPluginArray::~nsPluginArray()
44 {
45 }
47 nsPIDOMWindow*
48 nsPluginArray::GetParentObject() const
49 {
50 MOZ_ASSERT(mWindow);
51 return mWindow;
52 }
54 JSObject*
55 nsPluginArray::WrapObject(JSContext* aCx)
56 {
57 return PluginArrayBinding::Wrap(aCx, this);
58 }
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_3(nsPluginArray,
70 mWindow,
71 mPlugins,
72 mHiddenPlugins)
74 static void
75 GetPluginMimeTypes(const nsTArray<nsRefPtr<nsPluginElement> >& aPlugins,
76 nsTArray<nsRefPtr<nsMimeType> >& aMimeTypes)
77 {
78 for (uint32_t i = 0; i < aPlugins.Length(); ++i) {
79 nsPluginElement *plugin = aPlugins[i];
80 aMimeTypes.AppendElements(plugin->MimeTypes());
81 }
82 }
84 void
85 nsPluginArray::GetMimeTypes(nsTArray<nsRefPtr<nsMimeType> >& aMimeTypes,
86 nsTArray<nsRefPtr<nsMimeType> >& aHiddenMimeTypes)
87 {
88 aMimeTypes.Clear();
89 aHiddenMimeTypes.Clear();
91 if (!AllowPlugins()) {
92 return;
93 }
95 EnsurePlugins();
97 GetPluginMimeTypes(mPlugins, aMimeTypes);
98 GetPluginMimeTypes(mHiddenPlugins, aHiddenMimeTypes);
99 }
101 nsPluginElement*
102 nsPluginArray::Item(uint32_t aIndex)
103 {
104 bool unused;
105 return IndexedGetter(aIndex, unused);
106 }
108 nsPluginElement*
109 nsPluginArray::NamedItem(const nsAString& aName)
110 {
111 bool unused;
112 return NamedGetter(aName, unused);
113 }
115 void
116 nsPluginArray::Refresh(bool aReloadDocuments)
117 {
118 nsRefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
120 if(!AllowPlugins() || !pluginHost) {
121 return;
122 }
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;
141 }
142 }
144 mPlugins.Clear();
145 mHiddenPlugins.Clear();
147 nsCOMPtr<nsIDOMNavigator> navigator;
148 mWindow->GetNavigator(getter_AddRefs(navigator));
150 if (!navigator) {
151 return;
152 }
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);
159 }
160 }
162 nsPluginElement*
163 nsPluginArray::IndexedGetter(uint32_t aIndex, bool &aFound)
164 {
165 aFound = false;
167 if (!AllowPlugins()) {
168 return nullptr;
169 }
171 EnsurePlugins();
173 aFound = aIndex < mPlugins.Length();
175 return aFound ? mPlugins[aIndex] : nullptr;
176 }
178 void
179 nsPluginArray::Invalidate()
180 {
181 nsCOMPtr<nsIObserverService> obsService =
182 mozilla::services::GetObserverService();
183 if (obsService) {
184 obsService->RemoveObserver(this, "plugin-info-updated");
185 }
186 }
188 static nsPluginElement*
189 FindPlugin(const nsTArray<nsRefPtr<nsPluginElement> >& aPlugins,
190 const nsAString& aName)
191 {
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;
199 }
200 }
202 return nullptr;
203 }
205 nsPluginElement*
206 nsPluginArray::NamedGetter(const nsAString& aName, bool &aFound)
207 {
208 aFound = false;
210 if (!AllowPlugins()) {
211 return nullptr;
212 }
214 EnsurePlugins();
216 nsPluginElement* plugin = FindPlugin(mPlugins, aName);
217 if (!plugin) {
218 plugin = FindPlugin(mHiddenPlugins, aName);
219 }
221 aFound = (plugin != nullptr);
222 return plugin;
223 }
225 bool
226 nsPluginArray::NameIsEnumerable(const nsAString& aName)
227 {
228 return true;
229 }
231 uint32_t
232 nsPluginArray::Length()
233 {
234 if (!AllowPlugins()) {
235 return 0;
236 }
238 EnsurePlugins();
240 return mPlugins.Length();
241 }
243 void
244 nsPluginArray::GetSupportedNames(unsigned, nsTArray<nsString>& aRetval)
245 {
246 aRetval.Clear();
248 if (!AllowPlugins()) {
249 return;
250 }
252 for (uint32_t i = 0; i < mPlugins.Length(); ++i) {
253 nsAutoString pluginName;
254 mPlugins[i]->GetName(pluginName);
256 aRetval.AppendElement(pluginName);
257 }
258 }
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);
265 }
267 return NS_OK;
268 }
270 bool
271 nsPluginArray::AllowPlugins() const
272 {
273 nsCOMPtr<nsIDocShell> docShell = do_GetInterface(mWindow);
275 return docShell && docShell->PluginsAllowedInCurrentDoc();
276 }
278 static bool
279 HasStringPrefix(const nsCString& str, const nsACString& prefix) {
280 return str.Compare(prefix.BeginReading(), false, prefix.Length()) == 0;
281 }
283 static bool
284 IsPluginEnumerable(const nsTArray<nsCString>& enumerableNames,
285 const nsPluginTag* pluginTag)
286 {
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
294 }
295 }
297 return false; // hide plugin!
298 }
300 void
301 nsPluginArray::EnsurePlugins()
302 {
303 if (!mPlugins.IsEmpty() || !mHiddenPlugins.IsEmpty()) {
304 // We already have an array of plugin elements.
305 return;
306 }
308 nsRefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
309 if (!pluginHost) {
310 // We have no plugin host.
311 return;
312 }
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);
331 }
332 }
333 }
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));
347 }
348 }
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_2(nsPluginElement, mWindow, mMimeTypes)
361 nsPluginElement::nsPluginElement(nsPIDOMWindow* aWindow,
362 nsPluginTag* aPluginTag)
363 : mWindow(aWindow),
364 mPluginTag(aPluginTag)
365 {
366 SetIsDOMBinding();
367 }
369 nsPIDOMWindow*
370 nsPluginElement::GetParentObject() const
371 {
372 MOZ_ASSERT(mWindow);
373 return mWindow;
374 }
376 JSObject*
377 nsPluginElement::WrapObject(JSContext* aCx)
378 {
379 return PluginBinding::Wrap(aCx, this);
380 }
382 void
383 nsPluginElement::GetDescription(nsString& retval) const
384 {
385 CopyUTF8toUTF16(mPluginTag->mDescription, retval);
386 }
388 void
389 nsPluginElement::GetFilename(nsString& retval) const
390 {
391 CopyUTF8toUTF16(mPluginTag->mFileName, retval);
392 }
394 void
395 nsPluginElement::GetVersion(nsString& retval) const
396 {
397 CopyUTF8toUTF16(mPluginTag->mVersion, retval);
398 }
400 void
401 nsPluginElement::GetName(nsString& retval) const
402 {
403 CopyUTF8toUTF16(mPluginTag->mName, retval);
404 }
406 nsMimeType*
407 nsPluginElement::Item(uint32_t aIndex)
408 {
409 EnsurePluginMimeTypes();
411 return mMimeTypes.SafeElementAt(aIndex);
412 }
414 nsMimeType*
415 nsPluginElement::NamedItem(const nsAString& aName)
416 {
417 bool unused;
418 return NamedGetter(aName, unused);
419 }
421 nsMimeType*
422 nsPluginElement::IndexedGetter(uint32_t aIndex, bool &aFound)
423 {
424 EnsurePluginMimeTypes();
426 aFound = aIndex < mMimeTypes.Length();
428 return aFound ? mMimeTypes[aIndex] : nullptr;
429 }
431 nsMimeType*
432 nsPluginElement::NamedGetter(const nsAString& aName, bool &aFound)
433 {
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];
443 }
444 }
446 return nullptr;
447 }
449 bool
450 nsPluginElement::NameIsEnumerable(const nsAString& aName)
451 {
452 return true;
453 }
455 uint32_t
456 nsPluginElement::Length()
457 {
458 EnsurePluginMimeTypes();
460 return mMimeTypes.Length();
461 }
463 void
464 nsPluginElement::GetSupportedNames(unsigned, nsTArray<nsString>& retval)
465 {
466 EnsurePluginMimeTypes();
468 for (uint32_t i = 0; i < mMimeTypes.Length(); ++i) {
469 retval.AppendElement(mMimeTypes[i]->Type());
470 }
471 }
473 nsTArray<nsRefPtr<nsMimeType> >&
474 nsPluginElement::MimeTypes()
475 {
476 EnsurePluginMimeTypes();
478 return mMimeTypes;
479 }
481 void
482 nsPluginElement::EnsurePluginMimeTypes()
483 {
484 if (!mMimeTypes.IsEmpty()) {
485 return;
486 }
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));
491 }
492 }