The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1115 lines
36KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-7 by Raw Material Software ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the
  7. GNU General Public License, as published by the Free Software Foundation;
  8. either version 2 of the License, or (at your option) any later version.
  9. JUCE is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with JUCE; if not, visit www.gnu.org/licenses or write to the
  15. Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  16. Boston, MA 02111-1307 USA
  17. ------------------------------------------------------------------------------
  18. If you'd like to release a closed-source product which uses JUCE, commercial
  19. licenses are also available: visit www.rawmaterialsoftware.com/juce for
  20. more information.
  21. ==============================================================================
  22. */
  23. //==============================================================================
  24. /*
  25. This file contains all the mess that creates an NPAPI interface, and connects
  26. that interface to your BrowserPluginComponent object.
  27. */
  28. //==============================================================================
  29. #if defined (__APPLE__) && ! JUCE_NPAPI_WRAPPED_IN_MM
  30. #error "On the Mac, you can't compile this .cpp file directly - use juce_NPAPI_GlueCode.mm instead"
  31. #endif
  32. #define XPCOM_GLUE
  33. //==============================================================================
  34. #if _MSC_VER
  35. #define XP_WIN
  36. #define _X86_
  37. #include <windows.h>
  38. #include <windowsx.h>
  39. #include "npapi/npupp.h"
  40. // Cunning trick used to add functions to export list and avoid messing about with .def files.
  41. // (can't add a declspec because the functions have already been pre-declared in the npapi headers).
  42. #define EXPORTED_FUNCTION comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__)
  43. //==============================================================================
  44. #elif defined (__APPLE__)
  45. #define XP_MACOSX
  46. #define OSCALL
  47. #include <WebKit/npapi.h>
  48. #include <WebKit/npfunctions.h>
  49. #include <WebKit/npruntime.h>
  50. //==============================================================================
  51. #else
  52. #define XP_UNIX
  53. #include "npapi.h"
  54. #include "npupp.h"
  55. #include "npruntime.h"
  56. #endif
  57. //==============================================================================
  58. #include "../../../juce_amalgamated.h"
  59. #include "juce_BrowserPluginComponent.h"
  60. #include "juce_IncludeBrowserPluginInfo.h"
  61. #if JUCE_MAC && JUCE_DEBUG && 0
  62. static void log (const String& s)
  63. {
  64. FILE* f = fopen ("/Users/jules/Desktop/log.txt", "a+");
  65. fprintf (f, (const char*) s);
  66. fprintf (f, "\n");
  67. fflush (f);
  68. fclose (f);
  69. }
  70. #else
  71. #define log(a)
  72. #endif
  73. //==============================================================================
  74. #if JUCE_MAC
  75. static const String nsStringToJuce (NSString* s) { return String::fromUTF8 ((juce::uint8*) [s UTF8String]); }
  76. static NSString* juceStringToNS (const String& s) { return [NSString stringWithUTF8String: (const char*) s.toUTF8()]; }
  77. #pragma export on
  78. extern "C"
  79. {
  80. NPError NP_Initialize (NPNetscapeFuncs*);
  81. NPError NP_GetEntryPoints (NPPluginFuncs*);
  82. NPError NP_Shutdown();
  83. }
  84. #pragma export off
  85. #endif
  86. //==============================================================================
  87. static NPNetscapeFuncs browser;
  88. //==============================================================================
  89. NPError NP_GetValue (void* future, NPPVariable variable, void* value)
  90. {
  91. return NPP_GetValue ((NPP_t*) future, variable, value);
  92. }
  93. #if JUCE_WIN32 || JUCE_MAC
  94. NPError OSCALL NP_GetEntryPoints (NPPluginFuncs* funcs)
  95. {
  96. #if JUCE_WIN32
  97. #pragma EXPORTED_FUNCTION
  98. #endif
  99. log ("NP_GetEntryPoints");
  100. if (funcs == 0 || (funcs->size > 0 && funcs->size < sizeof (NPPluginFuncs)))
  101. return NPERR_INVALID_FUNCTABLE_ERROR;
  102. funcs->size = sizeof (NPPluginFuncs);
  103. funcs->version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
  104. funcs->newp = NPP_New;
  105. funcs->destroy = NPP_Destroy;
  106. funcs->setwindow = NPP_SetWindow;
  107. funcs->newstream = NPP_NewStream;
  108. funcs->destroystream = NPP_DestroyStream;
  109. funcs->asfile = NPP_StreamAsFile;
  110. funcs->writeready = NPP_WriteReady;
  111. #if JUCE_MAC
  112. funcs->write = (NPP_WriteProcPtr) NPP_Write;
  113. #else
  114. funcs->write = NPP_Write;
  115. #endif
  116. funcs->print = NPP_Print;
  117. funcs->event = NPP_HandleEvent;
  118. funcs->urlnotify = NPP_URLNotify;
  119. funcs->getvalue = NPP_GetValue;
  120. funcs->setvalue = NPP_SetValue;
  121. funcs->javaClass = 0;
  122. return NPERR_NO_ERROR;
  123. }
  124. #endif
  125. NPError OSCALL NP_Initialize (NPNetscapeFuncs* funcs
  126. #ifdef XP_UNIX
  127. , NPPluginFuncs* pluginFuncs
  128. #endif
  129. )
  130. {
  131. #if JUCE_WIN32
  132. #pragma EXPORTED_FUNCTION
  133. #endif
  134. log ("NP_Initialize");
  135. if (funcs == 0)
  136. return NPERR_INVALID_FUNCTABLE_ERROR;
  137. if (((funcs->version >> 8) & 0xff) > NP_VERSION_MAJOR)
  138. return NPERR_INCOMPATIBLE_VERSION_ERROR;
  139. if (funcs->size < sizeof (NPNetscapeFuncs))
  140. return NPERR_INVALID_FUNCTABLE_ERROR;
  141. browser.size = funcs->size;
  142. browser.version = funcs->version;
  143. browser.geturlnotify = funcs->geturlnotify;
  144. browser.geturl = funcs->geturl;
  145. browser.posturlnotify = funcs->posturlnotify;
  146. browser.posturl = funcs->posturl;
  147. browser.requestread = funcs->requestread;
  148. browser.newstream = funcs->newstream;
  149. browser.write = funcs->write;
  150. browser.destroystream = funcs->destroystream;
  151. browser.status = funcs->status;
  152. browser.uagent = funcs->uagent;
  153. browser.memalloc = funcs->memalloc;
  154. browser.memfree = funcs->memfree;
  155. browser.memflush = funcs->memflush;
  156. browser.reloadplugins = funcs->reloadplugins;
  157. browser.getJavaEnv = funcs->getJavaEnv;
  158. browser.getJavaPeer = funcs->getJavaPeer;
  159. browser.getvalue = funcs->getvalue;
  160. browser.setvalue = funcs->setvalue;
  161. browser.invalidaterect = funcs->invalidaterect;
  162. browser.invalidateregion = funcs->invalidateregion;
  163. browser.forceredraw = funcs->forceredraw;
  164. browser.getstringidentifier = funcs->getstringidentifier;
  165. browser.getstringidentifiers = funcs->getstringidentifiers;
  166. browser.getintidentifier = funcs->getintidentifier;
  167. browser.identifierisstring = funcs->identifierisstring;
  168. browser.utf8fromidentifier = funcs->utf8fromidentifier;
  169. browser.intfromidentifier = funcs->intfromidentifier;
  170. browser.createobject = funcs->createobject;
  171. browser.retainobject = funcs->retainobject;
  172. browser.releaseobject = funcs->releaseobject;
  173. browser.invoke = funcs->invoke;
  174. browser.invokeDefault = funcs->invokeDefault;
  175. browser.evaluate = funcs->evaluate;
  176. browser.getproperty = funcs->getproperty;
  177. browser.setproperty = funcs->setproperty;
  178. browser.removeproperty = funcs->removeproperty;
  179. browser.hasproperty = funcs->hasproperty;
  180. browser.hasmethod = funcs->hasmethod;
  181. browser.releasevariantvalue = funcs->releasevariantvalue;
  182. browser.setexception = funcs->setexception;
  183. #ifdef XP_UNIX
  184. pluginFuncs->version = (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR;
  185. pluginFuncs->size = sizeof (NPPluginFuncs);
  186. pluginFuncs->newp = NewNPP_NewProc (NPP_New);
  187. pluginFuncs->destroy = NewNPP_DestroyProc (NPP_Destroy);
  188. pluginFuncs->setwindow = NewNPP_SetWindowProc (NPP_SetWindow);
  189. pluginFuncs->newstream = NewNPP_NewStreamProc (NPP_NewStream);
  190. pluginFuncs->destroystream = NewNPP_DestroyStreamProc (NPP_DestroyStream);
  191. pluginFuncs->asfile = NewNPP_StreamAsFileProc (NPP_StreamAsFile);
  192. pluginFuncs->writeready = NewNPP_WriteReadyProc (NPP_WriteReady);
  193. pluginFuncs->write = NewNPP_WriteProc (NPP_Write);
  194. pluginFuncs->print = NewNPP_PrintProc (NPP_Print);
  195. pluginFuncs->urlnotify = NewNPP_URLNotifyProc (NPP_URLNotify);
  196. pluginFuncs->event = 0;
  197. pluginFuncs->getvalue = NewNPP_GetValueProc (NPP_GetValue);
  198. #ifdef OJI
  199. pluginFuncs->javaClass = NPP_GetJavaClass();
  200. #endif
  201. #endif
  202. return NPERR_NO_ERROR;
  203. }
  204. NPError OSCALL NP_Shutdown()
  205. {
  206. #if JUCE_WIN32
  207. #pragma EXPORTED_FUNCTION
  208. #endif
  209. log ("NP_Shutdown");
  210. return NPERR_NO_ERROR;
  211. }
  212. char* NP_GetMIMEDescription()
  213. {
  214. log ("NP_GetMIMEDescription");
  215. static String mimeDesc;
  216. mimeDesc = String (T(JuceBrowserPlugin_MimeType))
  217. + T(":") + String (T(JuceBrowserPlugin_FileSuffix))
  218. + T(":") + String (T(JuceBrowserPlugin_Name));
  219. return (char*) (const char*) mimeDesc.toUTF8();
  220. }
  221. //==============================================================================
  222. /*
  223. NPError NPN_GetURLNotify (NPP instance, const char *url, const char *target, void* notifyData)
  224. {
  225. return (browser.version & 0xFF) >= NPVERS_HAS_NOTIFICATION
  226. ? browser.geturlnotify (instance, url, target, notifyData);
  227. : NPERR_INCOMPATIBLE_VERSION_ERROR;
  228. }
  229. NPError NPN_PostURLNotify (NPP instance, const char* url, const char* window, uint32 len, const char* buf, NPBool file, void* notifyData)
  230. {
  231. return (browser.version & 0xFF) >= NPVERS_HAS_NOTIFICATION
  232. ? browser.posturlnotify (instance, url, window, len, buf, file, notifyData)
  233. : NPERR_INCOMPATIBLE_VERSION_ERROR;
  234. }
  235. NPError NPN_NewStream (NPP instance, NPMIMEType type, const char* target, NPStream** stream)
  236. {
  237. return (browser.version & 0xFF) >= NPVERS_HAS_STREAMOUTPUT
  238. ? browser.newstream (instance, type, target, stream)
  239. : NPERR_INCOMPATIBLE_VERSION_ERROR;
  240. }
  241. int32 NPN_Write (NPP instance, NPStream *stream, int32 len, void *buffer)
  242. {
  243. return (browser.version & 0xFF) >= NPVERS_HAS_STREAMOUTPUT
  244. ? browser.write (instance, stream, len, buffer)
  245. : -1;
  246. }
  247. NPError NPN_DestroyStream (NPP instance, NPStream* stream, NPError reason)
  248. {
  249. return (browser.version & 0xFF) >= NPVERS_HAS_STREAMOUTPUT
  250. ? browser.destroystream (instance, stream, reason)
  251. : NPERR_INCOMPATIBLE_VERSION_ERROR;
  252. }
  253. */
  254. //==============================================================================
  255. class BrowserPluginHolderComponent : public Component
  256. {
  257. public:
  258. //==============================================================================
  259. BrowserPluginHolderComponent (NPP npp_)
  260. : npp (npp_),
  261. child (0)
  262. {
  263. log ("BrowserPluginHolderComponent created");
  264. #if JUCE_WIN32
  265. parentHWND = 0;
  266. oldWinProc = 0;
  267. #else
  268. currentParentView = 0;
  269. #endif
  270. setOpaque (true);
  271. setWantsKeyboardFocus (false);
  272. addAndMakeVisible (child = createBrowserPlugin());
  273. jassert (child != 0); // You have to create one of these!
  274. }
  275. ~BrowserPluginHolderComponent()
  276. {
  277. log ("BrowserPluginHolderComponent deleted");
  278. setWindow (0);
  279. deleteAndZero (child);
  280. }
  281. //==============================================================================
  282. void paint (Graphics& g)
  283. {
  284. if (child == 0 || ! child->isOpaque())
  285. g.fillAll (Colours::white);
  286. }
  287. void resized()
  288. {
  289. if (child != 0)
  290. child->setBounds (0, 0, getWidth(), getHeight());
  291. }
  292. const var getObject()
  293. {
  294. return child->getJavascriptObject();
  295. }
  296. //==============================================================================
  297. NPP npp;
  298. BrowserPluginComponent* child;
  299. private:
  300. //==============================================================================
  301. #if JUCE_WIN32
  302. HWND parentHWND;
  303. WNDPROC oldWinProc;
  304. void resizeToParentWindow()
  305. {
  306. if (IsWindow (parentHWND))
  307. {
  308. RECT r;
  309. GetWindowRect (parentHWND, &r);
  310. setBounds (0, 0, r.right - r.left, r.bottom - r.top);
  311. }
  312. }
  313. static LRESULT CALLBACK interceptingWinProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  314. {
  315. switch (msg)
  316. {
  317. case WM_PAINT:
  318. {
  319. PAINTSTRUCT ps;
  320. HDC hdc = BeginPaint (hWnd, &ps);
  321. EndPaint (hWnd, &ps);
  322. }
  323. return 0;
  324. case WM_ERASEBKGND:
  325. return 1;
  326. case WM_WINDOWPOSCHANGING:
  327. if ((((WINDOWPOS*) lParam)->flags & SWP_NOSIZE) == 0)
  328. {
  329. BrowserPluginHolderComponent* const comp = (BrowserPluginHolderComponent*) GetWindowLong (hWnd, GWL_USERDATA);
  330. comp->resizeToParentWindow();
  331. }
  332. break;
  333. default:
  334. break;
  335. }
  336. return DefWindowProc (hWnd, msg, wParam, lParam);
  337. }
  338. public:
  339. void setWindow (NPWindow* window)
  340. {
  341. HWND newHWND = (window != 0 ? ((HWND) window->window) : 0);
  342. if (parentHWND != newHWND)
  343. {
  344. removeFromDesktop();
  345. setVisible (false);
  346. if (IsWindow (parentHWND))
  347. {
  348. SubclassWindow (parentHWND, oldWinProc); // restore the old winproc..
  349. oldWinProc = 0;
  350. }
  351. parentHWND = newHWND;
  352. if (parentHWND != 0)
  353. {
  354. addToDesktop (0);
  355. HWND ourHWND = (HWND) getWindowHandle();
  356. SetParent (ourHWND, parentHWND);
  357. DWORD val = GetWindowLong (ourHWND, GWL_STYLE);
  358. val = (val & ~WS_POPUP) | WS_CHILD;
  359. SetWindowLong (ourHWND, GWL_STYLE, val);
  360. setVisible (true);
  361. oldWinProc = SubclassWindow (parentHWND, (WNDPROC) interceptingWinProc);
  362. SetWindowLong (parentHWND, GWL_USERDATA, (LONG) this);
  363. resizeToParentWindow();
  364. }
  365. }
  366. }
  367. //==============================================================================
  368. #else
  369. NSView* currentParentView;
  370. NSView* findViewAt (NSView* parent, float x, float y) const
  371. {
  372. NSRect r = [parent frame];
  373. x -= r.origin.x;
  374. y -= r.origin.y;
  375. if (x >= 0 && x < r.size.width && y >= 0 && y < r.size.height)
  376. {
  377. for (int i = [[parent subviews] count]; --i >= 0;)
  378. {
  379. NSView* v = (NSView*) [[parent subviews] objectAtIndex: i];
  380. if (v != (NSView*) getWindowHandle())
  381. {
  382. NSView* found = findViewAt (v, x, y);
  383. if (found != 0)
  384. return found;
  385. }
  386. }
  387. return parent;
  388. }
  389. return 0;
  390. }
  391. public:
  392. static bool isBrowserContentView (NSView* v)
  393. {
  394. return [[v className] isEqualToString: @"WebNetscapePluginDocumentView"]
  395. || [[v className] isEqualToString: @"WebPluginDocumentView"]
  396. || [[v className] isEqualToString: @"ChildView"];
  397. }
  398. void setWindow (NPWindow* window)
  399. {
  400. const ScopedAutoReleasePool pool;
  401. NSView* parentView = 0;
  402. WindowRef windowRef = window != 0 ? ((NP_CGContext*) window->window)->window : 0;
  403. if (windowRef != 0)
  404. {
  405. NSWindow* win = [[[NSWindow alloc] initWithWindowRef: windowRef] autorelease];
  406. parentView = findViewAt ([win contentView], window->x + 0.5f, window->y + 0.5f);
  407. log (nsStringToJuce ([parentView description]));
  408. if (! isBrowserContentView (parentView))
  409. parentView = currentParentView;
  410. }
  411. if (parentView != currentParentView)
  412. {
  413. //log ("new view: " + nsStringToJuce ([parentView description]));
  414. removeFromDesktop();
  415. setVisible (false);
  416. currentParentView = parentView;
  417. if (parentView != 0)
  418. {
  419. setSize (window->width, window->height);
  420. addToDesktop (0, parentView);
  421. setVisible (true);
  422. }
  423. }
  424. if (window != 0)
  425. setSize (window->width, window->height);
  426. }
  427. #endif
  428. };
  429. //==============================================================================
  430. static NPIdentifier getIdentifierFromString (const var::identifier& s) throw()
  431. {
  432. return browser.getstringidentifier (s.name.toUTF8());
  433. }
  434. static const var createValueFromNPVariant (NPP npp, const NPVariant& v);
  435. static void createNPVariantFromValue (NPP npp, NPVariant& out, const var& v);
  436. #if JUCE_DEBUG
  437. static int numDOWNP = 0, numJuceSO = 0;
  438. #endif
  439. //==============================================================================
  440. class DynamicObjectWrappingNPObject : public DynamicObject
  441. {
  442. NPP npp;
  443. NPObject* const source;
  444. public:
  445. DynamicObjectWrappingNPObject (NPP npp_, NPObject* const source_)
  446. : npp (npp_),
  447. source (browser.retainobject (source_))
  448. {
  449. DBG ("num NP wrapper objs: " + String (++numDOWNP));
  450. }
  451. ~DynamicObjectWrappingNPObject()
  452. {
  453. browser.releaseobject (source);
  454. DBG ("num NP wrapper objs: " + String (--numDOWNP));
  455. }
  456. const var getProperty (const var::identifier& propertyName) const
  457. {
  458. NPVariant result;
  459. VOID_TO_NPVARIANT (result);
  460. browser.getproperty (npp, source, getIdentifierFromString (propertyName), &result);
  461. const var v (createValueFromNPVariant (npp, result));
  462. browser.releasevariantvalue (&result);
  463. return v;
  464. }
  465. bool hasProperty (const var::identifier& propertyName) const
  466. {
  467. NPVariant result;
  468. VOID_TO_NPVARIANT (result);
  469. const bool hasProp = browser.getproperty (npp, source, getIdentifierFromString (propertyName), &result);
  470. browser.releasevariantvalue (&result);
  471. return hasProp;
  472. }
  473. void setProperty (const var::identifier& propertyName, const var& newValue)
  474. {
  475. NPVariant value;
  476. createNPVariantFromValue (npp, value, newValue);
  477. browser.setproperty (npp, source, getIdentifierFromString (propertyName), &value);
  478. browser.releasevariantvalue (&value);
  479. }
  480. void removeProperty (const var::identifier& propertyName)
  481. {
  482. browser.removeproperty (npp, source, getIdentifierFromString (propertyName));
  483. }
  484. bool hasMethod (const var::identifier& methodName) const
  485. {
  486. return browser.hasmethod (npp, source, getIdentifierFromString (methodName));
  487. }
  488. const var invokeMethod (const var::identifier& methodName,
  489. const var* parameters,
  490. int numParameters)
  491. {
  492. var returnVal;
  493. NPVariant result;
  494. VOID_TO_NPVARIANT (result);
  495. if (numParameters > 0)
  496. {
  497. NPVariant* params = (NPVariant*) juce_malloc (sizeof (NPVariant*) * numParameters);
  498. int i;
  499. for (i = 0; i < numParameters; ++i)
  500. createNPVariantFromValue (npp, params[i], parameters[i]);
  501. if (browser.invoke (npp, source, getIdentifierFromString (methodName),
  502. params, numParameters, &result))
  503. {
  504. returnVal = createValueFromNPVariant (npp, result);
  505. browser.releasevariantvalue (&result);
  506. }
  507. for (i = 0; i < numParameters; ++i)
  508. browser.releasevariantvalue (&params[i]);
  509. juce_free (params);
  510. }
  511. else
  512. {
  513. if (browser.invoke (npp, source, getIdentifierFromString (methodName), 0, 0, &result))
  514. {
  515. returnVal = createValueFromNPVariant (npp, result);
  516. browser.releasevariantvalue (&result);
  517. }
  518. }
  519. return returnVal;
  520. }
  521. };
  522. //==============================================================================
  523. class NPObjectWrappingDynamicObject : public NPObject
  524. {
  525. public:
  526. static NPObject* create (NPP npp, const var& objectToWrap);
  527. virtual ~NPObjectWrappingDynamicObject()
  528. {
  529. DBG ("num Juce wrapper objs: " + String (--numJuceSO));
  530. }
  531. private:
  532. NPObjectWrappingDynamicObject (NPP npp_)
  533. : npp (npp_)
  534. {
  535. DBG ("num Juce wrapper objs: " + String (++numJuceSO));
  536. }
  537. //==============================================================================
  538. bool construct (const NPVariant *args, uint32_t argCount, NPVariant *result);
  539. void invalidate() {}
  540. bool hasMethod (NPIdentifier name)
  541. {
  542. DynamicObject* const o = object.getObject();
  543. return o != 0 && o->hasMethod (identifierToString (name));
  544. }
  545. bool invoke (NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* out)
  546. {
  547. DynamicObject* const o = object.getObject();
  548. const var::identifier methodName (identifierToString (name));
  549. if (o == 0 || ! o->hasMethod (methodName))
  550. return false;
  551. var* params = (var*) juce_calloc (sizeof (var) * argCount);
  552. for (uint32_t i = 0; i < argCount; ++i)
  553. params[i] = createValueFromNPVariant (npp, args[i]);
  554. const var result (o->invokeMethod (methodName, params, argCount));
  555. for (int i = argCount; --i >= 0;)
  556. params[i] = var();
  557. juce_free (params);
  558. if (out != 0)
  559. createNPVariantFromValue (npp, *out, result);
  560. return true;
  561. }
  562. bool invokeDefault (const NPVariant* args, uint32_t argCount, NPVariant* result)
  563. {
  564. return false;
  565. }
  566. bool hasProperty (NPIdentifier name)
  567. {
  568. DynamicObject* const o = object.getObject();
  569. return o != 0 && o->hasProperty (identifierToString (name));
  570. }
  571. bool getProperty (NPIdentifier name, NPVariant* out)
  572. {
  573. DynamicObject* const o = object.getObject();
  574. const var::identifier propName (identifierToString (name));
  575. if (o == 0 || ! o->hasProperty (propName))
  576. return false;
  577. const var result (o->getProperty (propName));
  578. if (out != 0)
  579. createNPVariantFromValue (npp, *out, result);
  580. return true;
  581. }
  582. bool setProperty (NPIdentifier name, const NPVariant* value)
  583. {
  584. DynamicObject* const o = object.getObject();
  585. if (value == 0 || o == 0)
  586. return false;
  587. o->setProperty (identifierToString (name), createValueFromNPVariant (npp, *value));
  588. return true;
  589. }
  590. bool removeProperty (NPIdentifier name)
  591. {
  592. DynamicObject* const o = object.getObject();
  593. const var::identifier propName (identifierToString (name));
  594. if (o == 0 || ! o->hasProperty (propName))
  595. return false;
  596. o->removeProperty (propName);
  597. return true;
  598. }
  599. bool enumerate (NPIdentifier** identifier, uint32_t* count)
  600. {
  601. return false;
  602. }
  603. //==============================================================================
  604. NPP npp;
  605. var object;
  606. static const var::identifier identifierToString (NPIdentifier id)
  607. {
  608. NPUTF8* const name = browser.utf8fromidentifier (id);
  609. const var::identifier result ((const char*) name);
  610. browser.memfree (name);
  611. return result;
  612. }
  613. public:
  614. //==============================================================================
  615. static NPObject* createInstance (NPP npp, NPClass* aClass) { return new NPObjectWrappingDynamicObject (npp); }
  616. static void class_deallocate (NPObject* npobj) { delete (NPObjectWrappingDynamicObject*) npobj; }
  617. static void class_invalidate (NPObject* npobj) { ((NPObjectWrappingDynamicObject*) npobj)->invalidate(); }
  618. static bool class_hasMethod (NPObject* npobj, NPIdentifier name) { return ((NPObjectWrappingDynamicObject*) npobj)->hasMethod (name); }
  619. static bool class_invoke (NPObject* npobj, NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* result) { return ((NPObjectWrappingDynamicObject*) npobj)->invoke (name, args, argCount, result); }
  620. static bool class_invokeDefault (NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result) { return ((NPObjectWrappingDynamicObject*) npobj)->invokeDefault (args, argCount, result); }
  621. static bool class_hasProperty (NPObject* npobj, NPIdentifier name) { return ((NPObjectWrappingDynamicObject*) npobj)->hasProperty (name); }
  622. static bool class_getProperty (NPObject* npobj, NPIdentifier name, NPVariant* result) { return ((NPObjectWrappingDynamicObject*) npobj)->getProperty (name, result); }
  623. static bool class_setProperty (NPObject* npobj, NPIdentifier name, const NPVariant* value) { return ((NPObjectWrappingDynamicObject*) npobj)->setProperty (name, value); }
  624. static bool class_removeProperty (NPObject* npobj, NPIdentifier name) { return ((NPObjectWrappingDynamicObject*) npobj)->removeProperty (name); }
  625. static bool class_enumerate (NPObject* npobj, NPIdentifier** identifier, uint32_t* count) { return ((NPObjectWrappingDynamicObject*) npobj)->enumerate (identifier, count); }
  626. static bool class_construct (NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result) { return ((NPObjectWrappingDynamicObject*) npobj)->construct (args, argCount, result); }
  627. };
  628. static NPClass sNPObjectWrappingDynamicObject_NPClass =
  629. {
  630. NP_CLASS_STRUCT_VERSION_ENUM, NPObjectWrappingDynamicObject::createInstance,
  631. NPObjectWrappingDynamicObject::class_deallocate, NPObjectWrappingDynamicObject::class_invalidate,
  632. NPObjectWrappingDynamicObject::class_hasMethod, NPObjectWrappingDynamicObject::class_invoke,
  633. NPObjectWrappingDynamicObject::class_invokeDefault, NPObjectWrappingDynamicObject::class_hasProperty,
  634. NPObjectWrappingDynamicObject::class_getProperty, NPObjectWrappingDynamicObject::class_setProperty,
  635. NPObjectWrappingDynamicObject::class_removeProperty, NPObjectWrappingDynamicObject::class_enumerate
  636. };
  637. bool NPObjectWrappingDynamicObject::construct (const NPVariant* args, uint32_t argCount, NPVariant* result)
  638. {
  639. NPObject* const newObj = browser.createobject (npp, &sNPObjectWrappingDynamicObject_NPClass);
  640. if (newObj == 0)
  641. return false;
  642. OBJECT_TO_NPVARIANT (newObj, *result);
  643. return true;
  644. }
  645. NPObject* NPObjectWrappingDynamicObject::create (NPP npp, const var& objectToWrap)
  646. {
  647. jassert (objectToWrap.getObject() != 0);
  648. NPObject* const nppObject = browser.createobject (npp, &sNPObjectWrappingDynamicObject_NPClass);
  649. if (nppObject != 0)
  650. ((NPObjectWrappingDynamicObject*) nppObject)->object = objectToWrap;
  651. return nppObject;
  652. }
  653. //==============================================================================
  654. static const var createValueFromNPVariant (NPP npp, const NPVariant& v)
  655. {
  656. if (NPVARIANT_IS_BOOLEAN (v))
  657. return var (NPVARIANT_TO_BOOLEAN (v));
  658. else if (NPVARIANT_IS_INT32 (v))
  659. return var (NPVARIANT_TO_INT32 (v));
  660. else if (NPVARIANT_IS_DOUBLE (v))
  661. return var (NPVARIANT_TO_DOUBLE (v));
  662. else if (NPVARIANT_IS_STRING (v))
  663. #if JUCE_MAC
  664. return var (String::fromUTF8 ((const juce::uint8*) (NPVARIANT_TO_STRING (v).UTF8Characters),
  665. (int) NPVARIANT_TO_STRING (v).UTF8Length));
  666. #else
  667. return var (String::fromUTF8 ((const juce::uint8*) (NPVARIANT_TO_STRING (v).utf8characters),
  668. (int) NPVARIANT_TO_STRING (v).utf8length));
  669. #endif
  670. else if (NPVARIANT_IS_OBJECT (v))
  671. return var (new DynamicObjectWrappingNPObject (npp, NPVARIANT_TO_OBJECT (v)));
  672. return var();
  673. }
  674. static void createNPVariantFromValue (NPP npp, NPVariant& out, const var& v)
  675. {
  676. if (v.isInt())
  677. INT32_TO_NPVARIANT ((int) v, out);
  678. else if (v.isBool())
  679. BOOLEAN_TO_NPVARIANT ((bool) v, out);
  680. else if (v.isDouble())
  681. DOUBLE_TO_NPVARIANT ((double) v, out);
  682. else if (v.isString())
  683. #if JUCE_MAC
  684. STRINGZ_TO_NPVARIANT (strdup (v.toString().toUTF8()), out);
  685. #else
  686. STRINGZ_TO_NPVARIANT (_strdup (v.toString().toUTF8()), out);
  687. #endif
  688. else if (v.isObject())
  689. OBJECT_TO_NPVARIANT (NPObjectWrappingDynamicObject::create (npp, v), out);
  690. else
  691. VOID_TO_NPVARIANT (out);
  692. }
  693. //==============================================================================
  694. class JucePluginInstance
  695. {
  696. public:
  697. //==============================================================================
  698. JucePluginInstance (NPP npp_)
  699. : npp (npp_),
  700. holderComp (0),
  701. scriptObject (0)
  702. {
  703. }
  704. ~JucePluginInstance()
  705. {
  706. setWindow (0);
  707. }
  708. bool setWindow (NPWindow* window)
  709. {
  710. if (window != 0)
  711. {
  712. if (holderComp == 0)
  713. holderComp = new BrowserPluginHolderComponent (npp);
  714. holderComp->setWindow (window);
  715. }
  716. else
  717. {
  718. deleteAndZero (holderComp);
  719. scriptObject = 0;
  720. }
  721. return true;
  722. }
  723. NPObject* getScriptableObject()
  724. {
  725. if (scriptObject == 0)
  726. scriptObject = NPObjectWrappingDynamicObject::create (npp, holderComp->getObject());
  727. if (scriptObject != 0 && shouldRetainBrowserObject())
  728. browser.retainobject (scriptObject);
  729. return scriptObject;
  730. }
  731. //==============================================================================
  732. NPP npp;
  733. BrowserPluginHolderComponent* holderComp;
  734. NPObject* scriptObject;
  735. private:
  736. bool shouldRetainBrowserObject() const
  737. {
  738. #if JUCE_MAC
  739. const String version (browser.uagent (npp));
  740. if (! version.containsIgnoreCase (T(" AppleWebKit/")))
  741. return true;
  742. int versionNum = version.fromFirstOccurrenceOf (T(" AppleWebKit/"), false, true).getIntValue();
  743. return versionNum == 0 || versionNum >= 420;
  744. #else
  745. return true;
  746. #endif
  747. }
  748. };
  749. //==============================================================================
  750. static NPP currentlyInitialisingNPP = 0;
  751. static int numPluginInstances = 0;
  752. NPError NPP_New (NPMIMEType pluginType, NPP npp, ::uint16 mode, ::int16 argc, char* argn[], char* argv[], NPSavedData* saved)
  753. {
  754. log ("NPP_New");
  755. if (npp == 0)
  756. return NPERR_INVALID_INSTANCE_ERROR;
  757. #if JUCE_MAC
  758. browser.setvalue (npp, (NPPVariable) NPNVpluginDrawingModel, (void*) NPDrawingModelCoreGraphics);
  759. #endif
  760. if (numPluginInstances++ == 0)
  761. {
  762. initialiseJuce_GUI();
  763. log ("initialiseJuce_GUI()");
  764. }
  765. currentlyInitialisingNPP = npp;
  766. JucePluginInstance* p = new JucePluginInstance (npp);
  767. currentlyInitialisingNPP = 0;
  768. npp->pdata = (void*) p;
  769. return NPERR_NO_ERROR;
  770. }
  771. NPError NPP_Destroy (NPP npp, NPSavedData** save)
  772. {
  773. log ("NPP_Destroy");
  774. if (npp == 0)
  775. return NPERR_INVALID_INSTANCE_ERROR;
  776. JucePluginInstance* const p = (JucePluginInstance*) npp->pdata;
  777. if (p != 0)
  778. {
  779. delete p;
  780. if (--numPluginInstances == 0)
  781. {
  782. shutdownJuce_GUI();
  783. log ("shutdownJuce_GUI()");
  784. }
  785. }
  786. return NPERR_NO_ERROR;
  787. }
  788. NPError NPP_SetWindow (NPP npp, NPWindow* pNPWindow)
  789. {
  790. if (npp == 0)
  791. return NPERR_INVALID_INSTANCE_ERROR;
  792. if (pNPWindow == 0)
  793. return NPERR_GENERIC_ERROR;
  794. JucePluginInstance* const p = (JucePluginInstance*) npp->pdata;
  795. if (p == 0)
  796. return NPERR_GENERIC_ERROR;
  797. currentlyInitialisingNPP = npp;
  798. NPError result = p->setWindow (pNPWindow) ? NPERR_NO_ERROR
  799. : NPERR_MODULE_LOAD_FAILED_ERROR;
  800. currentlyInitialisingNPP = 0;
  801. return result;
  802. }
  803. //==============================================================================
  804. NPError NPP_GetValue (NPP npp, NPPVariable variable, void* value)
  805. {
  806. if (npp == 0)
  807. return NPERR_INVALID_INSTANCE_ERROR;
  808. JucePluginInstance* const p = (JucePluginInstance*) npp->pdata;
  809. if (p == 0)
  810. return NPERR_GENERIC_ERROR;
  811. switch (variable)
  812. {
  813. case NPPVpluginNameString:
  814. *((char**) value) = JuceBrowserPlugin_Name;
  815. break;
  816. case NPPVpluginDescriptionString:
  817. *((char**) value) = JuceBrowserPlugin_Desc;
  818. break;
  819. case NPPVpluginScriptableNPObject:
  820. *((NPObject**) value) = p->getScriptableObject();
  821. break;
  822. default:
  823. return NPERR_GENERIC_ERROR;
  824. }
  825. return NPERR_NO_ERROR;
  826. }
  827. NPError NPP_NewStream (NPP npp,
  828. NPMIMEType type,
  829. NPStream* stream,
  830. NPBool seekable,
  831. ::uint16* stype)
  832. {
  833. if (npp == 0)
  834. return NPERR_INVALID_INSTANCE_ERROR;
  835. return NPERR_NO_ERROR;
  836. }
  837. ::int32 NPP_WriteReady (NPP npp, NPStream *stream)
  838. {
  839. if (npp == 0)
  840. return NPERR_INVALID_INSTANCE_ERROR;
  841. return 0x0fffffff;
  842. }
  843. ::int32 NPP_Write (NPP npp, NPStream *stream, ::int32 offset, ::int32 len, void *buffer)
  844. {
  845. if (npp == 0)
  846. return NPERR_INVALID_INSTANCE_ERROR;
  847. return len;
  848. }
  849. NPError NPP_DestroyStream (NPP npp, NPStream *stream, NPError reason)
  850. {
  851. if (npp == 0)
  852. return NPERR_INVALID_INSTANCE_ERROR;
  853. return NPERR_NO_ERROR;
  854. }
  855. void NPP_StreamAsFile (NPP npp, NPStream* stream, const char* fname)
  856. {
  857. if (npp == 0)
  858. return;
  859. }
  860. void NPP_Print (NPP npp, NPPrint* printInfo)
  861. {
  862. if (npp == 0)
  863. return;
  864. }
  865. void NPP_URLNotify (NPP npp, const char* url, NPReason reason, void* notifyData)
  866. {
  867. if (npp == 0)
  868. return;
  869. }
  870. NPError NPP_SetValue (NPP npp, NPNVariable variable, void* value)
  871. {
  872. if (npp == 0)
  873. return NPERR_INVALID_INSTANCE_ERROR;
  874. return NPERR_NO_ERROR;
  875. }
  876. ::int16 NPP_HandleEvent (NPP npp, void* ev)
  877. {
  878. if (npp != 0)
  879. {
  880. //JucePluginInstance* const p = (JucePluginInstance*) npp->pdata;
  881. }
  882. return 0;
  883. }
  884. //==============================================================================
  885. static NPP getInstance (const BrowserPluginComponent* bpc)
  886. {
  887. BrowserPluginHolderComponent* holder = dynamic_cast <BrowserPluginHolderComponent*> (bpc->getParentComponent());
  888. if (holder != 0)
  889. return holder->npp;
  890. return currentlyInitialisingNPP;
  891. }
  892. //==============================================================================
  893. BrowserPluginComponent::BrowserPluginComponent()
  894. {
  895. }
  896. BrowserPluginComponent::~BrowserPluginComponent()
  897. {
  898. }
  899. const String BrowserPluginComponent::getBrowserVersion() const
  900. {
  901. String s;
  902. if (getInstance (this) != 0)
  903. s << browser.uagent (getInstance (this));
  904. else
  905. s << "Netscape Plugin V" << (int) ((browser.version >> 8) & 0xff)
  906. << "." << (int) (browser.version & 0xff);
  907. return s;
  908. }