<commit_before>/*
 * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
 * Copyright (C) 2008 Collabora Ltd. All rights reserved.
 * Copyright (C) 2010 <NAME> <<EMAIL>>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 */

#include "config.h"
#include "content/web_impl_win/npapi/WebPluginImpl.h"

#include "content/web_impl_win/WebCookieJarCurlImpl.h"
#include "content/web_impl_win/npapi/PluginDatabase.h"
#include "content/web_impl_win/npapi/PluginPackage.h"
#include "content/web_impl_win/npapi/PluginMainThreadScheduler.h"
#include "content/web_impl_win/npapi/PluginMessageThrottlerWin.h"
#include "third_party/WebKit/public/platform/Platform.h"
#include "third_party/WebKit/Source/web/WebLocalFrameImpl.h"
#include "third_party/WebKit/Source/web/WebPluginContainerImpl.h"
#include "third_party/WebKit/Source/platform/network/ResourceRequest.h"
#include "third_party/WebKit/Source/platform/graphics/Image.h"
#include "third_party/WebKit/Source/platform/graphics/GraphicsContext.h"
#include "third_party/WebKit/Source/platform/UserGestureIndicator.h"
#include "third_party/WebKit/Source/core/loader/DocumentLoader.h"
#include "third_party/WebKit/Source/core/page/Page.h"
#include "third_party/WebKit/Source/core/page/ChromeClient.h"
#include "third_party/WebKit/Source/core/frame/FrameView.h"
#include "third_party/WebKit/Source/bindings/core/v8/ScriptController.h"
#include "third_party/WebKit/Source/bindings/core/v8/npruntime_impl.h"
#include "third_party/WebKit/Source/bindings/core/v8/ScriptSourceCode.h"
#include "third_party/WebKit/public/platform/WebTraceLocation.h"
#include "third_party/WebKit/public/web/WebPluginContainer.h"
#include "third_party/WebKit/public/web/WebElement.h"
#include "third_party/WebKit/public/web/WebViewClient.h"
#include "third_party/WebKit/Source/wtf/ASCIICType.h"
#include "third_party/WebKit/Source/wtf/text/WTFString.h"
#include "third_party/WebKit/Source/wtf/RefCountedLeakCounter.h"
#include "third_party/npapi/bindings/npapi.h"
#include "gen/blink/core/HTMLNames.h"
#include "wtf/text/WTFStringUtil.h"

using std::min;

using namespace WTF;
using namespace blink;

namespace content {

using namespace HTMLNames;

static int s_callingPlugin;

typedef HashMap<NPP, WebPluginImpl*> InstanceMap;

static InstanceMap& instanceMap()
{
    static InstanceMap& map = *new InstanceMap;
    return map;
}

static String scriptStringIfJavaScriptURL(const KURL& url)
{
    if (!protocolIsJavaScript(url))
        return String();

    // This returns an unescaped string
    return decodeURLEscapeSequences(url.string().substring(11));
}

static void buildResourceRequest(FrameLoadRequest* frameLoadRequest, blink::LocalFrame* parentFrame, const KURL& url, const char* target)
{
    if (target)
        frameLoadRequest->setFrameName(target);

    ResourceRequest* request = &frameLoadRequest->resourceRequest();

    request->setHTTPMethod("GET");
    request->setURL(url);
    //request->setHTTPHeaderField("x-requested-with", AtomicString("ShockwaveFlash/17.0.0.171"));
    //request->setHTTPHeaderField("accept-encoding", AtomicString("gzip, deflate, sdch"));
    //request->setHTTPHeaderField("accept", AtomicString("*/*"));
    request->setHTTPHeaderField("user-agent", AtomicString(String(blink::Platform::current()->userAgent())));

    if (parentFrame->document())
        request->setHTTPHeaderField("referer", AtomicString(parentFrame->document()->baseURL().string()));
}

RefPtr<Image> s_nullPluginImage;
WebPluginImpl* WebPluginImpl::s_currentPluginView = 0;

#ifndef NDEBUG
DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, webPluginImplCount, ("WebPluginImplCount"));
#endif

