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