Bug 596451 part D - Hook up asynchronous plugin painting on Windows. This part allows opaque plugins to paint correctly. r=jmathies

This commit is contained in:
Benjamin Smedberg 2010-10-25 13:57:13 -04:00
parent 04b10237dd
commit 4a85b8746d
12 changed files with 352 additions and 34 deletions

View File

@ -55,6 +55,7 @@ using mozilla::plugins::NativeWindowHandle;
using mozilla::gfxSurfaceType;
using gfxIntSize;
using mozilla::null_t;
using base::SharedMemoryHandle;
namespace mozilla {
namespace plugins {
@ -65,9 +66,15 @@ struct SurfaceDescriptorX11 {
gfxIntSize size;
};
struct SurfaceDescriptorWin {
SharedMemoryHandle handle;
gfxIntSize size;
};
union SurfaceDescriptor {
Shmem;
SurfaceDescriptorX11;
SurfaceDescriptorWin;
// Descriptor can be null here in case
// 1) of first Show call (prevSurface is null)
// 2) when child is going to destroy

View File

@ -48,6 +48,11 @@
#ifdef MOZ_X11
#include "gfxXlibSurface.h"
#endif
#ifdef XP_WIN
#include "mozilla/gfx/SharedDIBSurface.h"
using mozilla::gfx::SharedDIBSurface;
#endif
#include "gfxSharedImageSurface.h"
#include "gfxUtils.h"
#include "gfxAlphaRecovery.h"
@ -1420,7 +1425,7 @@ PluginInstanceChild::SharedSurfaceSetWindow(const NPRemoteWindow& aWindow)
else {
// Attach to the new shared surface parent handed us.
if (NS_FAILED(mSharedSurfaceDib.Attach((SharedDIB::Handle)aWindow.surfaceHandle,
aWindow.width, aWindow.height, 32)))
aWindow.width, aWindow.height)))
return false;
// Free any alpha extraction resources if needed. This will be reset
// the next time it's used.
@ -2037,6 +2042,12 @@ PluginInstanceChild::RecvAsyncSetWindow(const gfxSurfaceType& aSurfaceType,
mHelperSurface = nsnull;
mPendingForcePaint = true;
}
#ifdef XP_WIN
mPluginOffset.x = aWindow.x;
mPluginOffset.y = aWindow.y;
#endif
mWindow.x = aWindow.x;
mWindow.y = aWindow.y;
mWindow.width = aWindow.width;
@ -2098,14 +2109,26 @@ PluginInstanceChild::CreateOptSurface(void)
}
#endif
// Make common shmem implementation working for any platform
mCurrentSurface = new gfxSharedImageSurface();
if (NS_FAILED(static_cast<gfxSharedImageSurface*>(mCurrentSurface.get())->
Init(this, gfxIntSize(mWindow.width, mWindow.height), format))) {
return false;
#ifdef XP_WIN
if (mSurfaceType == gfxASurface::SurfaceTypeWin32 ||
mSurfaceType == gfxASurface::SurfaceTypeD2D) {
SharedDIBSurface* s = new SharedDIBSurface();
if (!s->Create(reinterpret_cast<HDC>(mWindow.window),
mWindow.width, mWindow.height))
return false;
mCurrentSurface = s;
return true;
}
return true;
NS_RUNTIMEABORT("Shared-memory drawing not expected on Windows.");
#endif
// Make common shmem implementation working for any platform
mCurrentSurface = new gfxSharedImageSurface();
return static_cast<gfxSharedImageSurface*>(mCurrentSurface.get())->
Init(this, gfxIntSize(mWindow.width, mWindow.height), format);
}
bool
@ -2234,8 +2257,24 @@ PluginInstanceChild::UpdateWindowAttributes(bool aForceSetWindow)
needWindowUpdate = PR_TRUE;
}
}
#endif
#endif
#endif // MAEMO
#endif // MOZ_X11
#ifdef XP_WIN
HDC dc = NULL;
if (curSurface) {
NS_ASSERTION(SharedDIBSurface::IsSharedDIBSurface(curSurface),
"Expected (SharedDIB) image surface.");
SharedDIBSurface* dibsurf = static_cast<SharedDIBSurface*>(curSurface.get());
dc = dibsurf->GetHDC();
}
if (mWindow.window != dc) {
mWindow.window = dc;
needWindowUpdate = true;
}
#endif // XP_WIN
if (!needWindowUpdate) {
return;
}
@ -2254,6 +2293,25 @@ PluginInstanceChild::UpdateWindowAttributes(bool aForceSetWindow)
newClipRect.bottom = clipRect.YMost();
mWindow.clipRect = newClipRect;
#ifdef XP_WIN
// Windowless plugins on Windows need a WM_WINDOWPOSCHANGED event to update
// their location... or at least Flash does: Silverlight uses the
// window.x/y passed to NPP_SetWindow
if (mPluginIface->event) {
WINDOWPOS winpos = {
0, 0,
mPluginOffset.x, mPluginOffset.y,
mWindow.width, mWindow.height
};
NPEvent pluginEvent = {
WM_WINDOWPOSCHANGED, 0,
(LPARAM) &winpos
};
mPluginIface->event(&mData, &pluginEvent);
}
#endif
if (mPluginIface->setwindow) {
mPluginIface->setwindow(&mData, &mWindow);
}
@ -2329,7 +2387,31 @@ PluginInstanceChild::PaintRectToPlatformSurface(const nsIntRect& aRect,
exposeEvent.minor_code = 0;
mPluginIface->event(&mData, reinterpret_cast<void*>(&exposeEvent));
mPendingPluginCall = false;
return;
#endif
#ifdef XP_WIN
NS_ASSERTION(SharedDIBSurface::IsSharedDIBSurface(aSurface),
"Expected (SharedDIB) image surface.");
mPendingPluginCall = true;
RECT rect = {
aRect.x,
aRect.y,
aRect.x + aRect.width,
aRect.y + aRect.height
};
NPEvent paintEvent = {
WM_PAINT,
uintptr_t(mWindow.window),
uintptr_t(&rect)
};
mPluginIface->event(&mData, reinterpret_cast<void*>(&paintEvent));
mPendingPluginCall = false;
return;
#endif
NS_RUNTIMEABORT("Surface type not implemented.");
}
void
@ -2492,6 +2574,15 @@ PluginInstanceChild::ShowPluginFrame()
// before giving drawable to another process
XSync(mWsInfo.display, False);
} else
#endif
#ifdef XP_WIN
if (SharedDIBSurface::IsSharedDIBSurface(mCurrentSurface)) {
base::SharedMemoryHandle handle = NULL;
SharedDIBSurface* s = static_cast<SharedDIBSurface*>(mCurrentSurface.get());
s->ShareToProcess(PluginModuleChild::current()->OtherProcess(), &handle);
currSurf = SurfaceDescriptorWin(handle, mCurrentSurface->GetSize());
s->Flush();
} else
#endif
if (gfxSharedImageSurface::IsSharedImage(mCurrentSurface)) {
currSurf = static_cast<gfxSharedImageSurface*>(mCurrentSurface.get())->GetShmem();

View File

@ -59,6 +59,9 @@
#if defined(OS_WIN)
#include <windowsx.h>
#include "mozilla/gfx/SharedDIBSurface.h"
using mozilla::gfx::SharedDIBSurface;
// Plugin focus event for widget.
extern const PRUnichar* kOOPPPluginFocusEventId;
@ -496,6 +499,14 @@ PluginInstanceParent::RecvShow(const NPRect& updatedRect,
xdesc.XID(), incFormat, xdesc.size());
}
#endif
#ifdef XP_WIN
else if (newSurface.type() == SurfaceDescriptor::TSurfaceDescriptorWin) {
SurfaceDescriptorWin windesc = newSurface.get_SurfaceDescriptorWin();
SharedDIBSurface* dibsurf = new SharedDIBSurface();
if (dibsurf->Attach(windesc.handle(), windesc.size().width, windesc.size().height))
surface = dibsurf;
}
#endif
mSentPaintNotification = PR_FALSE;
@ -1332,7 +1343,7 @@ PluginInstanceParent::SharedSurfaceSetWindow(const NPWindow* aWindow,
// allocate a new shared surface
SharedSurfaceRelease();
if (NS_FAILED(mSharedSurfaceDib.Create(reinterpret_cast<HDC>(aWindow->window),
newPort.width, newPort.height, 32)))
newPort.width, newPort.height)))
return false;
// save the new shared surface size we just allocated