WebPluginImpl::WebPluginImpl(WebLocalFrame* parentFrame, const blink::WebPluginParams& params)
    : m_parentFrame(toWebLocalFrameImpl(parentFrame)->frame())
    , m_plugin(nullptr)
    , m_widget(nullptr)
    , m_parentWidget(nullptr)
    , m_isStarted(false)
    , m_url(params.url)
    , m_status(PluginStatusLoadedSuccessfully)
    , m_requestTimer(this, &WebPluginImpl::requestTimerFired)
    , m_invalidateTimer(this, &WebPluginImpl::invalidateTimerFired)
    , m_popPopupsStateTimer(this, &WebPluginImpl::popPopupsStateTimerFired)
    , m_lifeSupportTimer(this, &WebPluginImpl::lifeSupportTimerFired)
    , m_asynStartTimer(this, &WebPluginImpl::platformStartAsyn)
    , m_setPlatformPluginWidgetVisibilityTimer(this, &WebPluginImpl::asynSetPlatformPluginWidgetVisibilityTimerFired)
    , m_mode(params.loadManually ? NP_FULL : NP_EMBED)
    , m_paramNames(0)
    , m_paramValues(0)
    , m_mimeType(params.mimeType)
    , m_instance(0)
    , m_isWindowed(true)
    , m_isTransparent(false)
    , m_haveInitialized(false)
    , m_isWaitingToStart(false)
    , m_pluginWndProc(0)
    , m_lastMessage(0)
    , m_isCallingPluginWndProc(false)
    , m_wmPrintHDC(0)
    , m_haveUpdatedPluginWidget(false)
    , m_loadManually(params.loadManually)
    , m_manualStream(nullptr)
    , m_isJavaScriptPaused(false)
    , m_haveCalledSetWindow(false)
    , m_memoryCanvas(nullptr)
    , m_webviewClient(nullptr)
{
#ifndef NDEBUG
    webPluginImplCount.increment();
#endif
    if (!m_parentFrame)
        return;

    // if we fail to find a plugin for this MIME type, findPlugin will search for
    // a plugin by the file extension and update the MIME type, so pass a mutable String
    m_plugin = PluginDatabase::installedPlugins()->findPlugin(m_url, m_mimeType);

    // No plugin was found, try refreshing the database and searching again
    if (!m_plugin && PluginDatabase::installedPlugins()->refresh())
        m_plugin = PluginDatabase::installedPlugins()->findPlugin(m_url, m_mimeType);

    if (!m_plugin) {
        m_status = PluginStatusCanNotFindPlugin;
        return;
    }

    m_instance = &m_instanceStruct;
    m_instance->ndata = this;
    m_instance->pdata = 0;

    instanceMap().add(m_instance, this);
    memset(&m_npWindow, 0, sizeof(m_npWindow));
    setParameters(params.attributeNames, params.attributeValues);

    //resize(size);
}

WebPluginImpl::~WebPluginImpl()
{
    //WTF_LOG(Plugins, "WebPluginImpl::~WebPluginImpl()");

    ASSERT(!m_lifeSupportTimer.isActive());

    // If we failed to find the plug-in, we'll return early in our constructor, and
    // m_instance will be 0.
    if (m_instance)
        instanceMap().remove(m_instance);

    //     if (m_isWaitingToStart)
    //         m_parentFrame->document()->removeMediaCanStartListener(this);

    stop();

    freeStringArray(m_paramNames, m_paramCount);
    freeStringArray(m_paramValues, m_paramCount);

    platformDestroy();

    //m_parentFrame->script().cleanupScriptObjectsForPlugin(this);

    if (m_plugin && !(m_plugin->quirks().contains(PluginQuirkDontUnloadPlugin)))
        m_plugin->unload();

#ifndef NDEBUG
    webPluginImplCount.decrement();
#endif
}

void WebPluginImpl::popPopupsStateTimerFired(blink::Timer<WebPluginImpl>*)
{
    popPopupsEnabledState();
}

void WebPluginImpl::init()
{
    if (m_haveInitialized)
        return;

    m_haveInitialized = true;

//     // if we fail to find a plugin for this MIME type, findPlugin will search for
//     // a plugin by the file extension and update the MIME type, so pass a mutable String
//     m_plugin = PluginDatabase::installedPlugins()->findPlugin(m_url, m_mimeType);

    // No plugin was found, try refreshing the database and searching again
    if (!m_plugin && PluginDatabase::installedPlugins()->refresh())
        m_plugin = PluginDatabase::installedPlugins()->findPlugin(m_url, m_mimeType);

    if (!m_plugin) {
        m_status = PluginStatusCanNotLoadPlugin;
        return;
    }

    //WTF_LOG(Plugins, "WebPluginImpl::init(): Initializing plug-in '%s'", m_plugin->name().utf8().data());
    if (!m_plugin->load()) {
        m_plugin = nullptr;
        m_status = PluginStatusCanNotLoadPlugin;
        return;
    }

    if (!startOrAddToUnstartedList()) {
        m_status = PluginStatusCanNotLoadPlugin;
        return;
    }

    m_status = PluginStatusLoadedSuccessfully;
}

