Back to index

lightning-sunbird  0.9+nobinonly
ns4xPluginInstance.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  *   Tim Copperfield <timecop@network.email.ne.jp>
00024  *   Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "prlog.h"
00041 #include "prmem.h"
00042 #include "nscore.h"
00043 #include "prenv.h"
00044 
00045 #include "ns4xPluginInstance.h"
00046 #include "ns4xPlugin.h"
00047 #include "ns4xPluginStreamListener.h"
00048 #include "nsPluginHostImpl.h"
00049 #include "nsPluginSafety.h"
00050 #include "nsPluginLogging.h"
00051 
00052 #include "nsPIPluginInstancePeer.h"
00053 #include "nsIDOMWindow.h"
00054 #include "nsPIDOMWindow.h"
00055 #include "nsIDocument.h"
00056 #include "nsIScriptGlobalObject.h"
00057 
00058 #include "nsJSNPRuntime.h"
00059 
00060 #ifdef XP_OS2
00061 #include "nsILegacyPluginWrapperOS2.h"
00062 #endif
00063 
00064 #ifdef MOZ_WIDGET_GTK
00065 #include <gdk/gdk.h>
00066 #include <gdk/gdkx.h>
00067 #include "gtkxtbin.h"
00068 #endif
00069 
00070 #ifdef MOZ_WIDGET_GTK2
00071 #include <gdk/gdk.h>
00072 #include <gdk/gdkx.h>
00073 #include "gtk2xtbin.h"
00074 #endif
00075 
00076 #ifdef MOZ_WIDGET_XLIB
00077 #include "xlibxtbin.h"
00078 #include "xlibrgb.h"
00079 #endif
00080 
00081 #if defined(MOZ_WIDGET_PHOTON) && defined (OJI)
00082 #include "nsPluginInstancePeer.h"
00083 #endif
00084 
00086 // CID's && IID's
00087 static NS_DEFINE_IID(kCPluginManagerCID, NS_PLUGINMANAGER_CID); // needed for NS_TRY_SAFE_CALL
00088 static NS_DEFINE_IID(kIPluginStreamListenerIID, NS_IPLUGINSTREAMLISTENER_IID);
00089 
00091 // ns4xPluginStreamListener Methods
00092 
00093 NS_IMPL_ISUPPORTS4(ns4xPluginStreamListener, nsIPluginStreamListener,
00094                    nsITimerCallback, nsIHTTPHeaderListener,
00095                    nsIHTTPHeaderListener_MOZILLA_1_8_BRANCH)
00096 
00097 
00098 
00099 ns4xPluginStreamListener::ns4xPluginStreamListener(nsIPluginInstance* inst, 
00100                                                    void* notifyData,
00101                                                    const char* aURL)
00102   : mNotifyData(notifyData),
00103     mStreamBuffer(nsnull),
00104     mNotifyURL(aURL ? PL_strdup(aURL) : nsnull),
00105     mInst((ns4xPluginInstance *)inst),
00106     mStreamBufferSize(0),
00107     mStreamBufferByteCount(0),
00108     mStreamType(nsPluginStreamType_Normal),
00109     mStreamStarted(PR_FALSE),
00110     mStreamCleanedUp(PR_FALSE),
00111     mCallNotify(PR_FALSE),
00112     mIsSuspended(PR_FALSE),
00113     mResponseHeaderBuf(nsnull)
00114 {
00115   // Initialize the 4.x interface structure
00116   memset(&mNPStream, 0, sizeof(mNPStream));
00117 
00118   NS_IF_ADDREF(mInst);
00119 }
00120 
00121 
00123 ns4xPluginStreamListener::~ns4xPluginStreamListener(void)
00124 {
00125   // remove itself from the instance stream list
00126   ns4xPluginInstance *inst = mInst;
00127   if(inst) {
00128     nsInstanceStream * prev = nsnull;
00129     for(nsInstanceStream *is = inst->mStreams; is != nsnull; is = is->mNext) {
00130       if(is->mPluginStreamListener == this) {
00131         if(prev == nsnull)
00132           inst->mStreams = is->mNext;
00133         else
00134           prev->mNext = is->mNext;
00135 
00136         delete is;
00137         break;
00138       }
00139       prev = is;
00140     }
00141   }
00142 
00143   // For those cases when NewStream is never called, we still may need
00144   // to fire a notification callback. Return network error as fallback
00145   // reason because for other cases, notify should have already been
00146   // called for other reasons elsewhere.
00147   CallURLNotify(NPRES_NETWORK_ERR);
00148 
00149   // lets get rid of the buffer
00150   if (mStreamBuffer)
00151   {
00152     PR_Free(mStreamBuffer);
00153     mStreamBuffer=nsnull;
00154   }
00155 
00156   NS_IF_RELEASE(inst);
00157 
00158   if (mNotifyURL)
00159     PL_strfree(mNotifyURL);
00160 
00161   if (mResponseHeaderBuf)
00162     PL_strfree(mResponseHeaderBuf);
00163 }
00164 
00166 nsresult ns4xPluginStreamListener::CleanUpStream(NPReason reason)
00167 {
00168   nsresult rv = NS_ERROR_FAILURE;
00169 
00170   if(mStreamCleanedUp)
00171     return NS_OK;
00172 
00173   if(!mInst || !mInst->IsStarted())
00174     return rv;
00175 
00176   const NPPluginFuncs *callbacks = nsnull;
00177   mInst->GetCallbacks(&callbacks);
00178   if(!callbacks)
00179     return rv;
00180 
00181   NPP npp;
00182   mInst->GetNPP(&npp);
00183 
00184   if (mStreamStarted && callbacks->destroystream != NULL)
00185   {
00186     PRLibrary* lib = nsnull;
00187     lib = mInst->fLibrary;
00188     NPError error;
00189     NS_TRY_SAFE_CALL_RETURN(error, CallNPP_DestroyStreamProc(callbacks->destroystream,
00190                                                                npp,
00191                                                                &mNPStream,
00192                                                                reason), lib, mInst);
00193 
00194     NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
00195     ("NPP DestroyStream called: this=%p, npp=%p, reason=%d, return=%d, url=%s\n",
00196     this, npp, reason, error, mNPStream.url));
00197 
00198     if(error == NPERR_NO_ERROR)
00199       rv = NS_OK;
00200   }
00201 
00202   mStreamCleanedUp = PR_TRUE;
00203   mStreamStarted   = PR_FALSE;
00204 
00205   StopDataPump();
00206 
00207   // fire notification back to plugin, just like before
00208   CallURLNotify(reason);
00209 
00210   return rv;
00211 }
00212 
00213 
00215 void ns4xPluginStreamListener::CallURLNotify(NPReason reason)
00216 {
00217   if(!mCallNotify || !mInst || !mInst->IsStarted())
00218     return;
00219 
00220   mCallNotify = PR_FALSE; // only do this ONCE and prevent recursion
00221 
00222   const NPPluginFuncs *callbacks = nsnull;
00223   mInst->GetCallbacks(&callbacks);
00224   if(!callbacks)
00225     return;
00226   
00227   if (callbacks->urlnotify) {
00228 
00229     NPP npp;
00230     mInst->GetNPP(&npp);
00231 
00232     NS_TRY_SAFE_CALL_VOID(CallNPP_URLNotifyProc(callbacks->urlnotify,
00233                                                 npp,
00234                                                 mNotifyURL,
00235                                                 reason,
00236                                                 mNotifyData), mInst->fLibrary, mInst);
00237 
00238     NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
00239     ("NPP URLNotify called: this=%p, npp=%p, notify=%p, reason=%d, url=%s\n",
00240     this, npp, mNotifyData, reason, mNotifyURL));
00241   }
00242 
00243   // Let's not leak this stream listener. Release the reference to the stream listener 
00244   // added for the notify callback in NewNotifyStream. 
00245   // Note: This may destroy us if we are not being destroyed already.
00246   NS_RELEASE_THIS();
00247 }
00248 
00249 
00251 NS_IMETHODIMP
00252 ns4xPluginStreamListener::OnStartBinding(nsIPluginStreamInfo* pluginInfo)
00253 {
00254   if(!mInst)
00255     return NS_ERROR_FAILURE;
00256 
00257   NPP npp;
00258   const NPPluginFuncs *callbacks = nsnull;
00259 
00260   mInst->GetCallbacks(&callbacks);
00261   mInst->GetNPP(&npp);
00262 
00263   if(!callbacks || !mInst->IsStarted())
00264     return NS_ERROR_FAILURE;
00265 
00266   PRBool seekable;
00267   nsMIMEType contentType;
00268   PRUint16 streamType = NP_NORMAL;
00269   NPError error;
00270 
00271   mNPStream.ndata = (void*) this;
00272   pluginInfo->GetURL(&mNPStream.url);
00273   mNPStream.notifyData = mNotifyData;
00274 
00275   pluginInfo->GetLength((PRUint32*)&(mNPStream.end));
00276   pluginInfo->GetLastModified((PRUint32*)&(mNPStream.lastmodified));
00277   pluginInfo->IsSeekable(&seekable);
00278   pluginInfo->GetContentType(&contentType);
00279   
00280   if (!mResponseHeaders.IsEmpty()) {
00281     mResponseHeaderBuf = PL_strdup(mResponseHeaders.get());
00282     mNPStream.headers = mResponseHeaderBuf;
00283   }
00284 
00285   mStreamInfo = pluginInfo;
00286 
00287   NS_TRY_SAFE_CALL_RETURN(error, CallNPP_NewStreamProc(callbacks->newstream,
00288                                                        npp,
00289                                                        (char *)contentType,
00290                                                        &mNPStream,
00291                                                        seekable,
00292                                                        &streamType), mInst->fLibrary, mInst);
00293 
00294   NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
00295   ("NPP NewStream called: this=%p, npp=%p, mime=%s, seek=%d, type=%d, return=%d, url=%s\n",
00296   this, npp, (char *)contentType, seekable, streamType, error, mNPStream.url));
00297 
00298   if(error != NPERR_NO_ERROR)
00299     return NS_ERROR_FAILURE;
00300 
00301   // translate the old 4x style stream type to the new one
00302   switch(streamType)
00303   {
00304     case NP_NORMAL:
00305       mStreamType = nsPluginStreamType_Normal; 
00306       break;
00307     case NP_ASFILEONLY:
00308       mStreamType = nsPluginStreamType_AsFileOnly; 
00309       break;
00310     case NP_ASFILE:
00311       mStreamType = nsPluginStreamType_AsFile; 
00312       break;
00313     case NP_SEEK:
00314       mStreamType = nsPluginStreamType_Seek; 
00315       break;
00316     default:
00317       return NS_ERROR_FAILURE;
00318   }
00319 
00320   mStreamStarted = PR_TRUE;
00321   return NS_OK;
00322 }
00323 
00324 nsresult
00325 ns4xPluginStreamListener::SuspendRequest()
00326 {
00327   NS_ASSERTION(!mIsSuspended,
00328                "Suspending a request that's already suspended!");
00329 
00330   nsCOMPtr<nsI4xPluginStreamInfo> pluginInfo4x =
00331     do_QueryInterface(mStreamInfo);
00332   nsIRequest *request;
00333 
00334   if (!pluginInfo4x || !(request = pluginInfo4x->GetRequest())) {
00335     NS_ERROR("Trying to suspend a non-suspendable stream!");
00336 
00337     return NS_ERROR_FAILURE;
00338   }
00339 
00340   nsresult rv = StartDataPump();
00341   NS_ENSURE_SUCCESS(rv, rv);
00342 
00343   mIsSuspended = PR_TRUE;
00344 
00345   return request->Suspend();
00346 }
00347 
00348 void
00349 ns4xPluginStreamListener::ResumeRequest()
00350 {
00351   nsCOMPtr<nsI4xPluginStreamInfo> pluginInfo4x =
00352     do_QueryInterface(mStreamInfo);
00353 
00354   nsIRequest *request = pluginInfo4x->GetRequest();
00355 
00356   // request can be null if the network stream is done.
00357   if (request) {
00358     request->Resume();
00359   }
00360 
00361   mIsSuspended = PR_FALSE;
00362 }
00363 
00364 nsresult
00365 ns4xPluginStreamListener::StartDataPump()
00366 {
00367   nsresult rv;
00368   mDataPumpTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
00369   NS_ENSURE_SUCCESS(rv, rv);
00370 
00371   // Start pumping data to the plugin every 100ms until it obeys and
00372   // eats the data.
00373   return mDataPumpTimer->InitWithCallback(this, 100,
00374                                           nsITimer::TYPE_REPEATING_SLACK);
00375 }
00376 
00377 void
00378 ns4xPluginStreamListener::StopDataPump()
00379 {
00380   if (mDataPumpTimer) {
00381     mDataPumpTimer->Cancel();
00382 
00383     mDataPumpTimer = nsnull;
00384   }
00385 }
00386 
00388 
00389 // This method is called when there's more data available off the
00390 // network, but it's also called from our data pump when we're feeding
00391 // the plugin data that we already got off the network, but the plugin
00392 // was unable to consume it at the point it arrived. In the case when
00393 // the plugin pump calls this method, the input argument will be null,
00394 // and the length will be the number of bytes available in our
00395 // internal buffer.
00396 NS_IMETHODIMP
00397 ns4xPluginStreamListener::OnDataAvailable(nsIPluginStreamInfo* pluginInfo,
00398                                           nsIInputStream* input,
00399                                           PRUint32 length)
00400 {
00401   if (!mInst || !mInst->IsStarted())
00402     return NS_ERROR_FAILURE;
00403 
00404   // Just in case the caller switches plugin info on us.
00405   mStreamInfo = pluginInfo;
00406 
00407   const NPPluginFuncs *callbacks = nsnull;
00408   mInst->GetCallbacks(&callbacks);
00409   // check out if plugin implements NPP_Write call
00410   if(!callbacks || !callbacks->write || !length)
00411     return NS_ERROR_FAILURE; // it'll cancel necko transaction 
00412   
00413   if (!mStreamBuffer)
00414   {
00415     // To optimize the mem usage & performance we have to allocate
00416     // mStreamBuffer here in first ODA when length of data available
00417     // in input stream is known.  mStreamBuffer will be freed in DTOR.
00418     // we also have to remember the size of that buff to make safe
00419     // consecutive Read() calls form input stream into our buff.
00420 
00421     PRUint32 contentLength;
00422     pluginInfo->GetLength(&contentLength);
00423 
00424     mStreamBufferSize = PR_MAX(length, contentLength);
00425 
00426     // Limit the size of the initial buffer to MAX_PLUGIN_NECKO_BUFFER
00427     // (16k). This buffer will grow if needed, as in the case where
00428     // we're getting data faster than the plugin can process it.
00429     mStreamBufferSize = PR_MIN(mStreamBufferSize, MAX_PLUGIN_NECKO_BUFFER);
00430 
00431     mStreamBuffer = (char*) PR_Malloc(mStreamBufferSize);
00432     if (!mStreamBuffer)
00433       return NS_ERROR_OUT_OF_MEMORY;
00434   }
00435   
00436   // prepare NPP_ calls params
00437   NPP npp;
00438   mInst->GetNPP(&npp);
00439 
00440   PRInt32 streamPosition;
00441   pluginInfo->GetStreamOffset(&streamPosition);
00442   PRInt32 streamOffset = streamPosition;
00443 
00444   if (input) {
00445     streamOffset += length;
00446 
00447     // Set new stream offset for the next ODA call regardless of how
00448     // following NPP_Write call will behave we pretend to consume all
00449     // data from the input stream.  It's possible that current steam
00450     // position will be overwritten from NPP_RangeRequest call made
00451     // from NPP_Write, so we cannot call SetStreamOffset after
00452     // NPP_Write.
00453     //
00454     // Note: there is a special case when data flow should be
00455     // temporarily stopped if NPP_WriteReady returns 0 (bug #89270)
00456     pluginInfo->SetStreamOffset(streamOffset);
00457 
00458     // set new end in case the content is compressed
00459     // initial end is less than end of decompressed stream
00460     // and some plugins (e.g. acrobat) can fail. 
00461     if ((PRInt32)mNPStream.end < streamOffset)
00462       mNPStream.end = streamOffset;
00463   }
00464 
00465   nsresult rv = NS_OK;
00466   while (NS_SUCCEEDED(rv) && length > 0) {
00467     if (input && length) {
00468       if (mStreamBufferSize < mStreamBufferByteCount + length &&
00469           mIsSuspended) {
00470         // We're in the ::OnDataAvailable() call that we might get
00471         // after suspending a request, or we suspended the request
00472         // from within this ::OnDataAvailable() call while there's
00473         // still data in the input, and we don't have enough space to
00474         // store what we got off the network. Reallocate our internal
00475         // buffer.
00476         mStreamBufferSize = mStreamBufferByteCount + length;
00477         char *buf = (char *)PR_Realloc(mStreamBuffer, mStreamBufferSize);
00478         if (!buf)
00479           return NS_ERROR_OUT_OF_MEMORY;
00480 
00481         mStreamBuffer = buf;
00482       }
00483 
00484       PRUint32 bytesToRead =
00485         PR_MIN(length, mStreamBufferSize - mStreamBufferByteCount);
00486 
00487       PRUint32 amountRead = 0;
00488       rv = input->Read(mStreamBuffer + mStreamBufferByteCount, bytesToRead,
00489                        &amountRead);
00490       NS_ENSURE_SUCCESS(rv, rv);
00491 
00492       if (amountRead == 0) {
00493         NS_NOTREACHED("input->Read() returns no data, it's almost impossible "
00494                       "to get here");
00495 
00496         break;
00497       }
00498 
00499       mStreamBufferByteCount += amountRead;
00500       length -= amountRead;
00501     } else {
00502       // No input, nothing to read. Set length to 0 so that we don't
00503       // keep iterating through this outer loop any more.
00504 
00505       length = 0;
00506     }
00507 
00508     // Temporary pointer to the beginning of the data we're writing as
00509     // we loop and feed the plugin data.
00510     char *ptrStreamBuffer = mStreamBuffer;
00511 
00512     // it is possible plugin's NPP_Write() returns 0 byte consumed. We
00513     // use zeroBytesWriteCount to count situation like this and break
00514     // the loop
00515     PRInt32 zeroBytesWriteCount = 0;
00516 
00517     // mStreamBufferByteCount tells us how many bytes there are in the
00518     // buffer. WriteReady returns to us how many bytes the plugin is
00519     // ready to handle.
00520     while (mStreamBufferByteCount > 0) {
00521       PRInt32 numtowrite;
00522       if (callbacks->writeready) {
00523         NS_TRY_SAFE_CALL_RETURN(numtowrite, 
00524                                 CallNPP_WriteReadyProc(callbacks->writeready,
00525                                                        npp, &mNPStream),
00526                                 mInst->fLibrary, mInst);
00527 
00528         NPP_PLUGIN_LOG(PLUGIN_LOG_NOISY,
00529                        ("NPP WriteReady called: this=%p, npp=%p, "
00530                         "return(towrite)=%d, url=%s\n",
00531                         this, npp, numtowrite, mNPStream.url));
00532 
00533         if (!mStreamStarted) {
00534           // The plugin called NPN_DestroyStream() from within
00535           // NPP_WriteReady(), kill the stream.
00536 
00537           return NS_BINDING_ABORTED;
00538         }
00539 
00540         // if WriteReady returned 0, the plugin is not ready to handle
00541         // the data, suspend the stream (if it isn't already
00542         // suspended).
00543         if (numtowrite <= 0) {
00544           if (!mIsSuspended) {
00545             rv = SuspendRequest();
00546           }
00547 
00548           // Break out of the inner loop, but keep going through the
00549           // outer loop in case there's more data to read from the
00550           // input stream.
00551 
00552           break;
00553         }
00554 
00555         numtowrite = PR_MIN(numtowrite, mStreamBufferByteCount);
00556       } else {
00557         // if WriteReady is not supported by the plugin, just write
00558         // the whole buffer
00559         numtowrite = mStreamBufferByteCount;
00560       }
00561 
00562       PRInt32 writeCount = 0; // bytes consumed by plugin instance
00563       NS_TRY_SAFE_CALL_RETURN(writeCount, 
00564                               CallNPP_WriteProc(callbacks->write, npp,
00565                                                 &mNPStream, streamPosition,
00566                                                 numtowrite,
00567                                                 ptrStreamBuffer),
00568                               mInst->fLibrary, mInst);
00569 
00570       NPP_PLUGIN_LOG(PLUGIN_LOG_NOISY,
00571                      ("NPP Write called: this=%p, npp=%p, pos=%d, len=%d, "
00572                       "buf=%s, return(written)=%d,  url=%s\n",
00573                       this, npp, streamPosition, numtowrite,
00574                       ptrStreamBuffer, writeCount, mNPStream.url));
00575 
00576       if (!mStreamStarted) {
00577         // The plugin called NPN_DestroyStream() from within
00578         // NPP_Write(), kill the stream.
00579 
00580         return NS_BINDING_ABORTED;
00581       }
00582 
00583       if (writeCount > 0) {
00584         NS_ASSERTION(writeCount <= mStreamBufferByteCount,
00585                      "Plugin read past the end of the available data!");
00586 
00587         writeCount = PR_MIN(writeCount, mStreamBufferByteCount);
00588         mStreamBufferByteCount -= writeCount;
00589 
00590         streamPosition += writeCount;
00591 
00592         zeroBytesWriteCount = 0;
00593 
00594         if (mStreamBufferByteCount > 0) {
00595           // This alignment code is most likely bogus, but we'll leave
00596           // it in for now in case it matters for some plugins on some
00597           // architectures. Who knows...
00598           if (writeCount % sizeof(PRWord)) {
00599             // memmove will take care  about alignment 
00600             memmove(mStreamBuffer, ptrStreamBuffer + writeCount,
00601                     mStreamBufferByteCount);
00602             ptrStreamBuffer = mStreamBuffer;
00603           } else {
00604             // if aligned we can use ptrStreamBuffer += to eliminate
00605             // memmove()
00606             ptrStreamBuffer += writeCount;
00607           }
00608         }
00609       } else if (writeCount == 0) {
00610         // if NPP_Write() returns writeCount == 0 lets say 3 times in
00611         // a row, suspend the request and continue feeding the plugin
00612         // the data we got so far. Once that data is consumed, we'll
00613         // resume the request.
00614         if (mIsSuspended || ++zeroBytesWriteCount == 3) {
00615           if (!mIsSuspended) {
00616             rv = SuspendRequest();
00617           }
00618 
00619           // Break out of the for loop, but keep going through the
00620           // while loop in case there's more data to read from the
00621           // input stream.
00622 
00623           break;
00624         }
00625       } else {
00626         // Something's really wrong, kill the stream.
00627         rv = NS_ERROR_FAILURE;
00628 
00629         break;
00630       }  
00631     } // end of inner while loop
00632 
00633     if (mStreamBufferByteCount && mStreamBuffer != ptrStreamBuffer) {
00634       memmove(mStreamBuffer, ptrStreamBuffer, mStreamBufferByteCount);
00635     }
00636   }
00637 
00638   if (streamPosition != streamOffset) {
00639     // The plugin didn't consume all available data, or consumed some
00640     // of our cached data while we're pumping cached data. Adjust the
00641     // plugin info's stream offset to match reality, except if the
00642     // plugin info's stream offset was set by a re-entering
00643     // NPN_RequestRead() call.
00644 
00645     PRInt32 postWriteStreamPosition;
00646     pluginInfo->GetStreamOffset(&postWriteStreamPosition);
00647 
00648     if (postWriteStreamPosition == streamOffset) {
00649       pluginInfo->SetStreamOffset(streamPosition);
00650     }
00651   }
00652 
00653   return rv;
00654 }
00655 
00657 NS_IMETHODIMP
00658 ns4xPluginStreamListener::OnFileAvailable(nsIPluginStreamInfo* pluginInfo, 
00659                                           const char* fileName)
00660 {
00661   if(!mInst || !mInst->IsStarted())
00662     return NS_ERROR_FAILURE;
00663 
00664   const NPPluginFuncs *callbacks = nsnull;
00665   mInst->GetCallbacks(&callbacks);
00666   if(!callbacks && !callbacks->asfile)
00667     return NS_ERROR_FAILURE;
00668   
00669   NPP npp;
00670   mInst->GetNPP(&npp);
00671 
00672   PRLibrary* lib = nsnull;
00673   lib = mInst->fLibrary;
00674 
00675   NS_TRY_SAFE_CALL_VOID(CallNPP_StreamAsFileProc(callbacks->asfile,
00676                                                    npp,
00677                                                    &mNPStream,
00678                                                    fileName), lib, mInst);
00679 
00680   NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
00681   ("NPP StreamAsFile called: this=%p, npp=%p, url=%s, file=%s\n",
00682   this, npp, mNPStream.url, fileName));
00683 
00684   return NS_OK;
00685 }
00686 
00687 
00689 NS_IMETHODIMP
00690 ns4xPluginStreamListener::OnStopBinding(nsIPluginStreamInfo* pluginInfo, 
00691                                         nsresult status)
00692 {
00693   StopDataPump();
00694 
00695   if (NS_FAILED(status)) {
00696     // The stream was destroyed, or died for some reason. Make sure we
00697     // cancel the underlying request.
00698     nsCOMPtr<nsI4xPluginStreamInfo> pluginInfo4x =
00699       do_QueryInterface(mStreamInfo);
00700 
00701     nsIRequest *request;
00702     if (pluginInfo4x && (request = pluginInfo4x->GetRequest())) {
00703       request->Cancel(status);
00704     }
00705   }
00706 
00707   if(!mInst || !mInst->IsStarted())
00708     return NS_ERROR_FAILURE;
00709 
00710   // check if the stream is of seekable type and later its destruction
00711   // see bug 91140    
00712   nsresult rv = NS_OK;
00713   if(mStreamType != nsPluginStreamType_Seek) {
00714     NPReason reason = NPRES_DONE;
00715 
00716     if (NS_FAILED(status))
00717       reason = NPRES_NETWORK_ERR;   // since the stream failed, we need to tell the plugin that
00718 
00719     rv = CleanUpStream(reason);
00720   }
00721 
00722   if(rv != NPERR_NO_ERROR)
00723     return NS_ERROR_FAILURE;
00724 
00725   return NS_OK;
00726 }
00727 
00728 NS_IMETHODIMP
00729 ns4xPluginStreamListener::GetStreamType(nsPluginStreamType *result)
00730 {
00731   *result = mStreamType;
00732   return NS_OK;
00733 }
00734 
00735 NS_IMETHODIMP
00736 ns4xPluginStreamListener::Notify(nsITimer *aTimer)
00737 {
00738   NS_ASSERTION(aTimer == mDataPumpTimer, "Uh, wrong timer?");
00739 
00740   PRInt32 oldStreamBufferByteCount = mStreamBufferByteCount;
00741 
00742   nsresult rv = OnDataAvailable(mStreamInfo, nsnull, mStreamBufferByteCount);
00743 
00744   if (NS_FAILED(rv)) {
00745     // We ran into an error, no need to keep firing this timer then.
00746 
00747     aTimer->Cancel();
00748 
00749     return NS_OK;
00750   }
00751 
00752   if (mStreamBufferByteCount != oldStreamBufferByteCount &&
00753       ((mStreamStarted && mStreamBufferByteCount < 1024) ||
00754        mStreamBufferByteCount == 0)) {
00755     // The plugin read some data and we've got less than 1024 bytes in
00756     // our buffer (or its empty and the stream is already
00757     // done). Resume the request so that we get more data off the
00758     // network.
00759 
00760     ResumeRequest();
00761 
00762     // Necko will pump data now that we've resumed the request.
00763     StopDataPump();
00764   }
00765 
00766   return NS_OK;
00767 }
00768 
00770 NS_IMETHODIMP
00771 ns4xPluginStreamListener::StatusLine(const char* line)
00772 {
00773   mResponseHeaders.Append(line);
00774   mResponseHeaders.Append('\n');
00775   return NS_OK;
00776 }
00777 
00779 NS_IMETHODIMP
00780 ns4xPluginStreamListener::NewResponseHeader(const char* headerName,
00781                                             const char* headerValue)
00782 {
00783   mResponseHeaders.Append(headerName);
00784   mResponseHeaders.Append(": ");
00785   mResponseHeaders.Append(headerValue);
00786   mResponseHeaders.Append('\n');
00787   return NS_OK;
00788 }
00789 
00791 nsInstanceStream::nsInstanceStream()
00792 {
00793   mNext = nsnull;
00794   mPluginStreamListener = nsnull;
00795 }
00796 
00797 
00799 nsInstanceStream::~nsInstanceStream()
00800 {
00801 }
00802 
00803 
00805 
00806 NS_IMPL_ISUPPORTS3(ns4xPluginInstance, nsIPluginInstance, nsIScriptablePlugin,
00807                    nsIPluginInstanceInternal)
00808 
00809 
00810 
00811 ns4xPluginInstance::ns4xPluginInstance(NPPluginFuncs* callbacks,
00812                                        PRLibrary* aLibrary)
00813   : fCallbacks(callbacks)
00814 {
00815   NS_ASSERTION(fCallbacks != NULL, "null callbacks");
00816 
00817   // Initialize the NPP structure.
00818 
00819   fNPP.pdata = NULL;
00820   fNPP.ndata = this;
00821 
00822   fLibrary = aLibrary;
00823   mWindowless = PR_FALSE;
00824   mTransparent = PR_FALSE;
00825   mStarted = PR_FALSE;
00826   mStreams = nsnull;
00827   mCached = PR_FALSE;
00828 
00829   PLUGIN_LOG(PLUGIN_LOG_BASIC, ("ns4xPluginInstance ctor: this=%p\n",this));
00830 }
00831 
00832 
00834 ns4xPluginInstance::~ns4xPluginInstance(void)
00835 {
00836   PLUGIN_LOG(PLUGIN_LOG_BASIC, ("ns4xPluginInstance dtor: this=%p\n",this));
00837 
00838 #if defined(MOZ_WIDGET_GTK) || defined (MOZ_WIDGET_GTK2)
00839   if (mXtBin)
00840     gtk_widget_destroy(mXtBin);
00841 #elif defined(MOZ_WIDGET_XLIB)
00842   if (mXlibXtBin) {
00843     delete mXlibXtBin;
00844   }
00845 #endif
00846 
00847   // clean the stream list if any
00848   for(nsInstanceStream *is = mStreams; is != nsnull;) {
00849     nsInstanceStream * next = is->mNext;
00850     delete is;
00851     is = next;
00852   }
00853 }
00854 
00855 
00857 PRBool
00858 ns4xPluginInstance::IsStarted(void)
00859 {
00860   return mStarted;
00861 }
00862 
00863 
00865 NS_IMETHODIMP ns4xPluginInstance::Initialize(nsIPluginInstancePeer* peer)
00866 {
00867   PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("ns4xPluginInstance::Initialize this=%p\n",this));
00868 
00869 #if defined (MOZ_WIDGET_GTK) || defined (MOZ_WIDGET_GTK2)
00870   mXtBin = nsnull;
00871 #elif defined(MOZ_WIDGET_XLIB)
00872   mXlibXtBin = nsnull;
00873 #endif
00874   return InitializePlugin(peer);
00875 }
00876 
00878 NS_IMETHODIMP ns4xPluginInstance::GetPeer(nsIPluginInstancePeer* *resultingPeer)
00879 {
00880   *resultingPeer = mPeer;
00881   NS_IF_ADDREF(*resultingPeer);
00882   
00883   return NS_OK;
00884 }
00885 
00887 NS_IMETHODIMP ns4xPluginInstance::Start(void)
00888 {
00889   PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("ns4xPluginInstance::Start this=%p\n",this));
00890 
00891 #ifdef MOZ_WIDGET_XLIB
00892   if (mXlibXtBin == nsnull)
00893     mXlibXtBin = new xtbin();
00894 
00895   if (mXlibXtBin == nsnull)
00896     return NS_ERROR_OUT_OF_MEMORY;
00897 
00898   if (!mXlibXtBin->xtbin_initialized())
00899     mXlibXtBin->xtbin_init();
00900 
00901 #ifdef NS_DEBUG
00902   printf("Made new XtBin: %p, %d\n", mXlibXtBin, mXlibXtBin->xtbin_initialized());
00903 #endif
00904 #endif
00905 
00906   if(mStarted)
00907     return NS_OK;
00908   else
00909     return InitializePlugin(mPeer); 
00910 }
00911 
00912 
00914 NS_IMETHODIMP ns4xPluginInstance::Stop(void)
00915 {
00916   PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("ns4xPluginInstance::Stop this=%p\n",this));
00917 
00918   NPError error;
00919 
00920   // Make sure the plugin didn't leave popups enabled.
00921   if (mPopupStates.Count() > 0) {
00922     nsCOMPtr<nsIDOMWindow> window = GetDOMWindow();
00923     nsCOMPtr<nsPIDOMWindow> piwindow = do_QueryInterface(window);
00924 
00925     if (piwindow) {
00926       piwindow->PopPopupControlState(openAbused);
00927     }
00928   }
00929 
00930 #if defined(MOZ_WIDGET_GTK) || defined (MOZ_WIDGET_GTK2)
00931   if (mXtBin) {
00932     gtk_widget_destroy(mXtBin);
00933     mXtBin = 0;
00934   }
00935 #elif defined(MOZ_WIDGET_XLIB)
00936   if (mXlibXtBin) {
00937     mXlibXtBin->xtbin_destroy();
00938     mXlibXtBin = 0;
00939   }
00940 #endif
00941 
00942   if(!mStarted)
00943     return NS_OK;
00944 
00945   if (fCallbacks->destroy == NULL)
00946     return NS_ERROR_FAILURE; // XXX right error?
00947 
00948   NPSavedData *sdata = 0;
00949 
00950   // clean up open streams
00951   for(nsInstanceStream *is = mStreams; is != nsnull;) {
00952     ns4xPluginStreamListener * listener = is->mPluginStreamListener;
00953 
00954     nsInstanceStream *next = is->mNext;
00955     delete is;
00956     is = next;
00957     mStreams = is;
00958 
00959     // Clean up our stream after removing it from the list because 
00960     // it may be released and destroyed at this point.
00961     if(listener)
00962       listener->CleanUpStream(NPRES_USER_BREAK);
00963   }
00964 
00965   NS_TRY_SAFE_CALL_RETURN(error, CallNPP_DestroyProc(fCallbacks->destroy, &fNPP, &sdata), fLibrary, this);
00966 
00967   NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
00968   ("NPP Destroy called: this=%p, npp=%p, return=%d\n", this, &fNPP, error));
00969 
00970   mStarted = PR_FALSE;
00971 
00972   nsJSNPRuntime::OnPluginDestroy(&fNPP);
00973 
00974   if(error != NPERR_NO_ERROR)
00975     return NS_ERROR_FAILURE;
00976   else
00977     return NS_OK;
00978 }
00979 
00980 already_AddRefed<nsIDOMWindow>
00981 ns4xPluginInstance::GetDOMWindow()
00982 {
00983   nsCOMPtr<nsPIPluginInstancePeer> pp (do_QueryInterface(mPeer));
00984   if (!pp) {
00985     return nsnull;
00986   }
00987 
00988   nsCOMPtr<nsIPluginInstanceOwner> owner;
00989   pp->GetOwner(getter_AddRefs(owner));
00990 
00991   if (!owner) {
00992     return nsnull;
00993   }
00994 
00995   nsCOMPtr<nsIDocument> doc;
00996   owner->GetDocument(getter_AddRefs(doc));
00997 
00998   if (!doc) {
00999     return nsnull;
01000   }
01001 
01002   nsIScriptGlobalObject *sgo = doc->GetScriptGlobalObject();
01003 
01004   if (!sgo) {
01005     return nsnull;
01006   }
01007 
01008   nsIDOMWindow *window;
01009   CallQueryInterface(sgo, &window);
01010 
01011   return window;
01012 }
01013 
01015 nsresult ns4xPluginInstance::InitializePlugin(nsIPluginInstancePeer* peer)
01016 {
01017   NS_ENSURE_ARG_POINTER(peer);
01018  
01019   nsCOMPtr<nsIPluginTagInfo2> taginfo = do_QueryInterface(peer);
01020   NS_ENSURE_TRUE(taginfo, NS_ERROR_NO_INTERFACE);
01021   
01022   PRUint16 count = 0;
01023   const char* const* names = nsnull;
01024   const char* const* values = nsnull;
01025   nsPluginTagType tagtype;
01026   nsresult rv = taginfo->GetTagType(&tagtype);
01027   if (NS_SUCCEEDED(rv)) {
01028     // Note: If we failed to get the tag type, we may be a full page plugin, so no arguments
01029     rv = taginfo->GetAttributes(count, names, values);
01030     NS_ENSURE_SUCCESS(rv, rv);
01031     
01032     // nsPluginTagType_Object or Applet may also have PARAM tags
01033     // Note: The arrays handed back by GetParameters() are
01034     // crafted specially to be directly behind the arrays from GetAtributes()
01035     // with a null entry as a separator. This is for 4.x backwards compatibility!
01036     // see bug 111008 for details
01037     if (tagtype != nsPluginTagType_Embed) {
01038       PRUint16 pcount = 0;
01039       const char* const* pnames = nsnull;
01040       const char* const* pvalues = nsnull;    
01041       if (NS_SUCCEEDED(taginfo->GetParameters(pcount, pnames, pvalues))) {
01042         NS_ASSERTION(nsnull == values[count], "attribute/parameter array not setup correctly for 4.x plugins");
01043         if (pcount)
01044           count += ++pcount; //if it's all setup correctly, then all we need is to change the count (attrs + PARAM/blank + params)
01045       }
01046     }
01047   }
01048 
01049 #if defined(MOZ_WIDGET_PHOTON) && defined (OJI)
01050   /* our plugins require that "voyager.documentBase"/docbase is present in the array */
01051   /* and also the java_code, java_codebase are present */
01052   const char **qnames = nsnull, **qvalues = nsnull;
01053   if (tagtype == nsPluginTagType_Object || tagtype == nsPluginTagType_Applet ) {
01054 
01055     nsCOMPtr<nsIJVMPluginTagInfo> javataginfo = do_QueryInterface(peer, &rv);
01056     if ( NS_SUCCEEDED(rv)) {
01057 
01058       taginfo->GetParameters(count, names, values);
01059       const char * tmpvalue;
01060       PRUint32 tmpivalue;
01061       char widthb[10], heightb[10];
01062       int i, c = 0;
01063       qnames = (const char **)PR_Calloc(count + 7, sizeof(char *));
01064       qvalues = (const char **)PR_Calloc(count + 7, sizeof(char *));
01065       if (qnames != nsnull && qvalues != nsnull) {
01066 
01067         if ( javataginfo->GetArchive(&tmpvalue) == NS_OK ) {
01068           qnames[c] = "java_archive";
01069           qvalues[c++] = tmpvalue;
01070         }
01071         if ( javataginfo->GetCode(&tmpvalue) == NS_OK ) {
01072           qnames[c] = "java_code";
01073           qvalues[c++] = tmpvalue;
01074         }
01075         if ( javataginfo->GetCodeBase(&tmpvalue) == NS_OK ) {
01076           qnames[c] = "java_codebase";
01077           qvalues[c++] = tmpvalue;
01078         }
01079         if ( taginfo->GetDocumentBase(&tmpvalue) == NS_OK ) {
01080           qnames[c] = "voyager.documentBase";
01081           qvalues[c++] = tmpvalue;
01082         }
01083         if ( taginfo->GetWidth(&tmpivalue) == NS_OK ) {
01084           qnames[c] = "width";
01085           qvalues[c++] = ltoa(tmpivalue, widthb, 10);
01086         }
01087         if ( taginfo->GetHeight(&tmpivalue) == NS_OK ) {
01088           qnames[c] = "height";
01089           qvalues[c++] = ltoa(tmpivalue, heightb, 10);
01090         }
01091 
01092         for( i = c; i < count + c; i++) {
01093           qnames[i] = names[i-c];
01094           qvalues[i] = values[i-c];
01095         }
01096 
01097         qnames[i] = nsnull;
01098         qvalues[i] = nsnull;
01099         names = qnames;
01100         values = qvalues;
01101         count = i;
01102         }
01103     }
01104   }
01105 #endif
01106 
01107   NS_ENSURE_TRUE(fCallbacks->newp, NS_ERROR_FAILURE);
01108   
01109   // XXX Note that the NPPluginType_* enums were crafted to be
01110   // backward compatible...
01111   
01112   nsPluginMode  mode;
01113   nsMIMEType    mimetype;
01114   NPError       error;
01115 
01116   peer->GetMode(&mode);
01117   peer->GetMIMEType(&mimetype);
01118 
01119   // Some older versions of Flash have a bug in them
01120   // that causes the stack to become currupt if we
01121   // pass swliveconect=1 in the NPP_NewProc arrays.
01122   // See bug 149336 (UNIX), bug 186287 (Mac)
01123   //
01124   // The code below disables the attribute unless
01125   // the environment variable:
01126   // MOZILLA_PLUGIN_DISABLE_FLASH_SWLIVECONNECT_HACK
01127   // is set.
01128   //
01129   // It is okay to disable this attribute because
01130   // back in 4.x, scripting required liveconnect to
01131   // start Java which was slow. Scripting no longer
01132   // requires starting Java and is quick plus controled
01133   // from the browser, so Flash now ignores this attribute.
01134   //
01135   // This code can not be put at the time of creating
01136   // the array because we may need to examine the
01137   // stream header to determine we want Flash.
01138 
01139   static const char flashMimeType[] = "application/x-shockwave-flash";
01140   static const char blockedParam[] = "swliveconnect";
01141   if (count && !PL_strcasecmp(mimetype, flashMimeType)) {
01142     static int cachedDisableHack = 0;
01143     if (!cachedDisableHack) {
01144        if (PR_GetEnv("MOZILLA_PLUGIN_DISABLE_FLASH_SWLIVECONNECT_HACK"))
01145          cachedDisableHack = -1;
01146        else
01147          cachedDisableHack = 1;
01148     }
01149     if (cachedDisableHack > 0) {
01150       for (PRUint16 i=0; i<count; i++) {
01151         if (!PL_strcasecmp(names[i], blockedParam)) {
01152           // BIG FAT WARNIG:
01153           // I'm ugly casting |const char*| to |char*| and altering it
01154           // because I know we do malloc it values in
01155           // http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/layout/html/base/src/nsObjectFrame.cpp&rev=1.349&root=/cvsroot#3020
01156           // and free it at line #2096, so it couldn't be a const ptr to string literal
01157           char *val = (char*) values[i];
01158           if (val && *val) {
01159             // we cannot just *val=0, it wont be free properly in such case
01160             val[0] = '0';
01161             val[1] = 0;
01162           }
01163           break;
01164         }
01165       }
01166     }
01167   }
01168 
01169   // Assign mPeer now and mark this instance as started before calling NPP_New 
01170   // because the plugin may call other NPAPI functions, like NPN_GetURLNotify,
01171   // that assume these are set before returning. If the plugin returns failure,
01172   // we'll clear them out below.
01173   mPeer = peer;
01174   mStarted = PR_TRUE;
01175 
01176   NS_TRY_SAFE_CALL_RETURN(error, CallNPP_NewProc(fCallbacks->newp,
01177                                           (char *)mimetype,
01178                                           &fNPP,
01179                                           (PRUint16)mode,
01180                                           count,
01181                                           (char**)names,
01182                                           (char**)values,
01183                                           NULL), fLibrary,this);
01184 
01185   NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
01186   ("NPP New called: this=%p, npp=%p, mime=%s, mode=%d, argc=%d, return=%d\n",
01187   this, &fNPP, mimetype, mode, count, error));
01188 
01189 #if defined(MOZ_WIDGET_PHOTON) && defined (OJI)
01190   /* free the names[], values[] arrays, since we overriden them */
01191   if( qnames ) PR_Free( (void*)qnames );
01192   if( qvalues ) PR_Free( (void*)qvalues );
01193 #endif
01194 
01195   if(error != NPERR_NO_ERROR) {
01196     // since the plugin returned failure, these should not be set
01197     mPeer = nsnull;
01198     mStarted = PR_FALSE;
01199 
01200     return NS_ERROR_FAILURE;
01201   }
01202   
01203   return NS_OK;
01204 }
01205 
01206 
01208 NS_IMETHODIMP ns4xPluginInstance::Destroy(void)
01209 {
01210   PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("ns4xPluginInstance::Destroy this=%p\n",this));
01211 
01212   // destruction is handled in the Stop call
01213   return NS_OK;
01214 }
01215 
01216 
01218 NS_IMETHODIMP ns4xPluginInstance::SetWindow(nsPluginWindow* window)
01219 {
01220 #if defined(MOZ_WIDGET_GTK) || defined (MOZ_WIDGET_GTK2) || defined(MOZ_WIDGET_XLIB)
01221   NPSetWindowCallbackStruct *ws;
01222 #endif
01223 
01224   // XXX 4.x plugins don't want a SetWindow(NULL).
01225   if (!window || !mStarted)
01226     return NS_OK;
01227   
01228   NPError error;
01229   
01230 #if defined (MOZ_WIDGET_GTK) || defined (MOZ_WIDGET_GTK2)
01231   PRBool isXembed = PR_FALSE;
01232   // bug 108337, flash plugin on linux doesn't like window->width <= 0
01233   if ((PRInt32) window->width <= 0 || (PRInt32) window->height <= 0)
01234     return NS_OK;
01235 
01236   // We need to test if this is an xembed window before doing checks
01237   // below, as they might be used on the first pass or on later passes
01238   // when we resize the plugin window.
01239   GdkWindow *win = gdk_window_lookup((XID)window->window);
01240   if (!win)
01241     return NS_ERROR_FAILURE;
01242 
01243   gpointer user_data = nsnull;
01244   gdk_window_get_user_data(win, &user_data);
01245   if (user_data && GTK_IS_WIDGET(user_data)) {
01246     GtkWidget* widget = GTK_WIDGET(user_data);
01247 
01248     if (GTK_IS_SOCKET(widget))
01249       isXembed = PR_TRUE;
01250   }
01251 
01252   // Allocate and fill out the ws_info data
01253   if (!window->ws_info) {
01254 #ifdef NS_DEBUG
01255     printf("About to create new ws_info...\n");
01256 #endif    
01257 
01258     // allocate a new NPSetWindowCallbackStruct structure at ws_info
01259     window->ws_info = (NPSetWindowCallbackStruct *)PR_MALLOC(sizeof(NPSetWindowCallbackStruct));
01260 
01261     if (!window->ws_info)
01262       return NS_ERROR_OUT_OF_MEMORY;
01263 
01264     ws = (NPSetWindowCallbackStruct *)window->ws_info;
01265 
01266     if (!isXembed)
01267     {  
01268 #ifdef NS_DEBUG      
01269       printf("About to create new xtbin of %i X %i from %p...\n",
01270              window->width, window->height, win);
01271 #endif
01272 
01273 #if 0
01274       // if we destroyed the plugin when we left the page, we could remove this
01275       // code (i believe) the problem here is that the window gets destroyed when
01276       // its parent, etc does by changing a page the plugin instance is being
01277       // held on to, so when we return to the page, we have a mXtBin, but it is
01278       // in a not-so-good state.
01279       // --
01280       // this is lame.  we shouldn't be destroying this everytime, but I can't find
01281       // a good way to tell if we need to destroy/recreate the xtbin or not
01282       // what if the plugin wants to change the window and not just resize it??
01283       // (pav)
01284 
01285       if (mXtBin) {
01286         gtk_widget_destroy(mXtBin);
01287         mXtBin = NULL;
01288       }
01289 #endif
01290 
01291 
01292       if (!mXtBin) {
01293         mXtBin = gtk_xtbin_new(win, 0);
01294         // Check to see if creating mXtBin failed for some reason.
01295         // if it did, we can't go any further.
01296         if (!mXtBin)
01297           return NS_ERROR_FAILURE;
01298       } 
01299 
01300       gtk_widget_set_usize(mXtBin, window->width, window->height);
01301 
01302 #ifdef NS_DEBUG
01303       printf("About to show xtbin(%p)...\n", mXtBin); fflush(NULL);
01304 #endif
01305       gtk_widget_show(mXtBin);
01306 #ifdef NS_DEBUG
01307       printf("completed gtk_widget_show(%p)\n", mXtBin); fflush(NULL);
01308 #endif
01309     }
01310 
01311     // fill in window info structure 
01312     ws->type = 0; // OK, that was a guess!!
01313 #ifdef MOZ_X11
01314     ws->depth = gdk_window_get_visual(win)->depth;
01315     if (!isXembed)
01316       ws->display = GTK_XTBIN(mXtBin)->xtdisplay;
01317     else
01318       ws->display = GDK_WINDOW_XDISPLAY(win);
01319     ws->visual = GDK_VISUAL_XVISUAL(gdk_window_get_visual(win));
01320     ws->colormap = GDK_COLORMAP_XCOLORMAP(gdk_window_get_colormap(win));
01321 
01322     XFlush(ws->display);
01323 #endif
01324   } // !window->ws_info
01325 
01326   if (!mXtBin && !isXembed)
01327     return NS_ERROR_FAILURE;
01328 
01329   if (!isXembed) {
01330     // And now point the NPWindow structures window 
01331     // to the actual X window
01332     window->window = (nsPluginPort *)GTK_XTBIN(mXtBin)->xtwindow;
01333     
01334     gtk_xtbin_resize(mXtBin, window->width, window->height);
01335   }
01336   
01337 #elif defined(MOZ_WIDGET_XLIB)
01338 
01339 
01340   // Allocate and fill out the ws_info data
01341   if (!window->ws_info) {
01342 #ifdef NS_DEBUG
01343     printf("About to create new ws_info...\n");
01344 #endif
01345 
01346     // allocate a new NPSetWindowCallbackStruct structure at ws_info
01347     window->ws_info = (NPSetWindowCallbackStruct *)PR_MALLOC(sizeof(NPSetWindowCallbackStruct));
01348 
01349     if (!window->ws_info)
01350       return NS_ERROR_OUT_OF_MEMORY;
01351 
01352     ws = (NPSetWindowCallbackStruct *)window->ws_info;
01353 
01354 #if 1
01355      /* See comment above in GTK+ port ... */
01356      if (mXlibXtBin) {
01357        delete mXlibXtBin;
01358        mXlibXtBin = nsnull;
01359      }
01360 #endif
01361 
01362       if (!mXlibXtBin) {
01363         mXlibXtBin = new xtbin();
01364         // Check to see if creating mXlibXtBin failed for some reason.
01365         // if it did, we can't go any further.
01366         if (!mXlibXtBin)
01367           return NS_ERROR_FAILURE;
01368       } 
01369       
01370     if (window->window) {
01371 #ifdef NS_DEBUG
01372       printf("About to create new xtbin of %i X %i from %08x...\n",
01373              window->width, window->height, window->window);
01374 #endif
01375 
01376       mXlibXtBin->xtbin_new((Window)window->window);
01377       mXlibXtBin->xtbin_resize(0, 0, window->width, window->height);
01378 #ifdef NS_DEBUG
01379       printf("About to show xtbin(%p)...\n", mXlibXtBin); fflush(NULL);
01380 #endif
01381       mXlibXtBin->xtbin_realize();
01382     }
01383     
01384     /* Set window attributes */
01385     XlibRgbHandle *xlibRgbHandle = xxlib_find_handle(XXLIBRGB_DEFAULT_HANDLE);
01386     Display *xdisplay = xxlib_rgb_get_display(xlibRgbHandle);
01387 
01388     /* Fill in window info structure */
01389     ws->type     = 0;
01390     ws->depth    = xxlib_rgb_get_depth(xlibRgbHandle);
01391     ws->display  = xdisplay;
01392     ws->visual   = xxlib_rgb_get_visual(xlibRgbHandle);
01393     ws->colormap = xxlib_rgb_get_cmap(xlibRgbHandle);
01394     XFlush(ws->display);
01395   } // !window->ws_info
01396 
01397   // And now point the NPWindow structures window 
01398   // to the actual X window
01399   window->window = (nsPluginPort *)mXlibXtBin->xtbin_xtwindow();
01400 #endif // MOZ_WIDGET
01401 
01402   if (fCallbacks->setwindow) {
01403     // XXX Turns out that NPPluginWindow and NPWindow are structurally
01404     // identical (on purpose!), so there's no need to make a copy.
01405 
01406     PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("ns4xPluginInstance::SetWindow (about to call it) this=%p\n",this));
01407 
01408     NS_TRY_SAFE_CALL_RETURN(error, CallNPP_SetWindowProc(fCallbacks->setwindow,
01409                                   &fNPP,
01410                                   (NPWindow*) window), fLibrary, this);
01411 
01412 
01413     NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
01414     ("NPP SetWindow called: this=%p, [x=%d,y=%d,w=%d,h=%d], clip[t=%d,b=%d,l=%d,r=%d], return=%d\n",
01415     this, window->x, window->y, window->width, window->height,
01416     window->clipRect.top, window->clipRect.bottom, window->clipRect.left, window->clipRect.right, error));
01417       
01418     // XXX In the old code, we'd just ignore any errors coming
01419     // back from the plugin's SetWindow(). Is this the correct
01420     // behavior?!?
01421 
01422   }
01423   return NS_OK;
01424 }
01425 
01426 
01428 /* NOTE: the caller must free the stream listener */
01429 // Create a normal stream, one without a urlnotify callback
01430 NS_IMETHODIMP ns4xPluginInstance::NewStream(nsIPluginStreamListener** listener)
01431 {
01432   return NewNotifyStream(listener, nsnull, PR_FALSE, nsnull);
01433 }
01434 
01435 
01437 // Create a stream that will notify when complete
01438 nsresult ns4xPluginInstance::NewNotifyStream(nsIPluginStreamListener** listener, 
01439                                              void* notifyData,
01440                                              PRBool aCallNotify,
01441                                              const char* aURL)
01442 {
01443   ns4xPluginStreamListener* stream = new ns4xPluginStreamListener(this, notifyData, aURL);
01444   NS_ENSURE_TRUE(stream, NS_ERROR_OUT_OF_MEMORY);
01445 
01446   // add it to the list
01447   nsInstanceStream * is = new nsInstanceStream();
01448   NS_ENSURE_TRUE(is, NS_ERROR_OUT_OF_MEMORY);
01449 
01450   is->mNext = mStreams;
01451   is->mPluginStreamListener = stream;
01452   mStreams = is;
01453   stream->SetCallNotify(aCallNotify);  // set flag in stream to call URLNotify
01454 
01455   NS_ADDREF(stream);  // Stabilize
01456     
01457   nsresult res = stream->QueryInterface(kIPluginStreamListenerIID, (void**)listener);
01458 
01459   // Destabilize and avoid leaks. Avoid calling delete <interface pointer>
01460   NS_RELEASE(stream);
01461 
01462   return res;
01463 }
01464 
01465 NS_IMETHODIMP ns4xPluginInstance::Print(nsPluginPrint* platformPrint)
01466 {
01467   NS_ENSURE_TRUE(platformPrint, NS_ERROR_NULL_POINTER);
01468 
01469   NPPrint* thePrint = (NPPrint *)platformPrint;
01470 
01471   // to be compatible with the older SDK versions and to match what
01472   // 4.x and other browsers do, overwrite |window.type| field with one
01473   // more copy of |platformPrint|. See bug 113264
01474   if(fCallbacks) {
01475     PRUint16 sdkmajorversion = (fCallbacks->version & 0xff00)>>8;
01476     PRUint16 sdkminorversion = fCallbacks->version & 0x00ff;
01477     if((sdkmajorversion == 0) && (sdkminorversion < 11)) { 
01478       // Let's copy platformPrint bytes over to where it was supposed to be 
01479       // in older versions -- four bytes towards the beginning of the struct
01480       // but we should be careful about possible misalignments
01481       if(sizeof(NPWindowType) >= sizeof(void *)) {
01482         void* source = thePrint->print.embedPrint.platformPrint; 
01483         void** destination = (void **)&(thePrint->print.embedPrint.window.type); 
01484         *destination = source;
01485       } 
01486       else 
01487         NS_ASSERTION(PR_FALSE, "Incompatible OS for assignment");
01488     }
01489   }
01490 
01491   NS_TRY_SAFE_CALL_VOID(CallNPP_PrintProc(fCallbacks->print,
01492                                           &fNPP,
01493                                           thePrint), fLibrary, this);
01494 
01495   NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
01496   ("NPP PrintProc called: this=%p, pDC=%p, [x=%d,y=%d,w=%d,h=%d], clip[t=%d,b=%d,l=%d,r=%d]\n",
01497   this,
01498   platformPrint->print.embedPrint.platformPrint,
01499   platformPrint->print.embedPrint.window.x,
01500   platformPrint->print.embedPrint.window.y,
01501   platformPrint->print.embedPrint.window.width,
01502   platformPrint->print.embedPrint.window.height,
01503   platformPrint->print.embedPrint.window.clipRect.top,
01504   platformPrint->print.embedPrint.window.clipRect.bottom,
01505   platformPrint->print.embedPrint.window.clipRect.left,
01506   platformPrint->print.embedPrint.window.clipRect.right));
01507 
01508   return NS_OK;
01509 }
01510 
01511 NS_IMETHODIMP ns4xPluginInstance::HandleEvent(nsPluginEvent* event, PRBool* handled)
01512 {
01513   if(!mStarted)
01514     return NS_OK;
01515 
01516   if (event == nsnull)
01517     return NS_ERROR_FAILURE;
01518 
01519   PRInt16 result = 0;
01520   
01521   if (fCallbacks->event) {
01522 #if defined(XP_MAC) || defined(XP_MACOSX)
01523     result = CallNPP_HandleEventProc(fCallbacks->event,
01524                                      &fNPP,
01525                                      (void*) event->event);
01526 #endif
01527 
01528 #if defined(XP_WIN) || defined(XP_OS2)
01529       NPEvent npEvent;
01530       npEvent.event = event->event;
01531       npEvent.wParam = event->wParam;
01532       npEvent.lParam = event->lParam;
01533 
01534       NS_TRY_SAFE_CALL_RETURN(result, CallNPP_HandleEventProc(fCallbacks->event,
01535                                     &fNPP,
01536                                     (void*)&npEvent), fLibrary, this);
01537 #endif
01538 
01539       NPP_PLUGIN_LOG(PLUGIN_LOG_NOISY,
01540       ("NPP HandleEvent called: this=%p, npp=%p, event=%d, return=%d\n", 
01541       this, &fNPP, event->event, result));
01542 
01543       *handled = result;
01544     }
01545 
01546   return NS_OK;
01547 }
01548 
01549 nsresult ns4xPluginInstance::GetValueInternal(NPPVariable variable, void* value)
01550 {
01551   nsresult  res = NS_OK;
01552   if(fCallbacks->getvalue && mStarted) {
01553 
01554     NS_TRY_SAFE_CALL_RETURN(res, 
01555                             CallNPP_GetValueProc(fCallbacks->getvalue, 
01556                                                  &fNPP, 
01557                                                  variable, 
01558                                                  value), 
01559                                                  fLibrary, this);
01560     NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
01561     ("NPP GetValue called: this=%p, npp=%p, var=%d, value=%d, return=%d\n", 
01562     this, &fNPP, variable, value, res));
01563 
01564 #ifdef XP_OS2
01565     /* Query interface for legacy Flash plugin */
01566     if (res == NS_OK && variable == NPPVpluginScriptableInstance)
01567     {
01568       nsCOMPtr<nsILegacyPluginWrapperOS2> wrapper =
01569                do_GetService(NS_LEGACY_PLUGIN_WRAPPER_CONTRACTID, &res);
01570       if (res == NS_OK)
01571       {
01572         nsIID *iid = nsnull; 
01573         res = CallNPP_GetValueProc(fCallbacks->getvalue, &fNPP, 
01574                                    NPPVpluginScriptableIID, (void *)&iid);
01575         if (res == NS_OK)
01576           res = wrapper->MaybeWrap(*iid, *(nsISupports**)value,
01577                                    (nsISupports**)value);
01578       }
01579     }
01580 #endif
01581   }
01582 
01583   return res;
01584 }
01585 
01586 
01588 NS_IMETHODIMP ns4xPluginInstance::GetValue(nsPluginInstanceVariable variable,
01589                                            void *value)
01590 {
01591   nsresult  res = NS_OK;
01592 
01593   switch (variable) {
01594     case nsPluginInstanceVariable_WindowlessBool:
01595       *(PRBool *)value = mWindowless;
01596       break;
01597 
01598     case nsPluginInstanceVariable_TransparentBool:
01599       *(PRBool *)value = mTransparent;
01600       break;
01601 
01602     case nsPluginInstanceVariable_DoCacheBool:
01603       *(PRBool *)value = mCached;
01604       break;
01605 
01606     case nsPluginInstanceVariable_CallSetWindowAfterDestroyBool:
01607       *(PRBool *)value = 0;  // not supported for 4.x plugins
01608       break;
01609 
01610     default:
01611       res = GetValueInternal((NPPVariable)variable, value);
01612   }
01613 
01614   return res;
01615 }
01616 
01617 
01619 nsresult ns4xPluginInstance::GetNPP(NPP* aNPP) 
01620 {
01621   if(aNPP != nsnull)
01622     *aNPP = &fNPP;
01623   else
01624     return NS_ERROR_NULL_POINTER;
01625 
01626   return NS_OK;
01627 }
01628 
01629 
01631 nsresult ns4xPluginInstance::GetCallbacks(const NPPluginFuncs ** aCallbacks)
01632 {
01633   if(aCallbacks != nsnull)
01634     *aCallbacks = fCallbacks;
01635   else
01636     return NS_ERROR_NULL_POINTER;
01637 
01638   return NS_OK;
01639 }
01640 
01641 
01643 nsresult ns4xPluginInstance::SetWindowless(PRBool aWindowless)
01644 {
01645   mWindowless = aWindowless;
01646   return NS_OK;
01647 }
01648 
01649 
01651 nsresult ns4xPluginInstance::SetTransparent(PRBool aTransparent)
01652 {
01653   mTransparent = aTransparent;
01654   return NS_OK;
01655 }
01656 
01658 /* readonly attribute nsQIResult scriptablePeer; */
01659 NS_IMETHODIMP ns4xPluginInstance::GetScriptablePeer(void * *aScriptablePeer)
01660 {
01661   if (!aScriptablePeer)
01662     return NS_ERROR_NULL_POINTER;
01663 
01664   *aScriptablePeer = nsnull;
01665   return GetValueInternal(NPPVpluginScriptableInstance, aScriptablePeer);
01666 }
01667 
01669 /* readonly attribute nsIIDPtr scriptableInterface; */
01670 NS_IMETHODIMP ns4xPluginInstance::GetScriptableInterface(nsIID * *aScriptableInterface)
01671 {
01672   if (!aScriptableInterface)
01673     return NS_ERROR_NULL_POINTER;
01674 
01675   *aScriptableInterface = nsnull;
01676   return GetValueInternal(NPPVpluginScriptableIID, (void*)aScriptableInterface);
01677 }
01678 
01679 JSObject *
01680 ns4xPluginInstance::GetJSObject(JSContext *cx)
01681 {
01682   JSObject *obj = nsnull;
01683   NPObject *npobj = nsnull;
01684 
01685   nsresult rv = GetValueInternal(NPPVpluginScriptableNPObject, &npobj);
01686 
01687   if (NS_SUCCEEDED(rv) && npobj) {
01688     obj = nsNPObjWrapper::GetNewOrUsed(&fNPP, cx, npobj);
01689 
01690     _releaseobject(npobj);
01691   }
01692 
01693   return obj;
01694 }
01695 
01696 nsresult
01697 ns4xPluginInstance::GetFormValue(nsAString& aValue)
01698 {
01699   aValue.Truncate();
01700 
01701   char *value = nsnull;
01702   nsresult rv = GetValueInternal(NPPVformValue, &value);
01703 
01704   if (NS_SUCCEEDED(rv) && value) {
01705     CopyUTF8toUTF16(value, aValue);
01706 
01707     // NPPVformValue allocates with NPN_MemAlloc(), which uses
01708     // nsMemory.
01709     nsMemory::Free(value);
01710   }
01711 
01712   return NS_OK;
01713 }
01714 
01715 void
01716 ns4xPluginInstance::PushPopupsEnabledState(PRBool aEnabled)
01717 {
01718   nsCOMPtr<nsIDOMWindow> window = GetDOMWindow();
01719   nsCOMPtr<nsPIDOMWindow> piwindow = do_QueryInterface(window);
01720 
01721   if (!piwindow)
01722     return;
01723 
01724   PopupControlState oldState =
01725     piwindow->PushPopupControlState(aEnabled ? openAllowed : openAbused,
01726                                     PR_TRUE);
01727 
01728   if (!mPopupStates.AppendElement(NS_INT32_TO_PTR(oldState))) {
01729     // Appending to our state stack failed, push what we just popped.
01730 
01731     piwindow->PopPopupControlState(oldState);
01732   }
01733 }
01734 
01735 void
01736 ns4xPluginInstance::PopPopupsEnabledState()
01737 {
01738   PRInt32 last = mPopupStates.Count() - 1;
01739 
01740   if (last < 0) {
01741     // Nothing to pop.
01742 
01743     return;
01744   }
01745 
01746   nsCOMPtr<nsIDOMWindow> window = GetDOMWindow();
01747   nsCOMPtr<nsPIDOMWindow> piwindow = do_QueryInterface(window);
01748 
01749   if (!piwindow)
01750     return;
01751 
01752   PopupControlState oldState =
01753     (PopupControlState)NS_PTR_TO_INT32(mPopupStates[last]);
01754 
01755   piwindow->PopPopupControlState(oldState);
01756 
01757   mPopupStates.RemoveElementAt(last);
01758 }
01759 
01760 PRUint16
01761 ns4xPluginInstance::GetPluginAPIVersion()
01762 {
01763   return fCallbacks->version;
01764 }