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.

1214 lines
39KB

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