1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/base/nsPluginArray.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,492 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsPluginArray.h" 1.10 + 1.11 +#include "mozilla/Preferences.h" 1.12 +#include "mozilla/dom/PluginArrayBinding.h" 1.13 +#include "mozilla/dom/PluginBinding.h" 1.14 + 1.15 +#include "nsCharSeparatedTokenizer.h" 1.16 +#include "nsMimeTypeArray.h" 1.17 +#include "Navigator.h" 1.18 +#include "nsIDocShell.h" 1.19 +#include "nsIWebNavigation.h" 1.20 +#include "nsPluginHost.h" 1.21 +#include "nsPluginTags.h" 1.22 +#include "nsIObserverService.h" 1.23 +#include "nsIWeakReference.h" 1.24 +#include "mozilla/Services.h" 1.25 +#include "nsIInterfaceRequestorUtils.h" 1.26 + 1.27 +using namespace mozilla; 1.28 +using namespace mozilla::dom; 1.29 + 1.30 +nsPluginArray::nsPluginArray(nsPIDOMWindow* aWindow) 1.31 + : mWindow(aWindow) 1.32 +{ 1.33 + SetIsDOMBinding(); 1.34 +} 1.35 + 1.36 +void 1.37 +nsPluginArray::Init() 1.38 +{ 1.39 + nsCOMPtr<nsIObserverService> obsService = 1.40 + mozilla::services::GetObserverService(); 1.41 + if (obsService) { 1.42 + obsService->AddObserver(this, "plugin-info-updated", true); 1.43 + } 1.44 +} 1.45 + 1.46 +nsPluginArray::~nsPluginArray() 1.47 +{ 1.48 +} 1.49 + 1.50 +nsPIDOMWindow* 1.51 +nsPluginArray::GetParentObject() const 1.52 +{ 1.53 + MOZ_ASSERT(mWindow); 1.54 + return mWindow; 1.55 +} 1.56 + 1.57 +JSObject* 1.58 +nsPluginArray::WrapObject(JSContext* aCx) 1.59 +{ 1.60 + return PluginArrayBinding::Wrap(aCx, this); 1.61 +} 1.62 + 1.63 +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPluginArray) 1.64 +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPluginArray) 1.65 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPluginArray) 1.66 + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY 1.67 + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver) 1.68 + NS_INTERFACE_MAP_ENTRY(nsIObserver) 1.69 + NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) 1.70 +NS_INTERFACE_MAP_END 1.71 + 1.72 +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_3(nsPluginArray, 1.73 + mWindow, 1.74 + mPlugins, 1.75 + mHiddenPlugins) 1.76 + 1.77 +static void 1.78 +GetPluginMimeTypes(const nsTArray<nsRefPtr<nsPluginElement> >& aPlugins, 1.79 + nsTArray<nsRefPtr<nsMimeType> >& aMimeTypes) 1.80 +{ 1.81 + for (uint32_t i = 0; i < aPlugins.Length(); ++i) { 1.82 + nsPluginElement *plugin = aPlugins[i]; 1.83 + aMimeTypes.AppendElements(plugin->MimeTypes()); 1.84 + } 1.85 +} 1.86 + 1.87 +void 1.88 +nsPluginArray::GetMimeTypes(nsTArray<nsRefPtr<nsMimeType> >& aMimeTypes, 1.89 + nsTArray<nsRefPtr<nsMimeType> >& aHiddenMimeTypes) 1.90 +{ 1.91 + aMimeTypes.Clear(); 1.92 + aHiddenMimeTypes.Clear(); 1.93 + 1.94 + if (!AllowPlugins()) { 1.95 + return; 1.96 + } 1.97 + 1.98 + EnsurePlugins(); 1.99 + 1.100 + GetPluginMimeTypes(mPlugins, aMimeTypes); 1.101 + GetPluginMimeTypes(mHiddenPlugins, aHiddenMimeTypes); 1.102 +} 1.103 + 1.104 +nsPluginElement* 1.105 +nsPluginArray::Item(uint32_t aIndex) 1.106 +{ 1.107 + bool unused; 1.108 + return IndexedGetter(aIndex, unused); 1.109 +} 1.110 + 1.111 +nsPluginElement* 1.112 +nsPluginArray::NamedItem(const nsAString& aName) 1.113 +{ 1.114 + bool unused; 1.115 + return NamedGetter(aName, unused); 1.116 +} 1.117 + 1.118 +void 1.119 +nsPluginArray::Refresh(bool aReloadDocuments) 1.120 +{ 1.121 + nsRefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst(); 1.122 + 1.123 + if(!AllowPlugins() || !pluginHost) { 1.124 + return; 1.125 + } 1.126 + 1.127 + // NS_ERROR_PLUGINS_PLUGINSNOTCHANGED on reloading plugins indicates 1.128 + // that plugins did not change and was not reloaded 1.129 + if (pluginHost->ReloadPlugins() == 1.130 + NS_ERROR_PLUGINS_PLUGINSNOTCHANGED) { 1.131 + nsTArray<nsRefPtr<nsPluginTag> > newPluginTags; 1.132 + pluginHost->GetPlugins(newPluginTags); 1.133 + 1.134 + // Check if the number of plugins we know about are different from 1.135 + // the number of plugin tags the plugin host knows about. If the 1.136 + // lengths are different, we refresh. This is safe because we're 1.137 + // notified for every plugin enabling/disabling event that 1.138 + // happens, and therefore the lengths will be in sync only when 1.139 + // the both arrays contain the same plugin tags (though as 1.140 + // different types). 1.141 + uint32_t pluginCount = mPlugins.Length() + mHiddenPlugins.Length(); 1.142 + if (newPluginTags.Length() == pluginCount) { 1.143 + return; 1.144 + } 1.145 + } 1.146 + 1.147 + mPlugins.Clear(); 1.148 + mHiddenPlugins.Clear(); 1.149 + 1.150 + nsCOMPtr<nsIDOMNavigator> navigator; 1.151 + mWindow->GetNavigator(getter_AddRefs(navigator)); 1.152 + 1.153 + if (!navigator) { 1.154 + return; 1.155 + } 1.156 + 1.157 + static_cast<mozilla::dom::Navigator*>(navigator.get())->RefreshMIMEArray(); 1.158 + 1.159 + nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(mWindow); 1.160 + if (aReloadDocuments && webNav) { 1.161 + webNav->Reload(nsIWebNavigation::LOAD_FLAGS_NONE); 1.162 + } 1.163 +} 1.164 + 1.165 +nsPluginElement* 1.166 +nsPluginArray::IndexedGetter(uint32_t aIndex, bool &aFound) 1.167 +{ 1.168 + aFound = false; 1.169 + 1.170 + if (!AllowPlugins()) { 1.171 + return nullptr; 1.172 + } 1.173 + 1.174 + EnsurePlugins(); 1.175 + 1.176 + aFound = aIndex < mPlugins.Length(); 1.177 + 1.178 + return aFound ? mPlugins[aIndex] : nullptr; 1.179 +} 1.180 + 1.181 +void 1.182 +nsPluginArray::Invalidate() 1.183 +{ 1.184 + nsCOMPtr<nsIObserverService> obsService = 1.185 + mozilla::services::GetObserverService(); 1.186 + if (obsService) { 1.187 + obsService->RemoveObserver(this, "plugin-info-updated"); 1.188 + } 1.189 +} 1.190 + 1.191 +static nsPluginElement* 1.192 +FindPlugin(const nsTArray<nsRefPtr<nsPluginElement> >& aPlugins, 1.193 + const nsAString& aName) 1.194 +{ 1.195 + for (uint32_t i = 0; i < aPlugins.Length(); ++i) { 1.196 + nsAutoString pluginName; 1.197 + nsPluginElement* plugin = aPlugins[i]; 1.198 + plugin->GetName(pluginName); 1.199 + 1.200 + if (pluginName.Equals(aName)) { 1.201 + return plugin; 1.202 + } 1.203 + } 1.204 + 1.205 + return nullptr; 1.206 +} 1.207 + 1.208 +nsPluginElement* 1.209 +nsPluginArray::NamedGetter(const nsAString& aName, bool &aFound) 1.210 +{ 1.211 + aFound = false; 1.212 + 1.213 + if (!AllowPlugins()) { 1.214 + return nullptr; 1.215 + } 1.216 + 1.217 + EnsurePlugins(); 1.218 + 1.219 + nsPluginElement* plugin = FindPlugin(mPlugins, aName); 1.220 + if (!plugin) { 1.221 + plugin = FindPlugin(mHiddenPlugins, aName); 1.222 + } 1.223 + 1.224 + aFound = (plugin != nullptr); 1.225 + return plugin; 1.226 +} 1.227 + 1.228 +bool 1.229 +nsPluginArray::NameIsEnumerable(const nsAString& aName) 1.230 +{ 1.231 + return true; 1.232 +} 1.233 + 1.234 +uint32_t 1.235 +nsPluginArray::Length() 1.236 +{ 1.237 + if (!AllowPlugins()) { 1.238 + return 0; 1.239 + } 1.240 + 1.241 + EnsurePlugins(); 1.242 + 1.243 + return mPlugins.Length(); 1.244 +} 1.245 + 1.246 +void 1.247 +nsPluginArray::GetSupportedNames(unsigned, nsTArray<nsString>& aRetval) 1.248 +{ 1.249 + aRetval.Clear(); 1.250 + 1.251 + if (!AllowPlugins()) { 1.252 + return; 1.253 + } 1.254 + 1.255 + for (uint32_t i = 0; i < mPlugins.Length(); ++i) { 1.256 + nsAutoString pluginName; 1.257 + mPlugins[i]->GetName(pluginName); 1.258 + 1.259 + aRetval.AppendElement(pluginName); 1.260 + } 1.261 +} 1.262 + 1.263 +NS_IMETHODIMP 1.264 +nsPluginArray::Observe(nsISupports *aSubject, const char *aTopic, 1.265 + const char16_t *aData) { 1.266 + if (!nsCRT::strcmp(aTopic, "plugin-info-updated")) { 1.267 + Refresh(false); 1.268 + } 1.269 + 1.270 + return NS_OK; 1.271 +} 1.272 + 1.273 +bool 1.274 +nsPluginArray::AllowPlugins() const 1.275 +{ 1.276 + nsCOMPtr<nsIDocShell> docShell = do_GetInterface(mWindow); 1.277 + 1.278 + return docShell && docShell->PluginsAllowedInCurrentDoc(); 1.279 +} 1.280 + 1.281 +static bool 1.282 +HasStringPrefix(const nsCString& str, const nsACString& prefix) { 1.283 + return str.Compare(prefix.BeginReading(), false, prefix.Length()) == 0; 1.284 +} 1.285 + 1.286 +static bool 1.287 +IsPluginEnumerable(const nsTArray<nsCString>& enumerableNames, 1.288 + const nsPluginTag* pluginTag) 1.289 +{ 1.290 + const nsCString& pluginName = pluginTag->mName; 1.291 + 1.292 + const uint32_t length = enumerableNames.Length(); 1.293 + for (uint32_t i = 0; i < length; i++) { 1.294 + const nsCString& name = enumerableNames[i]; 1.295 + if (HasStringPrefix(pluginName, name)) { 1.296 + return true; // don't hide plugin 1.297 + } 1.298 + } 1.299 + 1.300 + return false; // hide plugin! 1.301 +} 1.302 + 1.303 +void 1.304 +nsPluginArray::EnsurePlugins() 1.305 +{ 1.306 + if (!mPlugins.IsEmpty() || !mHiddenPlugins.IsEmpty()) { 1.307 + // We already have an array of plugin elements. 1.308 + return; 1.309 + } 1.310 + 1.311 + nsRefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst(); 1.312 + if (!pluginHost) { 1.313 + // We have no plugin host. 1.314 + return; 1.315 + } 1.316 + 1.317 + nsTArray<nsRefPtr<nsPluginTag> > pluginTags; 1.318 + pluginHost->GetPlugins(pluginTags); 1.319 + 1.320 + nsTArray<nsCString> enumerableNames; 1.321 + 1.322 + const nsAdoptingCString& enumerableNamesPref = 1.323 + Preferences::GetCString("plugins.enumerable_names"); 1.324 + 1.325 + bool disablePluginHiding = !enumerableNamesPref || 1.326 + enumerableNamesPref.EqualsLiteral("*"); 1.327 + 1.328 + if (!disablePluginHiding) { 1.329 + nsCCharSeparatedTokenizer tokens(enumerableNamesPref, ','); 1.330 + while (tokens.hasMoreTokens()) { 1.331 + const nsCSubstring& token = tokens.nextToken(); 1.332 + if (!token.IsEmpty()) { 1.333 + enumerableNames.AppendElement(token); 1.334 + } 1.335 + } 1.336 + } 1.337 + 1.338 + // need to wrap each of these with a nsPluginElement, which is 1.339 + // scriptable. 1.340 + for (uint32_t i = 0; i < pluginTags.Length(); ++i) { 1.341 + nsPluginTag* pluginTag = pluginTags[i]; 1.342 + 1.343 + // Add the plugin to the list of hidden plugins or non-hidden plugins? 1.344 + nsTArray<nsRefPtr<nsPluginElement> >& pluginArray = 1.345 + (disablePluginHiding || IsPluginEnumerable(enumerableNames, pluginTag)) 1.346 + ? mPlugins 1.347 + : mHiddenPlugins; 1.348 + 1.349 + pluginArray.AppendElement(new nsPluginElement(mWindow, pluginTag)); 1.350 + } 1.351 +} 1.352 + 1.353 +// nsPluginElement implementation. 1.354 + 1.355 +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPluginElement) 1.356 +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPluginElement) 1.357 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPluginElement) 1.358 + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY 1.359 + NS_INTERFACE_MAP_ENTRY(nsISupports) 1.360 +NS_INTERFACE_MAP_END 1.361 + 1.362 +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(nsPluginElement, mWindow, mMimeTypes) 1.363 + 1.364 +nsPluginElement::nsPluginElement(nsPIDOMWindow* aWindow, 1.365 + nsPluginTag* aPluginTag) 1.366 + : mWindow(aWindow), 1.367 + mPluginTag(aPluginTag) 1.368 +{ 1.369 + SetIsDOMBinding(); 1.370 +} 1.371 + 1.372 +nsPIDOMWindow* 1.373 +nsPluginElement::GetParentObject() const 1.374 +{ 1.375 + MOZ_ASSERT(mWindow); 1.376 + return mWindow; 1.377 +} 1.378 + 1.379 +JSObject* 1.380 +nsPluginElement::WrapObject(JSContext* aCx) 1.381 +{ 1.382 + return PluginBinding::Wrap(aCx, this); 1.383 +} 1.384 + 1.385 +void 1.386 +nsPluginElement::GetDescription(nsString& retval) const 1.387 +{ 1.388 + CopyUTF8toUTF16(mPluginTag->mDescription, retval); 1.389 +} 1.390 + 1.391 +void 1.392 +nsPluginElement::GetFilename(nsString& retval) const 1.393 +{ 1.394 + CopyUTF8toUTF16(mPluginTag->mFileName, retval); 1.395 +} 1.396 + 1.397 +void 1.398 +nsPluginElement::GetVersion(nsString& retval) const 1.399 +{ 1.400 + CopyUTF8toUTF16(mPluginTag->mVersion, retval); 1.401 +} 1.402 + 1.403 +void 1.404 +nsPluginElement::GetName(nsString& retval) const 1.405 +{ 1.406 + CopyUTF8toUTF16(mPluginTag->mName, retval); 1.407 +} 1.408 + 1.409 +nsMimeType* 1.410 +nsPluginElement::Item(uint32_t aIndex) 1.411 +{ 1.412 + EnsurePluginMimeTypes(); 1.413 + 1.414 + return mMimeTypes.SafeElementAt(aIndex); 1.415 +} 1.416 + 1.417 +nsMimeType* 1.418 +nsPluginElement::NamedItem(const nsAString& aName) 1.419 +{ 1.420 + bool unused; 1.421 + return NamedGetter(aName, unused); 1.422 +} 1.423 + 1.424 +nsMimeType* 1.425 +nsPluginElement::IndexedGetter(uint32_t aIndex, bool &aFound) 1.426 +{ 1.427 + EnsurePluginMimeTypes(); 1.428 + 1.429 + aFound = aIndex < mMimeTypes.Length(); 1.430 + 1.431 + return aFound ? mMimeTypes[aIndex] : nullptr; 1.432 +} 1.433 + 1.434 +nsMimeType* 1.435 +nsPluginElement::NamedGetter(const nsAString& aName, bool &aFound) 1.436 +{ 1.437 + EnsurePluginMimeTypes(); 1.438 + 1.439 + aFound = false; 1.440 + 1.441 + for (uint32_t i = 0; i < mMimeTypes.Length(); ++i) { 1.442 + if (mMimeTypes[i]->Type().Equals(aName)) { 1.443 + aFound = true; 1.444 + 1.445 + return mMimeTypes[i]; 1.446 + } 1.447 + } 1.448 + 1.449 + return nullptr; 1.450 +} 1.451 + 1.452 +bool 1.453 +nsPluginElement::NameIsEnumerable(const nsAString& aName) 1.454 +{ 1.455 + return true; 1.456 +} 1.457 + 1.458 +uint32_t 1.459 +nsPluginElement::Length() 1.460 +{ 1.461 + EnsurePluginMimeTypes(); 1.462 + 1.463 + return mMimeTypes.Length(); 1.464 +} 1.465 + 1.466 +void 1.467 +nsPluginElement::GetSupportedNames(unsigned, nsTArray<nsString>& retval) 1.468 +{ 1.469 + EnsurePluginMimeTypes(); 1.470 + 1.471 + for (uint32_t i = 0; i < mMimeTypes.Length(); ++i) { 1.472 + retval.AppendElement(mMimeTypes[i]->Type()); 1.473 + } 1.474 +} 1.475 + 1.476 +nsTArray<nsRefPtr<nsMimeType> >& 1.477 +nsPluginElement::MimeTypes() 1.478 +{ 1.479 + EnsurePluginMimeTypes(); 1.480 + 1.481 + return mMimeTypes; 1.482 +} 1.483 + 1.484 +void 1.485 +nsPluginElement::EnsurePluginMimeTypes() 1.486 +{ 1.487 + if (!mMimeTypes.IsEmpty()) { 1.488 + return; 1.489 + } 1.490 + 1.491 + for (uint32_t i = 0; i < mPluginTag->mMimeTypes.Length(); ++i) { 1.492 + NS_ConvertUTF8toUTF16 type(mPluginTag->mMimeTypes[i]); 1.493 + mMimeTypes.AppendElement(new nsMimeType(mWindow, this, i, type)); 1.494 + } 1.495 +}