From 705471067acbbfadec1f0fda164dddfff527ee65 Mon Sep 17 00:00:00 2001 From: Jim Mathies Date: Tue, 1 Dec 2009 15:05:26 -0600 Subject: [PATCH] Bug 522299 - Electrolysis: Get windowless plugins drawing on win32. r=jmuizelaar. --- dom/plugins/PluginInstanceChild.cpp | 175 +++++++++++++++++++------ dom/plugins/PluginInstanceChild.h | 14 ++ dom/plugins/PluginInstanceParent.cpp | 187 ++++++++++++++++++++++++++- dom/plugins/PluginInstanceParent.h | 21 +++ dom/plugins/PluginMessageUtils.h | 15 +++ dom/plugins/PluginModuleParent.h | 1 + gfx/Makefile.in | 4 + gfx/ipc/Makefile.in | 73 +++++++++++ gfx/ipc/SharedDIB.cpp | 118 +++++++++++++++++ gfx/ipc/SharedDIB.h | 82 ++++++++++++ gfx/ipc/SharedDIBWin.cpp | 161 +++++++++++++++++++++++ gfx/ipc/SharedDIBWin.h | 82 ++++++++++++ layout/generic/nsObjectFrame.cpp | 28 +++- layout/generic/nsObjectFrame.h | 3 + toolkit/library/libxul-config.mk | 1 + 15 files changed, 919 insertions(+), 46 deletions(-) create mode 100644 gfx/ipc/Makefile.in create mode 100644 gfx/ipc/SharedDIB.cpp create mode 100644 gfx/ipc/SharedDIB.h create mode 100644 gfx/ipc/SharedDIBWin.cpp create mode 100644 gfx/ipc/SharedDIBWin.h diff --git a/dom/plugins/PluginInstanceChild.cpp b/dom/plugins/PluginInstanceChild.cpp index 69b3a697669c..99885460ec23 100644 --- a/dom/plugins/PluginInstanceChild.cpp +++ b/dom/plugins/PluginInstanceChild.cpp @@ -21,6 +21,7 @@ * the Initial Developer. All Rights Reserved. * * Contributor(s): + * Jim Mathies * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -45,6 +46,7 @@ #include "mozilla/ipc/SyncChannel.h" using namespace mozilla::plugins; +using namespace mozilla::gfx; #ifdef MOZ_WIDGET_GTK2 @@ -328,8 +330,15 @@ PluginInstanceChild::AnswerNPP_HandleEvent(const NPRemoteEvent& event, event.event.xgraphicsexpose.drawable); #endif - // plugins might be fooling with these, make a copy + // Make a copy since we may modify values. NPEvent evcopy = event.event; + +#ifdef OS_WIN + // Setup the shared dib for painting and update evcopy. + if (NPWindowTypeDrawable == mWindow.type && WM_PAINT == evcopy.event) + SharedSurfaceBeforePaint(evcopy); +#endif + *handled = mPluginIface->event(&mData, reinterpret_cast(&evcopy)); #ifdef MOZ_X11 @@ -408,25 +417,43 @@ PluginInstanceChild::AnswerNPP_SetWindow(const NPRemoteWindow& aWindow, *rv = mPluginIface->setwindow(&mData, &mWindow); #elif defined(OS_WIN) - ReparentPluginWindow((HWND)aWindow.window); - SizePluginWindow(aWindow.width, aWindow.height); + switch (aWindow.type) { + case NPWindowTypeWindow: + { + if (!CreatePluginWindow()) + return false; - mWindow.window = (void*)mPluginWindowHWND; - mWindow.x = aWindow.x; - mWindow.y = aWindow.y; - mWindow.width = aWindow.width; - mWindow.height = aWindow.height; - mWindow.type = aWindow.type; + ReparentPluginWindow((HWND)aWindow.window); + SizePluginWindow(aWindow.width, aWindow.height); - *rv = mPluginIface->setwindow(&mData, &mWindow); - if (*rv == NPERR_NO_ERROR) { - WNDPROC wndProc = reinterpret_cast( - GetWindowLongPtr(mPluginWindowHWND, GWLP_WNDPROC)); - if (wndProc != PluginWindowProc) { - mPluginWndProc = reinterpret_cast( - SetWindowLongPtr(mPluginWindowHWND, GWLP_WNDPROC, - reinterpret_cast(PluginWindowProc))); - } + mWindow.window = (void*)mPluginWindowHWND; + mWindow.x = aWindow.x; + mWindow.y = aWindow.y; + mWindow.width = aWindow.width; + mWindow.height = aWindow.height; + mWindow.type = aWindow.type; + + *rv = mPluginIface->setwindow(&mData, &mWindow); + if (*rv == NPERR_NO_ERROR) { + WNDPROC wndProc = reinterpret_cast( + GetWindowLongPtr(mPluginWindowHWND, GWLP_WNDPROC)); + if (wndProc != PluginWindowProc) { + mPluginWndProc = reinterpret_cast( + SetWindowLongPtr(mPluginWindowHWND, GWLP_WNDPROC, + reinterpret_cast(PluginWindowProc))); + } + } + } + break; + + case NPWindowTypeDrawable: + return SharedSurfaceSetWindow(aWindow, rv); + break; + + default: + NS_NOTREACHED("Bad plugin window type."); + return false; + break; } #elif defined(OS_MACOSX) @@ -442,11 +469,6 @@ PluginInstanceChild::AnswerNPP_SetWindow(const NPRemoteWindow& aWindow, bool PluginInstanceChild::Initialize() { -#if defined(OS_WIN) - if (!CreatePluginWindow()) - return false; -#endif - return true; } @@ -468,6 +490,10 @@ PluginInstanceChild::Destroy() PluginScriptableObjectChild::ScriptableInvalidate(object); } } + +#if defined(OS_WIN) + SharedSurfaceRelease(); +#endif } #if defined(OS_WIN) @@ -505,26 +531,28 @@ PluginInstanceChild::RegisterWindowClass() bool PluginInstanceChild::CreatePluginWindow() { + // already initialized + if (mPluginWindowHWND) + return true; + if (!RegisterWindowClass()) return false; - if (!mPluginWindowHWND) { - mPluginWindowHWND = - CreateWindowEx(WS_EX_LEFT | WS_EX_LTRREADING | - WS_EX_NOPARENTNOTIFY | // XXXbent Get rid of this! - WS_EX_RIGHTSCROLLBAR, - kWindowClassName, 0, - WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 0, - 0, 0, NULL, 0, GetModuleHandle(NULL), 0); - if (!mPluginWindowHWND) - return false; - if (!SetProp(mPluginWindowHWND, kPluginInstanceChildProperty, this)) - return false; + mPluginWindowHWND = + CreateWindowEx(WS_EX_LEFT | WS_EX_LTRREADING | + WS_EX_NOPARENTNOTIFY | // XXXbent Get rid of this! + WS_EX_RIGHTSCROLLBAR, + kWindowClassName, 0, + WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 0, + 0, 0, NULL, 0, GetModuleHandle(NULL), 0); + if (!mPluginWindowHWND) + return false; + if (!SetProp(mPluginWindowHWND, kPluginInstanceChildProperty, this)) + return false; - // Apparently some plugins require an ASCII WndProc. - SetWindowLongPtrA(mPluginWindowHWND, GWLP_WNDPROC, - reinterpret_cast(DefWindowProcA)); - } + // Apparently some plugins require an ASCII WndProc. + SetWindowLongPtrA(mPluginWindowHWND, GWLP_WNDPROC, + reinterpret_cast(DefWindowProcA)); return true; } @@ -620,6 +648,60 @@ PluginInstanceChild::PluginWindowProc(HWND hWnd, return res; } +/* windowless drawing helpers */ + +bool +PluginInstanceChild::SharedSurfaceSetWindow(const NPRemoteWindow& aWindow, + NPError* rv) +{ + // If the surfaceHandle is empty, parent is telling us we can reuse our cached + // memory surface and hdc. Otherwise, we need to reset, usually due to a + // expanding plugin port size. + if (!aWindow.surfaceHandle) { + if (!mSharedSurfaceDib.IsValid()) { + return false; + } + } + else { + // Attach to the new shared surface parent handed us. + if (NS_FAILED(mSharedSurfaceDib.Attach((SharedDIB::Handle)aWindow.surfaceHandle, + aWindow.width, aWindow.height, 32))) + return false; + } + + // NPRemoteWindow's origin is the origin of our shared dib. + mWindow.x = 0; + mWindow.y = 0; + mWindow.width = aWindow.width; + mWindow.height = aWindow.height; + mWindow.type = aWindow.type; + + mWindow.window = reinterpret_cast(mSharedSurfaceDib.GetHDC()); + *rv = mPluginIface->setwindow(&mData, &mWindow); + + return true; +} + +void +PluginInstanceChild::SharedSurfaceRelease() +{ + mSharedSurfaceDib.Close(); +} + +void +PluginInstanceChild::SharedSurfaceBeforePaint(NPEvent& evcopy) +{ + // Update the clip rect on our internal hdc + RECT* pRect = reinterpret_cast(evcopy.lParam); + if (pRect) { + HRGN clip = ::CreateRectRgnIndirect(pRect); + ::SelectClipRgn(mSharedSurfaceDib.GetHDC(), clip); + ::DeleteObject(clip); + } + // pass the internal hdc to the plugin + evcopy.wParam = WPARAM(mSharedSurfaceDib.GetHDC()); +} + #endif // OS_WIN PPluginScriptableObjectChild* @@ -853,10 +935,17 @@ PluginInstanceChild::InternalInvalidateRect(NPRect* aInvalidRect) NS_ASSERTION(aInvalidRect, "Null pointer!"); #ifdef OS_WIN - NS_ASSERTION(IsWindow(mPluginWindowHWND), "Bad window?!"); - RECT rect = { aInvalidRect->left, aInvalidRect->top, - aInvalidRect->right, aInvalidRect->bottom }; - InvalidateRect(mPluginWindowHWND, &rect, FALSE); + // Invalidate and draw locally for windowed plugins. + if (mWindow.type == NPWindowTypeWindow) { + NS_ASSERTION(IsWindow(mPluginWindowHWND), "Bad window?!"); + RECT rect = { aInvalidRect->left, aInvalidRect->top, + aInvalidRect->right, aInvalidRect->bottom }; + InvalidateRect(mPluginWindowHWND, &rect, FALSE); + return false; + } + // Windowless need the invalidation to propegate to parent + // triggering wm_paint handle event calls. + return true; #endif // Windowless plugins must return true! diff --git a/dom/plugins/PluginInstanceChild.h b/dom/plugins/PluginInstanceChild.h index 81d68bde88ac..67f1b3de8a8f 100644 --- a/dom/plugins/PluginInstanceChild.h +++ b/dom/plugins/PluginInstanceChild.h @@ -41,6 +41,9 @@ #include "mozilla/plugins/PPluginInstanceChild.h" #include "mozilla/plugins/PluginScriptableObjectChild.h" +#if defined(OS_WIN) +#include "mozilla/gfx/SharedDIBWin.h" +#endif #include "npfunctions.h" #include "nsAutoPtr.h" @@ -204,6 +207,17 @@ private: #endif nsTArray > mScriptableObjects; + +#if defined(OS_WIN) +private: + // Shared dib rendering management for windowless plugins. + bool SharedSurfaceSetWindow(const NPRemoteWindow& aWindow, NPError* rv); + void SharedSurfaceBeforePaint(NPEvent& evcopy); + void SharedSurfaceRelease(); + +private: + gfx::SharedDIBWin mSharedSurfaceDib; +#endif // defined(OS_WIN) }; } // namespace plugins diff --git a/dom/plugins/PluginInstanceParent.cpp b/dom/plugins/PluginInstanceParent.cpp index ee76d69e39bf..b883f9ae85a4 100644 --- a/dom/plugins/PluginInstanceParent.cpp +++ b/dom/plugins/PluginInstanceParent.cpp @@ -21,6 +21,7 @@ * the Initial Developer. All Rights Reserved. * * Contributor(s): + * Jim Mathies * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -46,6 +47,10 @@ #include "npfunctions.h" #include "nsAutoPtr.h" +#if defined(OS_WIN) +#define NS_OOPP_DOUBLEPASS_MSGID TEXT("MozDoublePassMsg") +#endif + using namespace mozilla::plugins; PluginInstanceParent::PluginInstanceParent(PluginModuleParent* parent, @@ -53,8 +58,17 @@ PluginInstanceParent::PluginInstanceParent(PluginModuleParent* parent, const NPNetscapeFuncs* npniface) : mParent(parent), mNPP(npp), - mNPNIface(npniface) + mNPNIface(npniface), + mWindowType(NPWindowTypeWindow) { +#if defined(OS_WIN) + // Event sent from nsObjectFrame indicating double pass rendering for + // windowless plugins. RegisterWindowMessage makes it easy sync event + // values, and insures we never conflict with windowing events we allow + // for windowless plugins. + mDoublePassEvent = ::RegisterWindowMessage(NS_OOPP_DOUBLEPASS_MSGID); + mLocalCopyRender = false; +#endif } PluginInstanceParent::~PluginInstanceParent() @@ -78,6 +92,10 @@ PluginInstanceParent::Destroy() PluginScriptableObjectParent::ScriptableInvalidate(object); } } + +#if defined(OS_WIN) + SharedSurfaceRelease(); +#endif } PBrowserStreamParent* @@ -319,13 +337,34 @@ PluginInstanceParent::NPP_SetWindow(const NPWindow* aWindow) NS_ENSURE_TRUE(aWindow, NPERR_GENERIC_ERROR); NPRemoteWindow window; + mWindowType = aWindow->type; + +#if defined(OS_WIN) + // On windowless controls, reset the shared memory surface as needed. + if (mWindowType == NPWindowTypeDrawable) { + // SharedSurfaceSetWindow will take care of NPRemoteWindow. + if (!SharedSurfaceSetWindow(aWindow, window)) { + return NPERR_OUT_OF_MEMORY_ERROR; + } + } + else { + window.window = reinterpret_cast(aWindow->window); + window.x = aWindow->x; + window.y = aWindow->y; + window.width = aWindow->width; + window.height = aWindow->height; + window.type = aWindow->type; + } +#else window.window = reinterpret_cast(aWindow->window); window.x = aWindow->x; window.y = aWindow->y; window.width = aWindow->width; window.height = aWindow->height; - window.clipRect = aWindow->clipRect; + window.clipRect = aWindow->clipRect; // MacOS specific window.type = aWindow->type; +#endif + #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX) const NPSetWindowCallbackStruct* ws_info = static_cast(aWindow->ws_info); @@ -443,6 +482,21 @@ PluginInstanceParent::NPP_HandleEvent(void* event) NPRemoteEvent npremoteevent; npremoteevent.event = *npevent; +#if defined(OS_WIN) + RECT rect; + if (mWindowType == NPWindowTypeDrawable) { + if (mDoublePassEvent && mDoublePassEvent == npevent->event) { + // Sent from nsObjectFrame to let us know a double pass render is in progress. + mLocalCopyRender = PR_TRUE; + return true; + } else if (WM_PAINT == npevent->event) { + // Don't forward on the second pass, otherwise, fall through. + if (!SharedSurfaceBeforePaint(rect, npremoteevent)) + return true; + } + } +#endif + #if defined(MOZ_X11) if (GraphicsExpose == npevent->type) { printf(" schlepping drawable 0x%lx across the pipe\n", @@ -464,6 +518,12 @@ PluginInstanceParent::NPP_HandleEvent(void* event) if (!CallNPP_HandleEvent(npremoteevent, &handled)) { return 0; // no good way to handle errors here... } + +#if defined(OS_WIN) + if (handled && mWindowType == NPWindowTypeDrawable && WM_PAINT == npevent->event) + SharedSurfaceAfterPaint(npevent); +#endif + return handled; } @@ -632,3 +692,126 @@ PluginInstanceParent::AnswerNPN_PopPopupsEnabledState(bool* aSuccess) *aSuccess = mNPNIface->poppopupsenabledstate(mNPP); return true; } + +#if defined(OS_WIN) + +/* windowless drawing helpers */ + +void +PluginInstanceParent::SharedSurfaceRelease() +{ + mSharedSurfaceDib.Close(); +} + +bool +PluginInstanceParent::SharedSurfaceSetWindow(const NPWindow* aWindow, + NPRemoteWindow& aRemoteWindow) +{ + aRemoteWindow.window = nsnull; + aRemoteWindow.x = 0; + aRemoteWindow.y = 0; + aRemoteWindow.width = aWindow->width; + aRemoteWindow.height = aWindow->height; + aRemoteWindow.type = aWindow->type; + + nsIntRect newPort(aWindow->x, aWindow->y, aWindow->width, aWindow->height); + + // save the the rect location within the browser window. + mPluginPort = newPort; + + // move the port to our shared surface origin + newPort.MoveTo(0,0); + + // check to see if we have the room in shared surface + if (mSharedSurfaceDib.IsValid() && mSharedSize.Contains(newPort)) { + // ok to paint + aRemoteWindow.surfaceHandle = 0; + return true; + } + + // allocate a new shared surface + SharedSurfaceRelease(); + if (NS_FAILED(mSharedSurfaceDib.Create(reinterpret_cast(aWindow->window), + newPort.width, newPort.height, 32))) + return false; + + // save the new shared surface size we just allocated + mSharedSize = newPort; + + base::SharedMemoryHandle handle; + if (NS_FAILED(mSharedSurfaceDib.ShareToProcess(mParent->ChildProcessHandle(), &handle))) + return false; + + aRemoteWindow.surfaceHandle = handle; + + return true; +} + +bool +PluginInstanceParent::SharedSurfaceBeforePaint(RECT& rect, + NPRemoteEvent& npremoteevent) +{ + RECT* dr = (RECT*)npremoteevent.event.lParam; + HDC parentHdc = (HDC)npremoteevent.event.wParam; + + // We render twice per frame for windowless plugins that sit in transparent + // frames. (See nsObjectFrame and gfxWindowsNativeDrawing for details.) IPC + // message delays in OOP plugin painting can result in two passes yeilding + // different animation frames. The second rendering doesn't need to go over + // the wire (we already have a copy of the frame in mSharedSurfaceDib) so we + // skip off requesting the second. This also gives us a nice perf boost. + if (mLocalCopyRender) { + mLocalCopyRender = false; + // Reuse the old render. + SharedSurfaceAfterPaint(&npremoteevent.event); + return false; + } + + nsIntRect dirtyRect(dr->left, dr->top, dr->right-dr->left, dr->bottom-dr->top); + dirtyRect.MoveBy(-mPluginPort.x, -mPluginPort.y); // should always be smaller than dirtyRect + + ::BitBlt(mSharedSurfaceDib.GetHDC(), + dirtyRect.x, + dirtyRect.y, + dirtyRect.width, + dirtyRect.height, + parentHdc, + dr->left, + dr->top, + SRCCOPY); + + // setup the translated dirty rect we'll send to the child + rect.left = dirtyRect.x; + rect.top = dirtyRect.y; + rect.right = dirtyRect.width; + rect.bottom = dirtyRect.height; + + npremoteevent.event.wParam = WPARAM(0); + npremoteevent.event.lParam = LPARAM(&rect); + + // Send the event to the plugin + return true; +} + +void +PluginInstanceParent::SharedSurfaceAfterPaint(NPEvent* npevent) +{ + RECT* dr = (RECT*)npevent->lParam; + HDC parentHdc = (HDC)npevent->wParam; + + nsIntRect dirtyRect(dr->left, dr->top, dr->right-dr->left, dr->bottom-dr->top); + dirtyRect.MoveBy(-mPluginPort.x, -mPluginPort.y); + + // src copy the shared dib into the parent surface we are handed. + ::BitBlt(parentHdc, + dr->left, + dr->top, + dirtyRect.width, + dirtyRect.height, + mSharedSurfaceDib.GetHDC(), + dirtyRect.x, + dirtyRect.y, + SRCCOPY); +} + +#endif // defined(OS_WIN) diff --git a/dom/plugins/PluginInstanceParent.h b/dom/plugins/PluginInstanceParent.h index d305587c8ff2..dc0a4f2ce920 100644 --- a/dom/plugins/PluginInstanceParent.h +++ b/dom/plugins/PluginInstanceParent.h @@ -41,10 +41,14 @@ #include "mozilla/plugins/PPluginInstanceParent.h" #include "mozilla/plugins/PluginScriptableObjectParent.h" +#if defined(OS_WIN) +#include "mozilla/gfx/SharedDIBWin.h" +#endif #include "npfunctions.h" #include "nsAutoPtr.h" #include "nsTArray.h" +#include "nsRect.h" #undef _MOZ_LOG #define _MOZ_LOG(s) printf("[PluginInstanceParent] %s\n", s) @@ -218,8 +222,25 @@ private: PluginModuleParent* mParent; NPP mNPP; const NPNetscapeFuncs* mNPNIface; + NPWindowType mWindowType; nsTArray > mScriptableObjects; + +#if defined(OS_WIN) +private: + // Used in rendering windowless plugins in other processes. + bool SharedSurfaceSetWindow(const NPWindow* aWindow, NPRemoteWindow& aRemoteWindow); + bool SharedSurfaceBeforePaint(RECT &rect, NPRemoteEvent& npremoteevent); + void SharedSurfaceAfterPaint(NPEvent* npevent); + void SharedSurfaceRelease(); + +private: + gfx::SharedDIBWin mSharedSurfaceDib; + nsIntRect mPluginPort; + nsIntRect mSharedSize; + PRUint32 mDoublePassEvent; + bool mLocalCopyRender; +#endif // defined(XP_WIN) }; diff --git a/dom/plugins/PluginMessageUtils.h b/dom/plugins/PluginMessageUtils.h index 61880d14bfde..8157475a3c32 100644 --- a/dom/plugins/PluginMessageUtils.h +++ b/dom/plugins/PluginMessageUtils.h @@ -89,6 +89,9 @@ struct NPRemoteWindow VisualID visualID; Colormap colormap; #endif /* XP_UNIX */ +#if defined(XP_WIN) + base::SharedMemoryHandle surfaceHandle; +#endif }; // XXX maybe not the best place for these. better one? @@ -277,6 +280,9 @@ struct ParamTraits #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX) aMsg->WriteULong(aParam.visualID); aMsg->WriteULong(aParam.colormap); +#endif +#if defined(XP_WIN) + WriteParam(aMsg, aParam.surfaceHandle); #endif } @@ -304,6 +310,12 @@ struct ParamTraits return false; #endif +#if defined(XP_WIN) + base::SharedMemoryHandle surfaceHandle; + if (!ReadParam(aMsg, aIter, &surfaceHandle)) + return false; +#endif + aResult->window = window; aResult->x = x; aResult->y = y; @@ -314,6 +326,9 @@ struct ParamTraits #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX) aResult->visualID = visualID; aResult->colormap = colormap; +#endif +#if defined(XP_WIN) + aResult->surfaceHandle = surfaceHandle; #endif return true; } diff --git a/dom/plugins/PluginModuleParent.h b/dom/plugins/PluginModuleParent.h index 1fb81a6751d2..fd4e4a6ca832 100644 --- a/dom/plugins/PluginModuleParent.h +++ b/dom/plugins/PluginModuleParent.h @@ -141,6 +141,7 @@ public: bool EnsureValidNPIdentifier(NPIdentifier aIdentifier); + base::ProcessHandle ChildProcessHandle() { return mSubprocess->GetChildProcessHandle(); } private: void SetPluginFuncs(NPPluginFuncs* aFuncs); diff --git a/gfx/Makefile.in b/gfx/Makefile.in index 870cabc03e4a..5eeda93dd2fd 100644 --- a/gfx/Makefile.in +++ b/gfx/Makefile.in @@ -50,6 +50,10 @@ endif DIRS += thebes public idl src qcms +ifdef MOZ_IPC +DIRS += ipc +endif + ifdef ENABLE_TESTS ifndef MOZ_ENABLE_LIBXUL TOOL_DIRS += tests diff --git a/gfx/ipc/Makefile.in b/gfx/ipc/Makefile.in new file mode 100644 index 000000000000..cfb5c1dcdefe --- /dev/null +++ b/gfx/ipc/Makefile.in @@ -0,0 +1,73 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +ifdef MOZ_IPC + +MODULE = gfxipc +LIBRARY_NAME = gfxipc_s +FORCE_STATIC_LIB = 1 +LIBXUL_LIBRARY = 1 +EXPORT_LIBRARY = 1 + +EXPORTS_NAMESPACES = mozilla/gfx + +EXPORTS_mozilla/gfx = \ + SharedDIB.h \ + $(NULL) + +CPPSRCS = SharedDIB.cpp + +ENABLE_CXX_EXCEPTIONS = 1 + +ifeq ($(MOZ_WIDGET_TOOLKIT),windows) +CPPSRCS += SharedDIBWin.cpp +EXPORTS_mozilla/gfx += SharedDIBWin.h +endif + +include $(topsrcdir)/config/config.mk +include $(topsrcdir)/ipc/chromium/chromium-config.mk + +endif + +include $(topsrcdir)/config/rules.mk diff --git a/gfx/ipc/SharedDIB.cpp b/gfx/ipc/SharedDIB.cpp new file mode 100644 index 000000000000..8410a74be3a6 --- /dev/null +++ b/gfx/ipc/SharedDIB.cpp @@ -0,0 +1,118 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Jim Mathies + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "SharedDIB.h" + +namespace mozilla { +namespace gfx { + +SharedDIB::SharedDIB() : + mShMem(nsnull) +{ +} + +SharedDIB::~SharedDIB() +{ + Close(); +} + +nsresult +SharedDIB::Create(PRUint32 aSize) +{ + Close(); + + mShMem = new base::SharedMemory(); + if (!mShMem || !mShMem->Create(std::wstring(L""), false, false, aSize)) + return NS_ERROR_OUT_OF_MEMORY; + + // Map the entire section + if (!mShMem->Map(0)) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +bool +SharedDIB::IsValid() +{ + if (!mShMem) + return false; + + return (mShMem->handle() != mShMem->NULLHandle() ? true : false); +} + +nsresult +SharedDIB::Close() +{ + if (mShMem) + delete mShMem; + + mShMem = nsnull; + + return NS_OK; +} + +nsresult +SharedDIB::Attach(Handle aHandle, PRUint32 aSize) +{ + Close(); + + mShMem = new base::SharedMemory(aHandle, false); + if(!mShMem) + return NS_ERROR_OUT_OF_MEMORY; + + if (!mShMem->Map(aSize)) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +nsresult +SharedDIB::ShareToProcess(base::ProcessHandle aChildProcess, Handle *aChildHandle) +{ + if (!mShMem) + return NS_ERROR_UNEXPECTED; + + if (!mShMem->ShareToProcess(aChildProcess, aChildHandle)) + return NS_ERROR_UNEXPECTED; + + return NS_OK; +} + +} // gfx +} // mozilla diff --git a/gfx/ipc/SharedDIB.h b/gfx/ipc/SharedDIB.h new file mode 100644 index 000000000000..d873ec1d6c1d --- /dev/null +++ b/gfx/ipc/SharedDIB.h @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Jim Mathies + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef gfx_SharedDIB_h__ +#define gfx_SharedDIB_h__ + +#include "base/shared_memory.h" +#include "prtypes.h" +#include "nscore.h" + +namespace mozilla { +namespace gfx { + +class SharedDIB +{ +public: + typedef base::SharedMemoryHandle Handle; + +public: + SharedDIB(); + ~SharedDIB(); + + // Create and allocate a new shared dib. + nsresult Create(PRUint32 aSize); + + // Destroy or release resources associated with this dib. + nsresult Close(); + + // Returns true if this object contains a valid dib. + bool IsValid(); + + // Wrap a new shared dib around allocated shared memory. Note aHandle must point + // to a memory section large enough to hold a dib of size aSize, otherwise this + // will fail. + nsresult Attach(Handle aHandle, PRUint32 aSize); + + // Returns a SharedMemoryHandle suitable for sharing with another process. + nsresult ShareToProcess(base::ProcessHandle aChildProcess, Handle *aChildHandle); + +protected: + base::SharedMemory *mShMem; +}; + +} // gfx +} // mozilla + +#endif diff --git a/gfx/ipc/SharedDIBWin.cpp b/gfx/ipc/SharedDIBWin.cpp new file mode 100644 index 000000000000..dc9c3d3afc88 --- /dev/null +++ b/gfx/ipc/SharedDIBWin.cpp @@ -0,0 +1,161 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Jim Mathies + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "SharedDIBWin.h" +#include "nsMathUtils.h" +#include "nsDebug.h" + +namespace mozilla { +namespace gfx { + +SharedDIBWin::SharedDIBWin() : + mSharedHdc(nsnull) + , mSharedBmp(nsnull) + , mOldObj(nsnull) +{ +} + +SharedDIBWin::~SharedDIBWin() +{ + Close(); +} + +nsresult +SharedDIBWin::Close() +{ + if (mSharedHdc && mOldObj) + ::SelectObject(mSharedHdc, mOldObj); + + if (mSharedHdc) + ::DeleteObject(mSharedHdc); + + if (mSharedBmp) + ::DeleteObject(mSharedBmp); + + mSharedHdc = NULL; + mOldObj = mSharedBmp = NULL; + + SharedDIB::Close(); + + return NS_OK; +} + +nsresult +SharedDIBWin::Create(HDC aHdc, PRUint32 aWidth, PRUint32 aHeight, PRUint32 aDepth) +{ + Close(); + + // create the offscreen shared dib + BITMAPINFOHEADER bmih; + PRUint32 size = SetupBitmapHeader(aWidth, aHeight, aDepth, &bmih); + + nsresult rv = SharedDIB::Create(size); + if (NS_FAILED(rv)) + return rv; + + if (NS_FAILED(SetupSurface(aHdc, &bmih))) { + Close(); + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +nsresult +SharedDIBWin::Attach(Handle aHandle, PRUint32 aWidth, PRUint32 aHeight, PRUint32 aDepth) +{ + Close(); + + BITMAPINFOHEADER bmih; + SetupBitmapHeader(aWidth, aHeight, aDepth, &bmih); + + nsresult rv = SharedDIB::Attach(aHandle, 0); + if (NS_FAILED(rv)) + return rv; + + if (NS_FAILED(SetupSurface(NULL, &bmih))) { + Close(); + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +PRUint32 +SharedDIBWin::SetupBitmapHeader(PRUint32 aWidth, PRUint32 aHeight, PRUint32 aDepth, BITMAPINFOHEADER *aHeader) +{ + NS_ASSERTION(aDepth == 32, "Invalid SharedDIBWin depth"); + + memset((void*)aHeader, 0, sizeof(BITMAPINFOHEADER)); + aHeader->biSize = sizeof(BITMAPINFOHEADER); + aHeader->biWidth = aWidth; + aHeader->biHeight = aHeight; + aHeader->biPlanes = 1; + aHeader->biBitCount = aDepth; + aHeader->biCompression = BI_RGB; + + // deal better with varying depths. (we currently only ask for 32 bit) + return (sizeof(BITMAPINFOHEADER) + (aHeader->biHeight * aHeader->biWidth * (PRUint32)NS_ceil(aDepth/8))); +} + +nsresult +SharedDIBWin::SetupSurface(HDC aHdc, BITMAPINFOHEADER *aHdr) +{ + mSharedHdc = ::CreateCompatibleDC(aHdc); + + if (!mSharedHdc) + return NS_ERROR_FAILURE; + + void* ppvBits = nsnull; + mSharedBmp = ::CreateDIBSection(mSharedHdc, + (BITMAPINFO*)aHdr, + DIB_RGB_COLORS, + (void**)&ppvBits, + mShMem->handle(), + (unsigned long)sizeof(BITMAPINFOHEADER)); + if (!mSharedBmp) + return NS_ERROR_FAILURE; + + mOldObj = SelectObject(mSharedHdc, mSharedBmp); + + return NS_OK; +} + + +} // gfx +} // mozilla diff --git a/gfx/ipc/SharedDIBWin.h b/gfx/ipc/SharedDIBWin.h new file mode 100644 index 000000000000..a02fbc9d2a61 --- /dev/null +++ b/gfx/ipc/SharedDIBWin.h @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Jim Mathies + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef gfx_SharedDIBWin_h__ +#define gfx_SharedDIBWin_h__ + +#include + +#include "SharedDIB.h" + +namespace mozilla { +namespace gfx { + +class SharedDIBWin : public SharedDIB +{ +public: + SharedDIBWin(); + ~SharedDIBWin(); + + // Allocate a new win32 dib section compatible with an hdc. The dib will + // be selected into the hdc on return. + nsresult Create(HDC aHdc, PRUint32 aWidth, PRUint32 aHeight, PRUint32 aDepth); + + // Wrap a dib section around an existing shared memory object. aHandle should + // point to a section large enough for the dib's memory, otherwise this call + // will fail. + nsresult Attach(Handle aHandle, PRUint32 aWidth, PRUint32 aHeight, PRUint32 aDepth); + + // Destroy or release resources associated with this dib. + nsresult Close(); + + // Return the HDC of the shared dib. + HDC GetHDC() { return mSharedHdc; } + +private: + HDC mSharedHdc; + HBITMAP mSharedBmp; + HGDIOBJ mOldObj; + + PRUint32 SetupBitmapHeader(PRUint32 aWidth, PRUint32 aHeight, PRUint32 aDepth, BITMAPINFOHEADER *aHeader); + nsresult SetupSurface(HDC aHdc, BITMAPINFOHEADER *aHdr); +}; + +} // gfx +} // mozilla + +#endif diff --git a/layout/generic/nsObjectFrame.cpp b/layout/generic/nsObjectFrame.cpp index cfcf49afc079..2f9eeb62abd5 100644 --- a/layout/generic/nsObjectFrame.cpp +++ b/layout/generic/nsObjectFrame.cpp @@ -205,6 +205,9 @@ enum { XKeyPress = KeyPress }; #ifdef XP_WIN #include #include +#ifdef MOZ_IPC +#define NS_OOPP_DOUBLEPASS_MSGID TEXT("MozDoublePassMsg") +#endif #endif #ifdef XP_OS2 @@ -605,6 +608,9 @@ nsObjectFrame::Init(nsIContent* aContent, if (NS_SUCCEEDED(rv)) { NotifyPluginEventObservers(NS_LITERAL_STRING("init").get()); } +#ifdef XP_WIN + mDoublePassEvent = 0; +#endif return rv; } @@ -1680,6 +1686,7 @@ nsObjectFrame::PaintPlugin(nsIRenderingContext& aRenderingContext, nsPoint origin; gfxWindowsNativeDrawing nativeDraw(ctx, frameGfxRect); + PRBool doublePass = PR_FALSE; do { HDC hdc = nativeDraw.BeginNativeDrawing(); if (!hdc) @@ -1742,7 +1749,26 @@ nsObjectFrame::PaintPlugin(nsIRenderingContext& aRenderingContext, mInstanceOwner->Paint(dirty, hdc); nativeDraw.EndNativeDrawing(); - } while (nativeDraw.ShouldRenderAgain()); + doublePass = nativeDraw.ShouldRenderAgain(); +#ifdef MOZ_IPC + if (doublePass) { + // OOP plugin specific: let the shim know we are in the middle of a double pass + // render. The second pass will reuse the previous rendering without going over + // the wire. + if (!mDoublePassEvent) + mDoublePassEvent = ::RegisterWindowMessage(NS_OOPP_DOUBLEPASS_MSGID); + if (mDoublePassEvent) { + NPEvent pluginEvent; + pluginEvent.event = mDoublePassEvent; + pluginEvent.wParam = 0; + pluginEvent.lParam = 0; + PRBool eventHandled = PR_FALSE; + + inst->HandleEvent(&pluginEvent, &eventHandled); + } + } +#endif + } while (doublePass); nativeDraw.PaintToContext(); } else if (!(ctx->GetFlags() & gfxContext::FLAG_DESTINED_FOR_SCREEN)) { diff --git a/layout/generic/nsObjectFrame.h b/layout/generic/nsObjectFrame.h index 3e714bbe267f..cadf8e6fd662 100644 --- a/layout/generic/nsObjectFrame.h +++ b/layout/generic/nsObjectFrame.h @@ -235,6 +235,9 @@ private: nsIView* mInnerView; nsCOMPtr mWidget; nsIntRect mWindowlessRect; +#ifdef XP_WIN + PRUint32 mDoublePassEvent; +#endif // For assertions that make it easier to determine if a crash is due // to the underlying problem described in bug 136927, and to prevent diff --git a/toolkit/library/libxul-config.mk b/toolkit/library/libxul-config.mk index 1a8c0bfdbb87..8dd3ce9a403c 100644 --- a/toolkit/library/libxul-config.mk +++ b/toolkit/library/libxul-config.mk @@ -98,6 +98,7 @@ STATIC_LIBS += \ mozipc_s \ chromium_s \ ipcshell_s \ + gfxipc_s \ $(NULL) ifdef MOZ_IPDL_TESTS