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