bool WebPluginImpl::startOrAddToUnstartedList()
{
    if (!m_parentFrame->page())
        return false;

    // We only delay starting the plug-in if we're going to kick off the load
    // ourselves. Otherwise, the loader will try to deliver data before we've
    // started the plug-in.
//     if (!m_loadManually && !m_parentFrame->page()->canStartMedia()) {
//         m_parentFrame->document()->addMediaCanStartListener(this);
//         m_isWaitingToStart = true;
//         return true;
//     }

    return start();
}

bool WebPluginImpl::start()
{
    if (m_isStarted)
        return false;

    m_isWaitingToStart = false;

    PluginMainThreadScheduler::scheduler().registerPlugin(m_instance);

    ASSERT(m_plugin);
    ASSERT(m_plugin->pluginFuncs()->newp);

    NPError npErr;
    {
        WebPluginImpl::setCurrentPluginView(this);
        //JSC::JSLock::DropAllLocks dropAllLocks(JSDOMWindowBase::commonVM());
        setCallingPlugin(true);
        npErr = m_plugin->pluginFuncs()->newp((NPMIMEType)m_mimeType.utf8().data(), m_instance, m_mode, m_paramCount, m_paramNames, m_paramValues, NULL);
        setCallingPlugin(false);
        //LOG_NPERROR(npErr);
        WebPluginImpl::setCurrentPluginView(0);
    }

    if (npErr != NPERR_NO_ERROR) {
        m_status = PluginStatusCanNotLoadPlugin;
        PluginMainThreadScheduler::scheduler().unregisterPlugin(m_instance);
        return false;
    }

    m_isStarted = true;

    if (!m_url.isEmpty() && !m_loadManually) {
        FrameLoadRequest frameLoadRequest(m_parentFrame->document());
        buildResourceRequest(&frameLoadRequest, m_parentFrame, m_url, nullptr);

        load(frameLoadRequest, false, 0);
    }

    m_status = PluginStatusLoadedSuccessfully;

    if (!platformStart())
        m_status = PluginStatusCanNotLoadPlugin;

    if (m_status != PluginStatusLoadedSuccessfully)
        return false;

    return true;
}

void WebPluginImpl::mediaCanStart()
{
    ASSERT(!m_isStarted);
//     if (!start())
//         parentFrame()->loader().client().dispatchDidFailToStartPlugin(this);
}

void WebPluginImpl::stop()
{
    if (!m_isStarted)
        return;

    //WTF_LOG(Plugins, "WebPluginImpl::stop(): Stopping plug-in '%s'", m_plugin->name().utf8().data());

    HashSetStreams streams = m_streams;
    HashSetStreams::iterator end = streams.end();
    for (HashSetStreams::iterator it = streams.begin(); it != end; ++it) {
        PluginStream* stream = *it;
        stream->stop();
        disconnectStream(stream);
    }

    ASSERT(m_streams.isEmpty());

    m_isStarted = false;

    //JSC::JSLock::DropAllLocks dropAllLocks(JSDOMWindowBase::commonVM());

    // Unsubclass the window
    if (m_isWindowed) {
        WNDPROC currentWndProc = (WNDPROC)GetWindowLongPtr(platformPluginWidget(), GWLP_WNDPROC);

        if (currentWndProc == PluginViewWndProc)
            SetWindowLongPtr(platformPluginWidget(), GWLP_WNDPROC, (LONG_PTR)m_pluginWndProc);
    }

    // Clear the window
    m_npWindow.window = 0;

    if (m_plugin->pluginFuncs()->setwindow && !m_plugin->quirks().contains(PluginQuirkDontSetNullWindowHandleOnDestroy)) {
        WebPluginImpl::setCurrentPluginView(this);
        setCallingPlugin(true);
        m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow);
        setCallingPlugin(false);
        WebPluginImpl::setCurrentPluginView(0);
    }

    PluginMainThreadScheduler::scheduler().unregisterPlugin(m_instance);

    NPSavedData* savedData = 0;
    WebPluginImpl::setCurrentPluginView(this);
    setCallingPlugin(true);
    NPError npErr = m_plugin->pluginFuncs()->destroy(m_instance, &savedData);
    setCallingPlugin(false);
    //LOG_NPERROR(npErr);
    WebPluginImpl::setCurrentPluginView(0);

    if (savedData) {
        // TODO: Actually save this data instead of just discarding it
        if (savedData->buf)
            NPN_MemFree(savedData->buf);
        NPN_MemFree(savedData);
    }

    m_instance->pdata = 0;
}

