Fix regexp match pair end-index == -1 assumption. (r=dmandelin, a=blocker b=605754)
[mozilla-central.git] / dom / plugins / PluginModuleParent.cpp
blob032a3eb83880c839ef29ed4575f1f552559469b9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: sw=4 ts=4 et :
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is Mozilla Plugin App.
18 * The Initial Developer of the Original Code is
19 * Chris Jones <jones.chris.g@gmail.com>
20 * Portions created by the Initial Developer are Copyright (C) 2009
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 #ifdef MOZ_WIDGET_GTK2
40 #include <glib.h>
41 #elif XP_MACOSX
42 #include "PluginUtilsOSX.h"
43 #include "PluginInterposeOSX.h"
44 #endif
45 #ifdef MOZ_WIDGET_QT
46 #include <QtCore/QCoreApplication>
47 #include <QtCore/QEventLoop>
48 #endif
50 #include "base/process_util.h"
52 #include "mozilla/unused.h"
53 #include "mozilla/ipc/SyncChannel.h"
54 #include "mozilla/plugins/PluginModuleParent.h"
55 #include "mozilla/plugins/BrowserStreamParent.h"
56 #include "PluginIdentifierParent.h"
58 #include "nsAutoPtr.h"
59 #include "nsContentUtils.h"
60 #include "nsCRT.h"
61 #ifdef MOZ_CRASHREPORTER
62 #include "nsExceptionHandler.h"
63 #endif
64 #include "nsNPAPIPlugin.h"
66 using base::KillProcess;
68 using mozilla::PluginLibrary;
69 using mozilla::ipc::SyncChannel;
71 using namespace mozilla::plugins;
73 static const char kTimeoutPref[] = "dom.ipc.plugins.timeoutSecs";
74 static const char kLaunchTimeoutPref[] = "dom.ipc.plugins.processLaunchTimeoutSecs";
76 template<>
77 struct RunnableMethodTraits<mozilla::plugins::PluginModuleParent>
79 typedef mozilla::plugins::PluginModuleParent Class;
80 static void RetainCallee(Class* obj) { }
81 static void ReleaseCallee(Class* obj) { }
84 // static
85 PluginLibrary*
86 PluginModuleParent::LoadModule(const char* aFilePath)
88 PLUGIN_LOG_DEBUG_FUNCTION;
90 PRInt32 prefSecs = nsContentUtils::GetIntPref(kLaunchTimeoutPref, 0);
92 // Block on the child process being launched and initialized.
93 nsAutoPtr<PluginModuleParent> parent(new PluginModuleParent(aFilePath));
94 bool launched = parent->mSubprocess->Launch(prefSecs * 1000);
95 if (!launched) {
96 // Need to set this so the destructor doesn't complain.
97 parent->mShutdown = true;
98 return nsnull;
100 parent->Open(parent->mSubprocess->GetChannel(),
101 parent->mSubprocess->GetChildProcessHandle());
103 TimeoutChanged(kTimeoutPref, parent);
104 return parent.forget();
108 PluginModuleParent::PluginModuleParent(const char* aFilePath)
109 : mSubprocess(new PluginProcessParent(aFilePath))
110 , mPluginThread(0)
111 , mShutdown(false)
112 , mNPNIface(NULL)
113 , mPlugin(NULL)
114 , mProcessStartTime(time(NULL))
115 , mTaskFactory(this)
117 NS_ASSERTION(mSubprocess, "Out of memory!");
119 if (!mIdentifiers.Init()) {
120 NS_ERROR("Out of memory");
123 nsContentUtils::RegisterPrefCallback(kTimeoutPref, TimeoutChanged, this);
126 PluginModuleParent::~PluginModuleParent()
128 NS_ASSERTION(OkToCleanup(), "unsafe destruction");
130 #ifdef OS_MACOSX
131 if (mCATimer) {
132 mCATimer->Cancel();
134 #endif
136 if (!mShutdown) {
137 NS_WARNING("Plugin host deleted the module without shutting down.");
138 NPError err;
139 NP_Shutdown(&err);
141 NS_ASSERTION(mShutdown, "NP_Shutdown didn't");
143 if (mSubprocess) {
144 mSubprocess->Delete();
145 mSubprocess = nsnull;
148 nsContentUtils::UnregisterPrefCallback(kTimeoutPref, TimeoutChanged, this);
151 #ifdef MOZ_CRASHREPORTER
152 void
153 PluginModuleParent::WritePluginExtraDataForMinidump(const nsAString& id)
155 typedef nsDependentCString CS;
157 CrashReporter::AnnotationTable notes;
158 if (!notes.Init(32))
159 return;
161 notes.Put(CS("ProcessType"), CS("plugin"));
163 char startTime[32];
164 sprintf(startTime, "%lld", static_cast<PRInt64>(mProcessStartTime));
165 notes.Put(CS("StartupTime"), CS(startTime));
167 // Get the plugin filename, try to get just the file leafname
168 const std::string& pluginFile = mSubprocess->GetPluginFilePath();
169 size_t filePos = pluginFile.rfind(FILE_PATH_SEPARATOR);
170 if (filePos == std::string::npos)
171 filePos = 0;
172 else
173 filePos++;
174 notes.Put(CS("PluginFilename"), CS(pluginFile.substr(filePos).c_str()));
176 //TODO: add plugin name and version: bug 539841
177 // (as PluginName, PluginVersion)
178 notes.Put(CS("PluginName"), CS(""));
179 notes.Put(CS("PluginVersion"), CS(""));
181 if (!mCrashNotes.IsEmpty())
182 notes.Put(CS("Notes"), CS(mCrashNotes.get()));
184 if (!mHangID.IsEmpty())
185 notes.Put(CS("HangID"), NS_ConvertUTF16toUTF8(mHangID));
187 if (!CrashReporter::AppendExtraData(id, notes))
188 NS_WARNING("problem appending plugin data to .extra");
191 void
192 PluginModuleParent::WriteExtraDataForHang()
194 // this writes HangID
195 WritePluginExtraDataForMinidump(mPluginDumpID);
197 CrashReporter::AnnotationTable notes;
198 if (!notes.Init(4))
199 return;
201 notes.Put(nsDependentCString("HangID"), NS_ConvertUTF16toUTF8(mHangID));
202 if (!CrashReporter::AppendExtraData(mBrowserDumpID, notes))
203 NS_WARNING("problem appending browser data to .extra");
205 #endif // MOZ_CRASHREPORTER
207 bool
208 PluginModuleParent::RecvAppendNotesToCrashReport(const nsCString& aNotes)
210 mCrashNotes.Append(aNotes);
211 return true;
215 PluginModuleParent::TimeoutChanged(const char* aPref, void* aModule)
217 NS_ASSERTION(NS_IsMainThread(), "Wrong thead!");
218 NS_ABORT_IF_FALSE(!strcmp(aPref, kTimeoutPref),
219 "unexpected pref callback");
221 PRInt32 timeoutSecs = nsContentUtils::GetIntPref(kTimeoutPref, 0);
222 int32 timeoutMs = (timeoutSecs > 0) ? (1000 * timeoutSecs) :
223 SyncChannel::kNoTimeout;
225 static_cast<PluginModuleParent*>(aModule)->SetReplyTimeoutMs(timeoutMs);
226 return 0;
229 void
230 PluginModuleParent::CleanupFromTimeout()
232 if (!mShutdown)
233 Close();
236 bool
237 PluginModuleParent::ShouldContinueFromReplyTimeout()
239 #ifdef MOZ_CRASHREPORTER
240 nsCOMPtr<nsILocalFile> pluginDump;
241 nsCOMPtr<nsILocalFile> browserDump;
242 CrashReporter::ProcessHandle child;
243 #ifdef XP_MACOSX
244 child = mSubprocess->GetChildTask();
245 #else
246 child = OtherProcess();
247 #endif
248 if (CrashReporter::CreatePairedMinidumps(child,
249 mPluginThread,
250 &mHangID,
251 getter_AddRefs(pluginDump),
252 getter_AddRefs(browserDump)) &&
253 CrashReporter::GetIDFromMinidump(pluginDump, mPluginDumpID) &&
254 CrashReporter::GetIDFromMinidump(browserDump, mBrowserDumpID)) {
256 PLUGIN_LOG_DEBUG(
257 ("generated paired browser/plugin minidumps: %s/%s (ID=%s)",
258 NS_ConvertUTF16toUTF8(mBrowserDumpID).get(),
259 NS_ConvertUTF16toUTF8(mPluginDumpID).get(),
260 NS_ConvertUTF16toUTF8(mHangID).get()));
262 else {
263 NS_WARNING("failed to capture paired minidumps from hang");
265 #endif
267 // this must run before the error notification from the channel,
268 // or not at all
269 MessageLoop::current()->PostTask(
270 FROM_HERE,
271 mTaskFactory.NewRunnableMethod(
272 &PluginModuleParent::CleanupFromTimeout));
274 if (!KillProcess(OtherProcess(), 1, false))
275 NS_WARNING("failed to kill subprocess!");
277 return false;
280 void
281 PluginModuleParent::ActorDestroy(ActorDestroyReason why)
283 switch (why) {
284 case AbnormalShutdown: {
285 #ifdef MOZ_CRASHREPORTER
286 nsCOMPtr<nsILocalFile> pluginDump;
287 if (TakeMinidump(getter_AddRefs(pluginDump)) &&
288 CrashReporter::GetIDFromMinidump(pluginDump, mPluginDumpID)) {
289 PLUGIN_LOG_DEBUG(("got child minidump: %s",
290 NS_ConvertUTF16toUTF8(mPluginDumpID).get()));
291 WritePluginExtraDataForMinidump(mPluginDumpID);
293 else if (!mPluginDumpID.IsEmpty() && !mBrowserDumpID.IsEmpty()) {
294 WriteExtraDataForHang();
296 else {
297 NS_WARNING("[PluginModuleParent::ActorDestroy] abnormal shutdown without minidump!");
299 #endif
301 mShutdown = true;
302 // Defer the PluginCrashed method so that we don't re-enter
303 // and potentially modify the actor child list while enumerating it.
304 if (mPlugin)
305 MessageLoop::current()->PostTask(
306 FROM_HERE,
307 mTaskFactory.NewRunnableMethod(
308 &PluginModuleParent::NotifyPluginCrashed));
309 break;
311 case NormalShutdown:
312 mShutdown = true;
313 break;
315 default:
316 NS_ERROR("Unexpected shutdown reason for toplevel actor.");
320 void
321 PluginModuleParent::NotifyPluginCrashed()
323 if (!OkToCleanup()) {
324 // there's still plugin code on the C++ stack. try again
325 MessageLoop::current()->PostDelayedTask(
326 FROM_HERE,
327 mTaskFactory.NewRunnableMethod(
328 &PluginModuleParent::NotifyPluginCrashed), 10);
329 return;
332 if (mPlugin)
333 mPlugin->PluginCrashed(mPluginDumpID, mBrowserDumpID);
336 PPluginIdentifierParent*
337 PluginModuleParent::AllocPPluginIdentifier(const nsCString& aString,
338 const int32_t& aInt)
340 NPIdentifier npident = aString.IsVoid() ?
341 mozilla::plugins::parent::_getintidentifier(aInt) :
342 mozilla::plugins::parent::_getstringidentifier(aString.get());
344 if (!npident) {
345 NS_WARNING("Failed to get identifier!");
346 return nsnull;
349 PluginIdentifierParent* ident = new PluginIdentifierParent(npident);
350 mIdentifiers.Put(npident, ident);
351 return ident;
354 bool
355 PluginModuleParent::DeallocPPluginIdentifier(PPluginIdentifierParent* aActor)
357 delete aActor;
358 return true;
361 PPluginInstanceParent*
362 PluginModuleParent::AllocPPluginInstance(const nsCString& aMimeType,
363 const uint16_t& aMode,
364 const InfallibleTArray<nsCString>& aNames,
365 const InfallibleTArray<nsCString>& aValues,
366 NPError* rv)
368 NS_ERROR("Not reachable!");
369 return NULL;
372 bool
373 PluginModuleParent::DeallocPPluginInstance(PPluginInstanceParent* aActor)
375 PLUGIN_LOG_DEBUG_METHOD;
376 delete aActor;
377 return true;
380 void
381 PluginModuleParent::SetPluginFuncs(NPPluginFuncs* aFuncs)
383 aFuncs->version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
384 aFuncs->javaClass = nsnull;
386 aFuncs->newp = nsnull; // Gecko should always call this through a PluginLibrary object
387 aFuncs->destroy = NPP_Destroy;
388 aFuncs->setwindow = NPP_SetWindow;
389 aFuncs->newstream = NPP_NewStream;
390 aFuncs->destroystream = NPP_DestroyStream;
391 aFuncs->asfile = NPP_StreamAsFile;
392 aFuncs->writeready = NPP_WriteReady;
393 aFuncs->write = NPP_Write;
394 aFuncs->print = NPP_Print;
395 aFuncs->event = NPP_HandleEvent;
396 aFuncs->urlnotify = NPP_URLNotify;
397 aFuncs->getvalue = NPP_GetValue;
398 aFuncs->setvalue = NPP_SetValue;
401 NPError
402 PluginModuleParent::NPP_Destroy(NPP instance,
403 NPSavedData** /*saved*/)
405 // FIXME/cjones:
406 // (1) send a "destroy" message to the child
407 // (2) the child shuts down its instance
408 // (3) remove both parent and child IDs from map
409 // (4) free parent
410 PLUGIN_LOG_DEBUG_FUNCTION;
412 PluginInstanceParent* parentInstance =
413 static_cast<PluginInstanceParent*>(instance->pdata);
415 if (!parentInstance)
416 return NPERR_NO_ERROR;
418 NPError retval = parentInstance->Destroy();
419 instance->pdata = nsnull;
421 unused << PluginInstanceParent::Call__delete__(parentInstance);
422 return retval;
425 NPError
426 PluginModuleParent::NPP_NewStream(NPP instance, NPMIMEType type,
427 NPStream* stream, NPBool seekable,
428 uint16_t* stype)
430 PluginInstanceParent* i = InstCast(instance);
431 if (!i)
432 return NPERR_GENERIC_ERROR;
434 return i->NPP_NewStream(type, stream, seekable,
435 stype);
438 NPError
439 PluginModuleParent::NPP_SetWindow(NPP instance, NPWindow* window)
441 PluginInstanceParent* i = InstCast(instance);
442 if (!i)
443 return NPERR_GENERIC_ERROR;
445 return i->NPP_SetWindow(window);
448 NPError
449 PluginModuleParent::NPP_DestroyStream(NPP instance,
450 NPStream* stream,
451 NPReason reason)
453 PluginInstanceParent* i = InstCast(instance);
454 if (!i)
455 return NPERR_GENERIC_ERROR;
457 return i->NPP_DestroyStream(stream, reason);
460 int32_t
461 PluginModuleParent::NPP_WriteReady(NPP instance,
462 NPStream* stream)
464 BrowserStreamParent* s = StreamCast(instance, stream);
465 if (!s)
466 return -1;
468 return s->WriteReady();
471 int32_t
472 PluginModuleParent::NPP_Write(NPP instance,
473 NPStream* stream,
474 int32_t offset,
475 int32_t len,
476 void* buffer)
478 BrowserStreamParent* s = StreamCast(instance, stream);
479 if (!s)
480 return -1;
482 return s->Write(offset, len, buffer);
485 void
486 PluginModuleParent::NPP_StreamAsFile(NPP instance,
487 NPStream* stream,
488 const char* fname)
490 BrowserStreamParent* s = StreamCast(instance, stream);
491 if (!s)
492 return;
494 s->StreamAsFile(fname);
497 void
498 PluginModuleParent::NPP_Print(NPP instance, NPPrint* platformPrint)
500 PluginInstanceParent* i = InstCast(instance);
501 if (i)
502 i->NPP_Print(platformPrint);
505 int16_t
506 PluginModuleParent::NPP_HandleEvent(NPP instance, void* event)
508 PluginInstanceParent* i = InstCast(instance);
509 if (!i)
510 return false;
512 return i->NPP_HandleEvent(event);
515 void
516 PluginModuleParent::NPP_URLNotify(NPP instance, const char* url,
517 NPReason reason, void* notifyData)
519 PluginInstanceParent* i = InstCast(instance);
520 if (!i)
521 return;
523 i->NPP_URLNotify(url, reason, notifyData);
526 NPError
527 PluginModuleParent::NPP_GetValue(NPP instance,
528 NPPVariable variable, void *ret_value)
530 PluginInstanceParent* i = InstCast(instance);
531 if (!i)
532 return NPERR_GENERIC_ERROR;
534 return i->NPP_GetValue(variable, ret_value);
537 NPError
538 PluginModuleParent::NPP_SetValue(NPP instance, NPNVariable variable,
539 void *value)
541 PluginInstanceParent* i = InstCast(instance);
542 if (!i)
543 return NPERR_GENERIC_ERROR;
545 return i->NPP_SetValue(variable, value);
548 bool
549 PluginModuleParent::RecvBackUpXResources(const FileDescriptor& aXSocketFd)
551 #ifndef MOZ_X11
552 NS_RUNTIMEABORT("This message only makes sense on X11 platforms");
553 #else
554 NS_ABORT_IF_FALSE(0 > mPluginXSocketFdDup.mFd,
555 "Already backed up X resources??");
556 mPluginXSocketFdDup.mFd = aXSocketFd.fd;
557 #endif
558 return true;
561 bool
562 PluginModuleParent::AnswerNPN_UserAgent(nsCString* userAgent)
564 *userAgent = NullableString(mNPNIface->uagent(nsnull));
565 return true;
568 PPluginIdentifierParent*
569 PluginModuleParent::GetIdentifierForNPIdentifier(NPIdentifier aIdentifier)
571 PluginIdentifierParent* ident;
572 if (!mIdentifiers.Get(aIdentifier, &ident)) {
573 nsCString string;
574 int32_t intval = -1;
575 if (mozilla::plugins::parent::_identifierisstring(aIdentifier)) {
576 NPUTF8* chars =
577 mozilla::plugins::parent::_utf8fromidentifier(aIdentifier);
578 if (!chars) {
579 return nsnull;
581 string.Adopt(chars);
583 else {
584 intval = mozilla::plugins::parent::_intfromidentifier(aIdentifier);
585 string.SetIsVoid(PR_TRUE);
587 ident = new PluginIdentifierParent(aIdentifier);
588 if (!SendPPluginIdentifierConstructor(ident, string, intval))
589 return nsnull;
591 mIdentifiers.Put(aIdentifier, ident);
593 return ident;
596 PluginInstanceParent*
597 PluginModuleParent::InstCast(NPP instance)
599 PluginInstanceParent* ip =
600 static_cast<PluginInstanceParent*>(instance->pdata);
602 // If the plugin crashed and the PluginInstanceParent was deleted,
603 // instance->pdata will be NULL.
604 if (!ip)
605 return NULL;
607 if (instance != ip->mNPP) {
608 NS_RUNTIMEABORT("Corrupted plugin data.");
610 return ip;
613 BrowserStreamParent*
614 PluginModuleParent::StreamCast(NPP instance,
615 NPStream* s)
617 PluginInstanceParent* ip = InstCast(instance);
618 if (!ip)
619 return NULL;
621 BrowserStreamParent* sp =
622 static_cast<BrowserStreamParent*>(static_cast<AStream*>(s->pdata));
623 if (sp->mNPP != ip || s != sp->mStream) {
624 NS_RUNTIMEABORT("Corrupted plugin stream data.");
626 return sp;
629 bool
630 PluginModuleParent::HasRequiredFunctions()
632 return true;
635 nsresult
636 PluginModuleParent::AsyncSetWindow(NPP instance, NPWindow* window)
638 PluginInstanceParent* i = InstCast(instance);
639 if (!i)
640 return NS_ERROR_FAILURE;
642 return i->AsyncSetWindow(window);
645 nsresult
646 PluginModuleParent::GetSurface(NPP instance, gfxASurface** aSurface)
648 PluginInstanceParent* i = InstCast(instance);
649 if (!i)
650 return NS_ERROR_FAILURE;
652 return i->GetSurface(aSurface);
655 #if defined(XP_UNIX) && !defined(XP_MACOSX)
656 nsresult
657 PluginModuleParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs, NPError* error)
659 PLUGIN_LOG_DEBUG_METHOD;
661 mNPNIface = bFuncs;
663 if (mShutdown) {
664 *error = NPERR_GENERIC_ERROR;
665 return NS_ERROR_FAILURE;
668 if (!CallNP_Initialize(&mPluginThread, error)) {
669 return NS_ERROR_FAILURE;
671 else if (*error != NPERR_NO_ERROR) {
672 return NS_OK;
675 SetPluginFuncs(pFuncs);
676 return NS_OK;
678 #else
679 nsresult
680 PluginModuleParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPError* error)
682 PLUGIN_LOG_DEBUG_METHOD;
684 mNPNIface = bFuncs;
686 if (mShutdown) {
687 *error = NPERR_GENERIC_ERROR;
688 return NS_ERROR_FAILURE;
691 if (!CallNP_Initialize(&mPluginThread, error))
692 return NS_ERROR_FAILURE;
694 return NS_OK;
696 #endif
698 nsresult
699 PluginModuleParent::NP_Shutdown(NPError* error)
701 PLUGIN_LOG_DEBUG_METHOD;
703 if (mShutdown) {
704 *error = NPERR_GENERIC_ERROR;
705 return NS_ERROR_FAILURE;
708 bool ok = CallNP_Shutdown(error);
710 // if NP_Shutdown() is nested within another RPC call, this will
711 // break things. but lord help us if we're doing that anyway; the
712 // plugin dso will have been unloaded on the other side by the
713 // CallNP_Shutdown() message
714 Close();
716 return ok ? NS_OK : NS_ERROR_FAILURE;
719 nsresult
720 PluginModuleParent::NP_GetMIMEDescription(const char** mimeDesc)
722 PLUGIN_LOG_DEBUG_METHOD;
724 *mimeDesc = "application/x-foobar";
725 return NS_OK;
728 nsresult
729 PluginModuleParent::NP_GetValue(void *future, NPPVariable aVariable,
730 void *aValue, NPError* error)
732 PR_LOG(gPluginLog, PR_LOG_WARNING, ("%s Not implemented, requested variable %i", __FUNCTION__,
733 (int) aVariable));
735 //TODO: implement this correctly
736 *error = NPERR_GENERIC_ERROR;
737 return NS_OK;
740 #if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_OS2)
741 nsresult
742 PluginModuleParent::NP_GetEntryPoints(NPPluginFuncs* pFuncs, NPError* error)
744 NS_ASSERTION(pFuncs, "Null pointer!");
746 SetPluginFuncs(pFuncs);
747 *error = NPERR_NO_ERROR;
748 return NS_OK;
750 #endif
752 nsresult
753 PluginModuleParent::NPP_New(NPMIMEType pluginType, NPP instance,
754 uint16_t mode, int16_t argc, char* argn[],
755 char* argv[], NPSavedData* saved,
756 NPError* error)
758 PLUGIN_LOG_DEBUG_METHOD;
760 if (mShutdown) {
761 *error = NPERR_GENERIC_ERROR;
762 return NS_ERROR_FAILURE;
765 // create the instance on the other side
766 InfallibleTArray<nsCString> names;
767 InfallibleTArray<nsCString> values;
769 for (int i = 0; i < argc; ++i) {
770 names.AppendElement(NullableString(argn[i]));
771 values.AppendElement(NullableString(argv[i]));
774 PluginInstanceParent* parentInstance =
775 new PluginInstanceParent(this, instance,
776 nsDependentCString(pluginType), mNPNIface);
778 if (!parentInstance->Init()) {
779 delete parentInstance;
780 return NS_ERROR_FAILURE;
783 instance->pdata = parentInstance;
785 if (!CallPPluginInstanceConstructor(parentInstance,
786 nsDependentCString(pluginType), mode,
787 names, values, error)) {
788 // |parentInstance| is automatically deleted.
789 instance->pdata = nsnull;
790 // if IPC is down, we'll get an immediate "failed" return, but
791 // without *error being set. So make sure that the error
792 // condition is signaled to nsNPAPIPluginInstance
793 if (NPERR_NO_ERROR == *error)
794 *error = NPERR_GENERIC_ERROR;
795 return NS_ERROR_FAILURE;
798 if (*error != NPERR_NO_ERROR) {
799 NPP_Destroy(instance, 0);
800 return NS_ERROR_FAILURE;
803 return NS_OK;
806 bool
807 PluginModuleParent::AnswerNPN_GetValue_WithBoolReturn(const NPNVariable& aVariable,
808 NPError* aError,
809 bool* aBoolVal)
811 NPBool boolVal = false;
812 *aError = mozilla::plugins::parent::_getvalue(nsnull, aVariable, &boolVal);
813 *aBoolVal = boolVal ? true : false;
814 return true;
817 #if defined(MOZ_WIDGET_QT)
818 static const int kMaxtimeToProcessEvents = 30;
819 bool
820 PluginModuleParent::AnswerProcessSomeEvents()
822 PLUGIN_LOG_DEBUG(("Spinning mini nested loop ..."));
823 QCoreApplication::processEvents(QEventLoop::AllEvents, kMaxtimeToProcessEvents);
825 PLUGIN_LOG_DEBUG(("... quitting mini nested loop"));
827 return true;
830 #elif defined(XP_MACOSX)
831 bool
832 PluginModuleParent::AnswerProcessSomeEvents()
834 mozilla::plugins::PluginUtilsOSX::InvokeNativeEventLoop();
835 return true;
838 #elif !defined(MOZ_WIDGET_GTK2)
839 bool
840 PluginModuleParent::AnswerProcessSomeEvents()
842 NS_RUNTIMEABORT("unreached");
843 return false;
846 #else
847 static const int kMaxChancesToProcessEvents = 20;
849 bool
850 PluginModuleParent::AnswerProcessSomeEvents()
852 PLUGIN_LOG_DEBUG(("Spinning mini nested loop ..."));
854 int i = 0;
855 for (; i < kMaxChancesToProcessEvents; ++i)
856 if (!g_main_context_iteration(NULL, FALSE))
857 break;
859 PLUGIN_LOG_DEBUG(("... quitting mini nested loop; processed %i tasks", i));
861 return true;
863 #endif
865 bool
866 PluginModuleParent::RecvProcessNativeEventsInRPCCall()
868 PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
869 #if defined(OS_WIN)
870 ProcessNativeEventsInRPCCall();
871 return true;
872 #else
873 NS_NOTREACHED(
874 "PluginInstanceParent::RecvProcessNativeEventsInRPCCall not implemented!");
875 return false;
876 #endif
879 bool
880 PluginModuleParent::RecvPluginShowWindow(const uint32_t& aWindowId, const bool& aModal,
881 const int32_t& aX, const int32_t& aY,
882 const size_t& aWidth, const size_t& aHeight)
884 PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
885 #if defined(XP_MACOSX)
886 CGRect windowBound = ::CGRectMake(aX, aY, aWidth, aHeight);
887 mac_plugin_interposing::parent::OnPluginShowWindow(aWindowId, windowBound, aModal);
888 return true;
889 #else
890 NS_NOTREACHED(
891 "PluginInstanceParent::RecvPluginShowWindow not implemented!");
892 return false;
893 #endif
896 bool
897 PluginModuleParent::RecvPluginHideWindow(const uint32_t& aWindowId)
899 PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
900 #if defined(XP_MACOSX)
901 mac_plugin_interposing::parent::OnPluginHideWindow(aWindowId, OtherSidePID());
902 return true;
903 #else
904 NS_NOTREACHED(
905 "PluginInstanceParent::RecvPluginHideWindow not implemented!");
906 return false;
907 #endif
910 #ifdef OS_MACOSX
911 #define DEFAULT_REFRESH_MS 20 // CoreAnimation: 50 FPS
913 void
914 CAUpdate(nsITimer *aTimer, void *aClosure) {
915 nsTObserverArray<PluginInstanceParent*> *ips =
916 static_cast<nsTObserverArray<PluginInstanceParent*> *>(aClosure);
917 nsTObserverArray<PluginInstanceParent*>::ForwardIterator iter(*ips);
918 while (iter.HasMore()) {
919 iter.GetNext()->Invalidate();
923 void
924 PluginModuleParent::AddToRefreshTimer(PluginInstanceParent *aInstance) {
925 if (mCATimerTargets.Contains(aInstance)) {
926 return;
929 mCATimerTargets.AppendElement(aInstance);
930 if (mCATimerTargets.Length() == 1) {
931 if (!mCATimer) {
932 nsresult rv;
933 nsCOMPtr<nsITimer> xpcomTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
934 if (NS_FAILED(rv)) {
935 NS_WARNING("Could not create Core Animation timer for plugin.");
936 return;
938 mCATimer = xpcomTimer;
940 mCATimer->InitWithFuncCallback(CAUpdate, &mCATimerTargets, DEFAULT_REFRESH_MS,
941 nsITimer::TYPE_REPEATING_SLACK);
945 void
946 PluginModuleParent::RemoveFromRefreshTimer(PluginInstanceParent *aInstance) {
947 PRBool visibleRemoved = mCATimerTargets.RemoveElement(aInstance);
948 if (visibleRemoved && mCATimerTargets.IsEmpty()) {
949 mCATimer->Cancel();
952 #endif