PluginView.cpp 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506
  1. /*
  2. * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
  3. * Copyright (C) 2008 Collabora Ltd. All rights reserved.
  4. * Copyright (C) 2010 Girish Ramakrishnan <girish@forwardbias.in>
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
  16. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  18. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
  19. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  20. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  21. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  22. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  23. * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  25. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. #include "config.h"
  28. #include "PluginView.h"
  29. #include "BridgeJSC.h"
  30. #include "Chrome.h"
  31. #include "CookieJar.h"
  32. #include "Document.h"
  33. #include "DocumentLoader.h"
  34. #include "Element.h"
  35. #include "FocusController.h"
  36. #include "Frame.h"
  37. #include "FrameLoadRequest.h"
  38. #include "FrameLoader.h"
  39. #include "FrameLoaderClient.h"
  40. #include "FrameTree.h"
  41. #include "FrameView.h"
  42. #include "GraphicsContext.h"
  43. #include "HTMLNames.h"
  44. #include "HTMLPlugInElement.h"
  45. #include "Image.h"
  46. #include "JSDOMBinding.h"
  47. #include "JSDOMWindow.h"
  48. #include "KeyboardEvent.h"
  49. #include "MIMETypeRegistry.h"
  50. #include "MouseEvent.h"
  51. #include "NotImplemented.h"
  52. #include "Page.h"
  53. #include "PlatformMouseEvent.h"
  54. #include "PluginDatabase.h"
  55. #include "PluginDebug.h"
  56. #include "PluginMainThreadScheduler.h"
  57. #include "PluginPackage.h"
  58. #include "ProxyServer.h"
  59. #include "RenderBox.h"
  60. #include "RenderObject.h"
  61. #include "ScriptController.h"
  62. #include "ScriptValue.h"
  63. #include "SecurityOrigin.h"
  64. #include "Settings.h"
  65. #include "WheelEvent.h"
  66. #include "c_instance.h"
  67. #include "npruntime_impl.h"
  68. #include "runtime_root.h"
  69. #include <runtime/JSCJSValue.h>
  70. #include <runtime/JSLock.h>
  71. #include <wtf/ASCIICType.h>
  72. #include <wtf/text/WTFString.h>
  73. #if OS(WINDOWS) && ENABLE(NETSCAPE_PLUGIN_API)
  74. #include "PluginMessageThrottlerWin.h"
  75. #endif
  76. using JSC::ExecState;
  77. using JSC::JSLock;
  78. using JSC::JSObject;
  79. using JSC::JSValue;
  80. #if ENABLE(NETSCAPE_PLUGIN_API)
  81. using std::min;
  82. using namespace WTF;
  83. namespace WebCore {
  84. using namespace HTMLNames;
  85. static int s_callingPlugin;
  86. typedef HashMap<NPP, PluginView*> InstanceMap;
  87. static InstanceMap& instanceMap()
  88. {
  89. static InstanceMap& map = *new InstanceMap;
  90. return map;
  91. }
  92. static String scriptStringIfJavaScriptURL(const KURL& url)
  93. {
  94. if (!protocolIsJavaScript(url))
  95. return String();
  96. // This returns an unescaped string
  97. return decodeURLEscapeSequences(url.string().substring(11));
  98. }
  99. PluginView* PluginView::s_currentPluginView = 0;
  100. void PluginView::popPopupsStateTimerFired(Timer<PluginView>*)
  101. {
  102. popPopupsEnabledState();
  103. }
  104. IntRect PluginView::windowClipRect() const
  105. {
  106. // Start by clipping to our bounds.
  107. IntRect clipRect(m_windowRect);
  108. // Take our element and get the clip rect from the enclosing layer and frame view.
  109. FrameView* parentView = m_element->document()->view();
  110. clipRect.intersect(parentView->windowClipRectForFrameOwner(m_element, true));
  111. return clipRect;
  112. }
  113. void PluginView::setFrameRect(const IntRect& rect)
  114. {
  115. if (m_element->document()->printing())
  116. return;
  117. if (rect != frameRect())
  118. Widget::setFrameRect(rect);
  119. updatePluginWidget();
  120. #if OS(WINDOWS)
  121. // On Windows always call plugin to change geometry.
  122. setNPWindowRect(rect);
  123. #elif defined(XP_UNIX)
  124. // On Unix, multiple calls to setNPWindow() in windowed mode causes Flash to crash
  125. if (m_mode == NP_FULL || !m_isWindowed)
  126. setNPWindowRect(rect);
  127. #endif
  128. }
  129. void PluginView::frameRectsChanged()
  130. {
  131. updatePluginWidget();
  132. }
  133. void PluginView::clipRectChanged()
  134. {
  135. updatePluginWidget();
  136. }
  137. void PluginView::handleEvent(Event* event)
  138. {
  139. if (!m_plugin || m_isWindowed)
  140. return;
  141. // Protect the plug-in from deletion while dispatching the event.
  142. RefPtr<PluginView> protect(this);
  143. if (event->isMouseEvent())
  144. handleMouseEvent(static_cast<MouseEvent*>(event));
  145. else if (event->isKeyboardEvent())
  146. handleKeyboardEvent(static_cast<KeyboardEvent*>(event));
  147. #if defined(XP_MACOSX)
  148. else if (event->type() == eventNames().mousewheelEvent)
  149. handleWheelEvent(static_cast<WheelEvent*>(event));
  150. #endif
  151. else if (event->type() == eventNames().contextmenuEvent)
  152. event->setDefaultHandled(); // 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.
  153. #if defined(XP_UNIX) && ENABLE(NETSCAPE_PLUGIN_API)
  154. else if (event->type() == eventNames().focusoutEvent)
  155. handleFocusOutEvent();
  156. else if (event->type() == eventNames().focusinEvent)
  157. handleFocusInEvent();
  158. #endif
  159. }
  160. void PluginView::init()
  161. {
  162. if (m_haveInitialized)
  163. return;
  164. m_haveInitialized = true;
  165. if (!m_plugin) {
  166. ASSERT(m_status == PluginStatusCanNotFindPlugin);
  167. return;
  168. }
  169. LOG(Plugins, "PluginView::init(): Initializing plug-in '%s'", m_plugin->name().utf8().data());
  170. if (!m_plugin->load()) {
  171. m_plugin = 0;
  172. m_status = PluginStatusCanNotLoadPlugin;
  173. return;
  174. }
  175. if (!startOrAddToUnstartedList()) {
  176. m_status = PluginStatusCanNotLoadPlugin;
  177. return;
  178. }
  179. m_status = PluginStatusLoadedSuccessfully;
  180. }
  181. bool PluginView::startOrAddToUnstartedList()
  182. {
  183. if (!m_parentFrame->page())
  184. return false;
  185. // We only delay starting the plug-in if we're going to kick off the load
  186. // ourselves. Otherwise, the loader will try to deliver data before we've
  187. // started the plug-in.
  188. if (!m_loadManually && !m_parentFrame->page()->canStartMedia()) {
  189. m_parentFrame->document()->addMediaCanStartListener(this);
  190. m_isWaitingToStart = true;
  191. return true;
  192. }
  193. return start();
  194. }
  195. bool PluginView::start()
  196. {
  197. if (m_isStarted)
  198. return false;
  199. m_isWaitingToStart = false;
  200. PluginMainThreadScheduler::scheduler().registerPlugin(m_instance);
  201. ASSERT(m_plugin);
  202. ASSERT(m_plugin->pluginFuncs()->newp);
  203. NPError npErr;
  204. {
  205. PluginView::setCurrentPluginView(this);
  206. JSC::JSLock::DropAllLocks dropAllLocks(JSDOMWindowBase::commonVM());
  207. setCallingPlugin(true);
  208. npErr = m_plugin->pluginFuncs()->newp((NPMIMEType)m_mimeType.utf8().data(), m_instance, m_mode, m_paramCount, m_paramNames, m_paramValues, NULL);
  209. setCallingPlugin(false);
  210. LOG_NPERROR(npErr);
  211. PluginView::setCurrentPluginView(0);
  212. }
  213. if (npErr != NPERR_NO_ERROR) {
  214. m_status = PluginStatusCanNotLoadPlugin;
  215. PluginMainThreadScheduler::scheduler().unregisterPlugin(m_instance);
  216. return false;
  217. }
  218. m_isStarted = true;
  219. if (!m_url.isEmpty() && !m_loadManually) {
  220. FrameLoadRequest frameLoadRequest(m_parentFrame->document()->securityOrigin());
  221. frameLoadRequest.resourceRequest().setHTTPMethod("GET");
  222. frameLoadRequest.resourceRequest().setURL(m_url);
  223. load(frameLoadRequest, false, 0);
  224. }
  225. m_status = PluginStatusLoadedSuccessfully;
  226. if (!platformStart())
  227. m_status = PluginStatusCanNotLoadPlugin;
  228. if (m_status != PluginStatusLoadedSuccessfully)
  229. return false;
  230. return true;
  231. }
  232. void PluginView::mediaCanStart()
  233. {
  234. ASSERT(!m_isStarted);
  235. if (!start())
  236. parentFrame()->loader()->client()->dispatchDidFailToStartPlugin(this);
  237. }
  238. PluginView::~PluginView()
  239. {
  240. LOG(Plugins, "PluginView::~PluginView()");
  241. ASSERT(!m_lifeSupportTimer.isActive());
  242. // If we failed to find the plug-in, we'll return early in our constructor, and
  243. // m_instance will be 0.
  244. if (m_instance)
  245. instanceMap().remove(m_instance);
  246. if (m_isWaitingToStart)
  247. m_parentFrame->document()->removeMediaCanStartListener(this);
  248. stop();
  249. freeStringArray(m_paramNames, m_paramCount);
  250. freeStringArray(m_paramValues, m_paramCount);
  251. platformDestroy();
  252. m_parentFrame->script()->cleanupScriptObjectsForPlugin(this);
  253. if (m_plugin && !(m_plugin->quirks().contains(PluginQuirkDontUnloadPlugin)))
  254. m_plugin->unload();
  255. }
  256. void PluginView::stop()
  257. {
  258. if (!m_isStarted)
  259. return;
  260. LOG(Plugins, "PluginView::stop(): Stopping plug-in '%s'", m_plugin->name().utf8().data());
  261. HashSet<RefPtr<PluginStream> > streams = m_streams;
  262. HashSet<RefPtr<PluginStream> >::iterator end = streams.end();
  263. for (HashSet<RefPtr<PluginStream> >::iterator it = streams.begin(); it != end; ++it) {
  264. (*it)->stop();
  265. disconnectStream((*it).get());
  266. }
  267. ASSERT(m_streams.isEmpty());
  268. m_isStarted = false;
  269. JSC::JSLock::DropAllLocks dropAllLocks(JSDOMWindowBase::commonVM());
  270. #if ENABLE(NETSCAPE_PLUGIN_API)
  271. #if defined(XP_WIN) && !PLATFORM(GTK)
  272. // Unsubclass the window
  273. if (m_isWindowed) {
  274. #if OS(WINCE)
  275. WNDPROC currentWndProc = (WNDPROC)GetWindowLong(platformPluginWidget(), GWL_WNDPROC);
  276. if (currentWndProc == PluginViewWndProc)
  277. SetWindowLong(platformPluginWidget(), GWL_WNDPROC, (LONG)m_pluginWndProc);
  278. #else
  279. WNDPROC currentWndProc = (WNDPROC)GetWindowLongPtr(platformPluginWidget(), GWLP_WNDPROC);
  280. if (currentWndProc == PluginViewWndProc)
  281. SetWindowLongPtr(platformPluginWidget(), GWLP_WNDPROC, (LONG_PTR)m_pluginWndProc);
  282. #endif
  283. }
  284. #endif // !defined(XP_WIN) || PLATFORM(GTK)
  285. #endif // ENABLE(NETSCAPE_PLUGIN_API)
  286. #if !defined(XP_MACOSX)
  287. // Clear the window
  288. m_npWindow.window = 0;
  289. if (m_plugin->pluginFuncs()->setwindow && !m_plugin->quirks().contains(PluginQuirkDontSetNullWindowHandleOnDestroy)) {
  290. PluginView::setCurrentPluginView(this);
  291. setCallingPlugin(true);
  292. m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow);
  293. setCallingPlugin(false);
  294. PluginView::setCurrentPluginView(0);
  295. }
  296. #ifdef XP_UNIX
  297. delete static_cast<NPSetWindowCallbackStruct*>(m_npWindow.ws_info);
  298. m_npWindow.ws_info = 0;
  299. #endif
  300. #endif // !defined(XP_MACOSX)
  301. PluginMainThreadScheduler::scheduler().unregisterPlugin(m_instance);
  302. NPSavedData* savedData = 0;
  303. PluginView::setCurrentPluginView(this);
  304. setCallingPlugin(true);
  305. NPError npErr = m_plugin->pluginFuncs()->destroy(m_instance, &savedData);
  306. setCallingPlugin(false);
  307. LOG_NPERROR(npErr);
  308. PluginView::setCurrentPluginView(0);
  309. #if ENABLE(NETSCAPE_PLUGIN_API)
  310. if (savedData) {
  311. // TODO: Actually save this data instead of just discarding it
  312. if (savedData->buf)
  313. NPN_MemFree(savedData->buf);
  314. NPN_MemFree(savedData);
  315. }
  316. #endif
  317. m_instance->pdata = 0;
  318. }
  319. void PluginView::setCurrentPluginView(PluginView* pluginView)
  320. {
  321. s_currentPluginView = pluginView;
  322. }
  323. PluginView* PluginView::currentPluginView()
  324. {
  325. return s_currentPluginView;
  326. }
  327. static char* createUTF8String(const String& str)
  328. {
  329. CString cstr = str.utf8();
  330. const size_t cstrLength = cstr.length();
  331. char* result = reinterpret_cast<char*>(fastMalloc(cstrLength + 1));
  332. memcpy(result, cstr.data(), cstrLength);
  333. result[cstrLength] = '\0';
  334. return result;
  335. }
  336. void PluginView::performRequest(PluginRequest* request)
  337. {
  338. if (!m_isStarted)
  339. return;
  340. // don't let a plugin start any loads if it is no longer part of a document that is being
  341. // displayed unless the loads are in the same frame as the plugin.
  342. const String& targetFrameName = request->frameLoadRequest().frameName();
  343. if (m_parentFrame->loader()->documentLoader() != m_parentFrame->loader()->activeDocumentLoader() &&
  344. (targetFrameName.isNull() || m_parentFrame->tree()->find(targetFrameName) != m_parentFrame))
  345. return;
  346. KURL requestURL = request->frameLoadRequest().resourceRequest().url();
  347. String jsString = scriptStringIfJavaScriptURL(requestURL);
  348. if (jsString.isNull()) {
  349. // if this is not a targeted request, create a stream for it. otherwise,
  350. // just pass it off to the loader
  351. if (targetFrameName.isEmpty()) {
  352. RefPtr<PluginStream> stream = PluginStream::create(this, m_parentFrame.get(), request->frameLoadRequest().resourceRequest(), request->sendNotification(), request->notifyData(), plugin()->pluginFuncs(), instance(), m_plugin->quirks());
  353. m_streams.add(stream);
  354. stream->start();
  355. } else {
  356. // If the target frame is our frame, we could destroy the
  357. // PluginView, so we protect it. <rdar://problem/6991251>
  358. RefPtr<PluginView> protect(this);
  359. FrameLoadRequest frameRequest(m_parentFrame.get(), request->frameLoadRequest().resourceRequest());
  360. frameRequest.setFrameName(targetFrameName);
  361. frameRequest.setShouldCheckNewWindowPolicy(true);
  362. m_parentFrame->loader()->load(frameRequest);
  363. // FIXME: <rdar://problem/4807469> This should be sent when the document has finished loading
  364. if (request->sendNotification()) {
  365. PluginView::setCurrentPluginView(this);
  366. JSC::JSLock::DropAllLocks dropAllLocks(JSDOMWindowBase::commonVM());
  367. setCallingPlugin(true);
  368. m_plugin->pluginFuncs()->urlnotify(m_instance, requestURL.string().utf8().data(), NPRES_DONE, request->notifyData());
  369. setCallingPlugin(false);
  370. PluginView::setCurrentPluginView(0);
  371. }
  372. }
  373. return;
  374. }
  375. // Targeted JavaScript requests are only allowed on the frame that contains the JavaScript plugin
  376. // and this has been made sure in ::load.
  377. ASSERT(targetFrameName.isEmpty() || m_parentFrame->tree()->find(targetFrameName) == m_parentFrame);
  378. // Executing a script can cause the plugin view to be destroyed, so we keep a reference to it.
  379. RefPtr<PluginView> protector(this);
  380. ScriptValue result = m_parentFrame->script()->executeScript(jsString, request->shouldAllowPopups());
  381. if (targetFrameName.isNull()) {
  382. String resultString;
  383. ScriptState* scriptState = m_parentFrame->script()->globalObject(pluginWorld())->globalExec();
  384. CString cstr;
  385. if (result.getString(scriptState, resultString))
  386. cstr = resultString.utf8();
  387. RefPtr<PluginStream> stream = PluginStream::create(this, m_parentFrame.get(), request->frameLoadRequest().resourceRequest(), request->sendNotification(), request->notifyData(), plugin()->pluginFuncs(), instance(), m_plugin->quirks());
  388. m_streams.add(stream);
  389. stream->sendJavaScriptStream(requestURL, cstr);
  390. }
  391. }
  392. void PluginView::requestTimerFired(Timer<PluginView>* timer)
  393. {
  394. ASSERT_UNUSED(timer, timer == &m_requestTimer);
  395. ASSERT(!m_requests.isEmpty());
  396. ASSERT(!m_isJavaScriptPaused);
  397. OwnPtr<PluginRequest> request = m_requests[0].release();
  398. m_requests.remove(0);
  399. // Schedule a new request before calling performRequest since the call to
  400. // performRequest can cause the plugin view to be deleted.
  401. if (!m_requests.isEmpty())
  402. m_requestTimer.startOneShot(0);
  403. performRequest(request.get());
  404. }
  405. void PluginView::scheduleRequest(PassOwnPtr<PluginRequest> request)
  406. {
  407. m_requests.append(request);
  408. if (!m_isJavaScriptPaused)
  409. m_requestTimer.startOneShot(0);
  410. }
  411. NPError PluginView::load(const FrameLoadRequest& frameLoadRequest, bool sendNotification, void* notifyData)
  412. {
  413. ASSERT(frameLoadRequest.resourceRequest().httpMethod() == "GET" || frameLoadRequest.resourceRequest().httpMethod() == "POST");
  414. KURL url = frameLoadRequest.resourceRequest().url();
  415. if (url.isEmpty())
  416. return NPERR_INVALID_URL;
  417. // Don't allow requests to be made when the document loader is stopping all loaders.
  418. DocumentLoader* loader = m_parentFrame->loader()->documentLoader();
  419. if (!loader || loader->isStopping())
  420. return NPERR_GENERIC_ERROR;
  421. const String& targetFrameName = frameLoadRequest.frameName();
  422. String jsString = scriptStringIfJavaScriptURL(url);
  423. if (!jsString.isNull()) {
  424. // Return NPERR_GENERIC_ERROR if JS is disabled. This is what Mozilla does.
  425. if (!m_parentFrame->script()->canExecuteScripts(NotAboutToExecuteScript))
  426. return NPERR_GENERIC_ERROR;
  427. // For security reasons, only allow JS requests to be made on the frame that contains the plug-in.
  428. if (!targetFrameName.isNull() && m_parentFrame->tree()->find(targetFrameName) != m_parentFrame)
  429. return NPERR_INVALID_PARAM;
  430. } else if (!m_parentFrame->document()->securityOrigin()->canDisplay(url))
  431. return NPERR_GENERIC_ERROR;
  432. scheduleRequest(adoptPtr(new PluginRequest(frameLoadRequest, sendNotification, notifyData, arePopupsAllowed())));
  433. return NPERR_NO_ERROR;
  434. }
  435. static KURL makeURL(const KURL& baseURL, const char* relativeURLString)
  436. {
  437. String urlString = relativeURLString;
  438. // Strip return characters.
  439. urlString.replaceWithLiteral('\n', "");
  440. urlString.replaceWithLiteral('\r', "");
  441. return KURL(baseURL, urlString);
  442. }
  443. NPError PluginView::getURLNotify(const char* url, const char* target, void* notifyData)
  444. {
  445. FrameLoadRequest frameLoadRequest(m_parentFrame->document()->securityOrigin());
  446. frameLoadRequest.setFrameName(target);
  447. frameLoadRequest.resourceRequest().setHTTPMethod("GET");
  448. frameLoadRequest.resourceRequest().setURL(makeURL(m_parentFrame->document()->baseURL(), url));
  449. return load(frameLoadRequest, true, notifyData);
  450. }
  451. NPError PluginView::getURL(const char* url, const char* target)
  452. {
  453. FrameLoadRequest frameLoadRequest(m_parentFrame->document()->securityOrigin());
  454. frameLoadRequest.setFrameName(target);
  455. frameLoadRequest.resourceRequest().setHTTPMethod("GET");
  456. frameLoadRequest.resourceRequest().setURL(makeURL(m_parentFrame->document()->baseURL(), url));
  457. return load(frameLoadRequest, false, 0);
  458. }
  459. NPError PluginView::postURLNotify(const char* url, const char* target, uint32_t len, const char* buf, NPBool file, void* notifyData)
  460. {
  461. return handlePost(url, target, len, buf, file, notifyData, true, true);
  462. }
  463. NPError PluginView::postURL(const char* url, const char* target, uint32_t len, const char* buf, NPBool file)
  464. {
  465. // As documented, only allow headers to be specified via NPP_PostURL when using a file.
  466. return handlePost(url, target, len, buf, file, 0, false, file);
  467. }
  468. NPError PluginView::newStream(NPMIMEType, const char* /* target */, NPStream**)
  469. {
  470. notImplemented();
  471. // Unsupported
  472. return NPERR_GENERIC_ERROR;
  473. }
  474. int32_t PluginView::write(NPStream*, int32_t /* len */, void* /* buffer */)
  475. {
  476. notImplemented();
  477. // Unsupported
  478. return -1;
  479. }
  480. NPError PluginView::destroyStream(NPStream* stream, NPReason reason)
  481. {
  482. if (!stream || PluginStream::ownerForStream(stream) != m_instance)
  483. return NPERR_INVALID_INSTANCE_ERROR;
  484. PluginStream* browserStream = static_cast<PluginStream*>(stream->ndata);
  485. browserStream->cancelAndDestroyStream(reason);
  486. return NPERR_NO_ERROR;
  487. }
  488. void PluginView::status(const char* message)
  489. {
  490. if (Page* page = m_parentFrame->page())
  491. page->chrome().setStatusbarText(m_parentFrame.get(), String::fromUTF8(message));
  492. }
  493. NPError PluginView::setValue(NPPVariable variable, void* value)
  494. {
  495. LOG(Plugins, "PluginView::setValue(%s): ", prettyNameForNPPVariable(variable, value).data());
  496. switch (variable) {
  497. case NPPVpluginWindowBool:
  498. m_isWindowed = value;
  499. return NPERR_NO_ERROR;
  500. case NPPVpluginTransparentBool:
  501. m_isTransparent = value;
  502. return NPERR_NO_ERROR;
  503. #if defined(XP_MACOSX)
  504. case NPPVpluginDrawingModel: {
  505. // Can only set drawing model inside NPP_New()
  506. if (this != currentPluginView())
  507. return NPERR_GENERIC_ERROR;
  508. NPDrawingModel newDrawingModel = NPDrawingModel(uintptr_t(value));
  509. switch (newDrawingModel) {
  510. case NPDrawingModelCoreGraphics:
  511. return NPERR_NO_ERROR;
  512. case NPDrawingModelCoreAnimation:
  513. default:
  514. LOG(Plugins, "Plugin asked for unsupported drawing model: %s",
  515. prettyNameForDrawingModel(newDrawingModel));
  516. return NPERR_GENERIC_ERROR;
  517. }
  518. }
  519. case NPPVpluginEventModel: {
  520. // Can only set event model inside NPP_New()
  521. if (this != currentPluginView())
  522. return NPERR_GENERIC_ERROR;
  523. NPEventModel newEventModel = NPEventModel(uintptr_t(value));
  524. switch (newEventModel) {
  525. case NPEventModelCocoa:
  526. return NPERR_NO_ERROR;
  527. default:
  528. LOG(Plugins, "Plugin asked for unsupported event model: %s",
  529. prettyNameForEventModel(newEventModel));
  530. return NPERR_GENERIC_ERROR;
  531. }
  532. }
  533. #endif // defined(XP_MACOSX)
  534. default:
  535. notImplemented();
  536. return NPERR_GENERIC_ERROR;
  537. }
  538. }
  539. void PluginView::invalidateTimerFired(Timer<PluginView>* timer)
  540. {
  541. ASSERT_UNUSED(timer, timer == &m_invalidateTimer);
  542. for (unsigned i = 0; i < m_invalidRects.size(); i++)
  543. invalidateRect(m_invalidRects[i]);
  544. m_invalidRects.clear();
  545. }
  546. void PluginView::pushPopupsEnabledState(bool state)
  547. {
  548. m_popupStateStack.append(state);
  549. }
  550. void PluginView::popPopupsEnabledState()
  551. {
  552. m_popupStateStack.removeLast();
  553. }
  554. bool PluginView::arePopupsAllowed() const
  555. {
  556. if (!m_popupStateStack.isEmpty())
  557. return m_popupStateStack.last();
  558. return false;
  559. }
  560. void PluginView::setJavaScriptPaused(bool paused)
  561. {
  562. if (m_isJavaScriptPaused == paused)
  563. return;
  564. m_isJavaScriptPaused = paused;
  565. if (m_isJavaScriptPaused)
  566. m_requestTimer.stop();
  567. else if (!m_requests.isEmpty())
  568. m_requestTimer.startOneShot(0);
  569. }
  570. #if ENABLE(NETSCAPE_PLUGIN_API)
  571. NPObject* PluginView::npObject()
  572. {
  573. NPObject* object = 0;
  574. if (!m_isStarted || !m_plugin || !m_plugin->pluginFuncs()->getvalue)
  575. return 0;
  576. // On Windows, calling Java's NPN_GetValue can allow the message loop to
  577. // run, allowing loading to take place or JavaScript to run. Protect the
  578. // PluginView from destruction. <rdar://problem/6978804>
  579. RefPtr<PluginView> protect(this);
  580. NPError npErr;
  581. {
  582. PluginView::setCurrentPluginView(this);
  583. JSC::JSLock::DropAllLocks dropAllLocks(JSDOMWindowBase::commonVM());
  584. setCallingPlugin(true);
  585. npErr = m_plugin->pluginFuncs()->getvalue(m_instance, NPPVpluginScriptableNPObject, &object);
  586. setCallingPlugin(false);
  587. PluginView::setCurrentPluginView(0);
  588. }
  589. if (npErr != NPERR_NO_ERROR)
  590. return 0;
  591. return object;
  592. }
  593. #endif
  594. PassRefPtr<JSC::Bindings::Instance> PluginView::bindingInstance()
  595. {
  596. #if ENABLE(NETSCAPE_PLUGIN_API)
  597. NPObject* object = npObject();
  598. if (!object)
  599. return 0;
  600. if (hasOneRef()) {
  601. // The renderer for the PluginView was destroyed during the above call, and
  602. // the PluginView will be destroyed when this function returns, so we
  603. // return null.
  604. return 0;
  605. }
  606. RefPtr<JSC::Bindings::RootObject> root = m_parentFrame->script()->createRootObject(this);
  607. RefPtr<JSC::Bindings::Instance> instance = JSC::Bindings::CInstance::create(object, root.release());
  608. _NPN_ReleaseObject(object);
  609. return instance.release();
  610. #else
  611. return 0;
  612. #endif
  613. }
  614. void PluginView::disconnectStream(PluginStream* stream)
  615. {
  616. ASSERT(m_streams.contains(stream));
  617. m_streams.remove(stream);
  618. }
  619. void PluginView::setParameters(const Vector<String>& paramNames, const Vector<String>& paramValues)
  620. {
  621. ASSERT(paramNames.size() == paramValues.size());
  622. unsigned size = paramNames.size();
  623. unsigned paramCount = 0;
  624. m_paramNames = reinterpret_cast<char**>(fastMalloc(sizeof(char*) * size));
  625. m_paramValues = reinterpret_cast<char**>(fastMalloc(sizeof(char*) * size));
  626. for (unsigned i = 0; i < size; i++) {
  627. if (m_plugin->quirks().contains(PluginQuirkRemoveWindowlessVideoParam) && equalIgnoringCase(paramNames[i], "windowlessvideo"))
  628. continue;
  629. if (paramNames[i] == "pluginspage")
  630. m_pluginsPage = paramValues[i];
  631. m_paramNames[paramCount] = createUTF8String(paramNames[i]);
  632. m_paramValues[paramCount] = createUTF8String(paramValues[i]);
  633. paramCount++;
  634. }
  635. m_paramCount = paramCount;
  636. }
  637. PluginView::PluginView(Frame* parentFrame, const IntSize& size, PluginPackage* plugin, HTMLPlugInElement* element, const KURL& url, const Vector<String>& paramNames, const Vector<String>& paramValues, const String& mimeType, bool loadManually)
  638. : m_parentFrame(parentFrame)
  639. , m_plugin(plugin)
  640. , m_element(element)
  641. , m_isStarted(false)
  642. , m_url(url)
  643. , m_status(PluginStatusLoadedSuccessfully)
  644. , m_requestTimer(this, &PluginView::requestTimerFired)
  645. , m_invalidateTimer(this, &PluginView::invalidateTimerFired)
  646. , m_popPopupsStateTimer(this, &PluginView::popPopupsStateTimerFired)
  647. , m_lifeSupportTimer(this, &PluginView::lifeSupportTimerFired)
  648. , m_mode(loadManually ? NP_FULL : NP_EMBED)
  649. , m_paramNames(0)
  650. , m_paramValues(0)
  651. , m_mimeType(mimeType)
  652. , m_instance(0)
  653. #if defined(XP_MACOSX)
  654. , m_isWindowed(false)
  655. , m_updatedCocoaTextInputRequested(false)
  656. , m_keyDownSent(false)
  657. , m_disregardKeyUpCounter(0)
  658. #else
  659. , m_isWindowed(true)
  660. #endif
  661. , m_isTransparent(false)
  662. , m_haveInitialized(false)
  663. , m_isWaitingToStart(false)
  664. #if defined(XP_UNIX)
  665. , m_needsXEmbed(false)
  666. #endif
  667. #if OS(WINDOWS) && ENABLE(NETSCAPE_PLUGIN_API)
  668. , m_pluginWndProc(0)
  669. , m_lastMessage(0)
  670. , m_isCallingPluginWndProc(false)
  671. , m_wmPrintHDC(0)
  672. , m_haveUpdatedPluginWidget(false)
  673. #endif
  674. #if (PLATFORM(QT) && OS(WINDOWS)) || PLATFORM(EFL)
  675. , m_window(0)
  676. #endif
  677. #if defined(XP_MACOSX)
  678. , m_contextRef(0)
  679. #endif
  680. #if defined(XP_UNIX) && ENABLE(NETSCAPE_PLUGIN_API)
  681. , m_hasPendingGeometryChange(true)
  682. , m_drawable(0)
  683. , m_visual(0)
  684. , m_colormap(0)
  685. , m_pluginDisplay(0)
  686. #endif
  687. #if PLATFORM(QT) && defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO >= 5)
  688. , m_renderToImage(false)
  689. #endif
  690. , m_loadManually(loadManually)
  691. , m_manualStream(0)
  692. , m_isJavaScriptPaused(false)
  693. , m_haveCalledSetWindow(false)
  694. {
  695. if (!m_plugin) {
  696. m_status = PluginStatusCanNotFindPlugin;
  697. return;
  698. }
  699. m_instance = &m_instanceStruct;
  700. m_instance->ndata = this;
  701. m_instance->pdata = 0;
  702. instanceMap().add(m_instance, this);
  703. setParameters(paramNames, paramValues);
  704. memset(&m_npWindow, 0, sizeof(m_npWindow));
  705. #if defined(XP_MACOSX)
  706. memset(&m_npCgContext, 0, sizeof(m_npCgContext));
  707. #endif
  708. resize(size);
  709. }
  710. void PluginView::focusPluginElement()
  711. {
  712. if (Page* page = m_parentFrame->page())
  713. page->focusController()->setFocusedElement(m_element, m_parentFrame);
  714. else
  715. m_parentFrame->document()->setFocusedElement(m_element);
  716. }
  717. void PluginView::didReceiveResponse(const ResourceResponse& response)
  718. {
  719. if (m_status != PluginStatusLoadedSuccessfully)
  720. return;
  721. ASSERT(m_loadManually);
  722. ASSERT(!m_manualStream);
  723. m_manualStream = PluginStream::create(this, m_parentFrame.get(), m_parentFrame->loader()->activeDocumentLoader()->request(), false, 0, plugin()->pluginFuncs(), instance(), m_plugin->quirks());
  724. m_manualStream->setLoadManually(true);
  725. m_manualStream->didReceiveResponse(0, response);
  726. }
  727. void PluginView::didReceiveData(const char* data, int length)
  728. {
  729. if (m_status != PluginStatusLoadedSuccessfully)
  730. return;
  731. ASSERT(m_loadManually);
  732. ASSERT(m_manualStream);
  733. m_manualStream->didReceiveData(0, data, length);
  734. }
  735. void PluginView::didFinishLoading()
  736. {
  737. if (m_status != PluginStatusLoadedSuccessfully)
  738. return;
  739. ASSERT(m_loadManually);
  740. ASSERT(m_manualStream);
  741. m_manualStream->didFinishLoading(0);
  742. }
  743. void PluginView::didFail(const ResourceError& error)
  744. {
  745. if (m_status != PluginStatusLoadedSuccessfully)
  746. return;
  747. ASSERT(m_loadManually);
  748. if (m_manualStream)
  749. m_manualStream->didFail(0, error);
  750. }
  751. void PluginView::setCallingPlugin(bool b) const
  752. {
  753. if (!m_plugin->quirks().contains(PluginQuirkHasModalMessageLoop))
  754. return;
  755. if (b)
  756. ++s_callingPlugin;
  757. else
  758. --s_callingPlugin;
  759. ASSERT(s_callingPlugin >= 0);
  760. }
  761. bool PluginView::isCallingPlugin()
  762. {
  763. return s_callingPlugin > 0;
  764. }
  765. PassRefPtr<PluginView> PluginView::create(Frame* parentFrame, const IntSize& size, HTMLPlugInElement* element, const KURL& url, const Vector<String>& paramNames, const Vector<String>& paramValues, const String& mimeType, bool loadManually)
  766. {
  767. // if we fail to find a plugin for this MIME type, findPlugin will search for
  768. // a plugin by the file extension and update the MIME type, so pass a mutable String
  769. String mimeTypeCopy = mimeType;
  770. PluginPackage* plugin = PluginDatabase::installedPlugins()->findPlugin(url, mimeTypeCopy);
  771. // No plugin was found, try refreshing the database and searching again
  772. if (!plugin && PluginDatabase::installedPlugins()->refresh()) {
  773. mimeTypeCopy = mimeType;
  774. plugin = PluginDatabase::installedPlugins()->findPlugin(url, mimeTypeCopy);
  775. }
  776. return adoptRef(new PluginView(parentFrame, size, plugin, element, url, paramNames, paramValues, mimeTypeCopy, loadManually));
  777. }
  778. void PluginView::freeStringArray(char** stringArray, int length)
  779. {
  780. if (!stringArray)
  781. return;
  782. for (int i = 0; i < length; i++)
  783. fastFree(stringArray[i]);
  784. fastFree(stringArray);
  785. }
  786. static inline bool startsWithBlankLine(const Vector<char>& buffer)
  787. {
  788. return buffer.size() > 0 && buffer[0] == '\n';
  789. }
  790. static inline int locationAfterFirstBlankLine(const Vector<char>& buffer)
  791. {
  792. const char* bytes = buffer.data();
  793. unsigned length = buffer.size();
  794. for (unsigned i = 0; i < length - 4; i++) {
  795. // Support for Acrobat. It sends "\n\n".
  796. if (bytes[i] == '\n' && bytes[i + 1] == '\n')
  797. return i + 2;
  798. // Returns the position after 2 CRLF's or 1 CRLF if it is the first line.
  799. if (bytes[i] == '\r' && bytes[i + 1] == '\n') {
  800. i += 2;
  801. if (i == 2)
  802. return i;
  803. else if (bytes[i] == '\n')
  804. // Support for Director. It sends "\r\n\n" (3880387).
  805. return i + 1;
  806. else if (bytes[i] == '\r' && bytes[i + 1] == '\n')
  807. // Support for Flash. It sends "\r\n\r\n" (3758113).
  808. return i + 2;
  809. }
  810. }
  811. return -1;
  812. }
  813. static inline const char* findEOL(const char* bytes, unsigned length)
  814. {
  815. // According to the HTTP specification EOL is defined as
  816. // a CRLF pair. Unfortunately, some servers will use LF
  817. // instead. Worse yet, some servers will use a combination
  818. // of both (e.g. <header>CRLFLF<body>), so findEOL needs
  819. // to be more forgiving. It will now accept CRLF, LF or
  820. // CR.
  821. //
  822. // It returns NULL if EOLF is not found or it will return
  823. // a pointer to the first terminating character.
  824. for (unsigned i = 0; i < length; i++) {
  825. if (bytes[i] == '\n')
  826. return bytes + i;
  827. if (bytes[i] == '\r') {
  828. // Check to see if spanning buffer bounds
  829. // (CRLF is across reads). If so, wait for
  830. // next read.
  831. if (i + 1 == length)
  832. break;
  833. return bytes + i;
  834. }
  835. }
  836. return 0;
  837. }
  838. static inline String capitalizeRFC822HeaderFieldName(const String& name)
  839. {
  840. bool capitalizeCharacter = true;
  841. String result;
  842. for (unsigned i = 0; i < name.length(); i++) {
  843. UChar c;
  844. if (capitalizeCharacter && name[i] >= 'a' && name[i] <= 'z')
  845. c = toASCIIUpper(name[i]);
  846. else if (!capitalizeCharacter && name[i] >= 'A' && name[i] <= 'Z')
  847. c = toASCIILower(name[i]);
  848. else
  849. c = name[i];
  850. if (name[i] == '-')
  851. capitalizeCharacter = true;
  852. else
  853. capitalizeCharacter = false;
  854. result.append(c);
  855. }
  856. return result;
  857. }
  858. static inline HTTPHeaderMap parseRFC822HeaderFields(const Vector<char>& buffer, unsigned length)
  859. {
  860. const char* bytes = buffer.data();
  861. const char* eol;
  862. String lastKey;
  863. HTTPHeaderMap headerFields;
  864. // Loop ove rlines until we're past the header, or we can't find any more end-of-lines
  865. while ((eol = findEOL(bytes, length))) {
  866. const char* line = bytes;
  867. int lineLength = eol - bytes;
  868. // Move bytes to the character after the terminator as returned by findEOL.
  869. bytes = eol + 1;
  870. if ((*eol == '\r') && (*bytes == '\n'))
  871. bytes++; // Safe since findEOL won't return a spanning CRLF.
  872. length -= (bytes - line);
  873. if (lineLength == 0)
  874. // Blank line; we're at the end of the header
  875. break;
  876. else if (*line == ' ' || *line == '\t') {
  877. // Continuation of the previous header
  878. if (lastKey.isNull()) {
  879. // malformed header; ignore it and continue
  880. continue;
  881. } else {
  882. // Merge the continuation of the previous header
  883. String currentValue = headerFields.get(lastKey);
  884. String newValue(line, lineLength);
  885. headerFields.set(lastKey, currentValue + newValue);
  886. }
  887. } else {
  888. // Brand new header
  889. const char* colon;
  890. for (colon = line; *colon != ':' && colon != eol; colon++) {
  891. // empty loop
  892. }
  893. if (colon == eol)
  894. // malformed header; ignore it and continue
  895. continue;
  896. else {
  897. lastKey = capitalizeRFC822HeaderFieldName(String(line, colon - line));
  898. String value;
  899. for (colon++; colon != eol; colon++) {
  900. if (*colon != ' ' && *colon != '\t')
  901. break;
  902. }
  903. if (colon == eol)
  904. value = "";
  905. else
  906. value = String(colon, eol - colon);
  907. String oldValue = headerFields.get(lastKey);
  908. if (!oldValue.isNull())
  909. value = oldValue + ", " + value;
  910. headerFields.set(lastKey, value);
  911. }
  912. }
  913. }
  914. return headerFields;
  915. }
  916. NPError PluginView::handlePost(const char* url, const char* target, uint32_t len, const char* buf, bool file, void* notifyData, bool sendNotification, bool allowHeaders)
  917. {
  918. if (!url || !len || !buf)
  919. return NPERR_INVALID_PARAM;
  920. FrameLoadRequest frameLoadRequest(m_parentFrame->document()->securityOrigin());
  921. HTTPHeaderMap headerFields;
  922. Vector<char> buffer;
  923. if (file) {
  924. NPError readResult = handlePostReadFile(buffer, len, buf);
  925. if(readResult != NPERR_NO_ERROR)
  926. return readResult;
  927. } else {
  928. buffer.resize(len);
  929. memcpy(buffer.data(), buf, len);
  930. }
  931. const char* postData = buffer.data();
  932. int postDataLength = buffer.size();
  933. if (allowHeaders) {
  934. if (startsWithBlankLine(buffer)) {
  935. postData++;
  936. postDataLength--;
  937. } else {
  938. int location = locationAfterFirstBlankLine(buffer);
  939. if (location != -1) {
  940. // If the blank line is somewhere in the middle of the buffer, everything before is the header
  941. headerFields = parseRFC822HeaderFields(buffer, location);
  942. unsigned dataLength = buffer.size() - location;
  943. // Sometimes plugins like to set Content-Length themselves when they post,
  944. // but WebFoundation does not like that. So we will remove the header
  945. // and instead truncate the data to the requested length.
  946. String contentLength = headerFields.get("Content-Length");
  947. if (!contentLength.isNull())
  948. dataLength = min(contentLength.toInt(), (int)dataLength);
  949. headerFields.remove("Content-Length");
  950. postData += location;
  951. postDataLength = dataLength;
  952. }
  953. }
  954. }
  955. frameLoadRequest.resourceRequest().setHTTPMethod("POST");
  956. frameLoadRequest.resourceRequest().setURL(makeURL(m_parentFrame->document()->baseURL(), url));
  957. frameLoadRequest.resourceRequest().addHTTPHeaderFields(headerFields);
  958. frameLoadRequest.resourceRequest().setHTTPBody(FormData::create(postData, postDataLength));
  959. frameLoadRequest.setFrameName(target);
  960. return load(frameLoadRequest, sendNotification, notifyData);
  961. }
  962. void PluginView::invalidateWindowlessPluginRect(const IntRect& rect)
  963. {
  964. if (!isVisible())
  965. return;
  966. if (!m_element->renderer())
  967. return;
  968. RenderBox* renderer = toRenderBox(m_element->renderer());
  969. IntRect dirtyRect = rect;
  970. dirtyRect.move(renderer->borderLeft() + renderer->paddingLeft(), renderer->borderTop() + renderer->paddingTop());
  971. renderer->repaintRectangle(dirtyRect);
  972. }
  973. void PluginView::paintMissingPluginIcon(GraphicsContext* context, const IntRect& rect)
  974. {
  975. static RefPtr<Image> nullPluginImage;
  976. if (!nullPluginImage)
  977. nullPluginImage = Image::loadPlatformResource("nullPlugin");
  978. IntRect imageRect(frameRect().x(), frameRect().y(), nullPluginImage->width(), nullPluginImage->height());
  979. int xOffset = (frameRect().width() - imageRect.width()) / 2;
  980. int yOffset = (frameRect().height() - imageRect.height()) / 2;
  981. imageRect.move(xOffset, yOffset);
  982. if (!rect.intersects(imageRect))
  983. return;
  984. context->save();
  985. context->clip(windowClipRect());
  986. context->drawImage(nullPluginImage.get(), ColorSpaceDeviceRGB, imageRect.location());
  987. context->restore();
  988. }
  989. static const char* MozillaUserAgent = "Mozilla/5.0 ("
  990. #if defined(XP_MACOSX)
  991. "Macintosh; U; Intel Mac OS X;"
  992. #elif defined(XP_WIN)
  993. "Windows; U; Windows NT 5.1;"
  994. #elif defined(XP_UNIX)
  995. // The Gtk port uses X11 plugins in Mac.
  996. #if OS(DARWIN) && PLATFORM(GTK)
  997. "X11; U; Intel Mac OS X;"
  998. #else
  999. "X11; U; Linux i686;"
  1000. #endif
  1001. #endif
  1002. " en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0";
  1003. static const char* const ChromeUserAgent = "Mozilla/5.0 ("
  1004. #if defined(XP_MACOSX)
  1005. "Macintosh; U; Intel Mac OS X;"
  1006. #elif defined(XP_WIN)
  1007. "Windows; U; Windows NT 5.1;"
  1008. #elif defined(XP_UNIX)
  1009. // The Gtk port uses X11 plugins in Mac.
  1010. #if OS(DARWIN) && PLATFORM(GTK)
  1011. "X11; U; Intel Mac OS X;"
  1012. #else
  1013. "X11; U; Linux i686;"
  1014. #endif
  1015. #endif
  1016. " AppleWebKit/534.34 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/534.34";
  1017. const char* PluginView::userAgent()
  1018. {
  1019. if (m_plugin->quirks().contains(PluginQuirkWantsMozillaUserAgent))
  1020. return MozillaUserAgent;
  1021. else if (m_plugin->quirks().contains(PluginQuirkWantsChromeUserAgent))
  1022. return ChromeUserAgent;
  1023. if (m_userAgent.isNull())
  1024. m_userAgent = m_parentFrame->loader()->userAgent(m_url).utf8();
  1025. return m_userAgent.data();
  1026. }
  1027. #if ENABLE(NETSCAPE_PLUGIN_API)
  1028. const char* PluginView::userAgentStatic()
  1029. {
  1030. return MozillaUserAgent;
  1031. }
  1032. #endif
  1033. void PluginView::lifeSupportTimerFired(Timer<PluginView>*)
  1034. {
  1035. deref();
  1036. }
  1037. void PluginView::keepAlive()
  1038. {
  1039. if (m_lifeSupportTimer.isActive())
  1040. return;
  1041. ref();
  1042. m_lifeSupportTimer.startOneShot(0);
  1043. }
  1044. #if ENABLE(NETSCAPE_PLUGIN_API)
  1045. void PluginView::keepAlive(NPP instance)
  1046. {
  1047. PluginView* view = instanceMap().get(instance);
  1048. if (!view)
  1049. return;
  1050. view->keepAlive();
  1051. }
  1052. NPError PluginView::getValueStatic(NPNVariable variable, void* value)
  1053. {
  1054. LOG(Plugins, "PluginView::getValueStatic(%s)", prettyNameForNPNVariable(variable).data());
  1055. NPError result;
  1056. if (platformGetValueStatic(variable, value, &result))
  1057. return result;
  1058. return NPERR_GENERIC_ERROR;
  1059. }
  1060. NPError PluginView::getValue(NPNVariable variable, void* value)
  1061. {
  1062. LOG(Plugins, "PluginView::getValue(%s)", prettyNameForNPNVariable(variable).data());
  1063. NPError result;
  1064. if (platformGetValue(variable, value, &result))
  1065. return result;
  1066. if (platformGetValueStatic(variable, value, &result))
  1067. return result;
  1068. switch (variable) {
  1069. case NPNVWindowNPObject: {
  1070. if (m_isJavaScriptPaused)
  1071. return NPERR_GENERIC_ERROR;
  1072. NPObject* windowScriptObject = m_parentFrame->script()->windowScriptNPObject();
  1073. // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugin/npruntime.html>
  1074. if (windowScriptObject)
  1075. _NPN_RetainObject(windowScriptObject);
  1076. void** v = (void**)value;
  1077. *v = windowScriptObject;
  1078. return NPERR_NO_ERROR;
  1079. }
  1080. case NPNVPluginElementNPObject: {
  1081. if (m_isJavaScriptPaused)
  1082. return NPERR_GENERIC_ERROR;
  1083. NPObject* pluginScriptObject = 0;
  1084. if (m_element->hasTagName(appletTag) || m_element->hasTagName(embedTag) || m_element->hasTagName(objectTag))
  1085. pluginScriptObject = m_element->getNPObject();
  1086. // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugin/npruntime.html>
  1087. if (pluginScriptObject)
  1088. _NPN_RetainObject(pluginScriptObject);
  1089. void** v = (void**)value;
  1090. *v = pluginScriptObject;
  1091. return NPERR_NO_ERROR;
  1092. }
  1093. case NPNVprivateModeBool: {
  1094. Page* page = m_parentFrame->page();
  1095. if (!page)
  1096. return NPERR_GENERIC_ERROR;
  1097. *((NPBool*)value) = !page->settings() || page->settings()->privateBrowsingEnabled();
  1098. return NPERR_NO_ERROR;
  1099. }
  1100. default:
  1101. return NPERR_GENERIC_ERROR;
  1102. }
  1103. }
  1104. static Frame* getFrame(Frame* parentFrame, Element* element)
  1105. {
  1106. if (parentFrame)
  1107. return parentFrame;
  1108. Document* document = element->document();
  1109. if (!document)
  1110. document = element->ownerDocument();
  1111. if (document)
  1112. return document->frame();
  1113. return 0;
  1114. }
  1115. NPError PluginView::getValueForURL(NPNURLVariable variable, const char* url, char** value, uint32_t* len)
  1116. {
  1117. LOG(Plugins, "PluginView::getValueForURL(%s)", prettyNameForNPNURLVariable(variable).data());
  1118. NPError result = NPERR_NO_ERROR;
  1119. switch (variable) {
  1120. case NPNURLVCookie: {
  1121. KURL u(m_parentFrame->document()->baseURL(), url);
  1122. if (u.isValid()) {
  1123. Frame* frame = getFrame(parentFrame(), m_element);
  1124. if (frame) {
  1125. const CString cookieStr = cookies(frame->document(), u).utf8();
  1126. if (!cookieStr.isNull()) {
  1127. const int size = cookieStr.length();
  1128. *value = static_cast<char*>(NPN_MemAlloc(size+1));
  1129. if (*value) {
  1130. memset(*value, 0, size+1);
  1131. memcpy(*value, cookieStr.data(), size+1);
  1132. if (len)
  1133. *len = size;
  1134. } else
  1135. result = NPERR_OUT_OF_MEMORY_ERROR;
  1136. }
  1137. }
  1138. } else
  1139. result = NPERR_INVALID_URL;
  1140. break;
  1141. }
  1142. case NPNURLVProxy: {
  1143. KURL u(m_parentFrame->document()->baseURL(), url);
  1144. if (u.isValid()) {
  1145. Frame* frame = getFrame(parentFrame(), m_element);
  1146. const FrameLoader* frameLoader = frame ? frame->loader() : 0;
  1147. const NetworkingContext* context = frameLoader ? frameLoader->networkingContext() : 0;
  1148. const CString proxyStr = toString(proxyServersForURL(u, context)).utf8();
  1149. if (!proxyStr.isNull()) {
  1150. const int size = proxyStr.length();
  1151. *value = static_cast<char*>(NPN_MemAlloc(size+1));
  1152. if (*value) {
  1153. memset(*value, 0, size+1);
  1154. memcpy(*value, proxyStr.data(), size+1);
  1155. if (len)
  1156. *len = size;
  1157. } else
  1158. result = NPERR_OUT_OF_MEMORY_ERROR;
  1159. }
  1160. } else
  1161. result = NPERR_INVALID_URL;
  1162. break;
  1163. }
  1164. default:
  1165. result = NPERR_GENERIC_ERROR;
  1166. LOG(Plugins, "PluginView::getValueForURL: %s", prettyNameForNPNURLVariable(variable).data());
  1167. break;
  1168. }
  1169. return result;
  1170. }
  1171. NPError PluginView::setValueForURL(NPNURLVariable variable, const char* url, const char* value, uint32_t len)
  1172. {
  1173. LOG(Plugins, "PluginView::setValueForURL(%s)", prettyNameForNPNURLVariable(variable).data());
  1174. NPError result = NPERR_NO_ERROR;
  1175. switch (variable) {
  1176. case NPNURLVCookie: {
  1177. KURL u(m_parentFrame->document()->baseURL(), url);
  1178. if (u.isValid()) {
  1179. const String cookieStr = String::fromUTF8(value, len);
  1180. Frame* frame = getFrame(parentFrame(), m_element);
  1181. if (frame && !cookieStr.isEmpty())
  1182. setCookies(frame->document(), u, cookieStr);
  1183. } else
  1184. result = NPERR_INVALID_URL;
  1185. break;
  1186. }
  1187. case NPNURLVProxy:
  1188. LOG(Plugins, "PluginView::setValueForURL(%s): Plugins are NOT allowed to set proxy information.", prettyNameForNPNURLVariable(variable).data());
  1189. result = NPERR_GENERIC_ERROR;
  1190. break;
  1191. default:
  1192. LOG(Plugins, "PluginView::setValueForURL: %s", prettyNameForNPNURLVariable(variable).data());
  1193. result = NPERR_GENERIC_ERROR;
  1194. break;
  1195. }
  1196. return result;
  1197. }
  1198. NPError PluginView::getAuthenticationInfo(const char* protocol, const char* host, int32_t port, const char* /* scheme */, const char* /* realm */, char** /* username */, uint32_t* /* ulen */, char** /* password */, uint32_t* /* plen */)
  1199. {
  1200. #if LOG_DISABLED
  1201. UNUSED_PARAM(protocol);
  1202. UNUSED_PARAM(host);
  1203. UNUSED_PARAM(port);
  1204. #endif
  1205. LOG(Plugins, "PluginView::getAuthenticationInfo: protocol=%s, host=%s, port=%d", protocol, host, port);
  1206. notImplemented();
  1207. return NPERR_GENERIC_ERROR;
  1208. }
  1209. #endif
  1210. void PluginView::privateBrowsingStateChanged(bool privateBrowsingEnabled)
  1211. {
  1212. NPP_SetValueProcPtr setValue = m_plugin->pluginFuncs()->setvalue;
  1213. if (!setValue)
  1214. return;
  1215. PluginView::setCurrentPluginView(this);
  1216. JSC::JSLock::DropAllLocks dropAllLocks(JSDOMWindowBase::commonVM());
  1217. setCallingPlugin(true);
  1218. NPBool value = privateBrowsingEnabled;
  1219. setValue(m_instance, NPNVprivateModeBool, &value);
  1220. setCallingPlugin(false);
  1221. PluginView::setCurrentPluginView(0);
  1222. }
  1223. } // namespace WebCore
  1224. #endif // ENABLE(NETSCAPE_PLUGIN_API)