View File

@ -61,8 +61,15 @@ CPPSRCS = SharedDIB.cpp
ENABLE_CXX_EXCEPTIONS = 1
ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
CPPSRCS += SharedDIBWin.cpp
EXPORTS_mozilla/gfx += SharedDIBWin.h
EXPORTS_mozilla/gfx += \
SharedDIBWin.h \
SharedDIBSurface.h \
$(NULL)
CPPSRCS += \
SharedDIBWin.cpp \
SharedDIBSurface.cpp \
$(NULL)
endif
include $(topsrcdir)/config/config.mk
@ -71,3 +78,5 @@ include $(topsrcdir)/ipc/chromium/chromium-config.mk
endif
include $(topsrcdir)/config/rules.mk
CXXFLAGS += $(MOZ_CAIRO_CFLAGS) $(TK_CFLAGS)

View File

@ -0,0 +1,95 @@
/* -*- 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 Firefox.
*
* The Initial Developer of the Original Code is
* the Mozilla Foundation <http://www.mozilla.org>.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* 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 "SharedDIBSurface.h"
#include "cairo.h"
namespace mozilla {
namespace gfx {
static const cairo_user_data_key_t SHAREDDIB_KEY;
static const long kBytesPerPixel = 4;
bool
SharedDIBSurface::Create(HDC adc, PRUint32 aWidth, PRUint32 aHeight)
{
nsresult rv = mSharedDIB.Create(adc, aWidth, aHeight);
if (NS_FAILED(rv) || !mSharedDIB.IsValid())
return false;
InitSurface(aWidth, aHeight);
return true;
}
bool
SharedDIBSurface::Attach(Handle aHandle, PRUint32 aWidth, PRUint32 aHeight)
{
nsresult rv = mSharedDIB.Attach(aHandle, aWidth, aHeight);
if (NS_FAILED(rv) || !mSharedDIB.IsValid())
return false;
InitSurface(aWidth, aHeight);
return true;
}
void
SharedDIBSurface::InitSurface(PRUint32 aWidth, PRUint32 aHeight)
{
// Windows DIBs are bottom-to-top by default, so the stride is negative
// and the data is the beginning of the last row.
long stride = -long(aWidth * kBytesPerPixel);
unsigned char* data = reinterpret_cast<unsigned char*>(mSharedDIB.GetBits());
data -= (aHeight - 1) * stride;
gfxImageSurface::InitWithData(data, gfxIntSize(aWidth, aHeight),
stride, ImageFormatRGB24);
cairo_surface_set_user_data(mSurface, &SHAREDDIB_KEY, this, NULL);
}
bool
SharedDIBSurface::IsSharedDIBSurface(gfxASurface* aSurface)
{
return aSurface &&
aSurface->GetType() == gfxASurface::SurfaceTypeImage &&
aSurface->GetData(&SHAREDDIB_KEY);
}
} // namespace gfx
} // namespace mozilla

View File

@ -0,0 +1,93 @@
/* -*- 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 Firefox.
*
* The Initial Developer of the Original Code is
* the Mozilla Foundation <http://www.mozilla.org>.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* 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 mozilla_gfx_SharedDIBSurface_h
#define mozilla_gfx_SharedDIBSurface_h
#include "gfxImageSurface.h"
#include "SharedDIBWin.h"
#include <windows.h>
namespace mozilla {
namespace gfx {
/**
* A SharedDIBSurface owns an underlying SharedDIBWin.
*/
class SharedDIBSurface : public gfxImageSurface
{
public:
typedef base::SharedMemoryHandle Handle;
SharedDIBSurface() { }
~SharedDIBSurface() { }
/**
* Create this image surface backed by shared memory.
*/
bool Create(HDC adc, PRUint32 aWidth, PRUint32 aHeight);
/**
* Attach this surface to shared memory from another process.
*/
bool Attach(Handle aHandle, PRUint32 aWidth, PRUint32 aHeight);
/**
* After drawing to a surface via GDI, GDI must be flushed before the bitmap
* is valid.
*/
void Flush() { ::GdiFlush(); }
HDC GetHDC() { return mSharedDIB.GetHDC(); }
nsresult ShareToProcess(base::ProcessHandle aChildProcess, Handle* aChildHandle) {
return mSharedDIB.ShareToProcess(aChildProcess, aChildHandle);
}
static bool IsSharedDIBSurface(gfxASurface* aSurface);
private:
SharedDIBWin mSharedDIB;
void InitSurface(PRUint32 aWidth, PRUint32 aHeight);
};
} // namespace gfx
} // namespace mozilla
#endif // mozilla_gfx_SharedDIBSurface_h

