2010-09-28 Johnny Ding <jnd@chromium.org>
[WebKit-https.git] / WebKitTools / DumpRenderTree / TestNetscapePlugIn / main.cpp
1 /*
2  * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "PluginObject.h"
27
28 #include "PluginTest.h"
29 #include <string>
30
31 #if !defined(NP_NO_CARBON) && defined(QD_HEADERS_ARE_PRIVATE) && QD_HEADERS_ARE_PRIVATE
32 extern "C" void GlobalToLocal(Point*);
33 #endif
34
35 using namespace std;
36
37 #define CRASH() do { \
38     *(int *)(uintptr_t)0xbbadbeef = 0; \
39     ((void(*)())0)(); /* More reliable, but doesn't say BBADBEEF */ \
40 } while(false)
41
42 static bool getEntryPointsWasCalled;
43 static bool initializeWasCalled;
44
45 #if XP_WIN
46 #define STDCALL __stdcall
47
48 static inline int strcasecmp(const char* s1, const char* s2)
49 {
50     return _stricmp(s1, s2);
51 }
52
53 #else
54 #define STDCALL
55 #endif
56
57 // Entry points
58 extern "C"
59 NPError STDCALL NP_Initialize(NPNetscapeFuncs *browserFuncs)
60 {
61     initializeWasCalled = true;
62
63 #if XP_WIN
64     // Simulate Flash and QuickTime's behavior of crashing when NP_Initialize is called before NP_GetEntryPoints.
65     if (!getEntryPointsWasCalled)
66         CRASH();
67 #endif
68
69     browser = browserFuncs;
70     return NPERR_NO_ERROR;
71 }
72
73 extern "C"
74 NPError STDCALL NP_GetEntryPoints(NPPluginFuncs *pluginFuncs)
75 {
76     getEntryPointsWasCalled = true;
77
78 #if XP_MACOSX
79     // Simulate Silverlight's behavior of crashing when NP_GetEntryPoints is called before NP_Initialize.
80     if (!initializeWasCalled)
81         CRASH();
82 #endif
83
84     pluginFuncs->version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
85     pluginFuncs->size = sizeof(pluginFuncs);
86     pluginFuncs->newp = NPP_New;
87     pluginFuncs->destroy = NPP_Destroy;
88     pluginFuncs->setwindow = NPP_SetWindow;
89     pluginFuncs->newstream = NPP_NewStream;
90     pluginFuncs->destroystream = NPP_DestroyStream;
91     pluginFuncs->asfile = NPP_StreamAsFile;
92     pluginFuncs->writeready = NPP_WriteReady;
93     pluginFuncs->write = (NPP_WriteProcPtr)NPP_Write;
94     pluginFuncs->print = NPP_Print;
95     pluginFuncs->event = NPP_HandleEvent;
96     pluginFuncs->urlnotify = NPP_URLNotify;
97     pluginFuncs->getvalue = NPP_GetValue;
98     pluginFuncs->setvalue = NPP_SetValue;
99     
100     return NPERR_NO_ERROR;
101 }
102
103 extern "C"
104 void STDCALL NP_Shutdown(void)
105 {
106 }
107
108 static void executeScript(const PluginObject* obj, const char* script);
109
110 NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char *argn[], char *argv[], NPSavedData *saved)
111 {
112     bool forceCarbon = false;
113
114 #if XP_MACOSX
115     NPEventModel eventModel;
116     
117     // Always turn on the CG model
118     NPBool supportsCoreGraphics;
119     if (browser->getvalue(instance, NPNVsupportsCoreGraphicsBool, &supportsCoreGraphics) != NPERR_NO_ERROR)
120         supportsCoreGraphics = false;
121     
122     if (!supportsCoreGraphics)
123         return NPERR_INCOMPATIBLE_VERSION_ERROR;
124
125     NPDrawingModel drawingModelToUse = NPDrawingModelCoreGraphics;
126
127     NPBool supportsCoreAnimation;
128     if (browser->getvalue(instance, NPNVsupportsCoreAnimationBool, &supportsCoreAnimation) != NPERR_NO_ERROR)
129         supportsCoreAnimation = false;
130
131 #ifndef NP_NO_CARBON
132     NPBool supportsCarbon = false;
133 #endif
134     NPBool supportsCocoa = false;
135
136 #ifndef NP_NO_CARBON
137     // A browser that doesn't know about NPNVsupportsCarbonBool is one that only supports Carbon event model.
138     if (browser->getvalue(instance, NPNVsupportsCarbonBool, &supportsCarbon) != NPERR_NO_ERROR)
139         supportsCarbon = true;
140 #endif
141
142     if (browser->getvalue(instance, NPNVsupportsCocoaBool, &supportsCocoa) != NPERR_NO_ERROR)
143         supportsCocoa = false;
144
145     if (supportsCocoa && !forceCarbon) {
146         eventModel = NPEventModelCocoa;
147 #ifndef NP_NO_CARBON
148     } else if (supportsCarbon) {
149         eventModel = NPEventModelCarbon;
150 #endif
151     } else {
152         return NPERR_INCOMPATIBLE_VERSION_ERROR;
153     }
154
155      browser->setvalue(instance, NPPVpluginEventModel, (void *)eventModel);
156 #endif // XP_MACOSX
157
158     PluginObject* obj = (PluginObject*)browser->createobject(instance, getPluginClass());
159     instance->pdata = obj;
160
161 #if XP_MACOSX
162     obj->eventModel = eventModel;
163 #if !defined(BUILDING_ON_TIGER)
164     obj->coreAnimationLayer = 0;
165 #endif
166 #endif // XP_MACOSX
167
168     string testIdentifier;
169     
170     for (int i = 0; i < argc; i++) {
171         if (strcasecmp(argn[i], "test") == 0)
172             testIdentifier = argv[i];
173         if (strcasecmp(argn[i], "onstreamload") == 0 && !obj->onStreamLoad)
174             obj->onStreamLoad = strdup(argv[i]);
175         else if (strcasecmp(argn[i], "onStreamDestroy") == 0 && !obj->onStreamDestroy)
176             obj->onStreamDestroy = strdup(argv[i]);
177         else if (strcasecmp(argn[i], "onURLNotify") == 0 && !obj->onURLNotify)
178             obj->onURLNotify = strdup(argv[i]);
179         else if (strcasecmp(argn[i], "src") == 0 &&
180                  strcasecmp(argv[i], "data:application/x-webkit-test-netscape,returnerrorfromnewstream") == 0)
181             obj->returnErrorFromNewStream = TRUE;
182         else if (strcasecmp(argn[i], "onSetWindow") == 0 && !obj->onSetWindow)
183             obj->onSetWindow = strdup(argv[i]);
184         else if (strcasecmp(argn[i], "logfirstsetwindow") == 0)
185             obj->logSetWindow = TRUE;
186         else if (strcasecmp(argn[i], "testnpruntime") == 0)
187             testNPRuntime(instance);
188         else if (strcasecmp(argn[i], "forcecarbon") == 0)
189             forceCarbon = true;
190         else if (strcasecmp(argn[i], "logSrc") == 0) {
191             for (int i = 0; i < argc; i++)
192                 if (strcasecmp(argn[i], "src") == 0)
193                     pluginLog(instance, "src: %s", argv[i]);
194         } else if (strcasecmp(argn[i], "cleardocumentduringnew") == 0)
195             executeScript(obj, "document.body.innerHTML = ''");
196         else if (!strcasecmp(argn[i], "ondestroy"))
197             obj->onDestroy = strdup(argv[i]);
198         else if (strcasecmp(argn[i], "testwindowopen") == 0)
199             obj->testWindowOpen = TRUE;
200         else if (strcasecmp(argn[i], "drawingmodel") == 0) {
201 #if XP_MACOSX && !defined(BUILDING_ON_TIGER)
202             const char* value = argv[i];
203             if (strcasecmp(value, "coreanimation") == 0) {
204                 if (supportsCoreAnimation)
205                     drawingModelToUse = NPDrawingModelCoreAnimation;
206                 else
207                     return NPERR_INCOMPATIBLE_VERSION_ERROR;
208              } else if (strcasecmp(value, "coregraphics") == 0) {
209                 if (supportsCoreGraphics)
210                     drawingModelToUse = NPDrawingModelCoreGraphics;
211                 else
212                     return NPERR_INCOMPATIBLE_VERSION_ERROR;
213              } else
214                 return NPERR_INCOMPATIBLE_VERSION_ERROR;
215 #endif
216         } else if (strcasecmp(argn[i], "testGetURLOnDestroy") == 0) {
217 #if XP_WIN
218             // FIXME: When https://bugs.webkit.org/show_bug.cgi?id=41831 is fixed, this #ifdef can be removed.
219             obj->testGetURLOnDestroy = TRUE;
220 #endif
221         } else if (!strcasecmp(argn[i], "src") && strstr(argv[i], "plugin-document-has-focus.pl"))
222             obj->testKeyboardFocusForPlugins = TRUE;
223         else if (!strcasecmp(argn[i], "evaluatescript")) {
224             char* script = argv[i];
225             if (script == strstr(script, "mouse::")) {
226                 obj->mouseDownForEvaluateScript = true;
227                 obj->evaluateScriptOnMouseDownOrKeyDown = strdup(script + sizeof("mouse::") - 1);
228             } else if (script == strstr(script, "key::")) {
229                 obj->evaluateScriptOnMouseDownOrKeyDown = strdup(script + sizeof("key::") - 1);
230             }
231             // When testing evaluate script on mouse-down or key-down, allow event logging to handle events.
232             if (obj->evaluateScriptOnMouseDownOrKeyDown)
233                 obj->eventLogging = true;
234         }
235     }
236
237 #if XP_MACOSX
238     browser->setvalue(instance, NPPVpluginDrawingModel, (void *)drawingModelToUse);
239 #if !defined(BUILDING_ON_TIGER)
240     if (drawingModelToUse == NPDrawingModelCoreAnimation)
241         obj->coreAnimationLayer = createCoreAnimationLayer();
242 #endif
243 #endif
244
245     browser->getvalue(instance, NPNVprivateModeBool, (void *)&obj->cachedPrivateBrowsingMode);
246
247     obj->pluginTest = PluginTest::create(instance, testIdentifier);
248
249     return NPERR_NO_ERROR;
250 }
251
252 NPError NPP_Destroy(NPP instance, NPSavedData **save)
253 {
254     PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
255     if (obj) {
256         if (obj->testGetURLOnDestroy)
257             browser->geturlnotify(obj->npp, "about:blank", "", 0);
258
259         if (obj->onDestroy) {
260             executeScript(obj, obj->onDestroy);
261             free(obj->onDestroy);
262         }
263
264         if (obj->onStreamLoad)
265             free(obj->onStreamLoad);
266
267         if (obj->onStreamDestroy)
268             free(obj->onStreamDestroy);
269
270         if (obj->onURLNotify)
271             free(obj->onURLNotify);
272
273         if (obj->onSetWindow)
274             free(obj->onSetWindow);
275         
276         if (obj->logDestroy)
277             pluginLog(instance, "NPP_Destroy");
278
279 #if XP_MACOSX && !defined(BUILDING_ON_TIGER)
280         if (obj->coreAnimationLayer)
281             CFRelease(obj->coreAnimationLayer);
282 #endif
283
284         browser->releaseobject(&obj->header);
285     }
286     return NPERR_NO_ERROR;
287 }
288
289 NPError NPP_SetWindow(NPP instance, NPWindow *window)
290 {
291     PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
292
293     if (obj) {
294         obj->lastWindow = *window;
295
296         if (obj->logSetWindow) {
297             pluginLog(instance, "NPP_SetWindow: %d %d", (int)window->width, (int)window->height);
298             obj->logSetWindow = FALSE;
299         }
300
301         if (obj->onSetWindow)
302             executeScript(obj, obj->onSetWindow);
303
304         if (obj->testWindowOpen) {
305             testWindowOpen(instance);
306             obj->testWindowOpen = FALSE;
307         }
308
309         if (obj->testKeyboardFocusForPlugins) {
310             obj->eventLogging = true;
311             executeScript(obj, "eventSender.keyDown('A');");
312         }
313     }
314     
315     return obj->pluginTest->NPP_SetWindow(instance, window);
316 }
317
318 static void executeScript(const PluginObject* obj, const char* script)
319 {
320     NPObject *windowScriptObject;
321     browser->getvalue(obj->npp, NPNVWindowNPObject, &windowScriptObject);
322
323     NPString npScript;
324     npScript.UTF8Characters = script;
325     npScript.UTF8Length = strlen(script);
326
327     NPVariant browserResult;
328     browser->evaluate(obj->npp, windowScriptObject, &npScript, &browserResult);
329     browser->releasevariantvalue(&browserResult);
330 }
331
332 NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream *stream, NPBool seekable, uint16_t *stype)
333 {
334     PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
335     obj->stream = stream;
336     *stype = NP_NORMAL;
337
338     if (obj->returnErrorFromNewStream)
339         return NPERR_GENERIC_ERROR;
340     
341     if (browser->version >= NPVERS_HAS_RESPONSE_HEADERS)
342         notifyStream(obj, stream->url, stream->headers);
343
344     if (obj->onStreamLoad)
345         executeScript(obj, obj->onStreamLoad);
346
347     return NPERR_NO_ERROR;
348 }
349
350 NPError NPP_DestroyStream(NPP instance, NPStream *stream, NPReason reason)
351 {
352     PluginObject* obj = (PluginObject*)instance->pdata;
353
354     if (obj->onStreamDestroy) {
355         NPObject* windowObject = 0;
356         NPError error = browser->getvalue(instance, NPNVWindowNPObject, &windowObject);
357         
358         if (error == NPERR_NO_ERROR) {
359             NPVariant onStreamDestroyVariant;
360             if (browser->getproperty(instance, windowObject, browser->getstringidentifier(obj->onStreamDestroy), &onStreamDestroyVariant)) {
361                 if (NPVARIANT_IS_OBJECT(onStreamDestroyVariant)) {
362                     NPObject* onStreamDestroyFunction = NPVARIANT_TO_OBJECT(onStreamDestroyVariant);
363
364                     NPVariant reasonVariant;
365                     INT32_TO_NPVARIANT(reason, reasonVariant);
366
367                     NPVariant result;
368                     browser->invokeDefault(instance, onStreamDestroyFunction, &reasonVariant, 1, &result);
369                     browser->releasevariantvalue(&result);
370                 }
371                 browser->releasevariantvalue(&onStreamDestroyVariant);
372             }
373             browser->releaseobject(windowObject);
374         }
375     }
376
377     return obj->pluginTest->NPP_DestroyStream(stream, reason);
378 }
379
380 int32_t NPP_WriteReady(NPP instance, NPStream *stream)
381 {
382     return 4096;
383 }
384
385 int32_t NPP_Write(NPP instance, NPStream *stream, int32_t offset, int32_t len, void *buffer)
386 {
387     PluginObject* obj = (PluginObject*)instance->pdata;
388
389     if (obj->returnNegativeOneFromWrite)
390         return -1;
391
392     return len;
393 }
394
395 void NPP_StreamAsFile(NPP instance, NPStream *stream, const char *fname)
396 {
397 }
398
399 void NPP_Print(NPP instance, NPPrint *platformPrint)
400 {
401 }
402
403 #if XP_MACOSX
404 #ifndef NP_NO_CARBON
405 static int16_t handleEventCarbon(NPP instance, PluginObject* obj, EventRecord* event)
406 {
407     Point pt = { event->where.v, event->where.h };
408
409     switch (event->what) {
410         case nullEvent:
411             // these are delivered non-deterministically, don't log.
412             break;
413         case mouseDown:
414             GlobalToLocal(&pt);
415             pluginLog(instance, "mouseDown at (%d, %d)", pt.h, pt.v);
416             if (obj->evaluateScriptOnMouseDownOrKeyDown && obj->mouseDownForEvaluateScript)
417                 executeScript(obj, obj->evaluateScriptOnMouseDownOrKeyDown);
418             break;
419         case mouseUp:
420             GlobalToLocal(&pt);
421             pluginLog(instance, "mouseUp at (%d, %d)", pt.h, pt.v);
422             break;
423         case keyDown:
424             pluginLog(instance, "keyDown '%c'", (char)(event->message & 0xFF));
425             if (obj->evaluateScriptOnMouseDownOrKeyDown && !obj->mouseDownForEvaluateScript)
426                 executeScript(obj, obj->evaluateScriptOnMouseDownOrKeyDown);
427             break;
428         case keyUp:
429             pluginLog(instance, "keyUp '%c'", (char)(event->message & 0xFF));
430             if (obj->testKeyboardFocusForPlugins) {
431                 obj->eventLogging = false;
432                 obj->testKeyboardFocusForPlugins = FALSE;
433                 executeScript(obj, "layoutTestController.notifyDone();");
434             }
435             break;
436         case autoKey:
437             pluginLog(instance, "autoKey '%c'", (char)(event->message & 0xFF));
438             break;
439         case updateEvt:
440             pluginLog(instance, "updateEvt");
441             break;
442         case diskEvt:
443             pluginLog(instance, "diskEvt");
444             break;
445         case activateEvt:
446             pluginLog(instance, "activateEvt");
447             break;
448         case osEvt:
449             printf("PLUGIN: osEvt - ");
450             switch ((event->message & 0xFF000000) >> 24) {
451                 case suspendResumeMessage:
452                     printf("%s\n", (event->message & 0x1) ? "resume" : "suspend");
453                     break;
454                 case mouseMovedMessage:
455                     printf("mouseMoved\n");
456                     break;
457                 default:
458                     printf("%08lX\n", event->message);
459             }
460             break;
461         case kHighLevelEvent:
462             pluginLog(instance, "kHighLevelEvent");
463             break;
464         // NPAPI events
465         case getFocusEvent:
466             pluginLog(instance, "getFocusEvent");
467             break;
468         case loseFocusEvent:
469             pluginLog(instance, "loseFocusEvent");
470             break;
471         case adjustCursorEvent:
472             pluginLog(instance, "adjustCursorEvent");
473             break;
474         default:
475             pluginLog(instance, "event %d", event->what);
476     }
477     
478     return 0;
479 }
480 #endif
481
482 static int16_t handleEventCocoa(NPP instance, PluginObject* obj, NPCocoaEvent* event)
483 {
484     switch (event->type) {
485         case NPCocoaEventWindowFocusChanged:
486             
487         case NPCocoaEventFocusChanged:
488             if (event->data.focus.hasFocus)
489                 pluginLog(instance, "getFocusEvent");
490             else
491                 pluginLog(instance, "loseFocusEvent");
492             return 1;
493
494         case NPCocoaEventDrawRect:
495             return 1;
496
497         case NPCocoaEventKeyDown:
498             if (event->data.key.characters)
499                 pluginLog(instance, "keyDown '%c'", CFStringGetCharacterAtIndex(reinterpret_cast<CFStringRef>(event->data.key.characters), 0));
500             if (obj->evaluateScriptOnMouseDownOrKeyDown && !obj->mouseDownForEvaluateScript)
501                 executeScript(obj, obj->evaluateScriptOnMouseDownOrKeyDown);
502             return 1;
503
504         case NPCocoaEventKeyUp:
505             if (event->data.key.characters) {
506                 pluginLog(instance, "keyUp '%c'", CFStringGetCharacterAtIndex(reinterpret_cast<CFStringRef>(event->data.key.characters), 0));
507                 if (obj->testKeyboardFocusForPlugins) {
508                     obj->eventLogging = false;
509                     obj->testKeyboardFocusForPlugins = FALSE;
510                     executeScript(obj, "layoutTestController.notifyDone();");
511                 }
512             }
513             return 1;
514
515         case NPCocoaEventFlagsChanged:
516             return 1;
517
518         case NPCocoaEventMouseDown:
519             pluginLog(instance, "mouseDown at (%d, %d)", 
520                    (int)event->data.mouse.pluginX,
521                    (int)event->data.mouse.pluginY);
522             if (obj->evaluateScriptOnMouseDownOrKeyDown && obj->mouseDownForEvaluateScript)
523                 executeScript(obj, obj->evaluateScriptOnMouseDownOrKeyDown);
524             return 1;
525         case NPCocoaEventMouseUp:
526             pluginLog(instance, "mouseUp at (%d, %d)", 
527                    (int)event->data.mouse.pluginX,
528                    (int)event->data.mouse.pluginY);
529             return 1;
530             
531         case NPCocoaEventMouseMoved:
532         case NPCocoaEventMouseEntered:
533         case NPCocoaEventMouseExited:
534         case NPCocoaEventMouseDragged:
535         case NPCocoaEventScrollWheel:
536         case NPCocoaEventTextInput:
537             return 1;
538     }
539     
540     return 0;
541 }
542
543 #endif // XP_MACOSX
544
545 int16_t NPP_HandleEvent(NPP instance, void *event)
546 {
547     PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
548     if (!obj->eventLogging)
549         return 0;
550
551 #if XP_MACOSX
552 #ifndef NP_NO_CARBON
553     if (obj->eventModel == NPEventModelCarbon)
554         return handleEventCarbon(instance, obj, static_cast<EventRecord*>(event));
555 #endif
556
557     assert(obj->eventModel == NPEventModelCocoa);
558     return handleEventCocoa(instance, obj, static_cast<NPCocoaEvent*>(event));
559 #else
560     // FIXME: Implement for other platforms.
561     return 0;
562 #endif // XP_MACOSX
563 }
564
565 void NPP_URLNotify(NPP instance, const char *url, NPReason reason, void *notifyData)
566 {
567     PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
568  
569      if (obj->onURLNotify)
570          executeScript(obj, obj->onURLNotify);
571
572     handleCallback(obj, url, reason, notifyData);
573 }
574
575 NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value)
576 {
577     PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
578
579     // First, check if the PluginTest object supports getting this value.
580     if (obj->pluginTest->NPP_GetValue(variable, value) == NPERR_NO_ERROR)
581         return NPERR_NO_ERROR;
582
583     if (variable == NPPVpluginScriptableNPObject) {
584         void **v = (void **)value;
585         // Return value is expected to be retained
586         browser->retainobject((NPObject *)obj);
587         *v = obj;
588         return NPERR_NO_ERROR;
589     }
590     
591 #if XP_MACOSX && !defined(BUILDING_ON_TIGER)
592     if (variable == NPPVpluginCoreAnimationLayer) {
593         if (!obj->coreAnimationLayer)
594             return NPERR_GENERIC_ERROR;
595         
596         void **v = (void **)value;
597         *v = (void*)CFRetain(obj->coreAnimationLayer);
598         return NPERR_NO_ERROR;
599     }
600 #endif
601     
602     return NPERR_GENERIC_ERROR;
603 }
604
605 NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value)
606 {
607     PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
608
609     switch (variable) {
610         case NPNVprivateModeBool:
611             obj->cachedPrivateBrowsingMode = *(NPBool*)value;
612             return NPERR_NO_ERROR;
613         default:
614             return NPERR_GENERIC_ERROR;
615     }
616 }