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.

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