void WebPluginImpl::setCurrentPluginView(WebPluginImpl* pluginView)
{
    s_currentPluginView = pluginView;
}

WebPluginImpl* WebPluginImpl::currentPluginView()
{
    return s_currentPluginView;
}

static char* createUTF8String(const String& str)
{
    Vector<char> cstr = WTF::ensureStringToUTF8(str, false);
    const size_t cstrLength = cstr.size();
    char* result = reinterpret_cast<char*>(fastMalloc(cstrLength + 1));

    memcpy(result, cstr.data(), cstrLength);
    result[cstrLength] = '\0';

    return result;
}

void WebPluginImpl::performRequest(PluginRequest* request)
{
    if (!m_isStarted)
        return;

    // don't let a plugin start any loads if it is no longer part of a document that is being 
    // displayed unless the loads are in the same frame as the plugin.
    const AtomicString& targetFrameName = request->frameLoadRequest().frameName();
//     if (m_parentFrame->loader().documentLoader() != m_parentFrame->loader().activeDocumentLoader() && (targetFrameName.isNull() || m_parentFrame->tree().find(targetFrameName) != m_parentFrame))
//         return;

    KURL requestURL = request->frameLoadRequest().resourceRequest().url();
    String jsString = scriptStringIfJavaScriptURL(requestURL);

    Vector<char> requestUrlBuf = ensureStringToUTF8(requestURL.string(), true);
    
    UserGestureIndicator gestureIndicator(request->shouldAllowPopups() ? DefinitelyProcessingUserGesture : PossiblyProcessingUserGesture);

    if (jsString.isNull()) {
        // if this is not a targeted request, create a stream for it. otherwise,
        // just pass it off to the loader
        if (targetFrameName.isEmpty()) {
            PluginStream* stream = PluginStream::create(this, m_parentFrame, request->frameLoadRequest().resourceRequest(), request->sendNotification(), request->notifyData(), plugin()->pluginFuncs(), instance(), m_plugin->quirks());            
            m_streams.add((stream));
            stream->start();
        } else {
            // If the target frame is our frame, we could destroy the
            // WebPluginImpl, so we protect it. <rdar://problem/6991251>
            RefPtr<WebPluginImpl> protect(this);

            FrameLoadRequest frameRequest(m_parentFrame->document(), request->frameLoadRequest().resourceRequest());
            frameRequest.setFrameName(targetFrameName);
            //frameRequest.setShouldCheckNewWindowPolicy(true);
            m_parentFrame->loader().load(frameRequest);

            // FIXME: <rdar://problem/4807469> This should be sent when the document has finished loading
            if (request->sendNotification()) {
                WebPluginImpl::setCurrentPluginView(this);
                //JSC::JSLock::DropAllLocks dropAllLocks(JSDOMWindowBase::commonVM());
                setCallingPlugin(true);
                m_plugin->pluginFuncs()->urlnotify(m_instance, requestUrlBuf.data(), NPRES_DONE, request->notifyData());
                setCallingPlugin(false);
                WebPluginImpl::setCurrentPluginView(0);
            }
        }
        return;
    }

    // Targeted JavaScript requests are only allowed on the frame that contains the JavaScript plugin
    // and this has been made sure in ::load.
    ASSERT(targetFrameName.isEmpty() || m_parentFrame->tree().find(targetFrameName) == m_parentFrame);
    
    // Executing a script can cause the plugin view to be destroyed, so we keep a reference to it.
    RefPtr<WebPluginImpl> protector(this);
    blink::ScriptSourceCode jsCode(jsString);
    v8::Local<v8::Value> result = m_parentFrame->script().executeScriptInMainWorldAndReturnValue(jsCode);

    if (targetFrameName.isNull()) {
        String resultString;

        CString cstr;        
        if (result->IsString()) {
            v8::Local<v8::String> v8String = result->ToString();
            resultString = v8StringToWebCoreString<String>(v8String, blink::Externalize);
            cstr = resultString.utf8();
        }

        PluginStream* stream = PluginStream::create(this, m_parentFrame, request->frameLoadRequest().resourceRequest(), request->sendNotification(), request->notifyData(), plugin()->pluginFuncs(), instance(), m_plugin->quirks());
        m_streams.add(stream);
        stream->sendJavaScriptStream(requestURL, cstr);
    }
}
<commit_msg>* 修复打开www.ik123.com崩溃的bug<commit_after>/*
 * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
 * Copyright (C) 2008 Collabora Ltd. All rights reserved.
 * Copyright (C) 2010 <NAME> <<EMAIL>>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 */

