Bug 1185529: On Windows, ensure that NPAPI child window has the correct parent before setwindow is called. r=jimm

This commit is contained in:
Bob Owen 2015-08-07 08:48:16 +01:00
Родитель d3beba14ab
Коммит e00cc89ee9
5 изменённых файлов: 71 добавлений и 47 удалений

Просмотреть файл

@ -68,10 +68,12 @@ intr protocol PPluginInstance
child:
intr __delete__();
// Return value is only used on Windows and only when the window needs its
// parent set to the chrome widget native window.
intr NPP_SetWindow(NPRemoteWindow window)
returns (NPRemoteWindow childWindowToBeAdopted);
// This is only used on Windows and, for windowed plugins, must be called
// before the first call to NPP_SetWindow.
intr CreateChildPluginWindow(NPRemoteWindow window)
returns (NPRemoteWindow createdChild);
intr NPP_SetWindow(NPRemoteWindow window);
intr NPP_GetValue_NPPVpluginWantsAllNetworkStreams()
returns (bool value, NPError result);

Просмотреть файл

@ -1146,8 +1146,34 @@ void PluginInstanceChild::DeleteWindow()
#endif
bool
PluginInstanceChild::AnswerNPP_SetWindow(const NPRemoteWindow& aWindow,
NPRemoteWindow* aChildWindowToBeAdopted)
PluginInstanceChild::AnswerCreateChildPluginWindow(const NPRemoteWindow& aWindow,
NPRemoteWindow* aCreatedChild)
{
#if defined(XP_WIN)
MOZ_ASSERT(aWindow.type == NPWindowTypeWindow);
MOZ_ASSERT(!mPluginWindowHWND);
if ((GetQuirks() & PluginModuleChild::QUIRK_QUICKTIME_AVOID_SETWINDOW) &&
aWindow.width == 0 && aWindow.height == 0) {
// Skip CreateChildPluginWindow call for hidden QuickTime plugins.
return true;
}
if (!CreatePluginWindow()) {
return false;
}
aCreatedChild->window = reinterpret_cast<uint64_t>(mPluginWindowHWND);
return true;
#else
NS_NOTREACHED("PluginInstanceChild::CreateChildPluginWindow not implemented!");
return false;
#endif
}
bool
PluginInstanceChild::AnswerNPP_SetWindow(const NPRemoteWindow& aWindow)
{
PLUGIN_LOG_DEBUG(("%s (aWindow=<window: 0x%lx, x: %d, y: %d, width: %d, height: %d>)",
FULLFUNCTION,
@ -1235,35 +1261,17 @@ PluginInstanceChild::AnswerNPP_SetWindow(const NPRemoteWindow& aWindow,
return true;
}
if (!CreatePluginWindow())
return false;
MOZ_ASSERT(mPluginWindowHWND,
"Child plugin window must exist before call to SetWindow");
HWND parentHWND = reinterpret_cast<HWND>(aWindow.window);
if (mPluginWindowHWND != parentHWND) {
mPluginParentHWND = parentHWND;
ShowWindow(mPluginWindowHWND, SW_SHOWNA);
}
SizePluginWindow(aWindow.width, aWindow.height);
// If the window is not our parent set the return child window so that
// it can be re-parented in the chrome process. Re-parenting now
// happens there as we might not have sufficient permission.
// Also, this needs to be after SizePluginWindow because SetWindowPos
// relies on things that it sets.
HWND parentWindow = reinterpret_cast<HWND>(aWindow.window);
if (mPluginParentHWND != parentWindow && IsWindow(parentWindow)) {
mPluginParentHWND = parentWindow;
aChildWindowToBeAdopted->window =
reinterpret_cast<uint64_t>(mPluginWindowHWND);
} else {
// Now we know that the window has the correct parent we can show
// it. The actual visibility is controlled by its parent.
// First time round, these calls are made by our caller after the
// parent is set.
ShowWindow(mPluginWindowHWND, SW_SHOWNA);
// This used to be called in SizePluginWindow, but we need to make
// sure that mPluginWindowHWND has had it's parent set correctly,
// otherwise it can cause a focus issue.
SetWindowPos(mPluginWindowHWND, nullptr, 0, 0, aWindow.width,
aWindow.height, SWP_NOZORDER | SWP_NOREPOSITION);
}
mWindow.window = (void*)mPluginWindowHWND;
mWindow.x = aWindow.x;
mWindow.y = aWindow.y;
@ -1458,6 +1466,8 @@ PluginInstanceChild::SizePluginWindow(int width,
if (mPluginWindowHWND) {
mPluginSize.x = width;
mPluginSize.y = height;
SetWindowPos(mPluginWindowHWND, nullptr, 0, 0, width, height,
SWP_NOZORDER | SWP_NOREPOSITION);
}
}

Просмотреть файл

@ -65,8 +65,10 @@ class PluginInstanceChild : public PPluginInstanceChild
#endif
protected:
bool AnswerNPP_SetWindow(const NPRemoteWindow& window,
NPRemoteWindow* aChildWindowToBeAdopted) override;
bool AnswerCreateChildPluginWindow(const NPRemoteWindow& window,
NPRemoteWindow* aCreatedChild) override;
bool AnswerNPP_SetWindow(const NPRemoteWindow& window) override;
virtual bool
AnswerNPP_GetValue_NPPVpluginWantsAllNetworkStreams(bool* wantsAllStreams, NPError* rv) override;

Просмотреть файл

@ -117,6 +117,8 @@ PluginInstanceParent::PluginInstanceParent(PluginModuleParent* parent,
, mDrawingModel(kDefaultDrawingModel)
#if defined(OS_WIN)
, mPluginHWND(nullptr)
, mChildPluginHWND(nullptr)
, mChildPluginsParentHWND(nullptr)
, mPluginWndProc(nullptr)
, mNestedEventState(false)
#endif // defined(XP_WIN)
@ -1025,31 +1027,37 @@ PluginInstanceParent::NPP_SetWindow(const NPWindow* aWindow)
window.colormap = ws_info->colormap;
#endif
NPRemoteWindow childWindow;
if (!CallNPP_SetWindow(window, &childWindow)) {
return NPERR_GENERIC_ERROR;
#if defined(XP_WIN)
// On Windows we need to create and set the parent before we set the window
// on the plugin, or certain things like keyboard interaction will not work.
if (!mChildPluginHWND && mWindowType == NPWindowTypeWindow) {
NPRemoteWindow childWindow;
if (!CallCreateChildPluginWindow(window, &childWindow)) {
return NPERR_GENERIC_ERROR;
}
mChildPluginHWND = reinterpret_cast<HWND>(childWindow.window);
}
#if defined(XP_WIN)
// If a child window is returned it means that we need to re-parent it.
if (childWindow.window) {
// It's not clear if the parent window would ever change, but when this was
// done in the NPAPI child it used to allow for this.
if (mChildPluginHWND && mPluginHWND != mChildPluginsParentHWND) {
nsCOMPtr<nsIWidget> widget;
static_cast<const nsPluginNativeWindow*>(aWindow)->
GetPluginWidget(getter_AddRefs(widget));
if (widget) {
widget->SetNativeData(NS_NATIVE_CHILD_WINDOW,
static_cast<uintptr_t>(childWindow.window));
reinterpret_cast<uintptr_t>(mChildPluginHWND));
}
// Now it has got the correct parent, make sure it is visible.
// In subsequent calls to SetWindow these calls happen in the Child.
HWND childHWND = reinterpret_cast<HWND>(childWindow.window);
ShowWindow(childHWND, SW_SHOWNA);
SetWindowPos(childHWND, nullptr, 0, 0, window.width, window.height,
SWP_NOZORDER | SWP_NOREPOSITION);
mChildPluginsParentHWND = mPluginHWND;
}
#endif
if (!CallNPP_SetWindow(window)) {
return NPERR_GENERIC_ERROR;
}
return NPERR_NO_ERROR;
}

Просмотреть файл

@ -366,6 +366,8 @@ private:
nsIntRect mPluginPort;
nsIntRect mSharedSize;
HWND mPluginHWND;
HWND mChildPluginHWND;
HWND mChildPluginsParentHWND;
WNDPROC mPluginWndProc;
bool mNestedEventState;