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