#include "config.h"
#include "content/web_impl_win/npapi/WebPluginImpl.h"

#include "content/web_impl_win/WebCookieJarCurlImpl.h"
#include "content/web_impl_win/npapi/PluginDatabase.h"
#include "content/web_impl_win/npapi/PluginPackage.h"
#include "content/web_impl_win/npapi/PluginMainThreadScheduler.h"
#include "content/web_impl_win/npapi/PluginMessageThrottlerWin.h"
#include "third_party/WebKit/public/platform/Platform.h"
#include "third_party/WebKit/Source/web/WebLocalFrameImpl.h"
#include "third_party/WebKit/Source/web/WebPluginContainerImpl.h"
#include "third_party/WebKit/Source/platform/network/ResourceRequest.h"
#include "third_party/WebKit/Source/platform/graphics/Image.h"
#include "third_party/WebKit/Source/platform/graphics/GraphicsContext.h"
#include "third_party/WebKit/Source/platform/UserGestureIndicator.h"
#include "third_party/WebKit/Source/core/loader/DocumentLoader.h"
#include "third_party/WebKit/Source/core/page/Page.h"
#include "third_party/WebKit/Source/core/page/ChromeClient.h"
#include "third_party/WebKit/Source/core/frame/FrameView.h"
#include "third_party/WebKit/Source/bindings/core/v8/ScriptController.h"
#include "third_party/WebKit/Source/bindings/core/v8/npruntime_impl.h"
#include "third_party/WebKit/Source/bindings/core/v8/ScriptSourceCode.h"
#include "third_party/WebKit/public/platform/WebTraceLocation.h"
#include "third_party/WebKit/public/web/WebPluginContainer.h"
#include "third_party/WebKit/public/web/WebElement.h"
#include "third_party/WebKit/public/web/WebViewClient.h"
#include "third_party/WebKit/Source/wtf/ASCIICType.h"
#include "third_party/WebKit/Source/wtf/text/WTFString.h"
#include "third_party/WebKit/Source/wtf/RefCountedLeakCounter.h"
#include "third_party/npapi/bindings/npapi.h"
#include "gen/blink/core/HTMLNames.h"
#include "wtf/text/WTFStringUtil.h"

using std::min;

using namespace WTF;
using namespace blink;

namespace content {

using namespace HTMLNames;

static int s_callingPlugin;

typedef HashMap<NPP, WebPluginImpl*> InstanceMap;

static InstanceMap& instanceMap()
{
    static InstanceMap& map = *new InstanceMap;
    return map;
}

static String scriptStringIfJavaScriptURL(const KURL& url)
{
    if (!protocolIsJavaScript(url))
        return String();

    // This returns an unescaped string
    return decodeURLEscapeSequences(url.string().substring(11));
}

static void buildResourceRequest(FrameLoadRequest* frameLoadRequest, blink::LocalFrame* parentFrame, const KURL& url, const char* target)
{
    if (target)
        frameLoadRequest->setFrameName(target);

    ResourceRequest* request = &frameLoadRequest->resourceRequest();

    request->setHTTPMethod("GET");
    request->setURL(url);
    //request->setHTTPHeaderField("x-requested-with", AtomicString("ShockwaveFlash/17.0.0.171"));
    //request->setHTTPHeaderField("accept-encoding", AtomicString("gzip, deflate, sdch"));
    //request->setHTTPHeaderField("accept", AtomicString("*/*"));
    request->setHTTPHeaderField("user-agent", AtomicString(String(blink::Platform::current()->userAgent())));

    if (parentFrame->document())
        request->setHTTPHeaderField("referer", AtomicString(parentFrame->document()->baseURL().string()));
}

RefPtr<Image> s_nullPluginImage;
WebPluginImpl* WebPluginImpl::s_currentPluginView = 0;

#ifndef NDEBUG
DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, webPluginImplCount, ("WebPluginImplCount"));
#endif

