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