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.

1216 lines
40KB

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