WebPluginImpl::WebPluginImpl(WebLocalFrame* parentFrame, const blink::WebPluginParams& params)
    : m_parentFrame(toWebLocalFrameImpl(parentFrame)->frame())
    , m_plugin(nullptr)
    , m_widget(nullptr)
    , m_parentWidget(nullptr)
    , m_isStarted(false)
    , m_url(params.url)
    , m_status(PluginStatusLoadedSuccessfully)
    , m_requestTimer(this, &WebPluginImpl::requestTimerFired)
    , m_invalidateTimer(this, &WebPluginImpl::invalidateTimerFired)
    , m_popPopupsStateTimer(this, &WebPluginImpl::popPopupsStateTimerFired)
    , m_lifeSupportTimer(this, &WebPluginImpl::lifeSupportTimerFired)
    , m_asynStartTimer(this, &WebPluginImpl::platformStartAsyn)
    , m_setPlatformPluginWidgetVisibilityTimer(this, &WebPluginImpl::asynSetPlatformPluginWidgetVisibilityTimerFired)
    , m_mode(params.loadManually ? NP_FULL : NP_EMBED)
    , m_paramNames(0)
    , m_paramValues(0)
    , m_mimeType(params.mimeType)
    , m_instance(0)
    , m_isWindowed(true)
    , m_isTransparent(false)
    , m_haveInitialized(false)
    , m_isWaitingToStart(false)
    , m_pluginWndProc(0)
    , m_lastMessage(0)
    , m_isCallingPluginWndProc(false)
    , m_wmPrintHDC(0)
    , m_haveUpdatedPluginWidget(false)
    , m_loadManually(params.loadManually)
    , m_manualStream(nullptr)
    , m_isJavaScriptPaused(false)
    , m_haveCalledSetWindow(false)
    , m_memoryCanvas(nullptr)
    , m_webviewClient(nullptr)
{
#ifndef NDEBUG
    webPluginImplCount.increment();
#endif
    if (!m_parentFrame)
        return;

    // if we fail to find a plugin for this MIME type, findPlugin will search for
    // a plugin by the file extension and update the MIME type, so pass a mutable String
    m_plugin = PluginDatabase::installedPlugins()->findPlugin(m_url, m_mimeType);

    // No plugin was found, try refreshing the database and searching again
    if (!m_plugin && PluginDatabase::installedPlugins()->refresh())
        m_plugin = PluginDatabase::installedPlugins()->findPlugin(m_url, m_mimeType);

    if (!m_plugin) {
        m_status = PluginStatusCanNotFindPlugin;
        return;
    }

    m_instance = &m_instanceStruct;
    m_instance->ndata = this;
    m_instance->pdata = 0;

    instanceMap().add(m_instance, this);
    memset(&m_npWindow, 0, sizeof(m_npWindow));
    setParameters(params.attributeNames, params.attributeValues);

    //resize(size);
}

WebPluginImpl::~WebPluginImpl()
{
    //WTF_LOG(Plugins, "WebPluginImpl::~WebPluginImpl()");

    ASSERT(!m_lifeSupportTimer.isActive());

    // If we failed to find the plug-in, we'll return early in our constructor, and
    // m_instance will be 0.
    if (m_instance)
        instanceMap().remove(m_instance);

    //     if (m_isWaitingToStart)
    //         m_parentFrame->document()->removeMediaCanStartListener(this);

    stop();

    freeStringArray(m_paramNames, m_paramCount);
    freeStringArray(m_paramValues, m_paramCount);

    platformDestroy();

    //m_parentFrame->script().cleanupScriptObjectsForPlugin(this);

    if (m_plugin && !(m_plugin->quirks().contains(PluginQuirkDontUnloadPlugin)))
        m_plugin->unload();

#ifndef NDEBUG
    webPluginImplCount.decrement();
#endif
}

void WebPluginImpl::popPopupsStateTimerFired(blink::Timer<WebPluginImpl>*)
{
    popPopupsEnabledState();
}

void WebPluginImpl::init()
{
    if (m_haveInitialized)
        return;

    m_haveInitialized = true;

//     // if we fail to find a plugin for this MIME type, findPlugin will search for
//     // a plugin by the file extension and update the MIME type, so pass a mutable String
//     m_plugin = PluginDatabase::installedPlugins()->findPlugin(m_url, m_mimeType);

    // No plugin was found, try refreshing the database and searching again
    if (!m_plugin && PluginDatabase::installedPlugins()->refresh())
        m_plugin = PluginDatabase::installedPlugins()->findPlugin(m_url, m_mimeType);

    if (!m_plugin) {
        m_status = PluginStatusCanNotLoadPlugin;
        return;
    }

    //WTF_LOG(Plugins, "WebPluginImpl::init(): Initializing plug-in '%s'", m_plugin->name().utf8().data());
    if (!m_plugin->load()) {
        m_plugin = nullptr;
        m_status = PluginStatusCanNotLoadPlugin;
        return;
    }

    if (!startOrAddToUnstartedList()) {
        m_status = PluginStatusCanNotLoadPlugin;
        return;
    }

    m_status = PluginStatusLoadedSuccessfully;
}

