<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "webkit/glue/plugins/webplugin_delegate_impl.h"

#include <string>
#include <vector>

#include "base/file_util.h"
#include "base/message_loop.h"
#include "base/gfx/gdi_util.h"
#include "base/gfx/point.h"
#include "base/stats_counters.h"
#include "base/string_util.h"
#include "webkit/default_plugin/plugin_impl.h"
#include "webkit/glue/glue_util.h"
#include "webkit/glue/webplugin.h"
#include "webkit/glue/plugins/plugin_instance.h"
#include "webkit/glue/plugins/plugin_lib.h"
#include "webkit/glue/plugins/plugin_list.h"
#include "webkit/glue/plugins/plugin_stream_url.h"
#include "webkit/glue/webkit_glue.h"

static StatsCounter windowless_queue("Plugin.ThrottleQueue");

static const wchar_t kNativeWindowClassName[] = L"NativeWindowClass";
static const wchar_t kWebPluginDelegateProperty[] =
    L"WebPluginDelegateProperty";
static const wchar_t kPluginNameAtomProperty[] = L"PluginNameAtom";
static const wchar_t kDummyActivationWindowName[] = L"DummyWindowForActivation";
static const wchar_t kPluginOrigProc[] = L"OriginalPtr";
static const wchar_t kPluginFlashThrottle[] = L"FlashThrottle";

// The fastest we are willing to process WM_USER+1 events for Flash.
// Flash can easily exceed the limits of our CPU if we don't throttle it.
// The throttle has been chosen by testing various delays and compromising
// on acceptable Flash performance and reasonable CPU consumption.
//
// I'd like to make the throttle delay variable, based on the amount of
// time currently required to paint Flash plugins.  There isn't a good
// way to count the time spent in aggregate plugin painting, however, so
// this seems to work well enough.
static const int kFlashWMUSERMessageThrottleDelayMs = 5;

std::list<MSG> WebPluginDelegateImpl::throttle_queue_;

WebPluginDelegateImpl* WebPluginDelegateImpl::current_plugin_instance_ = NULL;

iat_patch::IATPatchFunction WebPluginDelegateImpl::iat_patch_track_popup_menu_;
iat_patch::IATPatchFunction WebPluginDelegateImpl::iat_patch_set_cursor_;

WebPluginDelegateImpl* WebPluginDelegateImpl::Create(
    const FilePath& filename,
    const std::string& mime_type,
    gfx::NativeView containing_view) {
  scoped_refptr<NPAPI::PluginLib> plugin =
      NPAPI::PluginLib::CreatePluginLib(filename);
  if (plugin.get() == NULL)
    return NULL;

  NPError err = plugin->NP_Initialize();
  if (err != NPERR_NO_ERROR)
    return NULL;

  scoped_refptr<NPAPI::PluginInstance> instance =
      plugin->CreateInstance(mime_type);
  return new WebPluginDelegateImpl(containing_view, instance.get());
}

bool WebPluginDelegateImpl::IsPluginDelegateWindow(HWND window) {
  // We use a buffer that is one char longer than we need to detect cases where
  // kNativeWindowClassName is a prefix of the given window's class name.  It
  // happens that GetClassNameW will just silently truncate the class name to
  // fit into the given buffer.
  wchar_t class_name[arraysize(kNativeWindowClassName) + 1];
  if (!GetClassNameW(window, class_name, arraysize(class_name)))
    return false;
  return wcscmp(class_name, kNativeWindowClassName) == 0;
}

bool WebPluginDelegateImpl::GetPluginNameFromWindow(
    HWND window, std::wstring *plugin_name) {
  if (NULL == plugin_name) {
    return false;
  }
  if (!IsPluginDelegateWindow(window)) {
    return false;
  }
  ATOM plugin_name_atom = reinterpret_cast<ATOM>(
      GetPropW(window, kPluginNameAtomProperty));
  if (plugin_name_atom != 0) {
    WCHAR plugin_name_local[MAX_PATH] = {0};
    GlobalGetAtomNameW(plugin_name_atom,
                       plugin_name_local,
                       ARRAYSIZE(plugin_name_local));
    *plugin_name = plugin_name_local;
    return true;
  }
  return false;
}

