1 /****************************************************************************
2 **
3 ** Copyright (C) 2003-2008 Trolltech ASA. All rights reserved.
4 **
5 ** This file is part of a Qt Solutions component.
6 **
7 ** This file may be used under the terms of the GNU General Public
8 ** License version 2.0 as published by the Free Software Foundation
9 ** and appearing in the file LICENSE.GPL included in the packaging of
10 ** this file.  Please review the following information to ensure GNU
11 ** General Public Licensing requirements will be met:
12 ** http://www.trolltech.com/products/qt/opensource.html
13 **
14 ** If you are unsure which license is appropriate for your use, please
15 ** review the following information:
16 ** http://www.trolltech.com/products/qt/licensing.html or contact the
17 ** Trolltech sales department at sales@trolltech.com.
18 **
19 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
20 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21 **
22 ****************************************************************************/
23 #include "qtbrowserplugin.h"
24 #include "qtbrowserplugin.moc"
25 
26 #include <QtGui>
27 
28 #include "qtnpapi.h"
29 
30 #include "qtbrowserplugin_p.h"
31 
32 #ifndef WINAPI
33 # ifdef Q_OS_WIN
34 #  define WINAPI __stdcall
35 # else
36 #  define WINAPI
37 # endif
38 #endif
39 
40 #ifdef Q_WS_X11
41 #  ifdef Bool
42 #    undef Bool
43 #  endif
44 
45 /*
46 static void debuginfo(const QString &str)
47 {
48     static bool inited = false;
49     QFile file("/tmp/qnsdebug.txt");
50     if (file.open(QFile::WriteOnly | QFile::Append)) {
51         if (!inited) {
52             file.write("\n\n*** New run started ***\n");
53             inited = true;
54         }
55         file.write(qtNPFactory()->pluginName().toLatin1() + ": " + str.toLatin1() + '\n');
56         file.close();
57     }
58 }
59 */
60 
61 #endif
62 
63 static QtNPFactory *qNP = 0;
64 static NPNetscapeFuncs *qNetscapeFuncs = 0;
65 
66 // The single global plugin
qtNPFactory()67 QtNPFactory *qtNPFactory()
68 {
69     extern QtNPFactory *qtns_instantiate();
70 
71     if (!qNP) {
72         qNP = qtns_instantiate();
73     }
74 
75     return qNP;
76 }
77 
78 // NPN functions, forwarding to function pointers provided by browser
NPN_Version(int * plugin_major,int * plugin_minor,int * netscape_major,int * netscape_minor)79 void NPN_Version(int* plugin_major, int* plugin_minor, int* netscape_major, int* netscape_minor)
80 {
81     Q_ASSERT(qNetscapeFuncs);
82     *plugin_major   = NP_VERSION_MAJOR;
83     *plugin_minor   = NP_VERSION_MINOR;
84     *netscape_major = qNetscapeFuncs->version  >> 8;  // Major version is in high byte
85     *netscape_minor = qNetscapeFuncs->version & 0xFF; // Minor version is in low byte
86 }
87 
88 #define NPN_Prolog(x) \
89     Q_ASSERT(qNetscapeFuncs); \
90     Q_ASSERT(qNetscapeFuncs->x); \
91 
NPN_UserAgent(NPP instance)92 const char *NPN_UserAgent(NPP instance)
93 {
94     NPN_Prolog(uagent);
95     return FIND_FUNCTION_POINTER(NPN_UserAgentFP, qNetscapeFuncs->uagent)(instance);
96 }
97 
NPN_Status(NPP instance,const char * message)98 void NPN_Status(NPP instance, const char* message)
99 {
100     NPN_Prolog(status);
101     FIND_FUNCTION_POINTER(NPN_StatusFP, qNetscapeFuncs->status)(instance, message);
102 }
103 
NPN_GetURL(NPP instance,const char * url,const char * window)104 NPError NPN_GetURL(NPP instance, const char* url, const char* window)
105 {
106     NPN_Prolog(geturl);
107     return FIND_FUNCTION_POINTER(NPN_GetURLFP, qNetscapeFuncs->geturl)(instance, url, window);
108 }
109 
NPN_GetURLNotify(NPP instance,const char * url,const char * window,void * notifyData)110 NPError NPN_GetURLNotify(NPP instance, const char* url, const char* window, void* notifyData)
111 {
112     if ((qNetscapeFuncs->version & 0xFF) < NPVERS_HAS_NOTIFICATION)
113         return NPERR_INCOMPATIBLE_VERSION_ERROR;
114 
115     NPN_Prolog(geturlnotify);
116     return FIND_FUNCTION_POINTER(NPN_GetURLNotifyFP, qNetscapeFuncs->geturlnotify)(instance, url, window, notifyData);
117 }
118 
NPN_PostURLNotify(NPP instance,const char * url,const char * window,uint32 len,const char * buf,NPBool file,void * notifyData)119 NPError NPN_PostURLNotify(NPP instance, const char* url, const char* window, uint32 len, const char* buf, NPBool file, void* notifyData)
120 {
121     if ((qNetscapeFuncs->version & 0xFF) < NPVERS_HAS_NOTIFICATION)
122         return NPERR_INCOMPATIBLE_VERSION_ERROR;
123 
124     NPN_Prolog(posturlnotify);
125     return FIND_FUNCTION_POINTER(NPN_PostURLNotifyFP, qNetscapeFuncs->posturlnotify)(instance, url, window, len, buf, file, notifyData);
126 }
127 
NPN_MemAlloc(uint32 size)128 void* NPN_MemAlloc(uint32 size)
129 {
130     NPN_Prolog(memalloc);
131     return FIND_FUNCTION_POINTER(NPN_MemAllocFP, qNetscapeFuncs->memalloc)(size);
132 }
133 
NPN_MemFree(void * ptr)134 void NPN_MemFree(void* ptr)
135 {
136     NPN_Prolog(memfree);
137     FIND_FUNCTION_POINTER(NPN_MemFreeFP, qNetscapeFuncs->memfree)(ptr);
138 }
139 
NPN_MemFlush(uint32 size)140 uint32 NPN_MemFlush(uint32 size)
141 {
142     NPN_Prolog(memflush);
143     return FIND_FUNCTION_POINTER(NPN_MemFlushFP, qNetscapeFuncs->memflush)(size);
144 }
145 
NPN_GetValue(NPP instance,NPNVariable variable,void * ret_value)146 NPError	NPN_GetValue(NPP instance, NPNVariable variable, void *ret_value)
147 {
148     NPN_Prolog(getvalue);
149     return FIND_FUNCTION_POINTER(NPN_GetValueFP, qNetscapeFuncs->getvalue)(instance, variable, ret_value);
150 }
151 
NPN_SetValue(NPP instance,NPPVariable variable,void * ret_value)152 NPError NPN_SetValue(NPP instance, NPPVariable variable, void *ret_value)
153 {
154     NPN_Prolog(setvalue);
155     return FIND_FUNCTION_POINTER(NPN_SetValueFP, qNetscapeFuncs->setvalue)(instance, variable, ret_value);
156 }
157 
NPN_GetStringIdentifier(const char * name)158 NPIdentifier NPN_GetStringIdentifier(const char* name)
159 {
160     NPN_Prolog(getstringidentifier);
161     return FIND_FUNCTION_POINTER(NPN_GetStringIdentifierFP, qNetscapeFuncs->getstringidentifier)(name);
162 }
163 
NPN_GetStringIdentifiers(const char ** names,int32 nameCount,NPIdentifier * identifiers)164 void NPN_GetStringIdentifiers(const char** names, int32 nameCount, NPIdentifier* identifiers)
165 {
166     NPN_Prolog(getstringidentifiers);
167     FIND_FUNCTION_POINTER(NPN_GetStringIdentifiersFP, qNetscapeFuncs->getstringidentifiers)(names, nameCount, identifiers);
168 }
169 
NPN_GetIntIdentifier(int32 intid)170 NPIdentifier NPN_GetIntIdentifier(int32 intid)
171 {
172     NPN_Prolog(getintidentifier);
173     return FIND_FUNCTION_POINTER(NPN_GetIntIdentifierFP, qNetscapeFuncs->getintidentifier)(intid);
174 }
175 
NPN_IdentifierIsString(NPIdentifier identifier)176 bool NPN_IdentifierIsString(NPIdentifier identifier)
177 {
178     NPN_Prolog(identifierisstring);
179     return FIND_FUNCTION_POINTER(NPN_IdentifierIsStringFP, qNetscapeFuncs->identifierisstring)(identifier);
180 }
181 
NPN_UTF8FromIdentifier(NPIdentifier identifier)182 char* NPN_UTF8FromIdentifier(NPIdentifier identifier)
183 {
184     NPN_Prolog(utf8fromidentifier);
185     return FIND_FUNCTION_POINTER(NPN_UTF8FromIdentifierFP, qNetscapeFuncs->utf8fromidentifier)(identifier);
186 }
187 
NPN_IntFromIdentifier(NPIdentifier identifier)188 int32 NPN_IntFromIdentifier(NPIdentifier identifier)
189 {
190     NPN_Prolog(intfromidentifier);
191     return FIND_FUNCTION_POINTER(NPN_IntFromIdentifierFP, qNetscapeFuncs->intfromidentifier)(identifier);
192 }
193 
NPN_CreateObject(NPP npp,NPClass * aClass)194 NPObject* NPN_CreateObject(NPP npp, NPClass *aClass)
195 {
196     NPN_Prolog(createobject);
197     return FIND_FUNCTION_POINTER(NPN_CreateObjectFP, qNetscapeFuncs->createobject)(npp, aClass);
198 }
199 
NPN_RetainObject(NPObject * obj)200 NPObject* NPN_RetainObject(NPObject *obj)
201 {
202     NPN_Prolog(retainobject);
203     return FIND_FUNCTION_POINTER(NPN_RetainObjectFP, qNetscapeFuncs->retainobject)(obj);
204 }
205 
NPN_ReleaseObject(NPObject * obj)206 void NPN_ReleaseObject(NPObject *obj)
207 {
208     NPN_Prolog(releaseobject);
209     FIND_FUNCTION_POINTER(NPN_ReleaseObjectFP, qNetscapeFuncs->releaseobject)(obj);
210 }
211 
212 // Scripting implementation (QObject calling JavaScript in browser) - we don't use those
NPN_Invoke(NPP npp,NPObject * obj,NPIdentifier methodName,const NPVariant * args,int32 argCount,NPVariant * result)213 bool NPN_Invoke(NPP npp, NPObject* obj, NPIdentifier methodName, const NPVariant *args, int32 argCount, NPVariant *result)
214 {
215     NPN_Prolog(invoke);
216     return FIND_FUNCTION_POINTER(NPN_InvokeFP, qNetscapeFuncs->invoke)(npp, obj, methodName, args, argCount, result);
217 }
218 
NPN_InvokeDefault(NPP npp,NPObject * obj,const NPVariant * args,int32 argCount,NPVariant * result)219 bool NPN_InvokeDefault(NPP npp, NPObject* obj, const NPVariant *args, int32 argCount, NPVariant *result)
220 {
221     NPN_Prolog(invokedefault);
222     return FIND_FUNCTION_POINTER(NPN_InvokeDefaultFP, qNetscapeFuncs->invokedefault)(npp, obj, args, argCount, result);
223 }
224 
NPN_Evaluate(NPP npp,NPObject * obj,NPString * script,NPVariant * result)225 bool NPN_Evaluate(NPP npp, NPObject *obj, NPString *script, NPVariant *result)
226 {
227     NPN_Prolog(evaluate);
228     return FIND_FUNCTION_POINTER(NPN_EvaluateFP, qNetscapeFuncs->evaluate)(npp, obj, script, result);
229 }
230 
NPN_GetProperty(NPP npp,NPObject * obj,NPIdentifier propertyName,NPVariant * result)231 bool NPN_GetProperty(NPP npp, NPObject *obj, NPIdentifier propertyName, NPVariant *result)
232 {
233     NPN_Prolog(getproperty);
234     return FIND_FUNCTION_POINTER(NPN_GetPropertyFP, qNetscapeFuncs->getproperty)(npp, obj, propertyName, result);
235 }
236 
NPN_SetProperty(NPP npp,NPObject * obj,NPIdentifier propertyName,const NPVariant * value)237 bool NPN_SetProperty(NPP npp, NPObject *obj, NPIdentifier propertyName, const NPVariant *value)
238 {
239     NPN_Prolog(setproperty);
240     return FIND_FUNCTION_POINTER(NPN_SetPropertyFP, qNetscapeFuncs->setproperty)(npp, obj, propertyName, value);
241 }
242 
NPN_RemoveProperty(NPP npp,NPObject * obj,NPIdentifier propertyName)243 bool NPN_RemoveProperty(NPP npp, NPObject *obj, NPIdentifier propertyName)
244 {
245     NPN_Prolog(removeproperty);
246     return FIND_FUNCTION_POINTER(NPN_RemovePropertyFP, qNetscapeFuncs->removeproperty)(npp, obj, propertyName);
247 }
248 
NPN_HasProperty(NPP npp,NPObject * obj,NPIdentifier propertyName)249 bool NPN_HasProperty(NPP npp, NPObject *obj, NPIdentifier propertyName)
250 {
251     NPN_Prolog(hasproperty);
252     return FIND_FUNCTION_POINTER(NPN_HasPropertyFP, qNetscapeFuncs->hasproperty)(npp, obj, propertyName);
253 }
254 
NPN_HasMethod(NPP npp,NPObject * obj,NPIdentifier methodName)255 bool NPN_HasMethod(NPP npp, NPObject *obj, NPIdentifier methodName)
256 {
257     NPN_Prolog(hasmethod);
258     return FIND_FUNCTION_POINTER(NPN_HasMethodFP, qNetscapeFuncs->hasmethod)(npp, obj, methodName);
259 }
260 
NPN_ReleaseVariantValue(NPVariant * variant)261 void NPN_ReleaseVariantValue(NPVariant *variant)
262 {
263     NPN_Prolog(releasevariantvalue);
264     FIND_FUNCTION_POINTER(NPN_ReleaseVariantValueFP, qNetscapeFuncs->releasevariantvalue)(variant);
265 }
266 
NPN_SetException(NPObject * obj,const char * message)267 void NPN_SetException(NPObject *obj, const char *message)
268 {
269     qDebug("NPN_SetException: %s", message);
270     NPN_Prolog(setexception);
271     FIND_FUNCTION_POINTER(NPN_SetExceptionFP, qNetscapeFuncs->setexception)(obj, message);
272 }
273 
274 // Scripting implementation (JavaScript calling QObject)
275 #define NPClass_Prolog \
276     if (!npobj->_class) return false; \
277     if (!npobj->_class->qtnp) return false; \
278     QtNPInstance *This = npobj->_class->qtnp; \
279     if (!This->qt.object) return false; \
280     QObject *qobject = This->qt.object \
281 
NPAllocate(NPP npp,NPClass * aClass)282 static NPObject *NPAllocate(NPP npp, NPClass *aClass)
283 {
284     Q_UNUSED(npp);
285     Q_UNUSED(aClass);
286 
287     Q_ASSERT(false);
288     return 0;
289 }
290 
NPDeallocate(NPObject * npobj)291 static void NPDeallocate(NPObject *npobj)
292 {
293     Q_UNUSED(npobj);
294 
295     Q_ASSERT(false);
296     return;
297 }
298 
NPInvalidate(NPObject * npobj)299 static void NPInvalidate(NPObject *npobj)
300 {
301     if (npobj)
302         delete npobj->_class;
303     npobj->_class = 0;
304 }
305 
306 enum MetaOffset { MetaProperty, MetaMethod };
307 
metaOffset(const QMetaObject * metaObject,MetaOffset offsetType)308 static int metaOffset(const QMetaObject *metaObject, MetaOffset offsetType)
309 {
310     int classInfoIndex = metaObject->indexOfClassInfo("ToSuperClass");
311     if (classInfoIndex == -1)
312         return 0;
313     QByteArray ToSuperClass = metaObject->classInfo(classInfoIndex).value();
314     int offset = offsetType == MetaProperty ? metaObject->propertyOffset()
315         : metaObject->methodOffset();
316 
317     while (ToSuperClass != metaObject->className()) {
318         metaObject = metaObject->superClass();
319         if (!metaObject)
320             break;
321         offset -= offsetType == MetaProperty ? metaObject->propertyCount()
322                     : metaObject->methodCount();
323     }
324     return offset;
325 }
326 
publicMethodIndex(NPObject * npobj,const QByteArray & slotName,int argCount=-1)327 static int publicMethodIndex(NPObject *npobj, const QByteArray &slotName, int argCount = -1)
328 {
329     NPClass_Prolog;
330     const QMetaObject *metaObject = qobject->metaObject();
331     for (int slotIndex = metaOffset(metaObject, MetaMethod); slotIndex < metaObject->methodCount(); ++slotIndex) {
332         const QMetaMethod slot = qobject->metaObject()->method(slotIndex);
333         if (slot.access() != QMetaMethod::Public || slot.methodType() == QMetaMethod::Signal)
334             continue;
335         QByteArray signature = slot.signature();
336         if (signature.left(signature.indexOf('(')) == slotName) {
337             if (argCount == -1 || slot.parameterTypes().count() == argCount)
338                 return slotIndex;
339         }
340     }
341     return -1;
342 }
343 
NPClass_HasMethod(NPObject * npobj,NPIdentifier name)344 static bool NPClass_HasMethod(NPObject *npobj, NPIdentifier name)
345 {
346     NPClass_Prolog;
347     Q_UNUSED(qobject);
348     return publicMethodIndex(npobj, NPN_UTF8FromIdentifier(name)) != -1;
349 }
350 
NPClass_Invoke(NPObject * npobj,NPIdentifier name,const NPVariant * args,uint32 argCount,NPVariant * result)351 static bool NPClass_Invoke(NPObject *npobj, NPIdentifier name, const NPVariant *args, uint32 argCount, NPVariant *result)
352 {
353     NPClass_Prolog;
354     const QByteArray slotName = NPN_UTF8FromIdentifier(name);
355     int slotIndex = publicMethodIndex(npobj, slotName, static_cast<int>(argCount));
356     if (slotIndex == -1) {
357         NPN_SetException(npobj, QByteArray("No method '" + slotName + "' with " + QByteArray::number(argCount) + " parameters").constData());
358         return false;
359     }
360 
361     const QMetaMethod slot = qobject->metaObject()->method(slotIndex);
362     QList<QByteArray> parameterTypes = slot.parameterTypes();
363     if (parameterTypes.count() != static_cast<int>(argCount)) {
364         NPN_SetException(npobj, QByteArray("Wrong parameter count for method " + slotName).constData());
365         return false;
366     }
367 
368     QVariant returnVariant(QVariant::nameToType(slot.typeName()), (void*)0);
369     QVector<QVariant> variants(parameterTypes.count()); // keep data alive
370     QVector<const void*> metacallArgs(parameterTypes.count() + 1); // arguments for qt_metacall
371     metacallArgs[0] = returnVariant.data(); // args[0] == return value
372 
373     for (int p = 0; p < parameterTypes.count(); ++p) {
374         QVariant::Type type = QVariant::nameToType(parameterTypes.at(p));
375         if (type == QVariant::Invalid && parameterTypes.at(p) != "QVariant") {
376             NPN_SetException(npobj, QString("Parameter %1 in method '%2' has invalid type")
377                 .arg(p).arg(QString::fromUtf8(slotName)).toAscii().constData());
378             return false;
379         }
380         QVariant qvar = args[p];
381         if (type != QVariant::Invalid && !qvar.convert(type)) {
382             NPN_SetException(npobj, QString("Parameter %1 to method '%2' needs to be convertable to '%3'")
383                 .arg(p).arg(QString::fromUtf8(slotName)).arg(QString::fromAscii(parameterTypes.at(p))).toAscii().constData());
384             return false;
385         }
386 
387         variants[p] = qvar;
388         if (type == QVariant::Invalid)
389             metacallArgs[p + 1] = &variants.at(p);
390         else
391             metacallArgs[p + 1] = variants.at(p).constData(); // must not detach!
392     }
393 
394     qobject->qt_metacall(QMetaObject::InvokeMetaMethod, slotIndex, const_cast<void**>(metacallArgs.data()));
395     if (returnVariant.isValid() && result)
396         *result = NPVariant::fromQVariant(This, returnVariant);
397 
398     return true;
399 }
400 
NPClass_InvokeDefault(NPObject *,const NPVariant *,uint32,NPVariant *)401 static bool NPClass_InvokeDefault(NPObject * /*npobj*/, const NPVariant * /*args*/, uint32 /*argCount*/, NPVariant * /*result*/)
402 {
403     return false;
404 }
405 
NPClass_HasProperty(NPObject * npobj,NPIdentifier name)406 static bool NPClass_HasProperty(NPObject *npobj, NPIdentifier name)
407 {
408     NPClass_Prolog;
409     const QByteArray qname = NPN_UTF8FromIdentifier(name);
410     const QMetaObject *metaObject = qobject->metaObject();
411     int propertyIndex = metaObject->indexOfProperty(qname);
412     if (propertyIndex == -1 || propertyIndex < metaOffset(metaObject, MetaProperty))
413         return false;
414     QMetaProperty property = qobject->metaObject()->property(propertyIndex);
415     if (!property.isScriptable())
416         return false;
417 
418     return true;
419 }
420 
NPClass_GetProperty(NPObject * npobj,NPIdentifier name,NPVariant * result)421 static bool NPClass_GetProperty(NPObject *npobj, NPIdentifier name, NPVariant *result)
422 {
423     NPClass_Prolog;
424     const QByteArray qname = NPN_UTF8FromIdentifier(name);
425     QVariant qvar = qobject->property(qname);
426     if (!qvar.isValid()) {
427         NPN_SetException(npobj, QByteArray("Failed to get value for property " + qname).constData());
428         return false;
429     }
430     *result = NPVariant::fromQVariant(This, qvar);
431     return true;
432 }
433 
NPClass_SetProperty(NPObject * npobj,NPIdentifier name,const NPVariant * result)434 static bool NPClass_SetProperty(NPObject *npobj, NPIdentifier name, const NPVariant *result)
435 {
436     NPClass_Prolog;
437     const QByteArray qname = NPN_UTF8FromIdentifier(name);
438     QVariant qvar = *result;
439     return qobject->setProperty(qname, qvar);
440 }
441 
NPClass_RemoveProperty(NPObject *,NPIdentifier)442 static bool NPClass_RemoveProperty(NPObject * /*npobj*/, NPIdentifier /*name*/)
443 {
444     return false;
445 }
446 
NPClass(QtNPInstance * This)447 NPClass::NPClass(QtNPInstance *This)
448 {
449     structVersion = NP_CLASS_STRUCT_VERSION;
450     allocate = 0;
451     deallocate = 0;
452     invalidate = NPInvalidate;
453     hasMethod = NPClass_HasMethod;
454     invoke = NPClass_Invoke;
455     invokeDefault = NPClass_InvokeDefault;
456     hasProperty = NPClass_HasProperty;
457     getProperty = NPClass_GetProperty;
458     setProperty = NPClass_SetProperty;
459     removeProperty = NPClass_RemoveProperty;
460     qtnp = This;
461     delete_qtnp = false;
462 }
463 
~NPClass()464 NPClass::~NPClass()
465 {
466     if (delete_qtnp)
467         delete qtnp;
468 }
469 
470 // Type conversions
fromQString(const QString & qstr)471 NPString NPString::fromQString(const QString &qstr)
472 {
473     NPString npstring;
474     const QByteArray qutf8 = qstr.toUtf8();
475 
476     npstring.utf8length = qutf8.length();
477     npstring.utf8characters = (char*)NPN_MemAlloc(npstring.utf8length);
478     memcpy((char*)npstring.utf8characters, qutf8.constData(), npstring.utf8length);
479 
480     return npstring;
481 }
482 
operator QString() const483 NPString::operator QString() const
484 {
485     return QString::fromUtf8(utf8characters, utf8length);
486 }
487 
fromQVariant(QtNPInstance * This,const QVariant & qvariant)488 NPVariant NPVariant::fromQVariant(QtNPInstance *This, const QVariant &qvariant)
489 {
490     Q_ASSERT(This);
491     NPVariant npvar;
492     npvar.type = Null;
493 
494     QVariant qvar(qvariant);
495     switch(qvariant.type()) {
496     case QVariant::Bool:
497         npvar.value.boolValue = qvar.toBool();
498         npvar.type = Boolean;
499         break;
500     case QVariant::Int:
501         npvar.value.intValue = qvar.toInt();
502         npvar.type = Int32;
503         break;
504     case QVariant::Double:
505         npvar.value.doubleValue = qvar.toDouble();
506         npvar.type = Double;
507         break;
508     case QVariant::UserType:
509         {
510             QByteArray userType = qvariant.typeName();
511             if (userType.endsWith('*')) {
512                 QtNPInstance *that = new QtNPInstance;
513                 that->npp = This->npp;
514                 that->qt.object = *(QObject**)qvariant.constData();
515                 NPClass *npclass = new NPClass(that);
516                 npclass->delete_qtnp = true;
517                 npvar.value.objectValue = NPN_CreateObject(This->npp, npclass);
518                 npvar.type = Object;
519             }
520         }
521         break;
522     default: // including QVariant::String
523         if (!qvar.convert(QVariant::String))
524             break;
525         npvar.type = String;
526         npvar.value.stringValue = NPString::fromQString(qvar.toString());
527         break;
528     }
529 
530     return npvar;
531 }
532 
operator QVariant() const533 NPVariant::operator QVariant() const
534 {
535     switch(type) {
536     case Void:
537     case Null:
538         return QVariant();
539     case Object:
540         {
541             if (!value.objectValue || !value.objectValue->_class)
542                 break;
543             NPClass *aClass = value.objectValue->_class;
544             // not one of ours?
545             if (aClass->invoke != NPClass_Invoke)
546                 break;
547             // or just empty for some reason
548             QObject *qobject = aClass->qtnp->qt.object;
549             if (!qobject)
550                 break;
551             QByteArray typeName = qobject->metaObject()->className();
552             int userType = QMetaType::type(typeName + "*");
553             if (userType == QVariant::Invalid)
554                 break;
555             QVariant result(userType, &aClass->qtnp->qt.object);
556             // sanity check
557             Q_ASSERT(*(QObject**)result.constData() == aClass->qtnp->qt.object);
558             return result;
559         }
560     case Boolean:
561         return value.boolValue;
562     case Int32:
563         return value.intValue;
564     case Double:
565         return value.doubleValue;
566     case String:
567         return QString(value.stringValue);
568     default:
569         break;
570     }
571     return QVariant();
572 }
573 
574 // Helper class for handling incoming data
575 class QtNPStream
576 {
577 public:
578     QtNPStream(NPP instance, NPStream *st);
~QtNPStream()579     virtual ~QtNPStream()
580     {
581     }
582 
583     QString url() const;
584     bool finish(QtNPBindable *bindable);
585 
586     QByteArray buffer;
587     QFile file;
588     QString mime;
589 
590     NPError reason;
591 
592     NPP npp;
593     NPStream* stream;
594 
595 protected:
596     qint64 readData(char *, qint64);
597     qint64 writeData(const char *, qint64);
598 };
599 
QtNPStream(NPP instance,NPStream * st)600 QtNPStream::QtNPStream(NPP instance, NPStream *st)
601     : reason(NPRES_DONE), npp(instance), stream(st)
602 {
603 }
604 
605 /*!
606     Returns the URL from which the stream was created, or the empty string
607     for write-only streams.
608 */
url() const609 QString QtNPStream::url() const
610 {
611     if (!stream)
612         return QString();
613     return QString::fromLocal8Bit(stream->url);
614 }
615 
616 class ErrorBuffer : public QBuffer
617 {
618     friend class QtNPStream;
619 };
620 
finish(QtNPBindable * bindable)621 bool QtNPStream::finish(QtNPBindable *bindable)
622 {
623     if (!bindable)
624         return false;
625 
626     bool res = false;
627     if (bindable) {
628         switch(reason) {
629         case NPRES_DONE:
630             // no data at all? url is probably local file (Opera)
631             if (buffer.isEmpty() && file.fileName().isEmpty()) {
632                 QUrl u = QUrl::fromEncoded(stream->url);
633                 QString lfn = u.toLocalFile();
634                 if (lfn.startsWith("//localhost/"))
635                     lfn = lfn.mid(12);
636                 file.setFileName(lfn);
637             }
638 
639             if (file.exists()) {
640                 file.setObjectName(url());
641                 res = bindable->readData(&file, mime);
642             } else {
643                 QBuffer io(&buffer);
644                 io.setObjectName(url());
645                 res = bindable->readData(&io, mime);
646             }
647             break;
648         case NPRES_USER_BREAK:
649             {
650                 ErrorBuffer empty;
651                 empty.setObjectName(url());
652                 empty.setErrorString("User cancelled operation."),
653                 res = bindable->readData(&empty, mime);
654             }
655             break;
656         case NPRES_NETWORK_ERR:
657             {
658                 ErrorBuffer empty;
659                 empty.setObjectName(url());
660                 empty.setErrorString("Network error during download."),
661                 res = bindable->readData(&empty, mime);
662             }
663             break;
664         default:
665             break;
666         }
667     }
668     stream->pdata = 0;
669     delete this;
670     return res;
671 }
672 
673 // Helper class for forwarding signal emissions to the respective JavaScript
674 class QtSignalForwarder : public QObject
675 {
676 public:
QtSignalForwarder(QtNPInstance * that)677     QtSignalForwarder(QtNPInstance *that)
678         : This(that), domNode(0)
679     {
680     }
681 
~QtSignalForwarder()682     ~QtSignalForwarder()
683     {
684         if (domNode)
685             NPN_ReleaseObject(domNode);
686     }
687 
688     int qt_metacall(QMetaObject::Call call, int index, void **args);
689 
690 private:
691     QtNPInstance *This;
692     NPObject *domNode;
693 };
694 
qt_metacall(QMetaObject::Call call,int index,void ** args)695 int QtSignalForwarder::qt_metacall(QMetaObject::Call call, int index, void **args)
696 {
697     // no support for QObject method/properties etc!
698     if (!This || !This->npp || call != QMetaObject::InvokeMetaMethod
699         || !This->qt.object)
700         return index;
701 
702     switch (index) {
703     case -1:
704         {
705             QString msg = *(QString*)args[1];
706             NPN_Status(This->npp, msg.toLocal8Bit().constData());
707         }
708         break;
709     default:
710         {
711             QObject *qobject = This->qt.object;
712             if (!domNode)
713                 NPN_GetValue(This->npp, NPNVPluginElementNPObject, &domNode);
714             if (!domNode)
715                 break;
716             const QMetaObject *metaObject = qobject->metaObject();
717             if (index < metaOffset(metaObject, MetaMethod))
718                 break;
719 
720             const QMetaMethod method = metaObject->method(index);
721             Q_ASSERT(method.methodType() == QMetaMethod::Signal);
722 
723             QByteArray signalSignature = method.signature();
724             QByteArray scriptFunction = signalSignature.left(signalSignature.indexOf('('));
725             NPIdentifier id = NPN_GetStringIdentifier(scriptFunction.constData());
726             if (NPN_HasMethod(This->npp, domNode, id)) {
727                 QList<QByteArray> parameterTypes = method.parameterTypes();
728                 QVector<NPVariant> parameters;
729                 NPVariant result;
730                 bool error = false;
731                 for (int p = 0; p < parameterTypes.count(); ++p) {
732                     QVariant::Type type = QVariant::nameToType(parameterTypes.at(p));
733                     if (type == QVariant::Invalid) {
734                         NPN_SetException(domNode, QByteArray("Unsupported parameter type in ") + scriptFunction);
735                         error = true;
736                         break;
737                     }
738                     QVariant qvar(type, args[p + 1]);
739                     NPVariant npvar = NPVariant::fromQVariant(This, qvar);
740                     if (npvar.type == NPVariant::Null || npvar.type == NPVariant::Void) {
741                         NPN_SetException(domNode, QByteArray("Unsupported parameter value in ") + scriptFunction);
742                         error =true;
743                         break;
744                     }
745                     parameters += npvar;
746                 }
747                 if (error)
748                     break;
749 
750                 NPError nperror = NPN_Invoke(This->npp, domNode, id, parameters.constData(), parameters.count(), &result);
751                 if (nperror != NPERR_NO_ERROR && false) { // disabled, as NPN_Invoke seems to always return GENERICERROR
752                     NPN_SetException(domNode, QByteArray("Error invoking event handler ") + scriptFunction);
753                 }
754                 // ### TODO: update return value (args[0]) (out-parameters not supported anyway)
755                 NPN_ReleaseVariantValue(&result);
756             }
757         }
758         break;
759     }
760 
761     return index;
762 }
763 
764 // Plugin functions
765 extern "C" NPError
NPP_GetValue(NPP instance,NPPVariable variable,void * value)766 NPP_GetValue(NPP instance, NPPVariable variable, void *value)
767 {
768     if (!instance || !instance->pdata)
769 	return NPERR_INVALID_INSTANCE_ERROR;
770 
771     QtNPInstance* This = (QtNPInstance*) instance->pdata;
772 
773     switch (variable) {
774     case NPPVpluginNameString:
775         {
776             static QByteArray name = qtNPFactory()->pluginName().toLocal8Bit();
777             *(const char**)value = name.constData();
778         }
779         break;
780     case NPPVpluginDescriptionString:
781         {
782             static QByteArray description = qtNPFactory()->pluginDescription().toLocal8Bit();
783             *(const char**)value = description.constData();
784         }
785         break;
786 
787 #ifdef Q_WS_X11
788     case NPPVpluginNeedsXEmbed:
789         *(int*)value = true; // PRBool = int
790         break;
791 #endif
792 
793     case NPPVpluginScriptableNPObject:
794         {
795             NPObject *object = NPN_CreateObject(instance, new NPClass(This));
796             *(NPObject**)value = object;
797         }
798         break;
799     case NPPVformValue:
800         {
801             QObject *object = This->qt.object;
802             const QMetaObject *metaObject = object->metaObject();
803             int defaultIndex = metaObject->indexOfClassInfo("DefaultProperty");
804             if (defaultIndex == -1)
805                 return NPERR_GENERIC_ERROR;
806             QByteArray defaultProperty = metaObject->classInfo(defaultIndex).value();
807             if (defaultProperty.isEmpty())
808                 return NPERR_GENERIC_ERROR;
809             QVariant defaultValue = object->property(defaultProperty);
810             if (!defaultValue.isValid())
811                 return NPERR_GENERIC_ERROR;
812             defaultProperty = defaultValue.toString().toUtf8();
813             int size = defaultProperty.size();
814             char *utf8 = (char*)NPN_MemAlloc(size + 1);
815             memcpy(utf8, defaultProperty.constData(), size);
816             utf8[size] = 0; // null-terminator
817             *(void**)value = utf8;
818         }
819         break;
820     default:
821         return NPERR_GENERIC_ERROR;
822     }
823 
824     return NPERR_NO_ERROR;
825 }
826 
827 extern "C" NPError
NPP_SetValue(NPP instance,NPPVariable variable,void * value)828 NPP_SetValue(NPP instance, NPPVariable variable, void *value)
829 {
830     Q_UNUSED(variable);
831     Q_UNUSED(value);
832 
833     if (!instance || !instance->pdata)
834 	return NPERR_INVALID_INSTANCE_ERROR;
835 
836     /*
837     switch(variable) {
838     default:
839         return NPERR_GENERIC_ERROR;
840     }
841     */
842     return NPERR_NO_ERROR;
843 }
844 
NPP_Event(NPP instance,NPEvent * event)845 extern "C" int16 NPP_Event(NPP instance, NPEvent* event)
846 {
847     if (!instance || !instance->pdata)
848 	return NPERR_INVALID_INSTANCE_ERROR;
849 
850     QtNPInstance* This = (QtNPInstance*) instance->pdata;
851     extern bool qtns_event(QtNPInstance *, NPEvent *);
852     return qtns_event(This, event) ? 1 : 0;
853 }
854 
855 #ifdef Q_WS_X11
856 // Instance state information about the plugin.
857 extern "C" char*
NP_GetMIMEDescription(void)858 NP_GetMIMEDescription(void)
859 {
860     static QByteArray mime = qtNPFactory()->mimeTypes().join(";").toLocal8Bit();
861     return (char*)mime.constData();
862 }
863 
864 extern "C" NPError
NP_GetValue(void *,NPPVariable aVariable,void * aValue)865 NP_GetValue(void*, NPPVariable aVariable, void *aValue)
866 {
867     NPError err = NPERR_NO_ERROR;
868 
869     static QByteArray name = qtNPFactory()->pluginName().toLocal8Bit();
870     static QByteArray descr = qtNPFactory()->pluginDescription().toLocal8Bit();
871 
872     switch (aVariable) {
873     case NPPVpluginNameString:
874         *static_cast<const char **> (aValue) = name.constData();
875         break;
876     case NPPVpluginDescriptionString:
877         *static_cast<const char **>(aValue) = descr.constData();
878         break;
879     case NPPVpluginNeedsXEmbed:
880         *static_cast<int*>(aValue) = true;
881         break;
882     case NPPVpluginTimerInterval:
883     case NPPVpluginKeepLibraryInMemory:
884     default:
885         err = NPERR_INVALID_PARAM;
886         break;
887     }
888     return err;
889 }
890 #endif
891 
892 /*
893 ** NPP_New is called when your plugin is instantiated (i.e. when an EMBED
894 ** tag appears on a page).
895 */
896 extern "C" NPError
NPP_New(NPMIMEType pluginType,NPP instance,uint16 mode,int16 argc,char * argn[],char * argv[],NPSavedData *)897 NPP_New(NPMIMEType pluginType,
898     NPP instance,
899     uint16 mode,
900     int16 argc,
901     char* argn[],
902     char* argv[],
903     NPSavedData* /*saved*/)
904 {
905     if (!instance)
906 	return NPERR_INVALID_INSTANCE_ERROR;
907 
908     QtNPInstance* This = new QtNPInstance;
909     if (!This)
910 	return NPERR_OUT_OF_MEMORY_ERROR;
911 
912     instance->pdata = This;
913     This->filter = 0;
914     This->bindable = 0;
915     This->npp = instance;
916     This->fMode = mode; // NP_EMBED, NP_FULL, or NP_BACKGROUND (see npapi.h)
917     This->window = 0;
918     This->qt.object = 0;
919 #ifdef Q_OS_MAC
920     This->rootWidget = 0;
921 #endif
922     This->pendingStream = 0; // stream might be created before instance
923     This->mimetype = QString::fromLatin1(pluginType);
924     This->notificationSeqNum = 0;
925 
926     for (int i = 0; i < argc; i++) {
927         QByteArray name = QByteArray(argn[i]).toLower();
928         if (name == "id")
929             This->htmlID = argv[i];
930         This->parameters[name] = QVariant(argv[i]);
931     }
932 
933     return NPERR_NO_ERROR;
934 }
935 
936 extern "C" NPError
NPP_Destroy(NPP instance,NPSavedData **)937 NPP_Destroy(NPP instance, NPSavedData** /*save*/)
938 {
939     if (!instance || !instance->pdata)
940 	return NPERR_INVALID_INSTANCE_ERROR;
941 
942     QtNPInstance* This = (QtNPInstance*) instance->pdata;
943 
944 #ifdef Q_WS_X11
945     //This->widget->destroy(false, false); // X has destroyed all windows
946 #endif
947     delete This->qt.object;
948     This->qt.object = 0;
949     delete This->filter;
950     This->filter = 0;
951     extern void qtns_destroy(QtNPInstance *This);
952     qtns_destroy(This);
953     delete This;
954     instance->pdata = 0;
955 
956     return NPERR_NO_ERROR;
957 }
958 
959 static QtNPInstance *next_pi = 0; // helper to connect to QtNPBindable
960 
961 extern "C" NPError
NPP_SetWindow(NPP instance,NPWindow * window)962 NPP_SetWindow(NPP instance, NPWindow* window)
963 {
964     if (!instance)
965 	return NPERR_INVALID_INSTANCE_ERROR;
966 
967     QtNPInstance* This = (QtNPInstance*) instance->pdata;
968     extern void qtns_setGeometry(QtNPInstance*, const QRect &, const QRect &);
969 
970     const QRect clipRect(window->clipRect.left, window->clipRect.top,
971                          window->clipRect.right - window->clipRect.left,
972                          window->clipRect.bottom - window->clipRect.top);
973     if (window)
974         This->geometry = QRect(window->x, window->y, window->width, window->height);
975 
976     // take a shortcut if all that was changed is the geometry
977     if (qobject_cast<QWidget*>(This->qt.object) && window && This->window == (QtNPInstance::Widget)window->window) {
978         qtns_setGeometry(This, This->geometry, clipRect);
979 	return NPERR_NO_ERROR;
980     }
981 
982 	delete This->qt.object;
983 	This->qt.object = 0;
984 	extern void qtns_destroy(QtNPInstance *This);
985 	qtns_destroy(This);
986 
987     if (!window) {
988         This->window = 0;
989 	return NPERR_NO_ERROR;
990     }
991 
992     This->window = (QtNPInstance::Widget)window->window;
993 #ifdef Q_WS_X11
994     //This->display = ((NPSetWindowCallbackStruct *)window->ws_info)->display;
995 #endif
996 
997     extern void qtns_initialize(QtNPInstance*);
998     qtns_initialize(This);
999 
1000     next_pi = This;
1001     This->qt.object = qtNPFactory()->createObject(This->mimetype);
1002     next_pi = 0;
1003 
1004     if (!This->qt.object)
1005         return NPERR_NO_ERROR;
1006 
1007     if (!This->htmlID.isEmpty())
1008         This->qt.object->setObjectName(QLatin1String(This->htmlID));
1009 
1010     This->filter = new QtSignalForwarder(This);
1011     QStatusBar *statusbar = qFindChild<QStatusBar*>(This->qt.object);
1012     if (statusbar) {
1013         int statusSignal = statusbar->metaObject()->indexOfSignal("messageChanged(QString)");
1014         if (statusSignal != -1) {
1015             QMetaObject::connect(statusbar, statusSignal, This->filter, -1);
1016             statusbar->hide();
1017         }
1018     }
1019 
1020     const QMetaObject *mo = This->qt.object->metaObject();
1021     for (int p = 0; p < mo->propertyCount(); ++p) {
1022         const QMetaProperty property = mo->property(p);
1023         QByteArray name(property.name());
1024         QVariant value = This->parameters.value(name.toLower());
1025         if (value.isValid())
1026             property.write(This->qt.object, value);
1027     }
1028     for (int methodIndex = 0; methodIndex < mo->methodCount(); ++methodIndex) {
1029         const QMetaMethod method = mo->method(methodIndex);
1030         if (method.methodType() == QMetaMethod::Signal)
1031             QMetaObject::connect(This->qt.object, methodIndex, This->filter, methodIndex);
1032     }
1033 
1034     if (This->pendingStream) {
1035         This->pendingStream->finish(This->bindable);
1036         This->pendingStream = 0;
1037     }
1038 
1039     if (!qobject_cast<QWidget*>(This->qt.object))
1040 	return NPERR_NO_ERROR;
1041 
1042     extern void qtns_embed(QtNPInstance*);
1043     qtns_embed(This);
1044 
1045     QEvent e(QEvent::EmbeddingControl);
1046     QApplication::sendEvent(This->qt.widget, &e);
1047 
1048     if (!This->qt.widget->testAttribute(Qt::WA_PaintOnScreen))
1049         This->qt.widget->setAutoFillBackground(true);
1050     This->qt.widget->raise();
1051     qtns_setGeometry(This, This->geometry, clipRect);
1052     This->qt.widget->show();
1053 
1054     return NPERR_NO_ERROR;
1055 }
1056 
1057 extern "C" NPError
NPP_NewStream(NPP instance,NPMIMEType type,NPStream * stream,NPBool,uint16 * stype)1058 NPP_NewStream(NPP instance,
1059 	  NPMIMEType type,
1060 	  NPStream *stream,
1061 	  NPBool /*seekable*/,
1062 	  uint16 *stype)
1063 {
1064     if (!instance)
1065 	return NPERR_INVALID_INSTANCE_ERROR;
1066 
1067     QtNPInstance* This = (QtNPInstance*) instance->pdata;
1068     if (!This)
1069         return NPERR_NO_ERROR;
1070 
1071     QtNPStream *qstream = new QtNPStream(instance, stream);
1072     qstream->mime = QString::fromLocal8Bit(type);
1073     stream->pdata = qstream;
1074 
1075     *stype = NP_ASFILEONLY;
1076 
1077     return NPERR_NO_ERROR;
1078 }
1079 
1080 extern "C" int32
NPP_WriteReady(NPP,NPStream * stream)1081 NPP_WriteReady(NPP, NPStream *stream)
1082 {
1083     if (stream->pdata)
1084         return 0x0FFFFFFF;
1085     return 0;
1086 }
1087 
1088 // Both Netscape and FireFox call this for OnDemand streams as well...
1089 extern "C" int32
NPP_Write(NPP instance,NPStream * stream,int32,int32 len,void * buffer)1090 NPP_Write(NPP instance, NPStream *stream, int32 /*offset*/, int32 len, void *buffer)
1091 {
1092     if (!instance || !stream || !stream->pdata)
1093         return NPERR_INVALID_INSTANCE_ERROR;
1094 
1095     // this should not be called, as we always demand a download
1096     QtNPStream *qstream = (QtNPStream*)stream->pdata;
1097     QByteArray data((const char*)buffer, len); // make deep copy
1098     qstream->buffer += data;
1099 
1100     return len;
1101 }
1102 
1103 // Opera calls this for OnDemand streams without calling NPP_Write first
1104 extern "C" NPError
NPP_DestroyStream(NPP instance,NPStream * stream,NPError reason)1105 NPP_DestroyStream(NPP instance, NPStream *stream, NPError reason)
1106 {
1107     if (!instance || !instance->pdata || !stream || !stream->pdata)
1108 	return NPERR_INVALID_INSTANCE_ERROR;
1109 
1110     QtNPInstance *This = (QtNPInstance*)instance->pdata;
1111     QtNPStream *qstream = (QtNPStream*)stream->pdata;
1112     qstream->reason = reason;
1113 
1114     if (!This->qt.object) { // not yet initialized
1115         This->pendingStream = qstream;
1116         return NPERR_NO_ERROR;
1117     }
1118 
1119     This->pendingStream = 0;
1120     qstream->finish(This->bindable);
1121 
1122     return NPERR_NO_ERROR;
1123 }
1124 
1125 extern "C" void
NPP_StreamAsFile(NPP instance,NPStream * stream,const char * fname)1126 NPP_StreamAsFile(NPP instance, NPStream *stream, const char* fname)
1127 {
1128     if (!instance || !stream || !stream->pdata)
1129         return;
1130 
1131     QString path = QString::fromLocal8Bit(fname);
1132 #ifdef Q_OS_MAC
1133     path = "/" + path.section(':', 1).replace(':', '/');
1134 #endif
1135 
1136     QtNPStream *qstream = (QtNPStream*)stream->pdata;
1137     qstream->file.setFileName(path);
1138 }
1139 
1140 extern "C" void
NPP_URLNotify(NPP instance,const char * url,NPReason reason,void * notifyData)1141 NPP_URLNotify(NPP instance,
1142 	      const char* url,
1143 	      NPReason reason,
1144 	      void* notifyData)
1145 {
1146     if (!instance)
1147         return;
1148     QtNPInstance* This = (QtNPInstance*) instance->pdata;
1149     if (!This->bindable)
1150         return;
1151 
1152     QtNPBindable::Reason r;
1153     switch (reason) {
1154     case NPRES_DONE:
1155 	r = QtNPBindable::ReasonDone;
1156 	break;
1157     case NPRES_USER_BREAK:
1158 	r = QtNPBindable::ReasonBreak;
1159 	break;
1160     case NPRES_NETWORK_ERR:
1161 	r = QtNPBindable::ReasonError;
1162 	break;
1163     default:
1164 	r = QtNPBindable::ReasonUnknown;
1165 	break;
1166     }
1167 
1168     qint32 id = static_cast<qint32>(reinterpret_cast<size_t>(notifyData));
1169     if (id < 0)  // Sanity check
1170         id = 0;
1171 
1172     This->bindable->transferComplete(QString::fromLocal8Bit(url), id, r);
1173 }
1174 
1175 extern "C" void
NPP_Print(NPP instance,NPPrint * printInfo)1176 NPP_Print(NPP instance, NPPrint* printInfo)
1177 {
1178     if(!printInfo || !instance)
1179 	return;
1180 
1181     QtNPInstance* This = (QtNPInstance*) instance->pdata;
1182     if (!This->bindable)
1183         return;
1184 
1185 /*
1186     if (printInfo->mode == NP_FULL) {
1187 	printInfo->print.fullPrint.pluginPrinted = This->bindable->printFullPage();
1188     } else if (printInfo->mode == NP_EMBED) {
1189         extern void qtns_print(QtNPInstance*, NPPrint*);
1190         qtns_print(This, printInfo);
1191     }
1192 */
1193 }
1194 
1195 // Plug-in entrypoints - these are called by the browser
1196 
1197 // Fills in functiontable used by browser to call entry points in plugin.
NP_GetEntryPoints(NPPluginFuncs * pFuncs)1198 extern "C" NPError WINAPI NP_GetEntryPoints(NPPluginFuncs* pFuncs)
1199 {
1200     if(!pFuncs)
1201         return NPERR_INVALID_FUNCTABLE_ERROR;
1202     if(!pFuncs->size)
1203         pFuncs->size = sizeof(NPPluginFuncs);
1204     else if (pFuncs->size < sizeof(NPPluginFuncs))
1205         return NPERR_INVALID_FUNCTABLE_ERROR;
1206 
1207     pFuncs->version       = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
1208     pFuncs->newp          = MAKE_FUNCTION_POINTER(NPP_New);
1209     pFuncs->destroy       = MAKE_FUNCTION_POINTER(NPP_Destroy);
1210     pFuncs->setwindow     = MAKE_FUNCTION_POINTER(NPP_SetWindow);
1211     pFuncs->newstream     = MAKE_FUNCTION_POINTER(NPP_NewStream);
1212     pFuncs->destroystream = MAKE_FUNCTION_POINTER(NPP_DestroyStream);
1213     pFuncs->asfile        = MAKE_FUNCTION_POINTER(NPP_StreamAsFile);
1214     pFuncs->writeready    = MAKE_FUNCTION_POINTER(NPP_WriteReady);
1215     pFuncs->write         = MAKE_FUNCTION_POINTER(NPP_Write);
1216     pFuncs->print         = MAKE_FUNCTION_POINTER(NPP_Print);
1217     pFuncs->event         = MAKE_FUNCTION_POINTER(NPP_Event);
1218     pFuncs->urlnotify     = MAKE_FUNCTION_POINTER(NPP_URLNotify);
1219     pFuncs->javaClass     = 0;
1220     pFuncs->getvalue      = MAKE_FUNCTION_POINTER(NPP_GetValue);
1221     pFuncs->setvalue      = MAKE_FUNCTION_POINTER(NPP_SetValue);
1222     return NPERR_NO_ERROR;
1223 }
1224 
1225 enum NPNToolkitType
1226 {
1227     NPNVGtk12 = 1,
1228     NPNVGtk2
1229 };
1230 
1231 #ifndef Q_WS_X11
NP_Initialize(NPNetscapeFuncs * pFuncs)1232 extern "C" NPError WINAPI NP_Initialize(NPNetscapeFuncs* pFuncs)
1233 {
1234     if(!pFuncs)
1235         return NPERR_INVALID_FUNCTABLE_ERROR;
1236 
1237     qNetscapeFuncs = pFuncs;
1238     int navMajorVers = qNetscapeFuncs->version >> 8;
1239 
1240     // if the plugin's major version is lower than the Navigator's,
1241     // then they are incompatible, and should return an error
1242     if(navMajorVers > NP_VERSION_MAJOR)
1243         return NPERR_INCOMPATIBLE_VERSION_ERROR;
1244 
1245     return NPERR_NO_ERROR;
1246 }
1247 #else
NP_Initialize(NPNetscapeFuncs * nFuncs,NPPluginFuncs * pFuncs)1248 extern "C" NPError WINAPI NP_Initialize(NPNetscapeFuncs* nFuncs, NPPluginFuncs* pFuncs)
1249 {
1250     if(!nFuncs)
1251         return NPERR_INVALID_FUNCTABLE_ERROR;
1252 
1253     qNetscapeFuncs = nFuncs;
1254     int navMajorVers = qNetscapeFuncs->version >> 8;
1255 
1256     // if the plugin's major version is lower than the Navigator's,
1257     // then they are incompatible, and should return an error
1258     if(navMajorVers > NP_VERSION_MAJOR)
1259         return NPERR_INCOMPATIBLE_VERSION_ERROR;
1260 
1261     // check if the Browser supports the XEmbed protocol
1262     int supportsXEmbed = 0;
1263     NPError err = NPN_GetValue(0, NPNVSupportsXEmbedBool, (void *)&supportsXEmbed);
1264     if (err != NPERR_NO_ERROR ||!supportsXEmbed)
1265         return NPERR_INCOMPATIBLE_VERSION_ERROR;
1266 
1267     return NP_GetEntryPoints(pFuncs);
1268 }
1269 #endif
1270 
NP_Shutdown()1271 extern "C" NPError WINAPI NP_Shutdown()
1272 {
1273     delete qNP;
1274     qNP = 0;
1275 
1276     extern void qtns_shutdown();
1277     qtns_shutdown();
1278 
1279     qNetscapeFuncs = 0;
1280     return NPERR_NO_ERROR;
1281 }
1282 
1283 /*!
1284     \class QtNPBindable qtnetscape.h
1285     \brief The QtNPBindable class provides an interface between a widget and the web browser.
1286 
1287     Inherit your plugin widget class from both QWidget (or QObject) and QtNPBindable
1288     to be able to call the functions of this class, and to reimplement the virtual
1289     functions. The \l{moc}{meta-object compiler} requires you to inherit from the
1290     QObject subclass first.
1291 
1292     \code
1293     class PluginWidget : public QWidget, public QtNPBindable
1294     {
1295         Q_OBJECT
1296     public:
1297         PluginWidget(QWidget *parent = 0)
1298         {
1299         }
1300 
1301         //...
1302     };
1303     \endcode
1304 */
1305 
1306 /*!
1307     \enum QtNPBindable::DisplayMode
1308 
1309     \brief This enum specifies the different display modes of a plugin
1310 
1311     \value Embedded The plugin widget is embedded in a web page, usually
1312     with the <EMBED> or the <OBJECT> tag.
1313     \value Fullpage The plugin widget is the primary content of the web browser, which
1314     is usually the case when the web browser displays a file the plugin supports.
1315 */
1316 
1317 /*!
1318     \enum QtNPBindable::Reason
1319 
1320     \brief This enum specifies how an URL operation was completed
1321 
1322     \value ReasonDone
1323     \value ReasonBreak
1324     \value ReasonError
1325     \value ReasonUnknown
1326 */
1327 
1328 /*!
1329     Constructs a QtNPBindable object.
1330 
1331     This can only happen when the plugin object is created.
1332 */
QtNPBindable()1333 QtNPBindable::QtNPBindable()
1334 : pi(next_pi)
1335 {
1336     if (pi)
1337         pi->bindable = this;
1338     next_pi = 0;
1339 }
1340 
1341 /*!
1342     Destroys the object.
1343 
1344     This can only happen when the plugin object is destroyed.
1345 */
~QtNPBindable()1346 QtNPBindable::~QtNPBindable()
1347 {
1348 }
1349 
1350 /*!
1351     Returns the parameters passed to the plugin instance.
1352 
1353     The framework sets the properties of the plugin to the corresponding
1354     parameters when the plugin object has been created, but you can
1355     use this function to process additional parameters.
1356 
1357     Note that the SGML specification does not permit multiple
1358     arguments with the same name.
1359 */
parameters() const1360 QMap<QByteArray, QVariant> QtNPBindable::parameters() const
1361 {
1362     if (!pi)
1363         return QMap<QByteArray, QVariant>();
1364     return pi->parameters;
1365 }
1366 
1367 /*!
1368     Returns the user agent (browser name) containing this plugin.
1369 
1370     This is a wrapper around NPN_UserAgent.
1371 
1372     \sa getBrowserVersion()
1373 */
userAgent() const1374 QString QtNPBindable::userAgent() const
1375 {
1376     if (!pi)
1377         return QString();
1378     return QString::fromLocal8Bit(NPN_UserAgent(pi->npp));
1379 }
1380 
1381 /*!
1382     Extracts the version of the plugin API used by this plugin into \a major
1383     and \a minor.
1384 
1385     See http://devedge-temp.mozilla.org/library/manuals/2002/plugin/1.0/
1386     for an explanation of those values.
1387 
1388     \sa getBrowserVersion() userAgent()
1389 */
getNppVersion(int * major,int * minor) const1390 void QtNPBindable::getNppVersion(int *major, int *minor) const
1391 {
1392     int dummy = 0;
1393     if (pi)
1394         NPN_Version(major, minor, &dummy, &dummy);
1395 }
1396 
1397 /*!
1398     Extracts the version of the browser into \a major and \a minor.
1399 
1400     See http://devedge-temp.mozilla.org/library/manuals/2002/plugin/1.0/
1401     for an explanation of those values.
1402 
1403     \sa getNppVersion() userAgent()
1404 */
getBrowserVersion(int * major,int * minor) const1405 void QtNPBindable::getBrowserVersion(int *major, int *minor) const
1406 {
1407     int dummy = 0;
1408     if (pi)
1409         NPN_Version(&dummy, &dummy, major, minor);
1410 }
1411 
1412 /*!
1413     Returns the display mode of the plugin.
1414 */
displayMode() const1415 QtNPBindable::DisplayMode QtNPBindable::displayMode() const
1416 {
1417     if (!pi)
1418         return Embedded;
1419     return (QtNPBindable::DisplayMode)pi->fMode;
1420 }
1421 
1422 /*!
1423     Returns the mime type this plugin has been instantiated for.
1424 */
mimeType() const1425 QString QtNPBindable::mimeType() const
1426 {
1427     if (!pi)
1428         return QString();
1429     return pi->mimetype;
1430 }
1431 
1432 /*!
1433     Returns the browser's plugin instance associated with this plugin object.
1434     The instance is required to call functions in the Netscape Plugin API,
1435     i.e. NPN_GetJavaPeer().
1436 
1437     The instance returned is only valid as long as this object is.
1438 
1439     See http://devedge-temp.mozilla.org/library/manuals/2002/plugin/1.0/
1440     for documentation of the \c NPP type.
1441 */
instance() const1442 NPP QtNPBindable::instance() const
1443 {
1444     if (!pi)
1445         return 0;
1446     return pi->npp;
1447 }
1448 
1449 /*!
1450     Reimplement this function to read data from \a source provided with
1451     mime type \a format. The data is the one specified in the \c src or
1452     \c data attribute of the \c{<EMBED>} or \c{<OBJECT>} tag of in
1453     HTML page. This function is called once for every stream the browser
1454     creates for the plugin.
1455 
1456     Return true to indicate successful processing of the data, otherwise
1457     return false. The default implementation does nothing and returns false.
1458 */
1459 
readData(QIODevice * source,const QString & format)1460 bool QtNPBindable::readData(QIODevice *source, const QString &format)
1461 {
1462     Q_UNUSED(source);
1463     Q_UNUSED(format);
1464     return false;
1465 }
1466 
1467 /*!
1468     Requests that the \a url be retrieved and sent to the named \a window (or
1469     a new window if \a window is empty), and returns the ID of the request that is
1470     delivered to transferComplete() when the get-operation has finished. Returns 0 when
1471     the browser or the system doesn't support notification, or -1 when an error occurred.
1472 
1473     \code
1474     void MyPlugin::aboutTrolltech()
1475     {
1476         openUrl("http://www.trolltech.com");
1477     }
1478     \endcode
1479 
1480     See Netscape's JavaScript documentation for an explanation of window names.
1481 
1482     \sa transferComplete() uploadData() uploadFile()
1483 */
openUrl(const QString & url,const QString & window)1484 int QtNPBindable::openUrl(const QString &url, const QString &window)
1485 {
1486     if (!pi)
1487         return -1;
1488     QString wnd = window;
1489     if (wnd.isEmpty())
1490         wnd = "_blank";
1491 
1492     qint32 id = pi->getNotificationSeqNum();
1493     NPError err = NPN_GetURLNotify(pi->npp, url.toLocal8Bit().constData(), wnd.toLocal8Bit().constData(), reinterpret_cast<void*>(id));
1494     if (err != NPERR_NO_ERROR)
1495         id = -1;
1496 
1497     if (err == NPERR_INCOMPATIBLE_VERSION_ERROR) {
1498         err = NPN_GetURL(pi->npp, url.toLocal8Bit().constData(), wnd.toLocal8Bit().constData());
1499         if (NPERR_NO_ERROR == err)
1500             id = 0;
1501         else
1502             id = -1;
1503     }
1504     return id;
1505 }
1506 
1507 /*!
1508     Posts \a data to \a url, and displays the result in \a window. Returns the ID of the request
1509     that is delivered to transferComplete() when the post-operation has finished. Returns 0 when
1510     the browser or the system doesn't support notification, or -1 when an error occurred.
1511 
1512     \code
1513     void MyPlugin::sendMail()
1514     {
1515         uploadData("mailto:fred@somewhere.com", QString(), "There is a new file for you!");
1516     }
1517     \endcode
1518 
1519     See Netscape's JavaScript documentation for an explanation of window names.
1520 
1521     \sa transferComplete() openUrl() uploadFile()
1522 */
uploadData(const QString & url,const QString & window,const QByteArray & data)1523 int QtNPBindable::uploadData(const QString &url, const QString &window, const QByteArray &data)
1524 {
1525     if (!pi)
1526         return -1;
1527 
1528     int id = pi->getNotificationSeqNum();
1529     if (NPERR_NO_ERROR != NPN_PostURLNotify(pi->npp, url.toLocal8Bit().constData(), window.isEmpty() ? 0 : window.toLocal8Bit().constData(), data.size(), data.constData(), false, reinterpret_cast<void*>(id)))
1530         id = -1;
1531 
1532     return id;
1533 }
1534 
1535 /*!
1536     Posts \a filename to \a url, and displays the result in \a window. Returns the ID of
1537     the request that is delivered to transferComplete() when the post-operation has finished.
1538     Returns 0 when the browser or the system doesn't support notification, or -1 when an
1539     error occurred.
1540 
1541     \code
1542     void MyPlugin::uploadFile()
1543     {
1544         uploadFile("ftp://ftp.somewhere.com/incoming", "response", "c:\\temp\\file.txt");
1545     }
1546     \endcode
1547 
1548     See Netscape's JavaScript documentation for an explanation of window names.
1549 
1550     \sa transferComplete() uploadData() openUrl()
1551 */
1552 
uploadFile(const QString & url,const QString & window,const QString & filename)1553 int QtNPBindable::uploadFile(const QString &url, const QString &window, const QString &filename)
1554 {
1555     if (!pi)
1556         return -1;
1557 
1558     QByteArray data = filename.toLocal8Bit();
1559     int id = pi->getNotificationSeqNum();
1560     if (NPERR_NO_ERROR != NPN_PostURLNotify(pi->npp, url.toLocal8Bit().constData(), window.isEmpty() ? 0 : window.toLocal8Bit().constData(), data.size(), data.constData(), true, reinterpret_cast<void*>(id)))
1561         id = -1;
1562 
1563     return id;
1564 }
1565 
1566 /*!
1567     Called as a result of a call to openUrl, uploadData or uploadFile.
1568     \a url corresponds to the respective parameter, and \a id to value returned
1569     by the call. \a reason indicates how the transfer was completed.
1570 */
transferComplete(const QString & url,int id,Reason reason)1571 void QtNPBindable::transferComplete(const QString &url, int id, Reason reason)
1572 {
1573     Q_UNUSED(url)
1574     Q_UNUSED(id)
1575     Q_UNUSED(reason)
1576 }
1577 
1578 /******************************************************************************
1579  * The plugin itself - only one ever exists, created by QtNPFactory::create()
1580  *****************************************************************************/
1581 
1582 /*!
1583     \class QtNPFactory qtbrowserplugin.h
1584     \brief The QtNPFactory class provides the factory for plugin objects.
1585 
1586     Implement this factory once in your plugin project to provide information
1587     about the plugin and to create the plugin objects. Subclass QtNPFactory and
1588     implement the pure virtual functions, and export the factory using the
1589     \c QTNPFACTORY_EXPORT() macro.
1590 
1591     If you use the Q_CLASSINFO macro in your object classes you can use the
1592     \c QTNPFACTORY_BEGIN(), \c QTNPCLASS() and \c QTNPFACTORY_END() macros to
1593     generate a factory implementation:
1594 
1595     \code
1596     class Widget : public QWidget
1597     {
1598         Q_OBJECT
1599         Q_CLASSINFO("MIME", "application/x-graphable:g1n:Graphable data")
1600     public:
1601         ...
1602     };
1603 
1604     QTNPFACTORY_BEGIN("Plugin name", "Plugin description")
1605         QTNPCLASS(WidgetClass)
1606     QTNPFACTORY_END()
1607     \endcode
1608 
1609     The classes exposed must provide a constructor.
1610 
1611     If Qt is linked to the plugin as a dynamic library, only one instance of
1612     QApplication will exist \e{across all plugins that have been made with Qt}.
1613     So, your plugin should tread lightly on global settings. Do not, for example,
1614     use QApplication::setFont() - that will change the font in every widget of
1615     every Qt-based plugin currently loaded!
1616 */
1617 
1618 /*!
1619     Creates a QtNPFactory.
1620 */
QtNPFactory()1621 QtNPFactory::QtNPFactory()
1622 {
1623 }
1624 
1625 /*!
1626     Destroys the QtNPFactory.
1627 
1628     This is called by the plugin binding code just before the plugin is
1629     about to be unloaded from memory. If createObject() has been called,
1630     a QApplication will still exist at this time, but will be deleted
1631     shortly after, just before the plugin is deleted.
1632 */
~QtNPFactory()1633 QtNPFactory::~QtNPFactory()
1634 {
1635 }
1636 
1637 /*!
1638     \fn QStringList QtNPFactory::mimeTypes() const
1639 
1640     Reimplement this function to return the MIME types of the data formats
1641     supported by your plugin. The format of each string is
1642     mime:extension(s):description:
1643 
1644     \code
1645     QStringList mimeTypes() const
1646     {
1647         QStringList list;
1648         list << "image/x-png:png:PNG Image"
1649              << "image/png:png:PNG Image"
1650              << "image/jpeg:jpg,jpeg:JPEG Image";
1651 	return list;
1652     }
1653     \endcode
1654 */
1655 
1656 /*!
1657     \fn QObject *QtNPFactory::createObject(const QString &type)
1658 
1659     Reimplement this function to return the QObject or QWidget subclass
1660     supporting the mime type \a type, or 0 if the factory doesn't support
1661     the type requested.
1662 
1663     \a type will be in the same form as the leftmost (mime) part of
1664     the string(s) returned by mimeTypes(), e.g. "image/png".
1665 */
1666 
1667 /*!
1668     \fn QString QtNPFactory::pluginName() const
1669 
1670     Reimplement this function to return the name of the plugin.
1671 */
1672 
1673 /*!
1674     \fn QString QtNPFactory::pluginDescription() const
1675 
1676     Reimplement this function to return the description of the plugin.
1677 */
1678