Make isTransparentSilverlightBackgroundValue handle all the possible transparent...
[WebKit-https.git] / Source / WebKit2 / WebProcess / Plugins / Netscape / NetscapePlugin.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 "NetscapePlugin.h"
28
29 #if ENABLE(NETSCAPE_PLUGIN_API)
30
31 #include "NPRuntimeObjectMap.h"
32 #include "NPRuntimeUtilities.h"
33 #include "NetscapePluginStream.h"
34 #include "PluginController.h"
35 #include "ShareableBitmap.h"
36 #include <WebCore/GraphicsContext.h>
37 #include <WebCore/HTTPHeaderMap.h>
38 #include <WebCore/IntRect.h>
39 #include <WebCore/KURL.h>
40 #include <runtime/JSObject.h>
41 #include <runtime/ScopeChain.h>
42 #include <utility>
43 #include <wtf/text/CString.h>
44
45 using namespace WebCore;
46 using namespace std;
47
48 namespace WebKit {
49
50 // The plug-in that we're currently calling NPP_New for.
51 static NetscapePlugin* currentNPPNewPlugin;
52
53 PassRefPtr<NetscapePlugin> NetscapePlugin::create(PassRefPtr<NetscapePluginModule> pluginModule)
54 {
55     if (!pluginModule)
56         return 0;
57
58     return adoptRef(new NetscapePlugin(pluginModule));
59 }
60     
61 NetscapePlugin::NetscapePlugin(PassRefPtr<NetscapePluginModule> pluginModule)
62     : m_nextRequestID(0)
63     , m_pluginModule(pluginModule)
64     , m_npWindow()
65     , m_isStarted(false)
66 #if PLATFORM(MAC)
67     , m_isWindowed(false)
68 #else
69     , m_isWindowed(true)
70 #endif
71     , m_isTransparent(false)
72     , m_inNPPNew(false)
73     , m_shouldUseManualLoader(false)
74     , m_hasCalledSetWindow(false)
75     , m_nextTimerID(0)
76 #if PLATFORM(MAC)
77     , m_drawingModel(static_cast<NPDrawingModel>(-1))
78     , m_eventModel(static_cast<NPEventModel>(-1))
79     , m_pluginReturnsNonretainedLayer(!m_pluginModule->pluginQuirks().contains(PluginQuirks::ReturnsRetainedCoreAnimationLayer))
80     , m_layerHostingMode(LayerHostingModeDefault)
81     , m_currentMouseEvent(0)
82     , m_pluginHasFocus(false)
83     , m_windowHasFocus(false)
84     , m_pluginWantsLegacyCocoaTextInput(true)
85     , m_isComplexTextInputEnabled(false)
86     , m_hasHandledAKeyDownEvent(false)
87     , m_ignoreNextKeyUpEventCounter(0)
88 #ifndef NP_NO_CARBON
89     , m_nullEventTimer(RunLoop::main(), this, &NetscapePlugin::nullEventTimerFired)
90     , m_npCGContext()
91 #endif
92 #elif PLUGIN_ARCHITECTURE(X11)
93     , m_drawable(0)
94     , m_pluginDisplay(0)
95 #if PLATFORM(GTK)
96     , m_platformPluginWidget(0)
97 #endif
98 #endif
99 {
100     m_npp.ndata = this;
101     m_npp.pdata = 0;
102     
103     m_pluginModule->incrementLoadCount();
104 }
105
106 NetscapePlugin::~NetscapePlugin()
107 {
108     ASSERT(!m_isStarted);
109     ASSERT(m_timers.isEmpty());
110
111     m_pluginModule->decrementLoadCount();
112 }
113
114 PassRefPtr<NetscapePlugin> NetscapePlugin::fromNPP(NPP npp)
115 {
116     if (npp)
117         return static_cast<NetscapePlugin*>(npp->ndata);
118
119     // FIXME: Return the current NetscapePlugin here.
120     ASSERT_NOT_REACHED();
121     return 0;
122 }
123
124 void NetscapePlugin::invalidate(const NPRect* invalidRect)
125 {
126     IntRect rect;
127     
128     if (!invalidRect)
129         rect = IntRect(0, 0, m_pluginSize.width(), m_pluginSize.height());
130     else
131         rect = IntRect(invalidRect->left, invalidRect->top, invalidRect->right - invalidRect->left, invalidRect->bottom - invalidRect->top);
132     
133     if (platformInvalidate(rect))
134         return;
135
136     controller()->invalidate(rect);
137 }
138
139 const char* NetscapePlugin::userAgent(NPP npp)
140 {
141     if (npp)
142         return fromNPP(npp)->userAgent();
143
144     if (currentNPPNewPlugin)
145         return currentNPPNewPlugin->userAgent();
146
147     return 0;
148 }
149
150 const char* NetscapePlugin::userAgent()
151 {
152 #if PLUGIN_ARCHITECTURE(WIN)
153     static const char* MozillaUserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0";
154     
155     if (quirks().contains(PluginQuirks::WantsMozillaUserAgent))
156         return MozillaUserAgent;
157 #endif
158
159     if (m_userAgent.isNull()) {
160         String userAgent = controller()->userAgent();
161         ASSERT(!userAgent.isNull());
162
163 #if PLUGIN_ARCHITECTURE(MAC)
164         if (quirks().contains(PluginQuirks::AppendVersion3UserAgent))
165             userAgent += " Version/3.2.1";
166 #endif
167
168         m_userAgent = userAgent.utf8();
169     }
170     return m_userAgent.data();
171 }
172
173 void NetscapePlugin::loadURL(const String& method, const String& urlString, const String& target, const HTTPHeaderMap& headerFields, const Vector<uint8_t>& httpBody,
174                              bool sendNotification, void* notificationData)
175 {
176     uint64_t requestID = ++m_nextRequestID;
177     
178     controller()->loadURL(requestID, method, urlString, target, headerFields, httpBody, allowPopups());
179
180     if (target.isNull()) {
181         // The browser is going to send the data in a stream, create a plug-in stream.
182         RefPtr<NetscapePluginStream> pluginStream = NetscapePluginStream::create(this, requestID, urlString, sendNotification, notificationData);
183         ASSERT(!m_streams.contains(requestID));
184
185         m_streams.set(requestID, pluginStream.release());
186         return;
187     }
188
189     if (sendNotification) {
190         // Eventually we are going to get a frameDidFinishLoading or frameDidFail call for this request.
191         // Keep track of the notification data so we can call NPP_URLNotify.
192         ASSERT(!m_pendingURLNotifications.contains(requestID));
193         m_pendingURLNotifications.set(requestID, make_pair(urlString, notificationData));
194     }
195 }
196
197 NPError NetscapePlugin::destroyStream(NPStream* stream, NPReason reason)
198 {
199     NetscapePluginStream* pluginStream = 0;
200
201     for (StreamsMap::const_iterator it = m_streams.begin(), end = m_streams.end(); it != end; ++it) {
202         if (it->second->npStream() == stream) {
203             pluginStream = it->second.get();
204             break;
205         }
206     }
207
208     if (!pluginStream)
209         return NPERR_INVALID_INSTANCE_ERROR;
210
211     return pluginStream->destroy(reason);
212 }
213
214 void NetscapePlugin::setIsWindowed(bool isWindowed)
215 {
216     // Once the plugin has started, it's too late to change whether the plugin is windowed or not.
217     // (This is true in Firefox and Chrome, too.) Disallow setting m_isWindowed in that case to
218     // keep our internal state consistent.
219     if (m_isStarted)
220         return;
221
222     m_isWindowed = isWindowed;
223 }
224
225 void NetscapePlugin::setIsTransparent(bool isTransparent)
226 {
227     m_isTransparent = isTransparent;
228 }
229
230 void NetscapePlugin::setStatusbarText(const String& statusbarText)
231 {
232     controller()->setStatusbarText(statusbarText);
233 }
234
235 static void (*setExceptionFunction)(const String&);
236
237 void NetscapePlugin::setSetExceptionFunction(void (*function)(const String&))
238 {
239     ASSERT(!setExceptionFunction || setExceptionFunction == function);
240     setExceptionFunction = function;
241 }
242
243 void NetscapePlugin::setException(const String& exceptionString)
244 {
245     ASSERT(setExceptionFunction);
246     setExceptionFunction(exceptionString);
247 }
248
249 bool NetscapePlugin::evaluate(NPObject* npObject, const String& scriptString, NPVariant* result)
250 {
251     return controller()->evaluate(npObject, scriptString, result, allowPopups());
252 }
253
254 bool NetscapePlugin::isPrivateBrowsingEnabled()
255 {
256     return controller()->isPrivateBrowsingEnabled();
257 }
258
259 NPObject* NetscapePlugin::windowScriptNPObject()
260 {
261     return controller()->windowScriptNPObject();
262 }
263
264 NPObject* NetscapePlugin::pluginElementNPObject()
265 {
266     return controller()->pluginElementNPObject();
267 }
268
269 void NetscapePlugin::cancelStreamLoad(NetscapePluginStream* pluginStream)
270 {
271     if (pluginStream == m_manualStream) {
272         controller()->cancelManualStreamLoad();
273         return;
274     }
275
276     // Ask the plug-in controller to cancel this stream load.
277     controller()->cancelStreamLoad(pluginStream->streamID());
278 }
279
280 void NetscapePlugin::removePluginStream(NetscapePluginStream* pluginStream)
281 {
282     if (pluginStream == m_manualStream) {
283         m_manualStream = 0;
284         return;
285     }
286
287     ASSERT(m_streams.get(pluginStream->streamID()) == pluginStream);
288     m_streams.remove(pluginStream->streamID());
289 }
290
291 bool NetscapePlugin::isAcceleratedCompositingEnabled()
292 {
293 #if USE(ACCELERATED_COMPOSITING)
294     return controller()->isAcceleratedCompositingEnabled();
295 #else
296     return false;
297 #endif
298 }
299
300 void NetscapePlugin::pushPopupsEnabledState(bool state)
301 {
302     m_popupEnabledStates.append(state);
303 }
304  
305 void NetscapePlugin::popPopupsEnabledState()
306 {
307     ASSERT(!m_popupEnabledStates.isEmpty());
308
309     m_popupEnabledStates.removeLast();
310 }
311
312 void NetscapePlugin::pluginThreadAsyncCall(void (*function)(void*), void* userData)
313 {
314     RunLoop::main()->dispatch(WTF::bind(&NetscapePlugin::handlePluginThreadAsyncCall, this, function, userData));
315 }
316     
317 void NetscapePlugin::handlePluginThreadAsyncCall(void (*function)(void*), void* userData)
318 {
319     if (!m_isStarted)
320         return;
321
322     function(userData);
323 }
324
325 PassOwnPtr<NetscapePlugin::Timer> NetscapePlugin::Timer::create(NetscapePlugin* netscapePlugin, unsigned timerID, unsigned interval, bool repeat, TimerFunc timerFunc)
326 {
327     return adoptPtr(new Timer(netscapePlugin, timerID, interval, repeat, timerFunc));
328 }
329
330 NetscapePlugin::Timer::Timer(NetscapePlugin* netscapePlugin, unsigned timerID, unsigned interval, bool repeat, TimerFunc timerFunc)
331     : m_netscapePlugin(netscapePlugin)
332     , m_timerID(timerID)
333     , m_interval(interval)
334     , m_repeat(repeat)
335     , m_timerFunc(timerFunc)
336     , m_timer(RunLoop::main(), this, &Timer::timerFired)
337 {
338 }
339
340 NetscapePlugin::Timer::~Timer()
341 {
342 }
343
344 void NetscapePlugin::Timer::start()
345 {
346     double timeInterval = m_interval / 1000.0;
347
348     if (m_repeat)
349         m_timer.startRepeating(timeInterval);
350     else
351         m_timer.startOneShot(timeInterval);
352 }
353
354 void NetscapePlugin::Timer::stop()
355 {
356     m_timer.stop();
357 }
358
359 void NetscapePlugin::Timer::timerFired()
360 {
361     m_timerFunc(&m_netscapePlugin->m_npp, m_timerID);
362
363     if (!m_repeat)
364         m_netscapePlugin->unscheduleTimer(m_timerID);
365 }
366
367 uint32_t NetscapePlugin::scheduleTimer(unsigned interval, bool repeat, void (*timerFunc)(NPP, unsigned timerID))
368 {
369     if (!timerFunc)
370         return 0;
371
372     // FIXME: Handle wrapping around.
373     unsigned timerID = ++m_nextTimerID;
374
375     OwnPtr<Timer> timer = Timer::create(this, timerID, interval, repeat, timerFunc);
376     
377     // FIXME: Based on the plug-in visibility, figure out if we should throttle the timer, or if we should start it at all.
378     timer->start();
379     m_timers.set(timerID, timer.leakPtr());
380
381     return timerID;
382 }
383
384 void NetscapePlugin::unscheduleTimer(unsigned timerID)
385 {
386     TimerMap::iterator it = m_timers.find(timerID);
387     if (it == m_timers.end())
388         return;
389
390     OwnPtr<Timer> timer = adoptPtr(it->second);
391     m_timers.remove(it);
392
393     timer->stop();
394 }
395
396 double NetscapePlugin::contentsScaleFactor()
397 {
398     return controller()->contentsScaleFactor();
399 }
400
401 String NetscapePlugin::proxiesForURL(const String& urlString)
402 {
403     return controller()->proxiesForURL(urlString);
404 }
405     
406 String NetscapePlugin::cookiesForURL(const String& urlString)
407 {
408     return controller()->cookiesForURL(urlString);
409 }
410
411 void NetscapePlugin::setCookiesForURL(const String& urlString, const String& cookieString)
412 {
413     controller()->setCookiesForURL(urlString, cookieString);
414 }
415
416 bool NetscapePlugin::getAuthenticationInfo(const ProtectionSpace& protectionSpace, String& username, String& password)
417 {
418     return controller()->getAuthenticationInfo(protectionSpace, username, password);
419 }    
420
421 NPError NetscapePlugin::NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData* savedData)
422 {
423     return m_pluginModule->pluginFuncs().newp(pluginType, &m_npp, mode, argc, argn, argv, savedData);
424 }
425     
426 NPError NetscapePlugin::NPP_Destroy(NPSavedData** savedData)
427 {
428     return m_pluginModule->pluginFuncs().destroy(&m_npp, savedData);
429 }
430
431 NPError NetscapePlugin::NPP_SetWindow(NPWindow* npWindow)
432 {
433     return m_pluginModule->pluginFuncs().setwindow(&m_npp, npWindow);
434 }
435
436 NPError NetscapePlugin::NPP_NewStream(NPMIMEType mimeType, NPStream* stream, NPBool seekable, uint16_t* streamType)
437 {
438     return m_pluginModule->pluginFuncs().newstream(&m_npp, mimeType, stream, seekable, streamType);
439 }
440
441 NPError NetscapePlugin::NPP_DestroyStream(NPStream* stream, NPReason reason)
442 {
443     return m_pluginModule->pluginFuncs().destroystream(&m_npp, stream, reason);
444 }
445
446 void NetscapePlugin::NPP_StreamAsFile(NPStream* stream, const char* filename)
447 {
448     return m_pluginModule->pluginFuncs().asfile(&m_npp, stream, filename);
449 }
450
451 int32_t NetscapePlugin::NPP_WriteReady(NPStream* stream)
452 {
453     return m_pluginModule->pluginFuncs().writeready(&m_npp, stream);
454 }
455
456 int32_t NetscapePlugin::NPP_Write(NPStream* stream, int32_t offset, int32_t len, void* buffer)
457 {
458     return m_pluginModule->pluginFuncs().write(&m_npp, stream, offset, len, buffer);
459 }
460
461 int16_t NetscapePlugin::NPP_HandleEvent(void* event)
462 {
463     return m_pluginModule->pluginFuncs().event(&m_npp, event);
464 }
465
466 void NetscapePlugin::NPP_URLNotify(const char* url, NPReason reason, void* notifyData)
467 {
468     m_pluginModule->pluginFuncs().urlnotify(&m_npp, url, reason, notifyData);
469 }
470
471 NPError NetscapePlugin::NPP_GetValue(NPPVariable variable, void *value)
472 {
473     if (!m_pluginModule->pluginFuncs().getvalue)
474         return NPERR_GENERIC_ERROR;
475
476     return m_pluginModule->pluginFuncs().getvalue(&m_npp, variable, value);
477 }
478
479 NPError NetscapePlugin::NPP_SetValue(NPNVariable variable, void *value)
480 {
481     if (!m_pluginModule->pluginFuncs().setvalue)
482         return NPERR_GENERIC_ERROR;
483
484     return m_pluginModule->pluginFuncs().setvalue(&m_npp, variable, value);
485 }
486
487 void NetscapePlugin::callSetWindow()
488 {
489     if (wantsPluginRelativeNPWindowCoordinates()) {
490         m_npWindow.x = 0;
491         m_npWindow.y = 0;
492         m_npWindow.clipRect.top = m_clipRect.y();
493         m_npWindow.clipRect.left = m_clipRect.x();
494     } else {
495         IntPoint pluginLocationInRootViewCoordinates = convertToRootView(IntPoint());
496         IntPoint clipRectInRootViewCoordinates = convertToRootView(m_clipRect.location());
497
498         m_npWindow.x = pluginLocationInRootViewCoordinates.x();
499         m_npWindow.y = pluginLocationInRootViewCoordinates.y();
500         m_npWindow.clipRect.top = clipRectInRootViewCoordinates.y();
501         m_npWindow.clipRect.left = clipRectInRootViewCoordinates.x();
502     }
503
504     m_npWindow.width = m_pluginSize.width();
505     m_npWindow.height = m_pluginSize.height();
506     m_npWindow.clipRect.right = m_npWindow.clipRect.left + m_clipRect.width();
507     m_npWindow.clipRect.bottom = m_npWindow.clipRect.top + m_clipRect.height();
508
509     NPP_SetWindow(&m_npWindow);
510     m_hasCalledSetWindow = true;
511 }
512
513 bool NetscapePlugin::shouldLoadSrcURL()
514 {
515     // Check if we should cancel the load
516     NPBool cancelSrcStream = false;
517
518     if (NPP_GetValue(NPPVpluginCancelSrcStream, &cancelSrcStream) != NPERR_NO_ERROR)
519         return true;
520
521     return !cancelSrcStream;
522 }
523
524 NetscapePluginStream* NetscapePlugin::streamFromID(uint64_t streamID)
525 {
526     return m_streams.get(streamID).get();
527 }
528
529 void NetscapePlugin::stopAllStreams()
530 {
531     Vector<RefPtr<NetscapePluginStream> > streams;
532     copyValuesToVector(m_streams, streams);
533
534     for (size_t i = 0; i < streams.size(); ++i)
535         streams[i]->stop(NPRES_USER_BREAK);
536 }
537
538 bool NetscapePlugin::allowPopups() const
539 {
540     if (m_pluginModule->pluginFuncs().version >= NPVERS_HAS_POPUPS_ENABLED_STATE) {
541         if (!m_popupEnabledStates.isEmpty())
542             return m_popupEnabledStates.last();
543     }
544
545     // FIXME: Check if the current event is a user gesture.
546     // Really old versions of Flash required this for popups to work, but all newer versions
547     // support NPN_PushPopupEnabledState/NPN_PopPopupEnabledState.
548     return false;
549 }
550
551 #if PLUGIN_ARCHITECTURE(MAC)
552 static bool isTransparentSilverlightBackgroundValue(const String& lowercaseBackgroundValue)
553 {
554     // This checks if the background color value is transparent, according to
555     // the forumat documented at http://msdn.microsoft.com/en-us/library/cc838148(VS.95).aspx
556     if (lowercaseBackgroundValue.startsWith('#')) {
557         if (lowercaseBackgroundValue.length() == 5 && lowercaseBackgroundValue[1] != 'f') {
558             // An 8-bit RGB value with alpha transparency, in the form #ARGB.
559             return true;
560         }
561
562         if (lowercaseBackgroundValue.length() == 9 && !(lowercaseBackgroundValue[1] == 'f' && lowercaseBackgroundValue[2] == 'f')) {
563             // A 16-bit RGB value with alpha transparency, in the form #AARRGGBB.
564             return true;
565         }
566     } else if (lowercaseBackgroundValue.startsWith("sc#")) {
567         Vector<String> components;
568         lowercaseBackgroundValue.substring(3).split(",", components);
569
570         // An ScRGB value with alpha transparency, in the form sc#A,R,G,B.
571         if (components.size() == 4) {
572             if (components[0].toDouble() < 1)
573                 return true;
574         }
575     } else if (lowercaseBackgroundValue == "transparent")
576         return true;
577
578     // This is an opaque color.
579     return false;
580 }
581 #endif
582
583 bool NetscapePlugin::initialize(const Parameters& parameters)
584 {
585     uint16_t mode = parameters.isFullFramePlugin ? NP_FULL : NP_EMBED;
586     
587     m_shouldUseManualLoader = parameters.shouldUseManualLoader;
588
589     CString mimeTypeCString = parameters.mimeType.utf8();
590
591     ASSERT(parameters.names.size() == parameters.values.size());
592
593     Vector<CString> paramNames;
594     Vector<CString> paramValues;
595     for (size_t i = 0; i < parameters.names.size(); ++i) {
596         String parameterName = parameters.names[i];
597
598 #if PLUGIN_ARCHITECTURE(MAC)
599         if (m_pluginModule->pluginQuirks().contains(PluginQuirks::WantsLowercaseParameterNames))
600             parameterName = parameterName.lower();
601 #endif
602
603         paramNames.append(parameterName.utf8());
604         paramValues.append(parameters.values[i].utf8());
605     }
606
607     // The strings that these pointers point to are kept alive by paramNames and paramValues.
608     Vector<const char*> names;
609     Vector<const char*> values;
610     for (size_t i = 0; i < paramNames.size(); ++i) {
611         names.append(paramNames[i].data());
612         values.append(paramValues[i].data());
613     }
614
615 #if PLUGIN_ARCHITECTURE(MAC)
616     if (m_pluginModule->pluginQuirks().contains(PluginQuirks::MakeOpaqueUnlessTransparentSilverlightBackgroundAttributeExists)) {
617         for (size_t i = 0; i < parameters.names.size(); ++i) {
618             if (equalIgnoringCase(parameters.names[i], "background")) {
619                 setIsTransparent(isTransparentSilverlightBackgroundValue(parameters.values[i].lower()));
620                 break;
621             }
622         }
623     }
624
625     m_layerHostingMode = parameters.layerHostingMode;
626 #endif
627
628     NetscapePlugin* previousNPPNewPlugin = currentNPPNewPlugin;
629     
630     m_inNPPNew = true;
631     currentNPPNewPlugin = this;
632
633     NPError error = NPP_New(const_cast<char*>(mimeTypeCString.data()), mode, names.size(),
634                             const_cast<char**>(names.data()), const_cast<char**>(values.data()), 0);
635
636     m_inNPPNew = false;
637     currentNPPNewPlugin = previousNPPNewPlugin;
638
639     if (error != NPERR_NO_ERROR)
640         return false;
641
642     m_isStarted = true;
643
644     // FIXME: This is not correct in all cases.
645     m_npWindow.type = NPWindowTypeDrawable;
646
647     if (!platformPostInitialize()) {
648         destroy();
649         return false;
650     }
651
652     // Load the src URL if needed.
653     if (!parameters.shouldUseManualLoader && !parameters.url.isEmpty() && shouldLoadSrcURL())
654         loadURL("GET", parameters.url.string(), String(), HTTPHeaderMap(), Vector<uint8_t>(), false, 0);
655     
656     return true;
657 }
658     
659 void NetscapePlugin::destroy()
660 {
661     ASSERT(m_isStarted);
662
663     // Stop all streams.
664     stopAllStreams();
665
666 #if !PLUGIN_ARCHITECTURE(MAC) && !PLUGIN_ARCHITECTURE(X11)
667     m_npWindow.window = 0;
668     callSetWindow();
669 #endif
670
671     NPP_Destroy(0);
672
673     m_isStarted = false;
674
675     platformDestroy();
676
677     deleteAllValues(m_timers);
678     m_timers.clear();
679 }
680     
681 void NetscapePlugin::paint(GraphicsContext* context, const IntRect& dirtyRect)
682 {
683     ASSERT(m_isStarted);
684     
685     platformPaint(context, dirtyRect);
686 }
687
688 PassRefPtr<ShareableBitmap> NetscapePlugin::snapshot()
689 {
690     if (!supportsSnapshotting() || m_pluginSize.isEmpty())
691         return 0;
692
693     ASSERT(m_isStarted);
694
695     IntSize backingStoreSize = m_pluginSize;
696     backingStoreSize.scale(contentsScaleFactor());
697
698     RefPtr<ShareableBitmap> bitmap = ShareableBitmap::createShareable(backingStoreSize, ShareableBitmap::SupportsAlpha);
699     OwnPtr<GraphicsContext> context = bitmap->createGraphicsContext();
700
701     // FIXME: We should really call applyDeviceScaleFactor instead of scale, but that ends up calling into WKSI
702     // which we currently don't have initiated in the plug-in process.
703     context->scale(FloatSize(contentsScaleFactor(), contentsScaleFactor()));
704
705     platformPaint(context.get(), IntRect(IntPoint(), m_pluginSize), true);
706
707     return bitmap.release();
708 }
709
710 bool NetscapePlugin::isTransparent()
711 {
712     return m_isTransparent;
713 }
714
715 bool NetscapePlugin::wantsWheelEvents()
716 {
717     return m_pluginModule->pluginQuirks().contains(PluginQuirks::WantsWheelEvents);
718 }
719
720 void NetscapePlugin::geometryDidChange(const IntSize& pluginSize, const IntRect& clipRect, const AffineTransform& pluginToRootViewTransform)
721 {
722     ASSERT(m_isStarted);
723
724     if (pluginSize == m_pluginSize && m_clipRect == clipRect && m_pluginToRootViewTransform == pluginToRootViewTransform) {
725         // Nothing to do.
726         return;
727     }
728
729     bool shouldCallSetWindow = true;
730
731     // If the plug-in doesn't want window relative coordinates, we don't need to call setWindow unless its size or clip rect changes.
732     if (m_hasCalledSetWindow && wantsPluginRelativeNPWindowCoordinates() && m_pluginSize == pluginSize && m_clipRect == clipRect)
733         shouldCallSetWindow = false;
734
735     m_pluginSize = pluginSize;
736     m_clipRect = clipRect;
737     m_pluginToRootViewTransform = pluginToRootViewTransform;
738
739     IntPoint frameRectLocationInWindowCoordinates = m_pluginToRootViewTransform.mapPoint(IntPoint());
740     m_frameRectInWindowCoordinates = IntRect(frameRectLocationInWindowCoordinates, m_pluginSize);
741
742     platformGeometryDidChange();
743
744     if (!shouldCallSetWindow)
745         return;
746
747     callSetWindow();
748 }
749
750 void NetscapePlugin::visibilityDidChange()
751 {
752     ASSERT(m_isStarted);
753
754     platformVisibilityDidChange();
755 }
756
757 void NetscapePlugin::frameDidFinishLoading(uint64_t requestID)
758 {
759     ASSERT(m_isStarted);
760     
761     PendingURLNotifyMap::iterator it = m_pendingURLNotifications.find(requestID);
762     if (it == m_pendingURLNotifications.end())
763         return;
764
765     String url = it->second.first;
766     void* notificationData = it->second.second;
767
768     m_pendingURLNotifications.remove(it);
769     
770     NPP_URLNotify(url.utf8().data(), NPRES_DONE, notificationData);
771 }
772
773 void NetscapePlugin::frameDidFail(uint64_t requestID, bool wasCancelled)
774 {
775     ASSERT(m_isStarted);
776     
777     PendingURLNotifyMap::iterator it = m_pendingURLNotifications.find(requestID);
778     if (it == m_pendingURLNotifications.end())
779         return;
780
781     String url = it->second.first;
782     void* notificationData = it->second.second;
783
784     m_pendingURLNotifications.remove(it);
785     
786     NPP_URLNotify(url.utf8().data(), wasCancelled ? NPRES_USER_BREAK : NPRES_NETWORK_ERR, notificationData);
787 }
788
789 void NetscapePlugin::didEvaluateJavaScript(uint64_t requestID, const String& result)
790 {
791     ASSERT(m_isStarted);
792     
793     if (NetscapePluginStream* pluginStream = streamFromID(requestID))
794         pluginStream->sendJavaScriptStream(result);
795 }
796
797 void NetscapePlugin::streamDidReceiveResponse(uint64_t streamID, const KURL& responseURL, uint32_t streamLength, 
798                                               uint32_t lastModifiedTime, const String& mimeType, const String& headers, const String& /* suggestedFileName */)
799 {
800     ASSERT(m_isStarted);
801     
802     if (NetscapePluginStream* pluginStream = streamFromID(streamID))
803         pluginStream->didReceiveResponse(responseURL, streamLength, lastModifiedTime, mimeType, headers);
804 }
805
806 void NetscapePlugin::streamDidReceiveData(uint64_t streamID, const char* bytes, int length)
807 {
808     ASSERT(m_isStarted);
809     
810     if (NetscapePluginStream* pluginStream = streamFromID(streamID))
811         pluginStream->didReceiveData(bytes, length);
812 }
813
814 void NetscapePlugin::streamDidFinishLoading(uint64_t streamID)
815 {
816     ASSERT(m_isStarted);
817     
818     if (NetscapePluginStream* pluginStream = streamFromID(streamID))
819         pluginStream->didFinishLoading();
820 }
821
822 void NetscapePlugin::streamDidFail(uint64_t streamID, bool wasCancelled)
823 {
824     ASSERT(m_isStarted);
825     
826     if (NetscapePluginStream* pluginStream = streamFromID(streamID))
827         pluginStream->didFail(wasCancelled);
828 }
829
830 void NetscapePlugin::manualStreamDidReceiveResponse(const KURL& responseURL, uint32_t streamLength, uint32_t lastModifiedTime, 
831                                                     const String& mimeType, const String& headers, const String& /* suggestedFileName */)
832 {
833     ASSERT(m_isStarted);
834     ASSERT(m_shouldUseManualLoader);
835     ASSERT(!m_manualStream);
836     
837     m_manualStream = NetscapePluginStream::create(this, 0, responseURL.string(), false, 0);
838     m_manualStream->didReceiveResponse(responseURL, streamLength, lastModifiedTime, mimeType, headers);
839 }
840
841 void NetscapePlugin::manualStreamDidReceiveData(const char* bytes, int length)
842 {
843     ASSERT(m_isStarted);
844     ASSERT(m_shouldUseManualLoader);
845     ASSERT(m_manualStream);
846
847     m_manualStream->didReceiveData(bytes, length);
848 }
849
850 void NetscapePlugin::manualStreamDidFinishLoading()
851 {
852     ASSERT(m_isStarted);
853     ASSERT(m_shouldUseManualLoader);
854     ASSERT(m_manualStream);
855
856     m_manualStream->didFinishLoading();
857 }
858
859 void NetscapePlugin::manualStreamDidFail(bool wasCancelled)
860 {
861     ASSERT(m_isStarted);
862     ASSERT(m_shouldUseManualLoader);
863
864     if (!m_manualStream)
865         return;
866     m_manualStream->didFail(wasCancelled);
867 }
868
869 bool NetscapePlugin::handleMouseEvent(const WebMouseEvent& mouseEvent)
870 {
871     ASSERT(m_isStarted);
872     
873     return platformHandleMouseEvent(mouseEvent);
874 }
875     
876 bool NetscapePlugin::handleWheelEvent(const WebWheelEvent& wheelEvent)
877 {
878     ASSERT(m_isStarted);
879
880     return platformHandleWheelEvent(wheelEvent);
881 }
882
883 bool NetscapePlugin::handleMouseEnterEvent(const WebMouseEvent& mouseEvent)
884 {
885     ASSERT(m_isStarted);
886
887     return platformHandleMouseEnterEvent(mouseEvent);
888 }
889
890 bool NetscapePlugin::handleMouseLeaveEvent(const WebMouseEvent& mouseEvent)
891 {
892     ASSERT(m_isStarted);
893
894     return platformHandleMouseLeaveEvent(mouseEvent);
895 }
896
897 bool NetscapePlugin::handleContextMenuEvent(const WebMouseEvent&)
898 {
899     // We don't know if the plug-in has handled mousedown event by displaying a context menu, so we never want WebKit to show a default one.
900     return true;
901 }
902
903 bool NetscapePlugin::handleKeyboardEvent(const WebKeyboardEvent& keyboardEvent)
904 {
905     ASSERT(m_isStarted);
906
907     return platformHandleKeyboardEvent(keyboardEvent);
908 }
909
910 void NetscapePlugin::setFocus(bool hasFocus)
911 {
912     ASSERT(m_isStarted);
913
914     platformSetFocus(hasFocus);
915 }
916
917 NPObject* NetscapePlugin::pluginScriptableNPObject()
918 {
919     ASSERT(m_isStarted);
920     NPObject* scriptableNPObject = 0;
921     
922     if (NPP_GetValue(NPPVpluginScriptableNPObject, &scriptableNPObject) != NPERR_NO_ERROR)
923         return 0;
924
925 #if PLUGIN_ARCHITECTURE(MAC)
926     if (m_pluginModule->pluginQuirks().contains(PluginQuirks::ReturnsNonRetainedScriptableNPObject))
927         retainNPObject(scriptableNPObject);        
928 #endif    
929
930     return scriptableNPObject;
931 }
932
933 void NetscapePlugin::contentsScaleFactorChanged(float scaleFactor)
934 {
935     ASSERT(m_isStarted);
936
937 #if PLUGIN_ARCHITECTURE(MAC)
938     double contentsScaleFactor = scaleFactor;
939     NPP_SetValue(NPNVcontentsScaleFactor, &contentsScaleFactor);
940 #endif
941 }
942
943 void NetscapePlugin::privateBrowsingStateChanged(bool privateBrowsingEnabled)
944 {
945     ASSERT(m_isStarted);
946
947     // From https://wiki.mozilla.org/Plugins:PrivateMode
948     //   When the browser turns private mode on or off it will call NPP_SetValue for "NPNVprivateModeBool" 
949     //   (assigned enum value 18) with a pointer to an NPBool value on all applicable instances.
950     //   Plugins should check the boolean value pointed to, not the pointer itself. 
951     //   The value will be true when private mode is on.
952     NPBool value = privateBrowsingEnabled;
953     NPP_SetValue(NPNVprivateModeBool, &value);
954 }
955
956 bool NetscapePlugin::getFormValue(String& formValue)
957 {
958     ASSERT(m_isStarted);
959
960     char* formValueString = 0;
961     if (NPP_GetValue(NPPVformValue, &formValueString) != NPERR_NO_ERROR)
962         return false;
963
964     formValue = String::fromUTF8(formValueString);
965
966     // The plug-in allocates the form value string with NPN_MemAlloc so it needs to be freed with NPN_MemFree.
967     npnMemFree(formValueString);
968     return true;
969 }
970
971 bool NetscapePlugin::handleScroll(ScrollDirection, ScrollGranularity)
972 {
973     return false;
974 }
975
976 Scrollbar* NetscapePlugin::horizontalScrollbar()
977 {
978     return 0;
979 }
980
981 Scrollbar* NetscapePlugin::verticalScrollbar()
982 {
983     return 0;
984 }
985
986 bool NetscapePlugin::supportsSnapshotting() const
987 {
988 #if PLATFORM(MAC)
989     return m_pluginModule && m_pluginModule->pluginQuirks().contains(PluginQuirks::SupportsSnapshotting);
990 #endif
991     return false;
992 }
993
994 IntPoint NetscapePlugin::convertToRootView(const IntPoint& pointInPluginCoordinates) const
995 {
996     return m_pluginToRootViewTransform.mapPoint(pointInPluginCoordinates);
997 }
998
999 bool NetscapePlugin::convertFromRootView(const IntPoint& pointInRootViewCoordinates, IntPoint& pointInPluginCoordinates)
1000 {
1001     if (!m_pluginToRootViewTransform.isInvertible())
1002         return false;
1003
1004     pointInPluginCoordinates = m_pluginToRootViewTransform.inverse().mapPoint(pointInRootViewCoordinates);
1005     return true;
1006 }
1007
1008 } // namespace WebKit
1009
1010 #endif // ENABLE(NETSCAPE_PLUGIN_API)