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