Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / modules / plugin / base / src / nsNPAPIPluginInstance.cpp
blob3480493469f1f8c7098c02c90c5c487532e7f4d8
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Tim Copperfield <timecop@network.email.ne.jp>
24 * Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 #include "prlog.h"
41 #include "prmem.h"
42 #include "nscore.h"
43 #include "prenv.h"
45 #include "nsNPAPIPluginInstance.h"
46 #include "nsNPAPIPlugin.h"
47 #include "nsNPAPIPluginStreamListener.h"
48 #include "nsPluginHostImpl.h"
49 #include "nsPluginSafety.h"
50 #include "nsPluginLogging.h"
52 #include "nsPIPluginInstancePeer.h"
53 #include "nsPIDOMWindow.h"
54 #include "nsIDocument.h"
56 #include "nsJSNPRuntime.h"
58 #ifdef XP_OS2
59 #include "nsILegacyPluginWrapperOS2.h"
60 #endif
62 static NS_DEFINE_IID(kCPluginManagerCID, NS_PLUGINMANAGER_CID); // needed for NS_TRY_SAFE_CALL
63 static NS_DEFINE_IID(kIPluginStreamListenerIID, NS_IPLUGINSTREAMLISTENER_IID);
65 // nsNPAPIPluginStreamListener Methods
67 NS_IMPL_ISUPPORTS3(nsNPAPIPluginStreamListener, nsIPluginStreamListener,
68 nsITimerCallback, nsIHTTPHeaderListener)
70 nsNPAPIPluginStreamListener::nsNPAPIPluginStreamListener(nsNPAPIPluginInstance* inst,
71 void* notifyData,
72 const char* aURL)
73 : mNotifyData(notifyData),
74 mStreamBuffer(nsnull),
75 mNotifyURL(aURL ? PL_strdup(aURL) : nsnull),
76 mInst(inst),
77 mStreamBufferSize(0),
78 mStreamBufferByteCount(0),
79 mStreamType(nsPluginStreamType_Normal),
80 mStreamStarted(PR_FALSE),
81 mStreamCleanedUp(PR_FALSE),
82 mCallNotify(PR_FALSE),
83 mIsSuspended(PR_FALSE),
84 mIsPluginInitJSStream(mInst->mInPluginInitCall &&
85 aURL && strncmp(aURL, "javascript:",
86 sizeof("javascript:") - 1) == 0),
87 mResponseHeaderBuf(nsnull)
89 memset(&mNPStream, 0, sizeof(mNPStream));
91 NS_IF_ADDREF(mInst);
94 nsNPAPIPluginStreamListener::~nsNPAPIPluginStreamListener(void)
96 // remove itself from the instance stream list
97 nsNPAPIPluginInstance *inst = mInst;
98 if (inst) {
99 nsInstanceStream * prev = nsnull;
100 for (nsInstanceStream *is = inst->mStreams; is != nsnull; is = is->mNext) {
101 if (is->mPluginStreamListener == this) {
102 if (!prev)
103 inst->mStreams = is->mNext;
104 else
105 prev->mNext = is->mNext;
107 delete is;
108 break;
110 prev = is;
114 // For those cases when NewStream is never called, we still may need
115 // to fire a notification callback. Return network error as fallback
116 // reason because for other cases, notify should have already been
117 // called for other reasons elsewhere.
118 CallURLNotify(NPRES_NETWORK_ERR);
120 // lets get rid of the buffer
121 if (mStreamBuffer) {
122 PR_Free(mStreamBuffer);
123 mStreamBuffer=nsnull;
126 NS_IF_RELEASE(inst);
128 if (mNotifyURL)
129 PL_strfree(mNotifyURL);
131 if (mResponseHeaderBuf)
132 PL_strfree(mResponseHeaderBuf);
135 nsresult nsNPAPIPluginStreamListener::CleanUpStream(NPReason reason)
137 nsresult rv = NS_ERROR_FAILURE;
139 if (mStreamCleanedUp)
140 return NS_OK;
142 if (!mInst || !mInst->IsStarted())
143 return rv;
145 PluginDestructionGuard guard(mInst);
147 const NPPluginFuncs *callbacks = nsnull;
148 mInst->GetCallbacks(&callbacks);
149 if (!callbacks)
150 return rv;
152 NPP npp;
153 mInst->GetNPP(&npp);
155 if (mStreamStarted && callbacks->destroystream) {
156 PRLibrary* lib = nsnull;
157 lib = mInst->fLibrary;
158 NPError error;
159 NS_TRY_SAFE_CALL_RETURN(error, (*callbacks->destroystream)(npp, &mNPStream, reason), lib, mInst);
161 NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
162 ("NPP DestroyStream called: this=%p, npp=%p, reason=%d, return=%d, url=%s\n",
163 this, npp, reason, error, mNPStream.url));
165 if (error == NPERR_NO_ERROR)
166 rv = NS_OK;
169 mStreamCleanedUp = PR_TRUE;
170 mStreamStarted = PR_FALSE;
172 StopDataPump();
174 // fire notification back to plugin, just like before
175 CallURLNotify(reason);
177 return rv;
180 void nsNPAPIPluginStreamListener::CallURLNotify(NPReason reason)
182 if (!mCallNotify || !mInst || !mInst->IsStarted())
183 return;
185 PluginDestructionGuard guard(mInst);
187 mCallNotify = PR_FALSE; // only do this ONCE and prevent recursion
189 const NPPluginFuncs *callbacks = nsnull;
190 mInst->GetCallbacks(&callbacks);
191 if (!callbacks)
192 return;
194 if (callbacks->urlnotify) {
196 NPP npp;
197 mInst->GetNPP(&npp);
199 NS_TRY_SAFE_CALL_VOID((*callbacks->urlnotify)(npp, mNotifyURL, reason, mNotifyData), mInst->fLibrary, mInst);
201 NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
202 ("NPP URLNotify called: this=%p, npp=%p, notify=%p, reason=%d, url=%s\n",
203 this, npp, mNotifyData, reason, mNotifyURL));
207 NS_IMETHODIMP
208 nsNPAPIPluginStreamListener::OnStartBinding(nsIPluginStreamInfo* pluginInfo)
210 if (!mInst)
211 return NS_ERROR_FAILURE;
213 PluginDestructionGuard guard(mInst);
215 NPP npp;
216 const NPPluginFuncs *callbacks = nsnull;
218 mInst->GetCallbacks(&callbacks);
219 mInst->GetNPP(&npp);
221 if (!callbacks || !mInst->IsStarted())
222 return NS_ERROR_FAILURE;
224 PRBool seekable;
225 nsMIMEType contentType;
226 PRUint16 streamType = NP_NORMAL;
227 NPError error;
229 mNPStream.ndata = (void*) this;
230 pluginInfo->GetURL(&mNPStream.url);
231 mNPStream.notifyData = mNotifyData;
233 pluginInfo->GetLength((PRUint32*)&(mNPStream.end));
234 pluginInfo->GetLastModified((PRUint32*)&(mNPStream.lastmodified));
235 pluginInfo->IsSeekable(&seekable);
236 pluginInfo->GetContentType(&contentType);
238 if (!mResponseHeaders.IsEmpty()) {
239 mResponseHeaderBuf = PL_strdup(mResponseHeaders.get());
240 mNPStream.headers = mResponseHeaderBuf;
243 mStreamInfo = pluginInfo;
245 NS_TRY_SAFE_CALL_RETURN(error, (*callbacks->newstream)(npp, (char*)contentType, &mNPStream, seekable, &streamType), mInst->fLibrary, mInst);
247 NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
248 ("NPP NewStream called: this=%p, npp=%p, mime=%s, seek=%d, type=%d, return=%d, url=%s\n",
249 this, npp, (char *)contentType, seekable, streamType, error, mNPStream.url));
251 if (error != NPERR_NO_ERROR)
252 return NS_ERROR_FAILURE;
254 switch(streamType)
256 case NP_NORMAL:
257 mStreamType = nsPluginStreamType_Normal;
258 break;
259 case NP_ASFILEONLY:
260 mStreamType = nsPluginStreamType_AsFileOnly;
261 break;
262 case NP_ASFILE:
263 mStreamType = nsPluginStreamType_AsFile;
264 break;
265 case NP_SEEK:
266 mStreamType = nsPluginStreamType_Seek;
267 break;
268 default:
269 return NS_ERROR_FAILURE;
272 mStreamStarted = PR_TRUE;
273 return NS_OK;
276 nsresult
277 nsNPAPIPluginStreamListener::SuspendRequest()
279 NS_ASSERTION(!mIsSuspended,
280 "Suspending a request that's already suspended!");
282 nsCOMPtr<nsINPAPIPluginStreamInfo> pluginInfoNPAPI =
283 do_QueryInterface(mStreamInfo);
284 nsIRequest *request;
286 if (!pluginInfoNPAPI || !(request = pluginInfoNPAPI->GetRequest())) {
287 NS_ERROR("Trying to suspend a non-suspendable stream!");
288 return NS_ERROR_FAILURE;
291 nsresult rv = StartDataPump();
292 NS_ENSURE_SUCCESS(rv, rv);
294 mIsSuspended = PR_TRUE;
296 return request->Suspend();
299 void
300 nsNPAPIPluginStreamListener::ResumeRequest()
302 nsCOMPtr<nsINPAPIPluginStreamInfo> pluginInfoNPAPI =
303 do_QueryInterface(mStreamInfo);
305 nsIRequest *request = pluginInfoNPAPI->GetRequest();
307 // request can be null if the network stream is done.
308 if (request)
309 request->Resume();
311 mIsSuspended = PR_FALSE;
314 nsresult
315 nsNPAPIPluginStreamListener::StartDataPump()
317 nsresult rv;
318 mDataPumpTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
319 NS_ENSURE_SUCCESS(rv, rv);
321 // Start pumping data to the plugin every 100ms until it obeys and
322 // eats the data.
323 return mDataPumpTimer->InitWithCallback(this, 100,
324 nsITimer::TYPE_REPEATING_SLACK);
327 void
328 nsNPAPIPluginStreamListener::StopDataPump()
330 if (mDataPumpTimer) {
331 mDataPumpTimer->Cancel();
332 mDataPumpTimer = nsnull;
336 // Return true if a javascript: load that was started while the plugin
337 // was being initialized is still in progress.
338 PRBool
339 nsNPAPIPluginStreamListener::PluginInitJSLoadInProgress()
341 for (nsInstanceStream *is = mInst->mStreams; is; is = is->mNext) {
342 if (is->mPluginStreamListener->mIsPluginInitJSStream) {
343 return PR_TRUE;
347 return PR_FALSE;
350 // This method is called when there's more data available off the
351 // network, but it's also called from our data pump when we're feeding
352 // the plugin data that we already got off the network, but the plugin
353 // was unable to consume it at the point it arrived. In the case when
354 // the plugin pump calls this method, the input argument will be null,
355 // and the length will be the number of bytes available in our
356 // internal buffer.
357 NS_IMETHODIMP
358 nsNPAPIPluginStreamListener::OnDataAvailable(nsIPluginStreamInfo* pluginInfo,
359 nsIInputStream* input,
360 PRUint32 length)
362 if (!mInst || !mInst->IsStarted())
363 return NS_ERROR_FAILURE;
365 PluginDestructionGuard guard(mInst);
367 // Just in case the caller switches plugin info on us.
368 mStreamInfo = pluginInfo;
370 const NPPluginFuncs *callbacks = nsnull;
371 mInst->GetCallbacks(&callbacks);
372 // check out if plugin implements NPP_Write call
373 if (!callbacks || !callbacks->write || !length)
374 return NS_ERROR_FAILURE; // it'll cancel necko transaction
376 if (!mStreamBuffer) {
377 // To optimize the mem usage & performance we have to allocate
378 // mStreamBuffer here in first ODA when length of data available
379 // in input stream is known. mStreamBuffer will be freed in DTOR.
380 // we also have to remember the size of that buff to make safe
381 // consecutive Read() calls form input stream into our buff.
383 PRUint32 contentLength;
384 pluginInfo->GetLength(&contentLength);
386 mStreamBufferSize = PR_MAX(length, contentLength);
388 // Limit the size of the initial buffer to MAX_PLUGIN_NECKO_BUFFER
389 // (16k). This buffer will grow if needed, as in the case where
390 // we're getting data faster than the plugin can process it.
391 mStreamBufferSize = PR_MIN(mStreamBufferSize, MAX_PLUGIN_NECKO_BUFFER);
393 mStreamBuffer = (char*) PR_Malloc(mStreamBufferSize);
394 if (!mStreamBuffer)
395 return NS_ERROR_OUT_OF_MEMORY;
398 // prepare NPP_ calls params
399 NPP npp;
400 mInst->GetNPP(&npp);
402 PRInt32 streamPosition;
403 pluginInfo->GetStreamOffset(&streamPosition);
404 PRInt32 streamOffset = streamPosition;
406 if (input) {
407 streamOffset += length;
409 // Set new stream offset for the next ODA call regardless of how
410 // following NPP_Write call will behave we pretend to consume all
411 // data from the input stream. It's possible that current steam
412 // position will be overwritten from NPP_RangeRequest call made
413 // from NPP_Write, so we cannot call SetStreamOffset after
414 // NPP_Write.
416 // Note: there is a special case when data flow should be
417 // temporarily stopped if NPP_WriteReady returns 0 (bug #89270)
418 pluginInfo->SetStreamOffset(streamOffset);
420 // set new end in case the content is compressed
421 // initial end is less than end of decompressed stream
422 // and some plugins (e.g. acrobat) can fail.
423 if ((PRInt32)mNPStream.end < streamOffset)
424 mNPStream.end = streamOffset;
427 nsresult rv = NS_OK;
428 while (NS_SUCCEEDED(rv) && length > 0) {
429 if (input && length) {
430 if (mStreamBufferSize < mStreamBufferByteCount + length && mIsSuspended) {
431 // We're in the ::OnDataAvailable() call that we might get
432 // after suspending a request, or we suspended the request
433 // from within this ::OnDataAvailable() call while there's
434 // still data in the input, and we don't have enough space to
435 // store what we got off the network. Reallocate our internal
436 // buffer.
437 mStreamBufferSize = mStreamBufferByteCount + length;
438 char *buf = (char*)PR_Realloc(mStreamBuffer, mStreamBufferSize);
439 if (!buf)
440 return NS_ERROR_OUT_OF_MEMORY;
442 mStreamBuffer = buf;
445 PRUint32 bytesToRead =
446 PR_MIN(length, mStreamBufferSize - mStreamBufferByteCount);
448 PRUint32 amountRead = 0;
449 rv = input->Read(mStreamBuffer + mStreamBufferByteCount, bytesToRead,
450 &amountRead);
451 NS_ENSURE_SUCCESS(rv, rv);
453 if (amountRead == 0) {
454 NS_NOTREACHED("input->Read() returns no data, it's almost impossible "
455 "to get here");
457 break;
460 mStreamBufferByteCount += amountRead;
461 length -= amountRead;
462 } else {
463 // No input, nothing to read. Set length to 0 so that we don't
464 // keep iterating through this outer loop any more.
466 length = 0;
469 // Temporary pointer to the beginning of the data we're writing as
470 // we loop and feed the plugin data.
471 char *ptrStreamBuffer = mStreamBuffer;
473 // it is possible plugin's NPP_Write() returns 0 byte consumed. We
474 // use zeroBytesWriteCount to count situation like this and break
475 // the loop
476 PRInt32 zeroBytesWriteCount = 0;
478 // mStreamBufferByteCount tells us how many bytes there are in the
479 // buffer. WriteReady returns to us how many bytes the plugin is
480 // ready to handle.
481 while (mStreamBufferByteCount > 0) {
482 PRInt32 numtowrite;
483 if (callbacks->writeready) {
484 NS_TRY_SAFE_CALL_RETURN(numtowrite, (*callbacks->writeready)(npp, &mNPStream), mInst->fLibrary, mInst);
485 NPP_PLUGIN_LOG(PLUGIN_LOG_NOISY,
486 ("NPP WriteReady called: this=%p, npp=%p, "
487 "return(towrite)=%d, url=%s\n",
488 this, npp, numtowrite, mNPStream.url));
490 if (!mStreamStarted) {
491 // The plugin called NPN_DestroyStream() from within
492 // NPP_WriteReady(), kill the stream.
494 return NS_BINDING_ABORTED;
497 // if WriteReady returned 0, the plugin is not ready to handle
498 // the data, suspend the stream (if it isn't already
499 // suspended).
501 // Also suspend the stream if the stream we're loading is not
502 // a javascript: URL load that was initiated during plugin
503 // initialization and there currently is such a stream
504 // loading. This is done to work around a Windows Media Player
505 // plugin bug where it can't deal with being fed data for
506 // other streams while it's waiting for data from the
507 // javascript: URL loads it requests during
508 // initialization. See bug 386493 for more details.
510 if (numtowrite <= 0 ||
511 (!mIsPluginInitJSStream && PluginInitJSLoadInProgress())) {
512 if (!mIsSuspended) {
513 rv = SuspendRequest();
516 // Break out of the inner loop, but keep going through the
517 // outer loop in case there's more data to read from the
518 // input stream.
520 break;
523 numtowrite = PR_MIN(numtowrite, mStreamBufferByteCount);
524 } else {
525 // if WriteReady is not supported by the plugin, just write
526 // the whole buffer
527 numtowrite = mStreamBufferByteCount;
530 PRInt32 writeCount = 0; // bytes consumed by plugin instance
531 NS_TRY_SAFE_CALL_RETURN(writeCount, (*callbacks->write)(npp, &mNPStream, streamPosition, numtowrite, ptrStreamBuffer), mInst->fLibrary, mInst);
533 NPP_PLUGIN_LOG(PLUGIN_LOG_NOISY,
534 ("NPP Write called: this=%p, npp=%p, pos=%d, len=%d, "
535 "buf=%s, return(written)=%d, url=%s\n",
536 this, npp, streamPosition, numtowrite,
537 ptrStreamBuffer, writeCount, mNPStream.url));
539 if (!mStreamStarted) {
540 // The plugin called NPN_DestroyStream() from within
541 // NPP_Write(), kill the stream.
542 return NS_BINDING_ABORTED;
545 if (writeCount > 0) {
546 NS_ASSERTION(writeCount <= mStreamBufferByteCount,
547 "Plugin read past the end of the available data!");
549 writeCount = PR_MIN(writeCount, mStreamBufferByteCount);
550 mStreamBufferByteCount -= writeCount;
552 streamPosition += writeCount;
554 zeroBytesWriteCount = 0;
556 if (mStreamBufferByteCount > 0) {
557 // This alignment code is most likely bogus, but we'll leave
558 // it in for now in case it matters for some plugins on some
559 // architectures. Who knows...
560 if (writeCount % sizeof(PRWord)) {
561 // memmove will take care about alignment
562 memmove(mStreamBuffer, ptrStreamBuffer + writeCount,
563 mStreamBufferByteCount);
564 ptrStreamBuffer = mStreamBuffer;
565 } else {
566 // if aligned we can use ptrStreamBuffer += to eliminate
567 // memmove()
568 ptrStreamBuffer += writeCount;
571 } else if (writeCount == 0) {
572 // if NPP_Write() returns writeCount == 0 lets say 3 times in
573 // a row, suspend the request and continue feeding the plugin
574 // the data we got so far. Once that data is consumed, we'll
575 // resume the request.
576 if (mIsSuspended || ++zeroBytesWriteCount == 3) {
577 if (!mIsSuspended) {
578 rv = SuspendRequest();
581 // Break out of the for loop, but keep going through the
582 // while loop in case there's more data to read from the
583 // input stream.
585 break;
587 } else {
588 // Something's really wrong, kill the stream.
589 rv = NS_ERROR_FAILURE;
591 break;
593 } // end of inner while loop
595 if (mStreamBufferByteCount && mStreamBuffer != ptrStreamBuffer) {
596 memmove(mStreamBuffer, ptrStreamBuffer, mStreamBufferByteCount);
600 if (streamPosition != streamOffset) {
601 // The plugin didn't consume all available data, or consumed some
602 // of our cached data while we're pumping cached data. Adjust the
603 // plugin info's stream offset to match reality, except if the
604 // plugin info's stream offset was set by a re-entering
605 // NPN_RequestRead() call.
607 PRInt32 postWriteStreamPosition;
608 pluginInfo->GetStreamOffset(&postWriteStreamPosition);
610 if (postWriteStreamPosition == streamOffset) {
611 pluginInfo->SetStreamOffset(streamPosition);
615 return rv;
618 NS_IMETHODIMP
619 nsNPAPIPluginStreamListener::OnFileAvailable(nsIPluginStreamInfo* pluginInfo,
620 const char* fileName)
622 if (!mInst || !mInst->IsStarted())
623 return NS_ERROR_FAILURE;
625 PluginDestructionGuard guard(mInst);
627 const NPPluginFuncs *callbacks = nsnull;
628 mInst->GetCallbacks(&callbacks);
629 if (!callbacks || !callbacks->asfile)
630 return NS_ERROR_FAILURE;
632 NPP npp;
633 mInst->GetNPP(&npp);
635 PRLibrary* lib = nsnull;
636 lib = mInst->fLibrary;
638 NS_TRY_SAFE_CALL_VOID((*callbacks->asfile)(npp, &mNPStream, fileName), lib, mInst);
640 NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
641 ("NPP StreamAsFile called: this=%p, npp=%p, url=%s, file=%s\n",
642 this, npp, mNPStream.url, fileName));
644 return NS_OK;
647 NS_IMETHODIMP
648 nsNPAPIPluginStreamListener::OnStopBinding(nsIPluginStreamInfo* pluginInfo,
649 nsresult status)
651 StopDataPump();
653 if (NS_FAILED(status)) {
654 // The stream was destroyed, or died for some reason. Make sure we
655 // cancel the underlying request.
656 nsCOMPtr<nsINPAPIPluginStreamInfo> pluginInfoNPAPI =
657 do_QueryInterface(mStreamInfo);
659 nsIRequest *request;
660 if (pluginInfoNPAPI && (request = pluginInfoNPAPI->GetRequest())) {
661 request->Cancel(status);
665 if (!mInst || !mInst->IsStarted())
666 return NS_ERROR_FAILURE;
668 // check if the stream is of seekable type and later its destruction
669 // see bug 91140
670 nsresult rv = NS_OK;
671 if (mStreamType != nsPluginStreamType_Seek) {
672 NPReason reason = NPRES_DONE;
674 if (NS_FAILED(status))
675 reason = NPRES_NETWORK_ERR; // since the stream failed, we need to tell the plugin that
677 rv = CleanUpStream(reason);
680 if (rv != NPERR_NO_ERROR)
681 return NS_ERROR_FAILURE;
683 return NS_OK;
686 NS_IMETHODIMP
687 nsNPAPIPluginStreamListener::GetStreamType(nsPluginStreamType *result)
689 *result = mStreamType;
690 return NS_OK;
693 NS_IMETHODIMP
694 nsNPAPIPluginStreamListener::Notify(nsITimer *aTimer)
696 NS_ASSERTION(aTimer == mDataPumpTimer, "Uh, wrong timer?");
698 PRInt32 oldStreamBufferByteCount = mStreamBufferByteCount;
700 nsresult rv = OnDataAvailable(mStreamInfo, nsnull, mStreamBufferByteCount);
702 if (NS_FAILED(rv)) {
703 // We ran into an error, no need to keep firing this timer then.
704 aTimer->Cancel();
705 return NS_OK;
708 if (mStreamBufferByteCount != oldStreamBufferByteCount &&
709 ((mStreamStarted && mStreamBufferByteCount < 1024) ||
710 mStreamBufferByteCount == 0)) {
711 // The plugin read some data and we've got less than 1024 bytes in
712 // our buffer (or its empty and the stream is already
713 // done). Resume the request so that we get more data off the
714 // network.
715 ResumeRequest();
716 // Necko will pump data now that we've resumed the request.
717 StopDataPump();
720 return NS_OK;
723 NS_IMETHODIMP
724 nsNPAPIPluginStreamListener::StatusLine(const char* line)
726 mResponseHeaders.Append(line);
727 mResponseHeaders.Append('\n');
728 return NS_OK;
731 NS_IMETHODIMP
732 nsNPAPIPluginStreamListener::NewResponseHeader(const char* headerName,
733 const char* headerValue)
735 mResponseHeaders.Append(headerName);
736 mResponseHeaders.Append(": ");
737 mResponseHeaders.Append(headerValue);
738 mResponseHeaders.Append('\n');
739 return NS_OK;
742 nsInstanceStream::nsInstanceStream()
744 mNext = nsnull;
745 mPluginStreamListener = nsnull;
748 nsInstanceStream::~nsInstanceStream()
752 NS_IMPL_ISUPPORTS3(nsNPAPIPluginInstance, nsIPluginInstance, nsIScriptablePlugin,
753 nsIPluginInstanceInternal)
755 nsNPAPIPluginInstance::nsNPAPIPluginInstance(NPPluginFuncs* callbacks,
756 PRLibrary* aLibrary)
757 : fCallbacks(callbacks),
758 #ifdef XP_MACOSX
759 #ifdef NP_NO_QUICKDRAW
760 mDrawingModel(NPDrawingModelCoreGraphics),
761 #else
762 mDrawingModel(NPDrawingModelQuickDraw),
763 #endif
764 #endif
765 mWindowless(PR_FALSE),
766 mTransparent(PR_FALSE),
767 mStarted(PR_FALSE),
768 mCached(PR_FALSE),
769 mIsJavaPlugin(PR_FALSE),
770 mWantsAllNetworkStreams(PR_FALSE),
771 mInPluginInitCall(PR_FALSE),
772 fLibrary(aLibrary),
773 mStreams(nsnull)
775 NS_ASSERTION(fCallbacks != NULL, "null callbacks");
777 // Initialize the NPP structure.
779 fNPP.pdata = NULL;
780 fNPP.ndata = this;
782 PLUGIN_LOG(PLUGIN_LOG_BASIC, ("nsNPAPIPluginInstance ctor: this=%p\n",this));
785 nsNPAPIPluginInstance::~nsNPAPIPluginInstance(void)
787 PLUGIN_LOG(PLUGIN_LOG_BASIC, ("nsNPAPIPluginInstance dtor: this=%p\n",this));
789 // clean the stream list if any
790 for (nsInstanceStream *is = mStreams; is != nsnull;) {
791 nsInstanceStream * next = is->mNext;
792 delete is;
793 is = next;
797 PRBool
798 nsNPAPIPluginInstance::IsStarted(void)
800 return mStarted;
803 NS_IMETHODIMP nsNPAPIPluginInstance::Initialize(nsIPluginInstancePeer* peer)
805 PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::Initialize this=%p\n",this));
807 return InitializePlugin(peer);
810 NS_IMETHODIMP nsNPAPIPluginInstance::GetPeer(nsIPluginInstancePeer* *resultingPeer)
812 *resultingPeer = mPeer;
813 NS_IF_ADDREF(*resultingPeer);
815 return NS_OK;
818 NS_IMETHODIMP nsNPAPIPluginInstance::Start(void)
820 PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::Start this=%p\n",this));
822 if (mStarted)
823 return NS_OK;
825 return InitializePlugin(mPeer);
828 NS_IMETHODIMP nsNPAPIPluginInstance::Stop(void)
830 PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::Stop this=%p\n",this));
832 NPError error;
834 // Make sure the plugin didn't leave popups enabled.
835 if (mPopupStates.Count() > 0) {
836 nsCOMPtr<nsPIDOMWindow> window = GetDOMWindow();
838 if (window) {
839 window->PopPopupControlState(openAbused);
843 if (!mStarted)
844 return NS_OK;
846 // If there's code from this plugin instance on the stack, delay the
847 // destroy.
848 if (PluginDestructionGuard::DelayDestroy(this)) {
849 return NS_OK;
852 // Make sure we lock while we're writing to mStarted after we've
853 // started as other threads might be checking that inside a lock.
854 EnterAsyncPluginThreadCallLock();
855 mStarted = PR_FALSE;
856 ExitAsyncPluginThreadCallLock();
858 OnPluginDestroy(&fNPP);
860 if (fCallbacks->destroy == NULL)
861 return NS_ERROR_FAILURE;
863 NPSavedData *sdata = 0;
865 // clean up open streams
866 for (nsInstanceStream *is = mStreams; is != nsnull;) {
867 nsNPAPIPluginStreamListener * listener = is->mPluginStreamListener;
869 nsInstanceStream *next = is->mNext;
870 delete is;
871 is = next;
872 mStreams = is;
874 // Clean up our stream after removing it from the list because
875 // it may be released and destroyed at this point.
876 if (listener)
877 listener->CleanUpStream(NPRES_USER_BREAK);
880 NS_TRY_SAFE_CALL_RETURN(error, (*fCallbacks->destroy)(&fNPP, &sdata), fLibrary, this);
882 NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
883 ("NPP Destroy called: this=%p, npp=%p, return=%d\n", this, &fNPP, error));
885 nsJSNPRuntime::OnPluginDestroy(&fNPP);
887 if (error != NPERR_NO_ERROR)
888 return NS_ERROR_FAILURE;
889 else
890 return NS_OK;
893 already_AddRefed<nsPIDOMWindow>
894 nsNPAPIPluginInstance::GetDOMWindow()
896 nsCOMPtr<nsPIPluginInstancePeer> pp (do_QueryInterface(mPeer));
897 if (!pp)
898 return nsnull;
900 nsCOMPtr<nsIPluginInstanceOwner> owner;
901 pp->GetOwner(getter_AddRefs(owner));
902 if (!owner)
903 return nsnull;
905 nsCOMPtr<nsIDocument> doc;
906 owner->GetDocument(getter_AddRefs(doc));
907 if (!doc)
908 return nsnull;
910 nsPIDOMWindow *window = doc->GetWindow();
911 NS_IF_ADDREF(window);
913 return window;
916 nsresult nsNPAPIPluginInstance::InitializePlugin(nsIPluginInstancePeer* peer)
918 NS_ENSURE_ARG_POINTER(peer);
920 nsCOMPtr<nsIPluginTagInfo2> taginfo = do_QueryInterface(peer);
921 NS_ENSURE_TRUE(taginfo, NS_ERROR_NO_INTERFACE);
923 PluginDestructionGuard guard(this);
925 PRUint16 count = 0;
926 const char* const* names = nsnull;
927 const char* const* values = nsnull;
928 nsPluginTagType tagtype;
929 nsresult rv = taginfo->GetTagType(&tagtype);
930 if (NS_SUCCEEDED(rv)) {
931 // Note: If we failed to get the tag type, we may be a full page plugin, so no arguments
932 rv = taginfo->GetAttributes(count, names, values);
933 NS_ENSURE_SUCCESS(rv, rv);
935 // nsPluginTagType_Object or Applet may also have PARAM tags
936 // Note: The arrays handed back by GetParameters() are
937 // crafted specially to be directly behind the arrays from GetAttributes()
938 // with a null entry as a separator. This is for 4.x backwards compatibility!
939 // see bug 111008 for details
940 if (tagtype != nsPluginTagType_Embed) {
941 PRUint16 pcount = 0;
942 const char* const* pnames = nsnull;
943 const char* const* pvalues = nsnull;
944 if (NS_SUCCEEDED(taginfo->GetParameters(pcount, pnames, pvalues))) {
945 NS_ASSERTION(!values[count], "attribute/parameter array not setup correctly for NPAPI plugins");
946 if (pcount)
947 count += ++pcount; // if it's all setup correctly, then all we need is to
948 // change the count (attrs + PARAM/blank + params)
953 NS_ENSURE_TRUE(fCallbacks->newp, NS_ERROR_FAILURE);
955 // XXX Note that the NPPluginType_* enums were crafted to be
956 // backward compatible...
958 nsPluginMode mode;
959 nsMIMEType mimetype;
960 NPError error;
962 peer->GetMode(&mode);
963 peer->GetMIMEType(&mimetype);
965 // Some older versions of Flash have a bug in them
966 // that causes the stack to become currupt if we
967 // pass swliveconect=1 in the NPP_NewProc arrays.
968 // See bug 149336 (UNIX), bug 186287 (Mac)
970 // The code below disables the attribute unless
971 // the environment variable:
972 // MOZILLA_PLUGIN_DISABLE_FLASH_SWLIVECONNECT_HACK
973 // is set.
975 // It is okay to disable this attribute because
976 // back in 4.x, scripting required liveconnect to
977 // start Java which was slow. Scripting no longer
978 // requires starting Java and is quick plus controled
979 // from the browser, so Flash now ignores this attribute.
981 // This code can not be put at the time of creating
982 // the array because we may need to examine the
983 // stream header to determine we want Flash.
985 static const char flashMimeType[] = "application/x-shockwave-flash";
986 static const char blockedParam[] = "swliveconnect";
987 if (count && !PL_strcasecmp(mimetype, flashMimeType)) {
988 static int cachedDisableHack = 0;
989 if (!cachedDisableHack) {
990 if (PR_GetEnv("MOZILLA_PLUGIN_DISABLE_FLASH_SWLIVECONNECT_HACK"))
991 cachedDisableHack = -1;
992 else
993 cachedDisableHack = 1;
995 if (cachedDisableHack > 0) {
996 for (PRUint16 i=0; i<count; i++) {
997 if (!PL_strcasecmp(names[i], blockedParam)) {
998 // BIG FAT WARNIG:
999 // I'm ugly casting |const char*| to |char*| and altering it
1000 // because I know we do malloc it values in
1001 // http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/layout/html/base/src/nsObjectFrame.cpp&rev=1.349&root=/cvsroot#3020
1002 // and free it at line #2096, so it couldn't be a const ptr to string literal
1003 char *val = (char*) values[i];
1004 if (val && *val) {
1005 // we cannot just *val=0, it won't be free properly in such case
1006 val[0] = '0';
1007 val[1] = 0;
1009 break;
1015 mIsJavaPlugin = nsPluginHostImpl::IsJavaMIMEType(mimetype);
1017 // Assign mPeer now and mark this instance as started before calling NPP_New
1018 // because the plugin may call other NPAPI functions, like NPN_GetURLNotify,
1019 // that assume these are set before returning. If the plugin returns failure,
1020 // we'll clear them out below.
1021 mPeer = peer;
1022 mStarted = PR_TRUE;
1024 PRBool oldVal = mInPluginInitCall;
1025 mInPluginInitCall = PR_TRUE;
1027 NS_TRY_SAFE_CALL_RETURN(error, (*fCallbacks->newp)((char*)mimetype, &fNPP, (PRUint16)mode, count, (char**)names, (char**)values, NULL), fLibrary,this);
1029 mInPluginInitCall = oldVal;
1031 NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
1032 ("NPP New called: this=%p, npp=%p, mime=%s, mode=%d, argc=%d, return=%d\n",
1033 this, &fNPP, mimetype, mode, count, error));
1035 if (error != NPERR_NO_ERROR) {
1036 // since the plugin returned failure, these should not be set
1037 mPeer = nsnull;
1038 mStarted = PR_FALSE;
1040 return NS_ERROR_FAILURE;
1043 return NS_OK;
1046 NS_IMETHODIMP nsNPAPIPluginInstance::Destroy(void)
1048 PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::Destroy this=%p\n",this));
1050 // destruction is handled in the Stop call
1051 return NS_OK;
1054 NS_IMETHODIMP nsNPAPIPluginInstance::SetWindow(nsPluginWindow* window)
1056 // XXX NPAPI plugins don't want a SetWindow(NULL).
1057 if (!window || !mStarted)
1058 return NS_OK;
1060 NPError error;
1062 #if defined (MOZ_WIDGET_GTK2)
1063 // bug 108347, flash plugin on linux doesn't like window->width <=
1064 // 0, but Java needs wants this call.
1065 if (!mIsJavaPlugin && window->type == nsPluginWindowType_Window &&
1066 (window->width <= 0 || window->height <= 0)) {
1067 return NS_OK;
1069 #endif // MOZ_WIDGET
1071 if (fCallbacks->setwindow) {
1072 PluginDestructionGuard guard(this);
1074 // XXX Turns out that NPPluginWindow and NPWindow are structurally
1075 // identical (on purpose!), so there's no need to make a copy.
1077 PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::SetWindow (about to call it) this=%p\n",this));
1079 PRBool oldVal = mInPluginInitCall;
1080 mInPluginInitCall = PR_TRUE;
1082 NS_TRY_SAFE_CALL_RETURN(error, (*fCallbacks->setwindow)(&fNPP, (NPWindow*)window), fLibrary, this);
1084 mInPluginInitCall = oldVal;
1086 NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
1087 ("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",
1088 this, window->x, window->y, window->width, window->height,
1089 window->clipRect.top, window->clipRect.bottom, window->clipRect.left, window->clipRect.right, error));
1091 // XXX In the old code, we'd just ignore any errors coming
1092 // back from the plugin's SetWindow(). Is this the correct
1093 // behavior?!?
1095 return NS_OK;
1098 /* NOTE: the caller must free the stream listener */
1099 // Create a normal stream, one without a urlnotify callback
1100 NS_IMETHODIMP nsNPAPIPluginInstance::NewStream(nsIPluginStreamListener** listener)
1102 return NewNotifyStream(listener, nsnull, PR_FALSE, nsnull);
1105 // Create a stream that will notify when complete
1106 nsresult nsNPAPIPluginInstance::NewNotifyStream(nsIPluginStreamListener** listener,
1107 void* notifyData,
1108 PRBool aCallNotify,
1109 const char* aURL)
1111 nsNPAPIPluginStreamListener* stream = new nsNPAPIPluginStreamListener(this, notifyData, aURL);
1112 NS_ENSURE_TRUE(stream, NS_ERROR_OUT_OF_MEMORY);
1114 // add it to the list
1115 nsInstanceStream * is = new nsInstanceStream();
1116 NS_ENSURE_TRUE(is, NS_ERROR_OUT_OF_MEMORY);
1118 is->mNext = mStreams;
1119 is->mPluginStreamListener = stream;
1120 mStreams = is;
1121 stream->SetCallNotify(aCallNotify); // set flag in stream to call URLNotify
1123 NS_ADDREF(stream); // Stabilize
1125 nsresult res = stream->QueryInterface(kIPluginStreamListenerIID, (void**)listener);
1127 // Destabilize and avoid leaks. Avoid calling delete <interface pointer>
1128 NS_RELEASE(stream);
1130 return res;
1133 NS_IMETHODIMP nsNPAPIPluginInstance::Print(nsPluginPrint* platformPrint)
1135 NS_ENSURE_TRUE(platformPrint, NS_ERROR_NULL_POINTER);
1137 PluginDestructionGuard guard(this);
1139 NPPrint* thePrint = (NPPrint *)platformPrint;
1141 // to be compatible with the older SDK versions and to match what
1142 // NPAPI and other browsers do, overwrite |window.type| field with one
1143 // more copy of |platformPrint|. See bug 113264
1144 if (fCallbacks) {
1145 PRUint16 sdkmajorversion = (fCallbacks->version & 0xff00)>>8;
1146 PRUint16 sdkminorversion = fCallbacks->version & 0x00ff;
1147 if ((sdkmajorversion == 0) && (sdkminorversion < 11)) {
1148 // Let's copy platformPrint bytes over to where it was supposed to be
1149 // in older versions -- four bytes towards the beginning of the struct
1150 // but we should be careful about possible misalignments
1151 if (sizeof(NPWindowType) >= sizeof(void *)) {
1152 void* source = thePrint->print.embedPrint.platformPrint;
1153 void** destination = (void **)&(thePrint->print.embedPrint.window.type);
1154 *destination = source;
1156 else
1157 NS_ASSERTION(PR_FALSE, "Incompatible OS for assignment");
1161 if (fCallbacks->print)
1162 NS_TRY_SAFE_CALL_VOID((*fCallbacks->print)(&fNPP, thePrint), fLibrary, this);
1164 NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
1165 ("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",
1166 this,
1167 platformPrint->print.embedPrint.platformPrint,
1168 platformPrint->print.embedPrint.window.x,
1169 platformPrint->print.embedPrint.window.y,
1170 platformPrint->print.embedPrint.window.width,
1171 platformPrint->print.embedPrint.window.height,
1172 platformPrint->print.embedPrint.window.clipRect.top,
1173 platformPrint->print.embedPrint.window.clipRect.bottom,
1174 platformPrint->print.embedPrint.window.clipRect.left,
1175 platformPrint->print.embedPrint.window.clipRect.right));
1177 return NS_OK;
1180 NS_IMETHODIMP nsNPAPIPluginInstance::HandleEvent(nsPluginEvent* event, PRBool* handled)
1182 if (!mStarted)
1183 return NS_OK;
1185 if (!event)
1186 return NS_ERROR_FAILURE;
1188 PluginDestructionGuard guard(this);
1190 PRInt16 result = 0;
1192 if (fCallbacks->event) {
1193 #ifdef XP_MACOSX
1194 result = (*fCallbacks->event)(&fNPP, (void*)event->event);
1196 #elif defined(XP_WIN) || defined(XP_OS2)
1197 NPEvent npEvent;
1198 npEvent.event = event->event;
1199 npEvent.wParam = event->wParam;
1200 npEvent.lParam = event->lParam;
1202 NS_TRY_SAFE_CALL_RETURN(result, (*fCallbacks->event)(&fNPP, (void*)&npEvent), fLibrary, this);
1204 #else // MOZ_X11 or other
1205 result = (*fCallbacks->event)(&fNPP, (void*)&event->event);
1206 #endif
1208 NPP_PLUGIN_LOG(PLUGIN_LOG_NOISY,
1209 ("NPP HandleEvent called: this=%p, npp=%p, event=%d, return=%d\n",
1210 this, &fNPP, event->event, result));
1212 *handled = result;
1215 return NS_OK;
1218 nsresult nsNPAPIPluginInstance::GetValueInternal(NPPVariable variable, void* value)
1220 nsresult res = NS_OK;
1221 if (fCallbacks->getvalue && mStarted) {
1222 PluginDestructionGuard guard(this);
1224 NS_TRY_SAFE_CALL_RETURN(res, (*fCallbacks->getvalue)(&fNPP, variable, value), fLibrary, this);
1225 NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
1226 ("NPP GetValue called: this=%p, npp=%p, var=%d, value=%d, return=%d\n",
1227 this, &fNPP, variable, value, res));
1229 #ifdef XP_OS2
1230 /* Query interface for legacy Flash plugin */
1231 if (res == NS_OK && variable == NPPVpluginScriptableInstance) {
1232 nsCOMPtr<nsILegacyPluginWrapperOS2> wrapper =
1233 do_GetService(NS_LEGACY_PLUGIN_WRAPPER_CONTRACTID, &res);
1234 if (res == NS_OK) {
1235 nsIID *iid = nsnull;
1236 res = (*fCallbacks->getvalue)(&fNPP, NPPVpluginScriptableIID, (void *)&iid);
1237 if (res == NS_OK)
1238 res = wrapper->MaybeWrap(*iid, *(nsISupports**)value, (nsISupports**)value);
1241 #endif
1244 return res;
1247 NS_IMETHODIMP nsNPAPIPluginInstance::GetValue(nsPluginInstanceVariable variable, void *value)
1249 nsresult res = NS_OK;
1251 switch (variable) {
1252 case nsPluginInstanceVariable_WindowlessBool:
1253 *(PRBool *)value = mWindowless;
1254 break;
1256 case nsPluginInstanceVariable_TransparentBool:
1257 *(PRBool *)value = mTransparent;
1258 break;
1260 case nsPluginInstanceVariable_DoCacheBool:
1261 *(PRBool *)value = mCached;
1262 break;
1264 case nsPluginInstanceVariable_CallSetWindowAfterDestroyBool:
1265 *(PRBool *)value = 0; // not supported for 4.x plugins
1266 break;
1268 #ifdef XP_MACOSX
1269 case nsPluginInstanceVariable_DrawingModel:
1270 *(NPDrawingModel*)value = mDrawingModel;
1271 break;
1272 #endif
1274 default:
1275 res = GetValueInternal((NPPVariable)variable, value);
1278 return res;
1281 nsresult nsNPAPIPluginInstance::GetNPP(NPP* aNPP)
1283 if (aNPP)
1284 *aNPP = &fNPP;
1285 else
1286 return NS_ERROR_NULL_POINTER;
1288 return NS_OK;
1291 nsresult nsNPAPIPluginInstance::GetCallbacks(const NPPluginFuncs ** aCallbacks)
1293 if (aCallbacks)
1294 *aCallbacks = fCallbacks;
1295 else
1296 return NS_ERROR_NULL_POINTER;
1298 return NS_OK;
1301 NPError nsNPAPIPluginInstance::SetWindowless(PRBool aWindowless)
1303 mWindowless = aWindowless;
1304 return NPERR_NO_ERROR;
1307 NPError nsNPAPIPluginInstance::SetTransparent(PRBool aTransparent)
1309 mTransparent = aTransparent;
1310 return NPERR_NO_ERROR;
1313 NPError nsNPAPIPluginInstance::SetWantsAllNetworkStreams(PRBool aWantsAllNetworkStreams)
1315 mWantsAllNetworkStreams = aWantsAllNetworkStreams;
1316 return NPERR_NO_ERROR;
1319 #ifdef XP_MACOSX
1320 void nsNPAPIPluginInstance::SetDrawingModel(NPDrawingModel aModel)
1322 mDrawingModel = aModel;
1325 NPDrawingModel nsNPAPIPluginInstance::GetDrawingModel()
1327 return mDrawingModel;
1329 #endif
1331 /* readonly attribute nsQIResult scriptablePeer; */
1332 NS_IMETHODIMP nsNPAPIPluginInstance::GetScriptablePeer(void * *aScriptablePeer)
1334 if (!aScriptablePeer)
1335 return NS_ERROR_NULL_POINTER;
1337 *aScriptablePeer = nsnull;
1338 return GetValueInternal(NPPVpluginScriptableInstance, aScriptablePeer);
1341 /* readonly attribute nsIIDPtr scriptableInterface; */
1342 NS_IMETHODIMP nsNPAPIPluginInstance::GetScriptableInterface(nsIID * *aScriptableInterface)
1344 if (!aScriptableInterface)
1345 return NS_ERROR_NULL_POINTER;
1347 *aScriptableInterface = nsnull;
1348 return GetValueInternal(NPPVpluginScriptableIID, (void*)aScriptableInterface);
1351 JSObject *
1352 nsNPAPIPluginInstance::GetJSObject(JSContext *cx)
1354 JSObject *obj = nsnull;
1355 NPObject *npobj = nsnull;
1357 nsresult rv = GetValueInternal(NPPVpluginScriptableNPObject, &npobj);
1359 if (NS_SUCCEEDED(rv) && npobj) {
1360 obj = nsNPObjWrapper::GetNewOrUsed(&fNPP, cx, npobj);
1362 _releaseobject(npobj);
1365 return obj;
1368 void
1369 nsNPAPIPluginInstance::DefineJavaProperties()
1371 NPObject *plugin_obj = nsnull;
1373 // The dummy Java plugin's scriptable object is what we want to
1374 // expose as window.Packages. And Window.Packages.java will be
1375 // exposed as window.java.
1377 // Get the scriptable plugin object.
1378 nsresult rv = GetValueInternal(NPPVpluginScriptableNPObject, &plugin_obj);
1380 if (NS_FAILED(rv) || !plugin_obj) {
1381 return;
1384 // Get the NPObject wrapper for window.
1385 NPObject *window_obj = _getwindowobject(&fNPP);
1387 if (!window_obj) {
1388 _releaseobject(plugin_obj);
1390 return;
1393 NPIdentifier java_id = _getstringidentifier("java");
1394 NPIdentifier packages_id = _getstringidentifier("Packages");
1396 NPObject *java_obj = nsnull;
1397 NPVariant v;
1398 OBJECT_TO_NPVARIANT(plugin_obj, v);
1400 // Define the properties.
1402 bool ok = _setproperty(&fNPP, window_obj, packages_id, &v);
1403 if (ok) {
1404 ok = _getproperty(&fNPP, plugin_obj, java_id, &v);
1406 if (ok && NPVARIANT_IS_OBJECT(v)) {
1407 // Set java_obj so that we properly release it at the end of
1408 // this function.
1409 java_obj = NPVARIANT_TO_OBJECT(v);
1411 ok = _setproperty(&fNPP, window_obj, java_id, &v);
1415 _releaseobject(window_obj);
1416 _releaseobject(plugin_obj);
1417 _releaseobject(java_obj);
1420 nsresult
1421 nsNPAPIPluginInstance::GetFormValue(nsAString& aValue)
1423 aValue.Truncate();
1425 char *value = nsnull;
1426 nsresult rv = GetValueInternal(NPPVformValue, &value);
1428 if (NS_SUCCEEDED(rv) && value) {
1429 CopyUTF8toUTF16(value, aValue);
1431 // NPPVformValue allocates with NPN_MemAlloc(), which uses
1432 // nsMemory.
1433 nsMemory::Free(value);
1436 return NS_OK;
1439 void
1440 nsNPAPIPluginInstance::PushPopupsEnabledState(PRBool aEnabled)
1442 nsCOMPtr<nsPIDOMWindow> window = GetDOMWindow();
1443 if (!window)
1444 return;
1446 PopupControlState oldState =
1447 window->PushPopupControlState(aEnabled ? openAllowed : openAbused,
1448 PR_TRUE);
1450 if (!mPopupStates.AppendElement(NS_INT32_TO_PTR(oldState))) {
1451 // Appending to our state stack failed, push what we just popped.
1452 window->PopPopupControlState(oldState);
1456 void
1457 nsNPAPIPluginInstance::PopPopupsEnabledState()
1459 PRInt32 last = mPopupStates.Count() - 1;
1461 if (last < 0) {
1462 // Nothing to pop.
1463 return;
1466 nsCOMPtr<nsPIDOMWindow> window = GetDOMWindow();
1467 if (!window)
1468 return;
1470 PopupControlState oldState =
1471 (PopupControlState)NS_PTR_TO_INT32(mPopupStates[last]);
1473 window->PopPopupControlState(oldState);
1475 mPopupStates.RemoveElementAt(last);
1478 PRUint16
1479 nsNPAPIPluginInstance::GetPluginAPIVersion()
1481 return fCallbacks->version;