bool WebPluginDelegateImpl::IsDummyActivationWindow(HWND window) {
  if (!IsWindow(window))
    return false;

  wchar_t window_title[MAX_PATH + 1] = {0};
  if (GetWindowText(window, window_title, arraysize(window_title))) {
    return (0 == lstrcmpiW(window_title, kDummyActivationWindowName));
  }
  return false;
}

LRESULT CALLBACK WebPluginDelegateImpl::HandleEventMessageFilterHook(
    int code, WPARAM wParam, LPARAM lParam) {

  DCHECK(current_plugin_instance_);
  current_plugin_instance_->OnModalLoopEntered();
  return CallNextHookEx(NULL, code, wParam, lParam);
}

WebPluginDelegateImpl::WebPluginDelegateImpl(
    gfx::NativeView containing_view,
    NPAPI::PluginInstance *instance)
    : parent_(containing_view),
      instance_(instance),
      quirks_(0),
      plugin_(NULL),
      windowless_(false),
      windowed_handle_(NULL),
      windowed_did_set_window_(false),
      windowless_needs_set_window_(true),
      plugin_wnd_proc_(NULL),
      last_message_(0),
      is_calling_wndproc(false),
      initial_plugin_resize_done_(false),
      dummy_window_for_activation_(NULL),
      handle_event_message_filter_hook_(NULL),
      handle_event_pump_messages_event_(NULL),
      handle_event_depth_(0),
      user_gesture_message_posted_(false),
