Back to index

lightning-sunbird  0.9+nobinonly
nsPluginArray.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Pierre Phaneuf <pp@ludusdesign.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsPluginArray.h"
00040 #include "nsMimeTypeArray.h"
00041 #include "nsGlobalWindow.h"
00042 #include "nsIScriptGlobalObject.h"
00043 #include "nsIDOMNavigator.h"
00044 #include "nsIDOMMimeType.h"
00045 #include "nsIServiceManager.h"
00046 #include "nsIPluginHost.h"
00047 #include "nsIDocShell.h"
00048 #include "nsIWebNavigation.h"
00049 #include "nsDOMClassInfo.h"
00050 #include "nsPluginError.h"
00051 #include "nsIComponentRegistrar.h"
00052 #include "nsContentUtils.h"
00053 
00054 static NS_DEFINE_CID(kPluginManagerCID, NS_PLUGINMANAGER_CID);
00055 
00056 nsPluginArray::nsPluginArray(nsNavigator* navigator,
00057                              nsIDocShell *aDocShell)
00058 {
00059   nsresult rv;
00060   mNavigator = navigator; // don't ADDREF here, needed for parent of script object.
00061   mPluginHost = do_GetService(kPluginManagerCID, &rv);
00062   mPluginCount = 0;
00063   mPluginArray = nsnull;
00064   mDocShell = aDocShell;
00065 }
00066 
00067 nsPluginArray::~nsPluginArray()
00068 {
00069   if (mPluginArray != nsnull) {
00070     for (PRUint32 i = 0; i < mPluginCount; i++) {
00071       NS_IF_RELEASE(mPluginArray[i]);
00072     }
00073     delete[] mPluginArray;
00074   }
00075 }
00076 
00077 // QueryInterface implementation for nsPluginArray
00078 NS_INTERFACE_MAP_BEGIN(nsPluginArray)
00079   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMPluginArray)
00080   NS_INTERFACE_MAP_ENTRY(nsIDOMPluginArray)
00081   NS_INTERFACE_MAP_ENTRY(nsIDOMJSPluginArray)
00082   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(PluginArray)
00083 NS_INTERFACE_MAP_END
00084 
00085 NS_IMPL_ADDREF(nsPluginArray)
00086 NS_IMPL_RELEASE(nsPluginArray)
00087 
00088 NS_IMETHODIMP
00089 nsPluginArray::GetLength(PRUint32* aLength)
00090 {
00091   if (AllowPlugins() && mPluginHost)
00092     return mPluginHost->GetPluginCount(aLength);
00093   
00094   *aLength = 0;
00095   return NS_OK;
00096 }
00097 
00098 PRBool
00099 nsPluginArray::AllowPlugins()
00100 {
00101   PRBool allowPlugins = PR_FALSE;
00102   if (mDocShell)
00103     if (NS_FAILED(mDocShell->GetAllowPlugins(&allowPlugins)))
00104       allowPlugins = PR_FALSE;
00105 
00106   return allowPlugins;
00107 }
00108 
00109 NS_IMETHODIMP
00110 nsPluginArray::Item(PRUint32 aIndex, nsIDOMPlugin** aReturn)
00111 {
00112   NS_PRECONDITION(nsnull != aReturn, "null arg");
00113   *aReturn = nsnull;
00114 
00115   if (!AllowPlugins())
00116     return NS_OK;
00117 
00118   if (mPluginArray == nsnull) {
00119     nsresult rv = GetPlugins();
00120     if (rv != NS_OK)
00121       return rv;
00122   }
00123 
00124   if (aIndex < mPluginCount) {
00125     *aReturn = mPluginArray[aIndex];
00126     NS_IF_ADDREF(*aReturn);
00127   }
00128 
00129   return NS_OK;
00130 }
00131 
00132 NS_IMETHODIMP
00133 nsPluginArray::NamedItem(const nsAString& aName, nsIDOMPlugin** aReturn)
00134 {
00135   NS_PRECONDITION(nsnull != aReturn, "null arg");
00136   *aReturn = nsnull;
00137 
00138   if (!AllowPlugins())
00139     return NS_OK;
00140 
00141   if (mPluginArray == nsnull) {
00142     nsresult rv = GetPlugins();
00143     if (rv != NS_OK)
00144       return rv;
00145   }
00146 
00147   for (PRUint32 i = 0; i < mPluginCount; i++) {
00148     nsAutoString pluginName;
00149     nsIDOMPlugin* plugin = mPluginArray[i];
00150     if (plugin->GetName(pluginName) == NS_OK) {
00151       if (pluginName.Equals(aName)) {
00152         *aReturn = plugin;
00153         NS_IF_ADDREF(plugin);
00154         break;
00155       }
00156     }
00157   }
00158 
00159   return NS_OK;
00160 }
00161 
00162 nsresult
00163 nsPluginArray::GetPluginHost(nsIPluginHost** aPluginHost)
00164 {
00165   NS_ENSURE_ARG_POINTER(aPluginHost);
00166 
00167   nsresult rv = NS_OK;
00168 
00169   if (!mPluginHost) {
00170     mPluginHost = do_GetService(kPluginManagerCID, &rv);
00171 
00172     if (NS_FAILED(rv)) {
00173       return rv;
00174     }
00175   }
00176 
00177   *aPluginHost = mPluginHost;
00178   NS_IF_ADDREF(*aPluginHost);
00179 
00180   return rv;
00181 }
00182 
00183 void
00184 nsPluginArray::SetDocShell(nsIDocShell* aDocShell)
00185 {
00186   mDocShell = aDocShell;
00187 }
00188 
00189 NS_IMETHODIMP
00190 nsPluginArray::Refresh(PRBool aReloadDocuments)
00191 {
00192   nsresult res = NS_OK;
00193   if (!AllowPlugins())
00194     return NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA;
00195 
00196   // refresh the component registry first, see bug 87913
00197   nsCOMPtr<nsIServiceManager> servManager;
00198   NS_GetServiceManager(getter_AddRefs(servManager));
00199   nsCOMPtr<nsIComponentRegistrar> registrar = do_QueryInterface(servManager);
00200   if (registrar)
00201     registrar->AutoRegister(nsnull);
00202 
00203   if (!mPluginHost) {
00204     mPluginHost = do_GetService(kPluginManagerCID, &res);
00205   }
00206 
00207   if(NS_FAILED(res)) {
00208     return res;
00209   }
00210 
00211   nsCOMPtr<nsIPluginManager> pm(do_QueryInterface(mPluginHost));
00212 
00213   // NS_ERROR_PLUGINS_PLUGINSNOTCHANGED on reloading plugins indicates
00214   // that plugins did not change and was not reloaded
00215   PRBool pluginsNotChanged = PR_FALSE;
00216   if(pm)
00217     pluginsNotChanged = (NS_ERROR_PLUGINS_PLUGINSNOTCHANGED == pm->ReloadPlugins(aReloadDocuments));
00218 
00219   // no need to reload the page if plugins have not been changed
00220   // in fact, if we do reload we can hit recursive load problem, see bug 93351
00221   if(pluginsNotChanged)
00222     return res;
00223 
00224   nsCOMPtr<nsIWebNavigation> webNav = do_QueryInterface(mDocShell);
00225 
00226   if (mPluginArray != nsnull) {
00227     for (PRUint32 i = 0; i < mPluginCount; i++) 
00228       NS_IF_RELEASE(mPluginArray[i]);
00229 
00230     delete[] mPluginArray;
00231   }
00232 
00233   mPluginCount = 0;
00234   mPluginArray = nsnull;
00235 
00236   if (mNavigator)
00237     mNavigator->RefreshMIMEArray();
00238   
00239   if (aReloadDocuments && webNav)
00240     webNav->Reload(nsIWebNavigation::LOAD_FLAGS_NONE);
00241 
00242   return res;
00243 }
00244 
00245 NS_IMETHODIMP
00246 nsPluginArray::Refresh()
00247 {
00248   nsCOMPtr<nsIXPCNativeCallContext> ncc;
00249   nsresult rv = nsContentUtils::XPConnect()->
00250     GetCurrentNativeCallContext(getter_AddRefs(ncc));
00251   NS_ENSURE_SUCCESS(rv, rv);
00252 
00253   if (!ncc)
00254     return NS_ERROR_NOT_AVAILABLE;
00255 
00256   PRBool reload_doc = PR_FALSE;
00257 
00258   PRUint32 argc;
00259 
00260   ncc->GetArgc(&argc);
00261 
00262   if (argc > 0) {
00263     jsval *argv = nsnull;
00264 
00265     ncc->GetArgvPtr(&argv);
00266     NS_ENSURE_TRUE(argv, NS_ERROR_UNEXPECTED);
00267 
00268     JSContext *cx = nsnull;
00269 
00270     rv = ncc->GetJSContext(&cx);
00271     NS_ENSURE_SUCCESS(rv, rv);
00272 
00273     JS_ValueToBoolean(cx, argv[0], &reload_doc);
00274   }
00275 
00276   return Refresh(reload_doc);
00277 }
00278 
00279 nsresult
00280 nsPluginArray::GetPlugins()
00281 {
00282   nsresult rv = GetLength(&mPluginCount);
00283   if (NS_SUCCEEDED(rv)) {
00284     mPluginArray = new nsIDOMPlugin*[mPluginCount];
00285     if (!mPluginArray)
00286       return NS_ERROR_OUT_OF_MEMORY;
00287 
00288     if (!mPluginCount)
00289       return NS_OK;
00290 
00291     rv = mPluginHost->GetPlugins(mPluginCount, mPluginArray);
00292     if (NS_SUCCEEDED(rv)) {
00293       // need to wrap each of these with a nsPluginElement, which
00294       // is scriptable.
00295       for (PRUint32 i = 0; i < mPluginCount; i++) {
00296         nsIDOMPlugin* wrapper = new nsPluginElement(mPluginArray[i]);
00297         NS_IF_ADDREF(wrapper);
00298         mPluginArray[i] = wrapper;
00299       }
00300     } else {
00301       /* XXX this code is all broken. If GetPlugins fails, there's no contract
00302        *     explaining what should happen. Instead of deleting elements in an
00303        *     array of random pointers, we mark the array as 0 length.
00304        */
00305       mPluginCount = 0;
00306     }
00307   }
00308   return rv;
00309 }
00310 
00311 //
00312 
00313 nsPluginElement::nsPluginElement(nsIDOMPlugin* plugin)
00314 {
00315   mPlugin = plugin;  // don't AddRef, see nsPluginArray::Item.
00316   mMimeTypeCount = 0;
00317   mMimeTypeArray = nsnull;
00318 }
00319 
00320 nsPluginElement::~nsPluginElement()
00321 {
00322   NS_IF_RELEASE(mPlugin);
00323 
00324   if (mMimeTypeArray != nsnull) {
00325     for (PRUint32 i = 0; i < mMimeTypeCount; i++)
00326       NS_IF_RELEASE(mMimeTypeArray[i]);
00327     delete[] mMimeTypeArray;
00328   }
00329 }
00330 
00331 
00332 // QueryInterface implementation for nsPluginElement
00333 NS_INTERFACE_MAP_BEGIN(nsPluginElement)
00334   NS_INTERFACE_MAP_ENTRY(nsISupports)
00335   NS_INTERFACE_MAP_ENTRY(nsIDOMPlugin)
00336   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Plugin)
00337 NS_INTERFACE_MAP_END
00338 
00339 
00340 NS_IMPL_ADDREF(nsPluginElement)
00341 NS_IMPL_RELEASE(nsPluginElement)
00342 
00343 
00344 NS_IMETHODIMP
00345 nsPluginElement::GetDescription(nsAString& aDescription)
00346 {
00347   return mPlugin->GetDescription(aDescription);
00348 }
00349 
00350 NS_IMETHODIMP
00351 nsPluginElement::GetFilename(nsAString& aFilename)
00352 {
00353   return mPlugin->GetFilename(aFilename);
00354 }
00355 
00356 NS_IMETHODIMP
00357 nsPluginElement::GetName(nsAString& aName)
00358 {
00359   return mPlugin->GetName(aName);
00360 }
00361 
00362 NS_IMETHODIMP
00363 nsPluginElement::GetLength(PRUint32* aLength)
00364 {
00365   return mPlugin->GetLength(aLength);
00366 }
00367 
00368 NS_IMETHODIMP
00369 nsPluginElement::Item(PRUint32 aIndex, nsIDOMMimeType** aReturn)
00370 {
00371   if (mMimeTypeArray == nsnull) {
00372     nsresult rv = GetMimeTypes();
00373     if (rv != NS_OK)
00374       return rv;
00375   }
00376   if (aIndex < mMimeTypeCount) {
00377     nsIDOMMimeType* mimeType = mMimeTypeArray[aIndex];
00378     NS_IF_ADDREF(mimeType);
00379     *aReturn = mimeType;
00380     return NS_OK;
00381   }
00382   return NS_ERROR_FAILURE;
00383 }
00384 
00385 NS_IMETHODIMP
00386 nsPluginElement::NamedItem(const nsAString& aName, nsIDOMMimeType** aReturn)
00387 {
00388   if (mMimeTypeArray == nsnull) {
00389     nsresult rv = GetMimeTypes();
00390     if (rv != NS_OK)
00391       return rv;
00392   }
00393 
00394   *aReturn = nsnull;
00395   for (PRUint32 i = 0; i < mMimeTypeCount; i++) {
00396     nsAutoString type;
00397     nsIDOMMimeType* mimeType = mMimeTypeArray[i];
00398     if (mimeType->GetType(type) == NS_OK) {
00399       if (type.Equals(aName)) {
00400         *aReturn = mimeType;
00401         NS_ADDREF(mimeType);
00402         break;
00403       }
00404     }
00405   }
00406 
00407   return NS_OK;
00408 }
00409 
00410 nsresult
00411 nsPluginElement::GetMimeTypes()
00412 {
00413   nsresult rv = mPlugin->GetLength(&mMimeTypeCount);
00414   if (rv == NS_OK) {
00415     mMimeTypeArray = new nsIDOMMimeType*[mMimeTypeCount];
00416     if (mMimeTypeArray == nsnull)
00417       return NS_ERROR_OUT_OF_MEMORY;
00418     for (PRUint32 i = 0; i < mMimeTypeCount; i++) {
00419       nsCOMPtr<nsIDOMMimeType> mimeType;
00420       rv = mPlugin->Item(i, getter_AddRefs(mimeType));
00421       if (rv != NS_OK)
00422         break;
00423       mimeType = new nsMimeType(this, mimeType);
00424       NS_IF_ADDREF(mMimeTypeArray[i] = mimeType);
00425     }
00426   }
00427   return rv;
00428 }