[Qt][WK2] Set up plugin process on Unix
[WebKit-https.git] / Source / WebKit2 / WebProcess / Plugins / Netscape / NetscapeBrowserFuncs.cpp
1 /*
2  * Copyright (C) 2010 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. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "NetscapeBrowserFuncs.h"
28
29 #include "NPRuntimeUtilities.h"
30 #include "NetscapePlugin.h"
31 #include "PluginController.h"
32 #include <WebCore/HTTPHeaderMap.h>
33 #include <WebCore/IdentifierRep.h>
34 #include <WebCore/NotImplemented.h>
35 #include <WebCore/ProtectionSpace.h>
36 #include <WebCore/SharedBuffer.h>
37 #include <utility>
38
39 #if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
40 #include "NetscapeSandboxFunctions.h"
41 #endif
42
43 using namespace WebCore;
44 using namespace std;
45
46 namespace WebKit {
47
48 // Helper class for delaying destruction of a plug-in.
49 class PluginDestructionProtector {
50 public:
51     explicit PluginDestructionProtector(NetscapePlugin* plugin)
52         : m_protector(static_cast<Plugin*>(plugin)->controller())
53     {
54     }
55     
56 private:
57     PluginController::PluginDestructionProtector m_protector;
58 };
59
60 static bool startsWithBlankLine(const char* bytes, unsigned length)
61 {
62     return length > 0 && bytes[0] == '\n';
63 }
64
65 static int locationAfterFirstBlankLine(const char* bytes, unsigned length)
66 {
67     for (unsigned i = 0; i < length - 4; i++) {
68         // Support for Acrobat. It sends "\n\n".
69         if (bytes[i] == '\n' && bytes[i + 1] == '\n')
70             return i + 2;
71         
72         // Returns the position after 2 CRLF's or 1 CRLF if it is the first line.
73         if (bytes[i] == '\r' && bytes[i + 1] == '\n') {
74             i += 2;
75             if (i == 2)
76                 return i;
77
78             if (bytes[i] == '\n') {
79                 // Support for Director. It sends "\r\n\n" (3880387).
80                 return i + 1;
81             }
82
83             if (bytes[i] == '\r' && bytes[i + 1] == '\n') {
84                 // Support for Flash. It sends "\r\n\r\n" (3758113).
85                 return i + 2;
86             }
87         }
88     }
89
90     return -1;
91 }
92
93 static const char* findEndOfLine(const char* bytes, unsigned length)
94 {
95     // According to the HTTP specification EOL is defined as
96     // a CRLF pair. Unfortunately, some servers will use LF
97     // instead. Worse yet, some servers will use a combination
98     // of both (e.g. <header>CRLFLF<body>), so findEOL needs
99     // to be more forgiving. It will now accept CRLF, LF or
100     // CR.
101     //
102     // It returns 0 if EOLF is not found or it will return
103     // a pointer to the first terminating character.
104     for (unsigned i = 0; i < length; i++) {
105         if (bytes[i] == '\n')
106             return bytes + i;
107         if (bytes[i] == '\r') {
108             // Check to see if spanning buffer bounds
109             // (CRLF is across reads). If so, wait for
110             // next read.
111             if (i + 1 == length)
112                 break;
113
114             return bytes + i;
115         }
116     }
117
118     return 0;
119 }
120
121 static String capitalizeRFC822HeaderFieldName(const String& name)
122 {
123     bool capitalizeCharacter = true;
124     String result;
125
126     for (unsigned i = 0; i < name.length(); i++) {
127         UChar c;
128
129         if (capitalizeCharacter && name[i] >= 'a' && name[i] <= 'z')
130             c = toASCIIUpper(name[i]);
131         else if (!capitalizeCharacter && name[i] >= 'A' && name[i] <= 'Z')
132             c = toASCIILower(name[i]);
133         else
134             c = name[i];
135
136         if (name[i] == '-')
137             capitalizeCharacter = true;
138         else
139             capitalizeCharacter = false;
140
141         result.append(c);
142     }
143
144     return result;
145 }
146
147 static HTTPHeaderMap parseRFC822HeaderFields(const char* bytes, unsigned length)
148 {
149     String lastHeaderKey;
150     HTTPHeaderMap headerFields;
151
152     // Loop over lines until we're past the header, or we can't find any more end-of-lines
153     while (const char* endOfLine = findEndOfLine(bytes, length)) {
154         const char* line = bytes;
155         int lineLength = endOfLine - bytes;
156
157         // Move bytes to the character after the terminator as returned by findEndOfLine.
158         bytes = endOfLine + 1;
159         if ((*endOfLine == '\r') && (*bytes == '\n'))
160             bytes++; // Safe since findEndOfLine won't return a spanning CRLF.
161
162         length -= (bytes - line);
163         if (!lineLength) {
164             // Blank line; we're at the end of the header
165             break;
166         }
167
168         if (*line == ' ' || *line == '\t') {
169             // Continuation of the previous header
170             if (lastHeaderKey.isNull()) {
171                 // malformed header; ignore it and continue
172                 continue;
173             } 
174             
175             // Merge the continuation of the previous header
176             String currentValue = headerFields.get(lastHeaderKey);
177             String newValue(line, lineLength);
178             
179             headerFields.set(lastHeaderKey, currentValue + newValue);
180         } else {
181             // Brand new header
182             const char* colon = line;
183             while (*colon != ':' && colon != endOfLine)
184                 colon++;
185
186             if (colon == endOfLine) {
187                 // malformed header; ignore it and continue
188                 continue;
189             }
190
191             lastHeaderKey = capitalizeRFC822HeaderFieldName(String(line, colon - line));
192             String value;
193             
194             for (colon++; colon != endOfLine; colon++) {
195                 if (*colon != ' ' && *colon != '\t')
196                     break;
197             }
198             if (colon == endOfLine)
199                 value = "";
200             else
201                 value = String(colon, endOfLine - colon);
202             
203             String oldValue = headerFields.get(lastHeaderKey);
204             if (!oldValue.isNull()) {
205                 String tmp = oldValue;
206                 tmp += ", ";
207                 tmp += value;
208                 value = tmp;
209             }
210             
211             headerFields.set(lastHeaderKey, value);
212         }
213     }
214
215     return headerFields;
216 }
217     
218 static NPError parsePostBuffer(bool isFile, const char *buffer, uint32_t length, bool parseHeaders, HTTPHeaderMap& headerFields, Vector<uint8_t>& bodyData)
219 {
220     RefPtr<SharedBuffer> fileContents;
221     const char* postBuffer = 0;
222     uint32_t postBufferSize = 0;
223
224     if (isFile) {
225         fileContents = SharedBuffer::createWithContentsOfFile(String::fromUTF8(buffer));
226         if (!fileContents)
227             return NPERR_FILE_NOT_FOUND;
228
229         postBuffer = fileContents->data();
230         postBufferSize = fileContents->size();
231
232         // FIXME: The NPAPI spec states that the file should be deleted here.
233     } else {
234         postBuffer = buffer;
235         postBufferSize = length;
236     }
237
238     if (parseHeaders) {
239         if (startsWithBlankLine(postBuffer, postBufferSize)) {
240             postBuffer++;
241             postBufferSize--;
242         } else {
243             int location = locationAfterFirstBlankLine(postBuffer, postBufferSize);
244             if (location != -1) {
245                 // If the blank line is somewhere in the middle of the buffer, everything before is the header
246                 headerFields = parseRFC822HeaderFields(postBuffer, location);
247                 unsigned dataLength = postBufferSize - location;
248                 
249                 // Sometimes plugins like to set Content-Length themselves when they post,
250                 // but WebFoundation does not like that. So we will remove the header
251                 // and instead truncate the data to the requested length.
252                 String contentLength = headerFields.get("Content-Length");
253                 
254                 if (!contentLength.isNull())
255                     dataLength = min(contentLength.toInt(), (int)dataLength);
256                 headerFields.remove("Content-Length");
257                 
258                 postBuffer += location;
259                 postBufferSize = dataLength;
260                 
261             }
262         }
263     }
264
265     ASSERT(bodyData.isEmpty());
266     bodyData.append(postBuffer, postBufferSize);
267
268     return NPERR_NO_ERROR;
269 }
270
271 static String makeURLString(const char* url)
272 {
273     String urlString(url);
274     
275     // Strip return characters.
276     urlString.replace('\r', "");
277     urlString.replace('\n', "");
278
279     return urlString;
280 }
281
282 static NPError NPN_GetURL(NPP npp, const char* url, const char* target)
283 {
284     if (!url)
285         return NPERR_GENERIC_ERROR;
286     
287     RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
288     plugin->loadURL("GET", makeURLString(url), target, HTTPHeaderMap(), Vector<uint8_t>(), false, 0);
289     
290     return NPERR_GENERIC_ERROR;
291 }
292
293 static NPError NPN_PostURL(NPP npp, const char* url, const char* target, uint32_t len, const char* buf, NPBool file)
294 {
295     HTTPHeaderMap headerFields;
296     Vector<uint8_t> postData;
297     
298     // NPN_PostURL only allows headers if the post buffer points to a file.
299     bool parseHeaders = file;
300
301     NPError error = parsePostBuffer(file, buf, len, parseHeaders, headerFields, postData);
302     if (error != NPERR_NO_ERROR)
303         return error;
304
305     RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
306     plugin->loadURL("POST", makeURLString(url), target, headerFields, postData, false, 0);
307     return NPERR_NO_ERROR;
308 }
309
310 static NPError NPN_RequestRead(NPStream* stream, NPByteRange* rangeList)
311 {
312     notImplemented();
313     return NPERR_GENERIC_ERROR;
314 }
315
316 static NPError NPN_NewStream(NPP instance, NPMIMEType type, const char* target, NPStream** stream)
317 {
318     notImplemented();
319     return NPERR_GENERIC_ERROR;
320 }
321     
322 static int32_t NPN_Write(NPP instance, NPStream* stream, int32_t len, void* buffer)
323 {
324     notImplemented();    
325     return -1;
326 }
327     
328 static NPError NPN_DestroyStream(NPP npp, NPStream* stream, NPReason reason)
329 {
330     RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
331     
332     return plugin->destroyStream(stream, reason);
333 }
334
335 static void NPN_Status(NPP npp, const char* message)
336 {
337     String statusbarText;
338     if (!message)
339         statusbarText = "";
340     else
341         statusbarText = String::fromUTF8WithLatin1Fallback(message, strlen(message));
342
343     RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
344     plugin->setStatusbarText(statusbarText);
345 }
346     
347 static const char* NPN_UserAgent(NPP npp)
348 {
349     return NetscapePlugin::userAgent(npp);
350 }
351
352 static void* NPN_MemAlloc(uint32_t size)
353 {
354     return npnMemAlloc(size);
355 }
356
357 static void NPN_MemFree(void* ptr)
358 {
359     npnMemFree(ptr);
360 }
361
362 static uint32_t NPN_MemFlush(uint32_t size)
363 {
364     return 0;
365 }
366
367 static void NPN_ReloadPlugins(NPBool reloadPages)
368 {
369     notImplemented();
370 }
371
372 static JRIEnv* NPN_GetJavaEnv(void)
373 {
374     notImplemented();
375     return 0;
376 }
377
378 static jref NPN_GetJavaPeer(NPP instance)
379 {
380     notImplemented();
381     return 0;
382 }
383
384 static NPError NPN_GetURLNotify(NPP npp, const char* url, const char* target, void* notifyData)
385 {
386     if (!url)
387         return NPERR_GENERIC_ERROR;
388
389     RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
390     plugin->loadURL("GET", makeURLString(url), target, HTTPHeaderMap(), Vector<uint8_t>(), true, notifyData);
391     
392     return NPERR_NO_ERROR;
393 }
394
395 static NPError NPN_PostURLNotify(NPP npp, const char* url, const char* target, uint32_t len, const char* buf, NPBool file, void* notifyData)
396 {
397     HTTPHeaderMap headerFields;
398     Vector<uint8_t> postData;
399     NPError error = parsePostBuffer(file, buf, len, true, headerFields, postData);
400     if (error != NPERR_NO_ERROR)
401         return error;
402
403     RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
404     plugin->loadURL("POST", makeURLString(url), target, headerFields, postData, true, notifyData);
405     return NPERR_NO_ERROR;
406 }
407
408 #if PLATFORM(MAC)
409 // Whether the browser supports compositing of Core Animation plug-ins.
410 static const unsigned WKNVSupportsCompositingCoreAnimationPluginsBool = 74656;
411
412 // Whether the browser expects a non-retained Core Animation layer.
413 static const unsigned WKNVExpectsNonretainedLayer = 74657;
414
415 // Whether plug-in code is allowed to enter (arbitrary) sandbox for the process.
416 static const unsigned WKNVAllowedToEnterSandbox = 74658;
417
418 // WKNVSandboxFunctions = 74659 is defined in NetscapeSandboxFunctions.h
419
420 // The Core Animation render server port.
421 static const unsigned WKNVCALayerRenderServerPort = 71879;
422
423 #endif
424
425 static NPError NPN_GetValue(NPP npp, NPNVariable variable, void *value)
426 {
427     switch (static_cast<unsigned>(variable)) {
428         case NPNVWindowNPObject: {
429             RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
430             PluginDestructionProtector protector(plugin.get());
431
432             NPObject* windowNPObject = plugin->windowScriptNPObject();
433             if (!windowNPObject)
434                 return NPERR_GENERIC_ERROR;
435
436             *(NPObject**)value = windowNPObject;
437             break;
438         }
439         case NPNVPluginElementNPObject: {
440             RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
441             PluginDestructionProtector protector(plugin.get());
442
443             NPObject* pluginElementNPObject = plugin->pluginElementNPObject();
444             *(NPObject**)value = pluginElementNPObject;
445             break;
446         }
447         case NPNVprivateModeBool: {
448             RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
449
450             *(NPBool*)value = plugin->isPrivateBrowsingEnabled();
451             break;
452         }
453 #if PLATFORM(MAC)
454         case NPNVsupportsCoreGraphicsBool:
455             // Always claim to support the Core Graphics drawing model.
456             *(NPBool*)value = true;
457             break;
458
459         case WKNVSupportsCompositingCoreAnimationPluginsBool:
460         case NPNVsupportsCoreAnimationBool: {
461             RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
462             
463             *(NPBool*)value = plugin->isAcceleratedCompositingEnabled();
464             break;
465         }
466         case NPNVcontentsScaleFactor: {
467             RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
468
469             *(double*)value = plugin->contentsScaleFactor();
470             break;
471         }
472         case NPNVsupportsCocoaBool:
473             // Always claim to support the Cocoa event model.
474             *(NPBool*)value = true;
475             break;
476
477         case NPNVsupportsUpdatedCocoaTextInputBool: {
478             // The plug-in is asking whether we support the updated Cocoa text input model.
479             // If we haven't yet delivered a key down event to the plug-in, we can opt into the updated
480             // model and say that we support it. Otherwise, we'll just fall back and say that we don't support it.
481             RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
482
483             bool supportsUpdatedTextInput = !plugin->hasHandledAKeyDownEvent();
484             if (supportsUpdatedTextInput)
485                 plugin->setPluginWantsLegacyCocoaTextInput(false);
486
487             *reinterpret_cast<NPBool*>(value) = supportsUpdatedTextInput;
488             break;
489         }
490
491         case WKNVCALayerRenderServerPort: {
492             RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
493
494             *(mach_port_t*)value = plugin->compositingRenderServerPort();
495             break;
496         }
497
498         case WKNVExpectsNonretainedLayer: {
499             RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
500
501             // Asking for this will make us expect a non-retained layer from the plug-in.
502             plugin->setPluginReturnsNonretainedLayer(true);
503             *(NPBool*)value = true;
504             break;
505         }
506
507         case WKNVAllowedToEnterSandbox:
508             *(NPBool*)value = true;
509             break;
510
511 #if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
512         case WKNVSandboxFunctions:
513         {
514             *(WKNSandboxFunctions **)value = netscapeSandboxFunctions();
515             break;
516         }
517 #endif
518
519 #ifndef NP_NO_QUICKDRAW
520         case NPNVsupportsQuickDrawBool:
521             // We don't support the QuickDraw drawing model.
522             *(NPBool*)value = false;
523             break;
524 #endif
525 #ifndef NP_NO_CARBON
526        case NPNVsupportsCarbonBool:
527             *(NPBool*)value = true;
528             break;
529 #endif
530 #elif PLATFORM(WIN)
531        case NPNVnetscapeWindow: {
532            RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
533            *reinterpret_cast<HWND*>(value) = plugin->containingWindow();
534            break;
535        }
536        case NPNVSupportsWindowless:
537            *(NPBool*)value = true;
538            break;
539 #elif PLUGIN_ARCHITECTURE(X11)
540        case NPNVxDisplay: {
541            if (!npp)
542                return NPERR_GENERIC_ERROR;
543            *reinterpret_cast<Display**>(value) = NetscapePlugin::x11HostDisplay();
544            break;
545        }
546        case NPNVSupportsXEmbedBool:
547            *static_cast<NPBool*>(value) = true;
548            break;
549        case NPNVSupportsWindowless:
550            *static_cast<NPBool*>(value) = true;
551            break;
552
553        case NPNVToolkit: {
554            // Gtk based plugins need to be assured about the toolkit version.
555            const uint32_t expectedGtkToolKitVersion = 2;
556            *reinterpret_cast<uint32_t*>(value) = expectedGtkToolKitVersion;
557            break;
558        }
559
560        // TODO: implement NPNVnetscapeWindow once we want to support windowed plugins.
561 #endif
562         default:
563             notImplemented();
564             return NPERR_GENERIC_ERROR;
565     }
566
567     return NPERR_NO_ERROR;
568 }
569
570 static NPError NPN_SetValue(NPP npp, NPPVariable variable, void *value)
571 {
572     switch (variable) {
573 #if PLATFORM(MAC)
574         case NPPVpluginDrawingModel: {
575             RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
576             
577             NPDrawingModel drawingModel = static_cast<NPDrawingModel>(reinterpret_cast<uintptr_t>(value));
578             return plugin->setDrawingModel(drawingModel);
579         }
580
581         case NPPVpluginEventModel: {
582             RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
583             
584             NPEventModel eventModel = static_cast<NPEventModel>(reinterpret_cast<uintptr_t>(value));
585             return plugin->setEventModel(eventModel);
586         }
587 #endif
588
589         case NPPVpluginWindowBool: {
590             RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
591             plugin->setIsWindowed(value);
592             return NPERR_NO_ERROR;
593         }
594
595         case NPPVpluginTransparentBool: {
596             RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
597             plugin->setIsTransparent(value);
598             return NPERR_NO_ERROR;
599         }
600
601         default:
602             notImplemented();
603             return NPERR_GENERIC_ERROR;
604     }
605 }
606
607 static void NPN_InvalidateRect(NPP npp, NPRect* invalidRect)
608 {
609 #if PLUGIN_ARCHITECTURE(X11)
610     // NSPluginWrapper, a plugin wrapper binary that allows running 32-bit plugins
611     // on 64-bit architectures typically used in X11, will sometimes give us a null NPP here.
612     if (!npp)
613         return;
614 #endif
615     RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
616     plugin->invalidate(invalidRect);
617 }
618
619 static void NPN_InvalidateRegion(NPP npp, NPRegion invalidRegion)
620 {
621     // FIXME: We could at least figure out the bounding rectangle of the invalid region.
622     RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
623     plugin->invalidate(0);
624 }
625
626 static void NPN_ForceRedraw(NPP instance)
627 {
628     notImplemented();
629 }
630
631 static NPIdentifier NPN_GetStringIdentifier(const NPUTF8 *name)
632 {
633     return static_cast<NPIdentifier>(IdentifierRep::get(name));
634 }
635     
636 static void NPN_GetStringIdentifiers(const NPUTF8 **names, int32_t nameCount, NPIdentifier *identifiers)
637 {
638     ASSERT(names);
639     ASSERT(identifiers);
640
641     if (!names || !identifiers)
642         return;
643
644     for (int32_t i = 0; i < nameCount; ++i)
645         identifiers[i] = NPN_GetStringIdentifier(names[i]);
646 }
647
648 static NPIdentifier NPN_GetIntIdentifier(int32_t intid)
649 {
650     return static_cast<NPIdentifier>(IdentifierRep::get(intid));
651 }
652
653 static bool NPN_IdentifierIsString(NPIdentifier identifier)
654 {
655     return static_cast<IdentifierRep*>(identifier)->isString();
656 }
657
658 static NPUTF8 *NPN_UTF8FromIdentifier(NPIdentifier identifier)
659 {
660     const char* string = static_cast<IdentifierRep*>(identifier)->string();
661     if (!string)
662         return 0;
663
664     uint32_t stringLength = strlen(string);
665     char* utf8String = npnMemNewArray<char>(stringLength + 1);
666     memcpy(utf8String, string, stringLength);
667     utf8String[stringLength] = '\0';
668     
669     return utf8String;
670 }
671
672 static int32_t NPN_IntFromIdentifier(NPIdentifier identifier)
673 {
674     return static_cast<IdentifierRep*>(identifier)->number();
675 }
676
677 static NPObject* NPN_CreateObject(NPP npp, NPClass *npClass)
678 {
679     return createNPObject(npp, npClass);
680 }
681
682 static NPObject *NPN_RetainObject(NPObject *npObject)
683 {
684     retainNPObject(npObject);
685     return npObject;
686 }
687
688 static void NPN_ReleaseObject(NPObject *npObject)
689 {
690     releaseNPObject(npObject);
691 }
692
693 static bool NPN_Invoke(NPP npp, NPObject *npObject, NPIdentifier methodName, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
694 {
695     if (npObject->_class->invoke)
696         return npObject->_class->invoke(npObject, methodName, arguments, argumentCount, result);
697
698     return false;
699 }
700
701 static bool NPN_InvokeDefault(NPP, NPObject *npObject, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
702 {
703     if (npObject->_class->invokeDefault)
704         return npObject->_class->invokeDefault(npObject, arguments, argumentCount, result);
705
706     return false;
707 }
708
709 static bool NPN_Evaluate(NPP npp, NPObject *npObject, NPString *script, NPVariant* result)
710 {
711     RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
712     PluginDestructionProtector protector(plugin.get());
713     
714     String scriptString = String::fromUTF8WithLatin1Fallback(script->UTF8Characters, script->UTF8Length);
715     
716     return plugin->evaluate(npObject, scriptString, result);
717 }
718
719 static bool NPN_GetProperty(NPP npp, NPObject* npObject, NPIdentifier propertyName, NPVariant* result)
720 {
721     RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
722     PluginDestructionProtector protector(plugin.get());
723     
724     if (npObject->_class->getProperty)
725         return npObject->_class->getProperty(npObject, propertyName, result);
726     
727     return false;
728 }
729
730 static bool NPN_SetProperty(NPP npp, NPObject* npObject, NPIdentifier propertyName, const NPVariant* value)
731 {
732     RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
733     PluginDestructionProtector protector(plugin.get());
734     
735     if (npObject->_class->setProperty)
736         return npObject->_class->setProperty(npObject, propertyName, value);
737
738     return false;
739 }
740
741 static bool NPN_RemoveProperty(NPP npp, NPObject* npObject, NPIdentifier propertyName)
742 {
743     RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
744     PluginDestructionProtector protector(plugin.get());
745     
746     if (npObject->_class->removeProperty)
747         return npObject->_class->removeProperty(npObject, propertyName);
748
749     return false;
750 }
751
752 static bool NPN_HasProperty(NPP npp, NPObject* npObject, NPIdentifier propertyName)
753 {
754     RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
755     PluginDestructionProtector protector(plugin.get());
756     
757     if (npObject->_class->hasProperty)
758         return npObject->_class->hasProperty(npObject, propertyName);
759
760     return false;
761 }
762
763 static bool NPN_HasMethod(NPP npp, NPObject* npObject, NPIdentifier methodName)
764 {
765     RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
766     PluginDestructionProtector protector(plugin.get());
767     
768     if (npObject->_class->hasMethod)
769         return npObject->_class->hasMethod(npObject, methodName);
770
771     return false;
772 }
773
774 static void NPN_ReleaseVariantValue(NPVariant* variant)
775 {
776     releaseNPVariantValue(variant);
777 }
778
779 static void NPN_SetException(NPObject*, const NPUTF8* message)
780 {
781     NetscapePlugin::setException(message);
782 }
783
784 static void NPN_PushPopupsEnabledState(NPP npp, NPBool enabled)
785 {
786     RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
787     plugin->pushPopupsEnabledState(enabled);
788 }
789     
790 static void NPN_PopPopupsEnabledState(NPP npp)
791 {
792     RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
793     plugin->popPopupsEnabledState();
794 }
795     
796 static bool NPN_Enumerate(NPP npp, NPObject* npObject, NPIdentifier** identifiers, uint32_t* identifierCount)
797 {
798     RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
799     PluginDestructionProtector protector(plugin.get());
800     
801     if (NP_CLASS_STRUCT_VERSION_HAS_ENUM(npObject->_class) && npObject->_class->enumerate)
802         return npObject->_class->enumerate(npObject, identifiers, identifierCount);
803
804     return false;
805 }
806
807 static void NPN_PluginThreadAsyncCall(NPP npp, void (*function)(void*), void* userData)
808 {
809     RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
810
811     plugin->pluginThreadAsyncCall(function, userData);
812 }
813
814 static bool NPN_Construct(NPP npp, NPObject* npObject, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
815 {
816     RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
817     PluginDestructionProtector protector(plugin.get());
818     
819     if (NP_CLASS_STRUCT_VERSION_HAS_CTOR(npObject->_class) && npObject->_class->construct)
820         return npObject->_class->construct(npObject, arguments, argumentCount, result);
821
822     return false;
823 }
824
825 static NPError copyCString(const CString& string, char** value, uint32_t* len)
826 {
827     ASSERT(!string.isNull());
828     ASSERT(value);
829     ASSERT(len);
830
831     *value = npnMemNewArray<char>(string.length());
832     if (!*value)
833         return NPERR_GENERIC_ERROR;
834
835     memcpy(*value, string.data(), string.length());
836     *len = string.length();
837     return NPERR_NO_ERROR;
838 }
839
840 static NPError NPN_GetValueForURL(NPP npp, NPNURLVariable variable, const char* url, char** value, uint32_t* len)
841 {
842     if (!value || !len)
843         return NPERR_GENERIC_ERROR;
844     
845     switch (variable) {
846         case NPNURLVCookie: {
847             RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
848             PluginDestructionProtector protector(plugin.get());
849             
850             String cookies = plugin->cookiesForURL(makeURLString(url));
851             if (cookies.isNull())
852                 return NPERR_GENERIC_ERROR;
853
854             return copyCString(cookies.utf8(), value, len);
855         }
856
857         case NPNURLVProxy: {
858             RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
859             PluginDestructionProtector protector(plugin.get());
860             
861             String proxies = plugin->proxiesForURL(makeURLString(url));
862             if (proxies.isNull())
863                 return NPERR_GENERIC_ERROR;
864
865             return copyCString(proxies.utf8(), value, len);
866         }
867         default:
868             notImplemented();
869             return NPERR_GENERIC_ERROR;
870     }
871 }
872
873 static NPError NPN_SetValueForURL(NPP npp, NPNURLVariable variable, const char* url, const char* value, uint32_t len)
874 {
875     switch (variable) {
876         case NPNURLVCookie: {
877             RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
878             PluginDestructionProtector protector(plugin.get());
879             
880             plugin->setCookiesForURL(makeURLString(url), String(value, len));
881             return NPERR_NO_ERROR;
882         }
883
884         case NPNURLVProxy:
885             // Can't set the proxy for a URL.
886             return NPERR_GENERIC_ERROR;
887
888         default:
889             notImplemented();
890             return NPERR_GENERIC_ERROR;
891     }
892 }
893
894 static bool initializeProtectionSpace(const char* protocol, const char* host, int port, const char* scheme, const char* realm, ProtectionSpace& protectionSpace)
895 {
896     ProtectionSpaceServerType serverType;
897     if (!strcasecmp(protocol, "http"))
898         serverType = ProtectionSpaceServerHTTP;
899     else if (!strcasecmp(protocol, "https"))
900         serverType = ProtectionSpaceServerHTTPS;
901     else {
902         // We only care about http and https.
903         return false;
904     }
905
906     ProtectionSpaceAuthenticationScheme authenticationScheme = ProtectionSpaceAuthenticationSchemeDefault;
907     if (serverType == ProtectionSpaceServerHTTP) {
908         if (!strcasecmp(scheme, "basic"))
909             authenticationScheme = ProtectionSpaceAuthenticationSchemeHTTPBasic;
910         else if (!strcmp(scheme, "digest"))
911             authenticationScheme = ProtectionSpaceAuthenticationSchemeHTTPDigest;
912     }
913
914     protectionSpace = ProtectionSpace(host, port, serverType, realm, authenticationScheme);
915     return true;
916 }
917
918 static NPError NPN_GetAuthenticationInfo(NPP npp, const char* protocol, const char* host, int32_t port, const char* scheme, 
919                                          const char* realm, char** username, uint32_t* usernameLength, char** password, uint32_t* passwordLength)
920 {
921     if (!protocol || !host || !scheme || !realm || !username || !usernameLength || !password || !passwordLength)
922         return NPERR_GENERIC_ERROR;
923
924     ProtectionSpace protectionSpace;
925     if (!initializeProtectionSpace(protocol, host, port, scheme, realm, protectionSpace))
926         return NPERR_GENERIC_ERROR;
927
928     RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
929     String usernameString;
930     String passwordString;
931     if (!plugin->getAuthenticationInfo(protectionSpace, usernameString, passwordString))
932         return NPERR_GENERIC_ERROR;
933
934     NPError result = copyCString(usernameString.utf8(), username, usernameLength);
935     if (result != NPERR_NO_ERROR)
936         return result;
937
938     result = copyCString(passwordString.utf8(), password, passwordLength);
939     if (result != NPERR_NO_ERROR) {
940         npnMemFree(*username);
941         return result;
942     }
943
944     return NPERR_NO_ERROR;
945 }
946
947 static uint32_t NPN_ScheduleTimer(NPP npp, uint32_t interval, NPBool repeat, void (*timerFunc)(NPP npp, uint32_t timerID))
948 {
949     RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
950
951     return plugin->scheduleTimer(interval, repeat, timerFunc);
952 }
953
954 static void NPN_UnscheduleTimer(NPP npp, uint32_t timerID)
955 {
956     RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
957
958     plugin->unscheduleTimer(timerID);
959 }
960
961 #if PLATFORM(MAC)
962 static NPError NPN_PopUpContextMenu(NPP npp, NPMenu* menu)
963 {
964     RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
965
966     return plugin->popUpContextMenu(menu);
967 }
968
969 static NPBool NPN_ConvertPoint(NPP npp, double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double* destX, double* destY, NPCoordinateSpace destSpace)
970 {
971     RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
972
973     double destinationX;
974     double destinationY;
975
976     bool returnValue = plugin->convertPoint(sourceX, sourceY, sourceSpace, destinationX, destinationY, destSpace);
977
978     if (destX)
979         *destX = destinationX;
980     if (destY)
981         *destY = destinationY;
982
983     return returnValue;
984 }
985 #endif
986
987 static void initializeBrowserFuncs(NPNetscapeFuncs &netscapeFuncs)
988 {
989     netscapeFuncs.size = sizeof(NPNetscapeFuncs);
990     netscapeFuncs.version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
991     
992     netscapeFuncs.geturl = NPN_GetURL;
993     netscapeFuncs.posturl = NPN_PostURL;
994     netscapeFuncs.requestread = NPN_RequestRead;
995     netscapeFuncs.newstream = NPN_NewStream;
996     netscapeFuncs.write = NPN_Write;
997     netscapeFuncs.destroystream = NPN_DestroyStream;
998     netscapeFuncs.status = NPN_Status;
999     netscapeFuncs.uagent = NPN_UserAgent;
1000     netscapeFuncs.memalloc = NPN_MemAlloc;
1001     netscapeFuncs.memfree = NPN_MemFree;
1002     netscapeFuncs.memflush = NPN_MemFlush;
1003     netscapeFuncs.reloadplugins = NPN_ReloadPlugins;
1004     netscapeFuncs.getJavaEnv = NPN_GetJavaEnv;
1005     netscapeFuncs.getJavaPeer = NPN_GetJavaPeer;
1006     netscapeFuncs.geturlnotify = NPN_GetURLNotify;
1007     netscapeFuncs.posturlnotify = NPN_PostURLNotify;
1008     netscapeFuncs.getvalue = NPN_GetValue;
1009     netscapeFuncs.setvalue = NPN_SetValue;
1010     netscapeFuncs.invalidaterect = NPN_InvalidateRect;
1011     netscapeFuncs.invalidateregion = NPN_InvalidateRegion;
1012     netscapeFuncs.forceredraw = NPN_ForceRedraw;
1013     
1014     netscapeFuncs.getstringidentifier = NPN_GetStringIdentifier;
1015     netscapeFuncs.getstringidentifiers = NPN_GetStringIdentifiers;
1016     netscapeFuncs.getintidentifier = NPN_GetIntIdentifier;
1017     netscapeFuncs.identifierisstring = NPN_IdentifierIsString;
1018     netscapeFuncs.utf8fromidentifier = NPN_UTF8FromIdentifier;
1019     netscapeFuncs.intfromidentifier = NPN_IntFromIdentifier;
1020     netscapeFuncs.createobject = NPN_CreateObject;
1021     netscapeFuncs.retainobject = NPN_RetainObject;
1022     netscapeFuncs.releaseobject = NPN_ReleaseObject;
1023     netscapeFuncs.invoke = NPN_Invoke;
1024     netscapeFuncs.invokeDefault = NPN_InvokeDefault;
1025     netscapeFuncs.evaluate = NPN_Evaluate;
1026     netscapeFuncs.getproperty = NPN_GetProperty;
1027     netscapeFuncs.setproperty = NPN_SetProperty;
1028     netscapeFuncs.removeproperty = NPN_RemoveProperty;
1029     netscapeFuncs.hasproperty = NPN_HasProperty;
1030     netscapeFuncs.hasmethod = NPN_HasMethod;
1031     netscapeFuncs.releasevariantvalue = NPN_ReleaseVariantValue;
1032     netscapeFuncs.setexception = NPN_SetException;
1033     netscapeFuncs.pushpopupsenabledstate = NPN_PushPopupsEnabledState;
1034     netscapeFuncs.poppopupsenabledstate = NPN_PopPopupsEnabledState;
1035     netscapeFuncs.enumerate = NPN_Enumerate;
1036     netscapeFuncs.pluginthreadasynccall = NPN_PluginThreadAsyncCall;
1037     netscapeFuncs.construct = NPN_Construct;
1038     netscapeFuncs.getvalueforurl = NPN_GetValueForURL;
1039     netscapeFuncs.setvalueforurl = NPN_SetValueForURL;
1040     netscapeFuncs.getauthenticationinfo = NPN_GetAuthenticationInfo;
1041     netscapeFuncs.scheduletimer = NPN_ScheduleTimer;
1042     netscapeFuncs.unscheduletimer = NPN_UnscheduleTimer;
1043 #if PLATFORM(MAC)
1044     netscapeFuncs.popupcontextmenu = NPN_PopUpContextMenu;
1045     netscapeFuncs.convertpoint = NPN_ConvertPoint;
1046 #else
1047     netscapeFuncs.popupcontextmenu = 0;
1048     netscapeFuncs.convertpoint = 0;
1049 #endif
1050 }
1051     
1052 NPNetscapeFuncs* netscapeBrowserFuncs()
1053 {
1054     static NPNetscapeFuncs netscapeFuncs;
1055     static bool initialized = false;
1056     
1057     if (!initialized) {
1058         initializeBrowserFuncs(netscapeFuncs);
1059         initialized = true;
1060     }
1061
1062     return &netscapeFuncs;
1063 }
1064
1065 } // namespace WebKit