View File

@ -43,6 +43,8 @@
namespace mozilla {
namespace gfx {
static const PRUint32 kBytesPerPixel = 4;
SharedDIBWin::SharedDIBWin() :
mSharedHdc(nsnull)
, mSharedBmp(nsnull)
@ -76,13 +78,13 @@ SharedDIBWin::Close()
}
nsresult
SharedDIBWin::Create(HDC aHdc, PRUint32 aWidth, PRUint32 aHeight, PRUint32 aDepth)
SharedDIBWin::Create(HDC aHdc, PRUint32 aWidth, PRUint32 aHeight)
{
Close();
// create the offscreen shared dib
BITMAPINFOHEADER bmih;
PRUint32 size = SetupBitmapHeader(aWidth, aHeight, aDepth, &bmih);
PRUint32 size = SetupBitmapHeader(aWidth, aHeight, &bmih);
nsresult rv = SharedDIB::Create(size);
if (NS_FAILED(rv))
@ -97,12 +99,12 @@ SharedDIBWin::Create(HDC aHdc, PRUint32 aWidth, PRUint32 aHeight, PRUint32 aDept
}
nsresult
SharedDIBWin::Attach(Handle aHandle, PRUint32 aWidth, PRUint32 aHeight, PRUint32 aDepth)
SharedDIBWin::Attach(Handle aHandle, PRUint32 aWidth, PRUint32 aHeight)
{
Close();
BITMAPINFOHEADER bmih;
SetupBitmapHeader(aWidth, aHeight, aDepth, &bmih);
SetupBitmapHeader(aWidth, aHeight, &bmih);
nsresult rv = SharedDIB::Attach(aHandle, 0);
if (NS_FAILED(rv))
@ -117,20 +119,17 @@ SharedDIBWin::Attach(Handle aHandle, PRUint32 aWidth, PRUint32 aHeight, PRUint32
}
PRUint32
SharedDIBWin::SetupBitmapHeader(PRUint32 aWidth, PRUint32 aHeight, PRUint32 aDepth, BITMAPINFOHEADER *aHeader)
SharedDIBWin::SetupBitmapHeader(PRUint32 aWidth, PRUint32 aHeight, 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->biBitCount = 32;
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)));
return (sizeof(BITMAPINFOHEADER) + (aHeader->biHeight * aHeader->biWidth * kBytesPerPixel));
}
nsresult
@ -141,11 +140,10 @@ SharedDIBWin::SetupSurface(HDC aHdc, BITMAPINFOHEADER *aHdr)
if (!mSharedHdc)
return NS_ERROR_FAILURE;
void* ppvBits = nsnull;
mSharedBmp = ::CreateDIBSection(mSharedHdc,
(BITMAPINFO*)aHdr,
DIB_RGB_COLORS,
(void**)&ppvBits,
&mBitmapBits,
mShMem->handle(),
(unsigned long)sizeof(BITMAPINFOHEADER));
if (!mSharedBmp)

