зеркало из https://github.com/mozilla/pjs.git
Bug 558629 - Meter WM_USER events for Flash in PluginInstanceChild to improve responsiveness and lower CPU utilization. r=bsmedberg, a=developers.
This commit is contained in:
Родитель
7366c8ae2e
Коммит
374d8cbc09
|
@ -61,12 +61,19 @@ ChildAsyncCall::Cancel()
|
|||
}
|
||||
|
||||
void
|
||||
ChildAsyncCall::Run()
|
||||
ChildAsyncCall::RemoveFromAsyncList()
|
||||
{
|
||||
if (mFunc) {
|
||||
if (mInstance) {
|
||||
MutexAutoLock lock(mInstance->mAsyncCallMutex);
|
||||
mInstance->mPendingAsyncCalls.RemoveElement(this);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ChildAsyncCall::Run()
|
||||
{
|
||||
RemoveFromAsyncList();
|
||||
|
||||
if (mFunc)
|
||||
mFunc(mData);
|
||||
}
|
||||
|
|
|
@ -59,11 +59,13 @@ public:
|
|||
|
||||
NS_OVERRIDE void Run();
|
||||
NS_OVERRIDE void Cancel();
|
||||
|
||||
private:
|
||||
|
||||
protected:
|
||||
PluginInstanceChild* mInstance;
|
||||
PluginThreadCallback mFunc;
|
||||
void* mData;
|
||||
|
||||
void RemoveFromAsyncList();
|
||||
};
|
||||
|
||||
} // namespace plugins
|
||||
|
|
|
@ -77,6 +77,11 @@ using mozilla::gfx::SharedDIB;
|
|||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
|
||||
// Flash WM_USER message delay time for PostDelayedTask. Borrowed
|
||||
// from Chromium's web plugin delegate src. See 'flash msg throttling
|
||||
// helpers' section for details.
|
||||
const int kFlashWMUSERMessageThrottleDelayMs = 5;
|
||||
|
||||
#define NS_OOPP_DOUBLEPASS_MSGID TEXT("MozDoublePassMsg")
|
||||
|
||||
#ifndef WM_MOUSEHWHEEL
|
||||
|
@ -101,6 +106,7 @@ PluginInstanceChild::PluginInstanceChild(const NPPluginFuncs* aPluginIface,
|
|||
, mNestedEventState(false)
|
||||
, mCachedWinlessPluginHWND(0)
|
||||
, mWinlessPopupSurrogateHWND(0)
|
||||
, mWinlessThrottleOldWndProc(0)
|
||||
#endif // OS_WIN
|
||||
, mAsyncCallMutex("PluginInstanceChild::mAsyncCallMutex")
|
||||
#if defined(OS_MACOSX)
|
||||
|
@ -161,6 +167,7 @@ PluginInstanceChild::InitQuirksModes(const nsCString& aMimeType)
|
|||
}
|
||||
else if (FindInReadable(flash, aMimeType)) {
|
||||
mQuirks |= QUIRK_WINLESS_TRACKPOPUP_HOOK;
|
||||
mQuirks |= QUIRK_FLASH_THROTTLE_WMUSER_EVENTS;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -840,8 +847,11 @@ PluginInstanceChild::AnswerNPP_SetWindow(const NPRemoteWindow& aWindow)
|
|||
break;
|
||||
|
||||
case NPWindowTypeDrawable:
|
||||
mWindow.type = aWindow.type;
|
||||
if (mQuirks & QUIRK_WINLESS_TRACKPOPUP_HOOK)
|
||||
CreateWinlessPopupSurrogate();
|
||||
if (mQuirks & QUIRK_FLASH_THROTTLE_WMUSER_EVENTS)
|
||||
SetupFlashMsgThrottle();
|
||||
return SharedSurfaceSetWindow(aWindow);
|
||||
break;
|
||||
|
||||
|
@ -1065,6 +1075,12 @@ PluginInstanceChild::PluginWindowProc(HWND hWnd,
|
|||
}
|
||||
}
|
||||
|
||||
if (message == WM_USER+1 &&
|
||||
(self->mQuirks & PluginInstanceChild::QUIRK_FLASH_THROTTLE_WMUSER_EVENTS)) {
|
||||
self->FlashThrottleMessage(hWnd, message, wParam, lParam, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LRESULT res = CallWindowProc(self->mPluginWndProc, hWnd, message, wParam,
|
||||
lParam);
|
||||
|
||||
|
@ -1543,6 +1559,157 @@ PluginInstanceChild::SharedSurfacePaint(NPEvent& evcopy)
|
|||
return false;
|
||||
}
|
||||
|
||||
/* flash msg throttling helpers */
|
||||
|
||||
// Flash has the unfortunate habit of flooding dispatch loops with custom
|
||||
// windowing events they use for timing. We throttle these by dropping the
|
||||
// delivery priority below any other event, including pending ipc io
|
||||
// notifications. We do this for both windowed and windowless controls.
|
||||
|
||||
// static
|
||||
LRESULT CALLBACK
|
||||
PluginInstanceChild::WinlessHiddenFlashWndProc(HWND hWnd,
|
||||
UINT message,
|
||||
WPARAM wParam,
|
||||
LPARAM lParam)
|
||||
{
|
||||
PluginInstanceChild* self = reinterpret_cast<PluginInstanceChild*>(
|
||||
GetProp(hWnd, kPluginInstanceChildProperty));
|
||||
if (!self) {
|
||||
NS_NOTREACHED("Badness!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
NS_ASSERTION(self->mWinlessThrottleOldWndProc,
|
||||
"Missing subclass procedure!!");
|
||||
|
||||
// Throttle
|
||||
if (message == WM_USER+1) {
|
||||
self->FlashThrottleMessage(hWnd, message, wParam, lParam, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Unhook
|
||||
if (message == WM_NCDESTROY) {
|
||||
WNDPROC tmpProc = self->mWinlessThrottleOldWndProc;
|
||||
self->mWinlessThrottleOldWndProc = nsnull;
|
||||
SetWindowLongPtr(hWnd, GWLP_WNDPROC,
|
||||
reinterpret_cast<LONG>(tmpProc));
|
||||
LRESULT res = CallWindowProc(tmpProc, hWnd, message, wParam, lParam);
|
||||
RemoveProp(hWnd, kPluginInstanceChildProperty);
|
||||
return res;
|
||||
}
|
||||
|
||||
return CallWindowProc(self->mWinlessThrottleOldWndProc,
|
||||
hWnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
// Enumerate all thread windows looking for flash's hidden message window.
|
||||
// Once we find it, sub class it so we can throttle user msgs.
|
||||
// static
|
||||
BOOL CALLBACK
|
||||
PluginInstanceChild::EnumThreadWindowsCallback(HWND hWnd,
|
||||
LPARAM aParam)
|
||||
{
|
||||
PluginInstanceChild* self = reinterpret_cast<PluginInstanceChild*>(aParam);
|
||||
if (!self) {
|
||||
NS_NOTREACHED("Enum befuddled!");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
PRUnichar className[64];
|
||||
if (!GetClassNameW(hWnd, className, sizeof(className)/sizeof(PRUnichar)))
|
||||
return TRUE;
|
||||
|
||||
if (!wcscmp(className, L"SWFlash_PlaceholderX")) {
|
||||
WNDPROC oldWndProc =
|
||||
reinterpret_cast<WNDPROC>(GetWindowLongPtr(hWnd, GWLP_WNDPROC));
|
||||
// Only set this if we haven't already.
|
||||
if (oldWndProc != WinlessHiddenFlashWndProc) {
|
||||
if (self->mWinlessThrottleOldWndProc) {
|
||||
NS_WARNING("mWinlessThrottleWndProc already set???");
|
||||
return FALSE;
|
||||
}
|
||||
// Subsclass and store self as a property
|
||||
self->mWinlessThrottleOldWndProc =
|
||||
reinterpret_cast<WNDPROC>(SetWindowLongPtr(hWnd, GWLP_WNDPROC,
|
||||
reinterpret_cast<LONG>(WinlessHiddenFlashWndProc)));
|
||||
SetProp(hWnd, kPluginInstanceChildProperty, self);
|
||||
NS_ASSERTION(self->mWinlessThrottleOldWndProc,
|
||||
"SetWindowLongPtr failed?!");
|
||||
}
|
||||
// Return no matter what once we find the right window.
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PluginInstanceChild::SetupFlashMsgThrottle()
|
||||
{
|
||||
if (mWindow.type == NPWindowTypeDrawable) {
|
||||
// Search for the flash hidden message window and subclass it. Only
|
||||
// search for flash windows belonging to our ui thread!
|
||||
if (mWinlessThrottleOldWndProc)
|
||||
return;
|
||||
EnumThreadWindows(GetCurrentThreadId(), EnumThreadWindowsCallback,
|
||||
reinterpret_cast<LPARAM>(this));
|
||||
}
|
||||
else {
|
||||
// Already setup through quirks and the subclass.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
WNDPROC
|
||||
PluginInstanceChild::FlashThrottleAsyncMsg::GetProc()
|
||||
{
|
||||
if (mInstance) {
|
||||
return mWindowed ? mInstance->mPluginWndProc :
|
||||
mInstance->mWinlessThrottleOldWndProc;
|
||||
}
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
void
|
||||
PluginInstanceChild::FlashThrottleAsyncMsg::Run()
|
||||
{
|
||||
RemoveFromAsyncList();
|
||||
|
||||
// GetProc() checks mInstance, and pulls the procedure from
|
||||
// PluginInstanceChild. We don't transport sub-class procedure
|
||||
// ptrs around in FlashThrottleAsyncMsg msgs.
|
||||
if (!GetProc())
|
||||
return;
|
||||
|
||||
// deliver the event to flash
|
||||
CallWindowProc(GetProc(), GetWnd(), GetMsg(), GetWParam(), GetLParam());
|
||||
}
|
||||
|
||||
void
|
||||
PluginInstanceChild::FlashThrottleMessage(HWND aWnd,
|
||||
UINT aMsg,
|
||||
WPARAM aWParam,
|
||||
LPARAM aLParam,
|
||||
bool isWindowed)
|
||||
{
|
||||
// We reuse ChildAsyncCall so we get the cancelation work
|
||||
// that's done in Destroy.
|
||||
FlashThrottleAsyncMsg* task = new FlashThrottleAsyncMsg(this,
|
||||
aWnd, aMsg, aWParam, aLParam, isWindowed);
|
||||
if (!task)
|
||||
return;
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mAsyncCallMutex);
|
||||
mPendingAsyncCalls.AppendElement(task);
|
||||
}
|
||||
MessageLoop::current()->PostDelayedTask(FROM_HERE,
|
||||
task, kFlashWMUSERMessageThrottleDelayMs);
|
||||
}
|
||||
|
||||
#endif // OS_WIN
|
||||
|
||||
bool
|
||||
|
|
|
@ -209,11 +209,15 @@ private:
|
|||
// Win32: Translate mouse input based on WM_WINDOWPOSCHANGED
|
||||
// windowing events due to winless shared dib rendering. See
|
||||
// WinlessHandleEvent for details.
|
||||
QUIRK_SILVERLIGHT_WINLESS_INPUT_TRANSLATION = 1,
|
||||
QUIRK_SILVERLIGHT_WINLESS_INPUT_TRANSLATION = 1 << 0,
|
||||
// Win32: Hook TrackPopupMenu api so that we can swap out parent
|
||||
// hwnds. The api will fail with parents not associated with our
|
||||
// child ui thread. See WinlessHandleEvent for details.
|
||||
QUIRK_WINLESS_TRACKPOPUP_HOOK = 2,
|
||||
QUIRK_WINLESS_TRACKPOPUP_HOOK = 1 << 1,
|
||||
// Win32: Throttle flash WM_USER+1 heart beat messages to prevent
|
||||
// flooding chromium's dispatch loop, which can cause ipc traffic
|
||||
// processing lag.
|
||||
QUIRK_FLASH_THROTTLE_WMUSER_EVENTS = 1 << 2,
|
||||
};
|
||||
|
||||
void InitQuirksModes(const nsCString& aMimeType);
|
||||
|
@ -237,6 +241,8 @@ private:
|
|||
void DestroyWinlessPopupSurrogate();
|
||||
void InitPopupMenuHook();
|
||||
void InternalCallSetNestedEventState(bool aState);
|
||||
void SetupFlashMsgThrottle();
|
||||
void FlashThrottleMessage(HWND, UINT, WPARAM, LPARAM, bool);
|
||||
static LRESULT CALLBACK DummyWindowProc(HWND hWnd,
|
||||
UINT message,
|
||||
WPARAM wParam,
|
||||
|
@ -262,6 +268,45 @@ private:
|
|||
int nReserved,
|
||||
HWND hWnd,
|
||||
CONST RECT *prcRect);
|
||||
static BOOL CALLBACK EnumThreadWindowsCallback(HWND hWnd,
|
||||
LPARAM aParam);
|
||||
static LRESULT CALLBACK WinlessHiddenFlashWndProc(HWND hWnd,
|
||||
UINT message,
|
||||
WPARAM wParam,
|
||||
LPARAM lParam);
|
||||
|
||||
class FlashThrottleAsyncMsg : public ChildAsyncCall
|
||||
{
|
||||
public:
|
||||
FlashThrottleAsyncMsg();
|
||||
FlashThrottleAsyncMsg(PluginInstanceChild* aInst,
|
||||
HWND aWnd, UINT aMsg,
|
||||
WPARAM aWParam, LPARAM aLParam,
|
||||
bool isWindowed)
|
||||
: ChildAsyncCall(aInst, nsnull, nsnull),
|
||||
mWnd(aWnd),
|
||||
mMsg(aMsg),
|
||||
mWParam(aWParam),
|
||||
mLParam(aLParam),
|
||||
mWindowed(isWindowed)
|
||||
{}
|
||||
|
||||
NS_OVERRIDE void Run();
|
||||
|
||||
WNDPROC GetProc();
|
||||
HWND GetWnd() { return mWnd; }
|
||||
UINT GetMsg() { return mMsg; }
|
||||
WPARAM GetWParam() { return mWParam; }
|
||||
LPARAM GetLParam() { return mLParam; }
|
||||
|
||||
private:
|
||||
HWND mWnd;
|
||||
UINT mMsg;
|
||||
WPARAM mWParam;
|
||||
LPARAM mLParam;
|
||||
bool mWindowed;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
const NPPluginFuncs* mPluginIface;
|
||||
|
@ -286,6 +331,7 @@ private:
|
|||
HWND mWinlessPopupSurrogateHWND;
|
||||
nsIntPoint mPluginSize;
|
||||
nsIntPoint mPluginOffset;
|
||||
WNDPROC mWinlessThrottleOldWndProc;
|
||||
#endif
|
||||
|
||||
friend class ChildAsyncCall;
|
||||
|
|
Загрузка…
Ссылка в новой задаче