bool WebPluginImpl::startOrAddToUnstartedList()
{
    if (!m_parentFrame->page())
        return false;

    // We only delay starting the plug-in if we're going to kick off the load
    // ourselves. Otherwise, the loader will try to deliver data before we've
    // started the plug-in.
//     if (!m_loadManually && !m_parentFrame->page()->canStartMedia()) {
//         m_parentFrame->document()->addMediaCanStartListener(this);
//         m_isWaitingToStart = true;
//         return true;
//     }

    return start();
}

bool WebPluginImpl::start()
{
    if (m_isStarted)
        return false;

    m_isWaitingToStart = false;

    PluginMainThreadScheduler::scheduler().registerPlugin(m_instance);

    ASSERT(m_plugin);
    ASSERT(m_plugin->pluginFuncs()->newp);

    NPError npErr;
    {
        WebPluginImpl::setCurrentPluginView(this);
        //JSC::JSLock::DropAllLocks dropAllLocks(JSDOMWindowBase::commonVM());
        setCallingPlugin(true);
        npErr = m_plugin->pluginFuncs()->newp((NPMIMEType)m_mimeType.utf8().data(), m_instance, m_mode, m_paramCount, m_paramNames, m_paramValues, NULL);
        setCallingPlugin(false);
        //LOG_NPERROR(npErr);
        WebPluginImpl::setCurrentPluginView(0);
    }

    if (npErr != NPERR_NO_ERROR) {
        m_status = PluginStatusCanNotLoadPlugin;
        PluginMainThreadScheduler::scheduler().unregisterPlugin(m_instance);
        return false;
    }

    m_isStarted = true;

    if (!m_url.isEmpty() && !m_loadManually) {
        FrameLoadRequest frameLoadRequest(m_parentFrame->document());
        buildResourceRequest(&frameLoadRequest, m_parentFrame, m_url, nullptr);

        load(frameLoadRequest, false, 0);
    }

    m_status = PluginStatusLoadedSuccessfully;

    if (!platformStart())
        m_status = PluginStatusCanNotLoadPlugin;

    if (m_status != PluginStatusLoadedSuccessfully)
        return false;

    return true;
}

void WebPluginImpl::mediaCanStart()
{
    ASSERT(!m_isStarted);
//     if (!start())
//         parentFrame()->loader().client().dispatchDidFailToStartPlugin(this);
}

void WebPluginImpl::stop()
{
    if (!m_isStarted)
        return;

    //WTF_LOG(Plugins, "WebPluginImpl::stop(): Stopping plug-in '%s'", m_plugin->name().utf8().data());

    HashSetStreams streams = m_streams;
    HashSetStreams::iterator end = streams.end();
    for (HashSetStreams::iterator it = streams.begin(); it != end; ++it) {
        PluginStream* stream = *it;
        stream->stop();
        disconnectStream(stream);
    }

    ASSERT(m_streams.isEmpty());

    m_isStarted = false;

    //JSC::JSLock::DropAllLocks dropAllLocks(JSDOMWindowBase::commonVM());

    // Unsubclass the window
    if (m_isWindowed) {
        WNDPROC currentWndProc = (WNDPROC)GetWindowLongPtr(platformPluginWidget(), GWLP_WNDPROC);

        if (currentWndProc == PluginViewWndProc)
            SetWindowLongPtr(platformPluginWidget(), GWLP_WNDPROC, (LONG_PTR)m_pluginWndProc);
    }

    // Clear the window
    m_npWindow.window = 0;

    if (m_plugin->pluginFuncs()->setwindow && !m_plugin->quirks().contains(PluginQuirkDontSetNullWindowHandleOnDestroy)) {
        WebPluginImpl::setCurrentPluginView(this);
        setCallingPlugin(true);
        m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow);
        setCallingPlugin(false);
        WebPluginImpl::setCurrentPluginView(0);
    }

    PluginMainThreadScheduler::scheduler().unregisterPlugin(m_instance);

    NPSavedData* savedData = 0;
    WebPluginImpl::setCurrentPluginView(this);
    setCallingPlugin(true);
    NPError npErr = m_plugin->pluginFuncs()->destroy(m_instance, &savedData);
    setCallingPlugin(false);
    //LOG_NPERROR(npErr);
    WebPluginImpl::setCurrentPluginView(0);

    if (savedData) {
        // TODO: Actually save this data instead of just discarding it
        if (savedData->buf)
            NPN_MemFree(savedData->buf);
        NPN_MemFree(savedData);
    }

    m_instance->pdata = 0;
}

void WebPluginImpl::setCurrentPluginView(WebPluginImpl* pluginView)
{
    s_currentPluginView = pluginView;
}