View File

@ -54,12 +54,12 @@ public:
// 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);
nsresult Create(HDC aHdc, PRUint32 aWidth, PRUint32 aHeight);
// 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);
nsresult Attach(Handle aHandle, PRUint32 aWidth, PRUint32 aHeight);
// Destroy or release resources associated with this dib.
nsresult Close();
@ -67,12 +67,16 @@ public:
// Return the HDC of the shared dib.
HDC GetHDC() { return mSharedHdc; }
// Return the bitmap bits.
void* GetBits() { return mBitmapBits; }
private:
HDC mSharedHdc;
HBITMAP mSharedBmp;
HGDIOBJ mOldObj;
void* mBitmapBits;
PRUint32 SetupBitmapHeader(PRUint32 aWidth, PRUint32 aHeight, PRUint32 aDepth, BITMAPINFOHEADER *aHeader);
PRUint32 SetupBitmapHeader(PRUint32 aWidth, PRUint32 aHeight, BITMAPINFOHEADER *aHeader);
nsresult SetupSurface(HDC aHdc, BITMAPINFOHEADER *aHdr);
};

View File

@ -64,12 +64,20 @@ gfxImageSurface::InitFromSurface(cairo_surface_t *csurf)
gfxImageSurface::gfxImageSurface(unsigned char *aData, const gfxIntSize& aSize,
long aStride, gfxImageFormat aFormat)
: mSize(aSize)
, mOwnsData(PR_FALSE)
, mData(aData)
, mFormat(aFormat)
, mStride(aStride)
{
InitWithData(aData, aSize, aStride, aFormat);
}
void
gfxImageSurface::InitWithData(unsigned char *aData, const gfxIntSize& aSize,
long aStride, gfxImageFormat aFormat)
{
mSize = aSize;
mOwnsData = PR_FALSE;
mData = aData;
mFormat = aFormat;
mStride = aStride;
if (!CheckSurfaceSize(aSize))
return;

View File

@ -108,6 +108,8 @@ public:
protected:
gfxImageSurface();
void InitWithData(unsigned char *aData, const gfxIntSize& aSize,
long aStride, gfxImageFormat aFormat);
void InitFromSurface(cairo_surface_t *csurf);
long ComputeStride() const;

View File

@ -44,7 +44,7 @@
using mozilla::ipc::SharedMemory;
static cairo_user_data_key_t SHM_KEY;
static const cairo_user_data_key_t SHM_KEY;
typedef struct _SharedImageInfo
{

View File

@ -85,7 +85,7 @@ nsNPAPIPluginInstance::nsNPAPIPluginInstance(nsNPAPIPlugin* plugin)
mMIMEType(nsnull),
mOwner(nsnull),
mCurrentPluginEvent(nsnull),
#ifdef MOZ_X11
#if defined(MOZ_X11) || defined(XP_WIN)
mUsePluginLayersPref(PR_TRUE)
#else
mUsePluginLayersPref(PR_FALSE)