diff --git a/dom/plugins/ipc/PPluginInstance.ipdl b/dom/plugins/ipc/PPluginInstance.ipdl index 40338138667b..b86ce11b48e6 100644 --- a/dom/plugins/ipc/PPluginInstance.ipdl +++ b/dom/plugins/ipc/PPluginInstance.ipdl @@ -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); diff --git a/dom/plugins/ipc/PluginInstanceChild.cpp b/dom/plugins/ipc/PluginInstanceChild.cpp index aa4e333d0bde..71af5ae0c267 100644 --- a/dom/plugins/ipc/PluginInstanceChild.cpp +++ b/dom/plugins/ipc/PluginInstanceChild.cpp @@ -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(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=)", 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(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(aWindow.window); - if (mPluginParentHWND != parentWindow && IsWindow(parentWindow)) { - mPluginParentHWND = parentWindow; - aChildWindowToBeAdopted->window = - reinterpret_cast(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); } } diff --git a/dom/plugins/ipc/PluginInstanceChild.h b/dom/plugins/ipc/PluginInstanceChild.h index a37eae3a9976..0d03bb3aee98 100644 --- a/dom/plugins/ipc/PluginInstanceChild.h +++ b/dom/plugins/ipc/PluginInstanceChild.h @@ -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; diff --git a/dom/plugins/ipc/PluginInstanceParent.cpp b/dom/plugins/ipc/PluginInstanceParent.cpp index 46a067ffc035..255edba382a8 100644 --- a/dom/plugins/ipc/PluginInstanceParent.cpp +++ b/dom/plugins/ipc/PluginInstanceParent.cpp @@ -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(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 widget; static_cast(aWindow)-> GetPluginWidget(getter_AddRefs(widget)); if (widget) { widget->SetNativeData(NS_NATIVE_CHILD_WINDOW, - static_cast(childWindow.window)); + reinterpret_cast(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(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; } diff --git a/dom/plugins/ipc/PluginInstanceParent.h b/dom/plugins/ipc/PluginInstanceParent.h index 80af054cf936..6a2f0f0bdbf9 100644 --- a/dom/plugins/ipc/PluginInstanceParent.h +++ b/dom/plugins/ipc/PluginInstanceParent.h @@ -366,6 +366,8 @@ private: nsIntRect mPluginPort; nsIntRect mSharedSize; HWND mPluginHWND; + HWND mChildPluginHWND; + HWND mChildPluginsParentHWND; WNDPROC mPluginWndProc; bool mNestedEventState;