WebPluginImpl* WebPluginImpl::currentPluginView()
{
    return s_currentPluginView;
}

static char* createUTF8String(const String& str)
{
    Vector<char> cstr = WTF::ensureStringToUTF8(str, false);
    const size_t cstrLength = cstr.size();
    char* result = reinterpret_cast<char*>(fastMalloc(cstrLength + 1));

    memcpy(result, cstr.data(), cstrLength);
    result[cstrLength] = '\0';

    return result;
}

void WebPluginImpl::performRequest(PluginRequest* request)
{
    if (!m_isStarted)
        return;

    // don't let a plugin start any loads if it is no longer part of a document that is being 
    // displayed unless the loads are in the same frame as the plugin.
    const AtomicString& targetFrameName = request->frameLoadRequest().frameName();
//     if (m_parentFrame->loader().documentLoader() != m_parentFrame->loader().activeDocumentLoader() && (targetFrameName.isNull() || m_parentFrame->tree().find(targetFrameName) != m_parentFrame))
//         return;

    KURL requestURL = request->frameLoadRequest().resourceRequest().url();
    String jsString = scriptStringIfJavaScriptURL(requestURL);

    Vector<char> requestUrlBuf = ensureStringToUTF8(requestURL.string(), true);
    
    UserGestureIndicator gestureIndicator(request->shouldAllowPopups() ? DefinitelyProcessingUserGesture : PossiblyProcessingUserGesture);

    if (jsString.isNull()) {
        // if this is not a targeted request, create a stream for it. otherwise,
        // just pass it off to the loader
        if (targetFrameName.isEmpty()) {
            PluginStream* stream = PluginStream::create(this, m_parentFrame, request->frameLoadRequest().resourceRequest(), request->sendNotification(), request->notifyData(), plugin()->pluginFuncs(), instance(), m_plugin->quirks());            
            m_streams.add((stream));
            stream->start();
        } else {
            // If the target frame is our frame, we could destroy the
            // WebPluginImpl, so we protect it. <rdar://problem/6991251>
            RefPtr<WebPluginImpl> protect(this);

            FrameLoadRequest frameRequest(m_parentFrame->document(), request->frameLoadRequest().resourceRequest());
            frameRequest.setFrameName(targetFrameName);
            //frameRequest.setShouldCheckNewWindowPolicy(true);
            m_parentFrame->loader().load(frameRequest);

            // FIXME: <rdar://problem/4807469> This should be sent when the document has finished loading
            if (request->sendNotification()) {
                WebPluginImpl::setCurrentPluginView(this);
                //JSC::JSLock::DropAllLocks dropAllLocks(JSDOMWindowBase::commonVM());
                setCallingPlugin(true);
                m_plugin->pluginFuncs()->urlnotify(m_instance, requestUrlBuf.data(), NPRES_DONE, request->notifyData());
                setCallingPlugin(false);
                WebPluginImpl::setCurrentPluginView(0);
            }
        }
        return;
    }

    // Targeted JavaScript requests are only allowed on the frame that contains the JavaScript plugin
    // and this has been made sure in ::load.
    ASSERT(targetFrameName.isEmpty() || m_parentFrame->tree().find(targetFrameName) == m_parentFrame);
    
    // Executing a script can cause the plugin view to be destroyed, so we keep a reference to it.
    RefPtr<WebPluginImpl> protector(this);
    v8::HandleScope handleScope(toIsolate(m_parentFrame));
    blink::ScriptSourceCode jsCode(jsString);
    v8::Local<v8::Value> result = m_parentFrame->script().executeScriptInMainWorldAndReturnValue(jsCode);

    if (targetFrameName.isNull()) {
        String resultString;

        CString cstr;        
        if (result->IsString()) {
            v8::Local<v8::String> v8String = result->ToString();
            resultString = v8StringToWebCoreString<String>(v8String, blink::Externalize);
            cstr = resultString.utf8();
        }

        PluginStream* stream = PluginStream::create(this, m_parentFrame, request->frameLoadRequest().resourceRequest(), request->sendNotification(), request->notifyData(), plugin()->pluginFuncs(), instance(), m_plugin->quirks());
        m_streams.add(stream);
        stream->sendJavaScriptStream(requestURL, cstr);
    }
}

{'fraction_non_alphanumeric': 0.11693904908587889, 'fraction_numerical': 0.005247996349219931, 'mean_word_length': 4.0318599311136625, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 197, 'https://': 0, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2225159', 'n_tokens_mistral': 10885, 'n_tokens_neox': 10462, 'n_words': 2163}