#pragma warning(suppress: 4355)  // can use this
      user_gesture_msg_factory_(this),
      plugin_module_handle_(NULL) {
  memset(&window_, 0, sizeof(window_));

  const WebPluginInfo& plugin_info = instance_->plugin_lib()->plugin_info();
  std::string filename =
      WideToASCII(StringToLowerASCII(plugin_info.path.BaseName().value()));

  if (instance_->mime_type() == "application/x-shockwave-flash" ||
      filename == "npswf32.dll") {
    // Flash only requests windowless plugins if we return a Mozilla user
    // agent.
    instance_->set_use_mozilla_user_agent();
    quirks_ |= PLUGIN_QUIRK_THROTTLE_WM_USER_PLUS_ONE;
    quirks_ |= PLUGIN_QUIRK_PATCH_SETCURSOR;
  } else if (filename == "nppdf32.dll") {
    // Check for the version number above or equal 9.
    std::vector<std::wstring> version;
    SplitString(plugin_info.version, L'.', &version);
    if (version.size() > 0) {
      int major = static_cast<int>(StringToInt64(version[0]));
      if (major >= 9) {
        quirks_ |= PLUGIN_QUIRK_DIE_AFTER_UNLOAD;
      }
    }
  } else if (plugin_info.name.find(L"Windows Media Player") !=
             std::wstring::npos) {
    // Windows Media Player needs two NPP_SetWindow calls.
    quirks_ |= PLUGIN_QUIRK_SETWINDOW_TWICE;
  } else if (instance_->mime_type() == "audio/x-pn-realaudio-plugin" ||
             filename == "nppl3260.dll") {
    quirks_ |= PLUGIN_QUIRK_DONT_CALL_WND_PROC_RECURSIVELY;
  } else if (plugin_info.name.find(L"VLC Multimedia Plugin") !=
             std::wstring::npos) {
    // VLC hangs on NPP_Destroy if we call NPP_SetWindow with a null window
    // handle
    quirks_ |= PLUGIN_QUIRK_DONT_SET_NULL_WINDOW_HANDLE_ON_DESTROY;
    // VLC 0.8.6d and 0.8.6e crash if multiple instances are created.<commit_msg>Fix plugin_tests failure TBR=avi Review URL: http://codereview.chromium.org/18236<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "webkit/glue/plugins/webplugin_delegate_impl.h"

#include <string>
#include <vector>

#include "base/file_util.h"
#include "base/message_loop.h"
#include "base/gfx/gdi_util.h"
#include "base/gfx/point.h"
#include "base/stats_counters.h"
#include "base/string_util.h"
#include "webkit/default_plugin/plugin_impl.h"
#include "webkit/glue/glue_util.h"
#include "webkit/glue/webplugin.h"
#include "webkit/glue/plugins/plugin_instance.h"
#include "webkit/glue/plugins/plugin_lib.h"
#include "webkit/glue/plugins/plugin_list.h"
#include "webkit/glue/plugins/plugin_stream_url.h"
#include "webkit/glue/webkit_glue.h"

static StatsCounter windowless_queue("Plugin.ThrottleQueue");

static const wchar_t kNativeWindowClassName[] = L"NativeWindowClass";
static const wchar_t kWebPluginDelegateProperty[] =
    L"WebPluginDelegateProperty";
static const wchar_t kPluginNameAtomProperty[] = L"PluginNameAtom";
static const wchar_t kDummyActivationWindowName[] = L"DummyWindowForActivation";
static const wchar_t kPluginOrigProc[] = L"OriginalPtr";
static const wchar_t kPluginFlashThrottle[] = L"FlashThrottle";

// The fastest we are willing to process WM_USER+1 events for Flash.
// Flash can easily exceed the limits of our CPU if we don't throttle it.
// The throttle has been chosen by testing various delays and compromising
// on acceptable Flash performance and reasonable CPU consumption.
//
// I'd like to make the throttle delay variable, based on the amount of
// time currently required to paint Flash plugins.  There isn't a good
// way to count the time spent in aggregate plugin painting, however, so
// this seems to work well enough.
static const int kFlashWMUSERMessageThrottleDelayMs = 5;

std::list<MSG> WebPluginDelegateImpl::throttle_queue_;

WebPluginDelegateImpl* WebPluginDelegateImpl::current_plugin_instance_ = NULL;

iat_patch::IATPatchFunction WebPluginDelegateImpl::iat_patch_track_popup_menu_;
iat_patch::IATPatchFunction WebPluginDelegateImpl::iat_patch_set_cursor_;

WebPluginDelegateImpl* WebPluginDelegateImpl::Create(
    const FilePath& filename,
    const std::string& mime_type,
    gfx::NativeView containing_view) {
  scoped_refptr<NPAPI::PluginLib> plugin =
      NPAPI::PluginLib::CreatePluginLib(filename);
  if (plugin.get() == NULL)
    return NULL;

  NPError err = plugin->NP_Initialize();
  if (err != NPERR_NO_ERROR)
    return NULL;

  scoped_refptr<NPAPI::PluginInstance> instance =
      plugin->CreateInstance(mime_type);
  return new WebPluginDelegateImpl(containing_view, instance.get());
}

bool WebPluginDelegateImpl::IsPluginDelegateWindow(HWND window) {
  // We use a buffer that is one char longer than we need to detect cases where
  // kNativeWindowClassName is a prefix of the given window's class name.  It
  // happens that GetClassNameW will just silently truncate the class name to
  // fit into the given buffer.
  wchar_t class_name[arraysize(kNativeWindowClassName) + 1];
  if (!GetClassNameW(window, class_name, arraysize(class_name)))
    return false;
  return wcscmp(class_name, kNativeWindowClassName) == 0;
}

bool WebPluginDelegateImpl::GetPluginNameFromWindow(
    HWND window, std::wstring *plugin_name) {
  if (NULL == plugin_name) {
    return false;
  }
  if (!IsPluginDelegateWindow(window)) {
    return false;
  }
  ATOM plugin_name_atom = reinterpret_cast<ATOM>(
      GetPropW(window, kPluginNameAtomProperty));
  if (plugin_name_atom != 0) {
    WCHAR plugin_name_local[MAX_PATH] = {0};
    GlobalGetAtomNameW(plugin_name_atom,
                       plugin_name_local,
                       ARRAYSIZE(plugin_name_local));
    *plugin_name = plugin_name_local;
    return true;
  }
  return false;
}

bool WebPluginDelegateImpl::IsDummyActivationWindow(HWND window) {
  if (!IsWindow(window))
    return false;

  wchar_t window_title[MAX_PATH + 1] = {0};
  if (GetWindowText(window, window_title, arraysize(window_title))) {
    return (0 == lstrcmpiW(window_title, kDummyActivationWindowName));
  }
  return false;
}

LRESULT CALLBACK WebPluginDelegateImpl::HandleEventMessageFilterHook(
    int code, WPARAM wParam, LPARAM lParam) {

  DCHECK(current_plugin_instance_);
  current_plugin_instance_->OnModalLoopEntered();
  return CallNextHookEx(NULL, code, wParam, lParam);
}

WebPluginDelegateImpl::WebPluginDelegateImpl(
    gfx::NativeView containing_view,
    NPAPI::PluginInstance *instance)
    : parent_(containing_view),
      instance_(instance),
      quirks_(0),
      plugin_(NULL),
      windowless_(false),
      windowed_handle_(NULL),
      windowed_did_set_window_(false),
      windowless_needs_set_window_(true),
      plugin_wnd_proc_(NULL),
      last_message_(0),
      is_calling_wndproc(false),
      initial_plugin_resize_done_(false),
      dummy_window_for_activation_(NULL),
      handle_event_message_filter_hook_(NULL),
      handle_event_pump_messages_event_(NULL),
      handle_event_depth_(0),
      user_gesture_message_posted_(false),
#pragma warning(suppress: 4355)  // can use this
      user_gesture_msg_factory_(this),
      plugin_module_handle_(NULL) {
  memset(&window_, 0, sizeof(window_));

  const WebPluginInfo& plugin_info = instance_->plugin_lib()->plugin_info();
  std::string filename =
      WideToUTF8(StringToLowerASCII(plugin_info.path.BaseName().value()));

  if (instance_->mime_type() == "application/x-shockwave-flash" ||
      filename == "npswf32.dll") {
    // Flash only requests windowless plugins if we return a Mozilla user
    // agent.
    instance_->set_use_mozilla_user_agent();
    quirks_ |= PLUGIN_QUIRK_THROTTLE_WM_USER_PLUS_ONE;
    quirks_ |= PLUGIN_QUIRK_PATCH_SETCURSOR;
  } else if (filename == "nppdf32.dll") {
    // Check for the version number above or equal 9.
    std::vector<std::wstring> version;
    SplitString(plugin_info.version, L'.', &version);
    if (version.size() > 0) {
      int major = static_cast<int>(StringToInt64(version[0]));
      if (major >= 9) {
        quirks_ |= PLUGIN_QUIRK_DIE_AFTER_UNLOAD;
      }
    }
  } else if (plugin_info.name.find(L"Windows Media Player") !=
             std::wstring::npos) {
    // Windows Media Player needs two NPP_SetWindow calls.
    quirks_ |= PLUGIN_QUIRK_SETWINDOW_TWICE;
  } else if (instance_->mime_type() == "audio/x-pn-realaudio-plugin" ||
             filename == "nppl3260.dll") {
    quirks_ |= PLUGIN_QUIRK_DONT_CALL_WND_PROC_RECURSIVELY;
  } else if (plugin_info.name.find(L"VLC Multimedia Plugin") !=
             std::wstring::npos) {
    // VLC hangs on NPP_Destroy if we call NPP_SetWindow with a null window
    // handle
    quirks_ |= PLUGIN_QUIRK_DONT_SET_NULL_WINDOW_HANDLE_ON_DESTROY;
    // VLC 0.8.6d and 0.8.6e crash if multiple instances are created.
{'fraction_non_alphanumeric': 0.10248290752069089, 'fraction_numerical': 0.006908960057574667, 'mean_word_length': 4.562850280224179, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, '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': '5555506', 'n_tokens_mistral': 4602, 'n_tokens_neox': 4438, 'n_words': 1015}