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