Bug 626602, part 9: When possible, copy from a background to an opaque surface and have transparent plugins draw directly on the copied background, instead of doing alpha recovery or hoping plugins give us alpha values. r=bsmedberg,karlt sr=roc

This commit is contained in:
Chris Jones 2011-02-08 18:44:14 -06:00
Родитель ab81441789
Коммит 24e1378cae
11 изменённых файлов: 643 добавлений и 80 удалений

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

@ -0,0 +1,70 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: sw=4 ts=8 et :
*/
/* ***** 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 Code.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Chris Jones <jones.chris.g@gmail.com>
*
* 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 protocol PPluginInstance;
namespace mozilla {
namespace plugins {
/**
* This protocol exists to allow us to correctly destroy background
* surfaces. The browser owns the surfaces, but shares a "reference"
* with the plugin. The browser needs to notify the plugin when the
* background is going to be destroyed, but it can't rely on the
* plugin to destroy it because the plugin may crash at any time. So
* the plugin instance relinquishes destruction of the its old
* background to actors of this protocol, which can deal with crashy
* corner cases more easily than the instance.
*/
protocol PPluginBackgroundDestroyer {
manager PPluginInstance;
// The ctor message for this protocol serves double-duty as
// notification that that the background is stale.
parent:
__delete__();
state DESTROYING:
recv __delete__;
};
} // namespace plugins
} // namespace mozilla

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

@ -37,6 +37,7 @@
*
* ***** END LICENSE BLOCK ***** */
include protocol PPluginBackgroundDestroyer;
include protocol PPluginModule;
include protocol PPluginScriptableObject;
include protocol PBrowserStream;
@ -57,6 +58,7 @@ using mozilla::gfxSurfaceType;
using gfxIntSize;
using mozilla::null_t;
using mozilla::plugins::WindowsSharedMemoryHandle;
using nsIntRect;
namespace mozilla {
namespace plugins {
@ -83,6 +85,7 @@ rpc protocol PPluginInstance
{
manager PPluginModule;
manages PPluginBackgroundDestroyer;
manages PPluginScriptableObject;
manages PBrowserStream;
manages PPluginStream;
@ -126,6 +129,13 @@ child:
// with type equals to surfaceType
async AsyncSetWindow(gfxSurfaceType surfaceType, NPRemoteWindow window);
// There is now an opaque background behind this instance (or the
// background was updated). The changed area is |rect|. The
// browser owns the background surface, and it's read-only from
// within the plugin process. |background| is either null_t to
// refer to the existing background or a fresh descriptor.
async UpdateBackground(SurfaceDescriptor background, nsIntRect rect);
rpc NPP_Destroy()
returns (NPError rv);
@ -236,6 +246,8 @@ parent:
child:
rpc SetPluginFocus();
rpc UpdateWindow();
async PPluginBackgroundDestroyer();
};
} // namespace plugins

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

@ -0,0 +1,108 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: sw=4 ts=8 et :
*/
/* ***** 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 Code.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Chris Jones <jones.chris.g@gmail.com>
*
* 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 dom_plugins_PluginBackgroundDestroyer
#define dom_plugins_PluginBackgroundDestroyer
#include "mozilla/plugins/PPluginBackgroundDestroyerChild.h"
#include "mozilla/plugins/PPluginBackgroundDestroyerParent.h"
#include "gfxASurface.h"
#include "gfxSharedImageSurface.h"
namespace mozilla {
namespace plugins {
/**
* When instances of this class are destroyed, the old background goes
* along with them, completing the destruction process (whether or not
* the plugin stayed alive long enough to ack).
*/
class PluginBackgroundDestroyerParent : public PPluginBackgroundDestroyerParent {
public:
PluginBackgroundDestroyerParent(gfxASurface* aDyingBackground)
: mDyingBackground(aDyingBackground)
{ }
virtual ~PluginBackgroundDestroyerParent() { }
private:
NS_OVERRIDE
virtual void ActorDestroy(ActorDestroyReason why)
{
switch(why) {
case Deletion:
case AncestorDeletion:
if (gfxSharedImageSurface::IsSharedImage(mDyingBackground)) {
gfxSharedImageSurface* s =
static_cast<gfxSharedImageSurface*>(mDyingBackground.get());
DeallocShmem(s->GetShmem());
}
break;
default:
// We're shutting down or crashed, let automatic cleanup
// take care of our shmem, if we have one.
break;
}
}
nsRefPtr<gfxASurface> mDyingBackground;
};
/**
* This class exists solely to instruct its instance to release its
* current background, a new one may be coming.
*/
class PluginBackgroundDestroyerChild : public PPluginBackgroundDestroyerChild {
public:
PluginBackgroundDestroyerChild() { }
virtual ~PluginBackgroundDestroyerChild() { }
private:
// Implementing this for good hygiene.
NS_OVERRIDE
virtual void ActorDestroy(ActorDestroyReason why)
{ }
};
} // namespace plugins
} // namespace mozilla
#endif // dom_plugins_PluginBackgroundDestroyer

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

@ -37,6 +37,7 @@
*
* ***** END LICENSE BLOCK ***** */
#include "PluginBackgroundDestroyer.h"
#include "PluginInstanceChild.h"
#include "PluginModuleChild.h"
#include "BrowserStreamChild.h"
@ -166,7 +167,6 @@ PluginInstanceChild::PluginInstanceChild(const NPPluginFuncs* aPluginIface)
#endif // OS_WIN
#if defined(OS_WIN)
InitPopupMenuHook();
HookSystemParametersInfo();
#endif // OS_WIN
#ifdef MOZ_X11
// Maemo flash can render plugin with any provided rectangle and not require this quirk.
@ -924,6 +924,11 @@ PluginInstanceChild::AnswerNPP_SetWindow(const NPRemoteWindow& aWindow)
}
#endif
PLUGIN_LOG_DEBUG(
("[InstanceChild][%p] Answer_SetWindow w=<x=%d,y=%d, w=%d,h=%d>, clip=<l=%d,t=%d,r=%d,b=%d>",
this, mWindow.x, mWindow.y, mWindow.width, mWindow.height,
mWindow.clipRect.left, mWindow.clipRect.top, mWindow.clipRect.right, mWindow.clipRect.bottom));
if (mPluginIface->setwindow)
(void) mPluginIface->setwindow(&mData, &mWindow);
@ -1228,47 +1233,6 @@ PluginInstanceChild::PluginWindowProc(HWND hWnd,
return res;
}
/* system parameters info hook for flash */
typedef BOOL (WINAPI *User32SystemParametersInfoW)(UINT uiAction,
UINT uiParam,
PVOID pvParam,
UINT fWinIni);
static User32SystemParametersInfoW sUser32SystemParametersInfoWStub = NULL;
static BOOL WINAPI User32SystemParametersInfoHook(UINT uiAction,
UINT uiParam,
PVOID pvParam,
UINT fWinIni)
{
if (!sUser32SystemParametersInfoWStub) {
NS_NOTREACHED("sUser32SystemParametersInfoWStub not set??");
return FALSE;
}
// Tell them cleartype is disabled, so they don't mess with
// the alpha channel in our buffers.
if (uiAction == SPI_GETFONTSMOOTHINGTYPE && pvParam) {
*((UINT*)(pvParam)) = FE_FONTSMOOTHINGSTANDARD;
return TRUE;
}
return sUser32SystemParametersInfoWStub(uiAction, uiParam, pvParam, fWinIni);
}
void
PluginInstanceChild::HookSystemParametersInfo()
{
if (!(GetQuirks() & PluginModuleChild::QUIRK_FLASH_MASK_CLEARTYPE_SETTINGS))
return;
if (sUser32SystemParametersInfoWStub)
return;
sUser32Intercept.Init("gdi32.dll");
sUser32Intercept.AddHook("SystemParametersInfoW", User32SystemParametersInfoHook,
(void**) &sUser32SystemParametersInfoWStub);
}
/* set window long ptr hook for flash */
/*
@ -2287,6 +2251,10 @@ PluginInstanceChild::DoAsyncSetWindow(const gfxSurfaceType& aSurfaceType,
const NPRemoteWindow& aWindow,
bool aIsAsync)
{
PLUGIN_LOG_DEBUG(
("[InstanceChild][%p] AsyncSetWindow to <x=%d,y=%d, w=%d,h=%d>",
this, aWindow.x, aWindow.y, aWindow.width, aWindow.height));
AssertPluginThread();
NS_ASSERTION(!aWindow.window, "Remote window should be null.");
NS_ASSERTION(!mPendingPluginCall, "Can't do SetWindow during plugin call!");
@ -2300,6 +2268,10 @@ PluginInstanceChild::DoAsyncSetWindow(const gfxSurfaceType& aSurfaceType,
mWindow.window = NULL;
if (mWindow.width != aWindow.width || mWindow.height != aWindow.height) {
// We weakly assume here that the SetWindow arrives before the
// next UpdateBackground, for the new window size, if we were
// going to get one.
mBackground = nsnull;
ClearCurrentSurface();
mAccumulatedInvalidRect = nsIntRect(0, 0, aWindow.width, aWindow.height);
}
@ -2347,9 +2319,11 @@ PluginInstanceChild::CreateOptSurface(void)
NS_ASSERTION(!mCurrentSurface, "mCurrentSurfaceActor can get out of sync.");
nsRefPtr<gfxASurface> retsurf;
// Use an opaque surface unless we're transparent and *don't* have
// a background to source from.
gfxASurface::gfxImageFormat format =
mIsTransparent ? gfxASurface::ImageFormatARGB32 :
gfxASurface::ImageFormatRGB24;
(mIsTransparent && !mBackground) ? gfxASurface::ImageFormatARGB32 :
gfxASurface::ImageFormatRGB24;
#if (MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6)
// On Maemo 5, we must send the Visibility event to activate the plugin
@ -2387,10 +2361,12 @@ PluginInstanceChild::CreateOptSurface(void)
#ifdef XP_WIN
if (mSurfaceType == gfxASurface::SurfaceTypeWin32 ||
mSurfaceType == gfxASurface::SurfaceTypeD2D) {
bool willHaveTransparentPixels = mIsTransparent && !mBackground;
SharedDIBSurface* s = new SharedDIBSurface();
if (!s->Create(reinterpret_cast<HDC>(mWindow.window),
mWindow.width, mWindow.height, mIsTransparent))
mWindow.width, mWindow.height,
willHaveTransparentPixels))
return false;
mCurrentSurface = s;
@ -2471,6 +2447,8 @@ PluginInstanceChild::MaybeCreatePlatformHelperSurface(void)
return false;
}
}
#elif defined(XP_WIN)
mDoAlphaExtraction = mIsTransparent && !mBackground;
#endif
return true;
@ -2529,7 +2507,7 @@ PluginInstanceChild::UpdateWindowAttributes(bool aForceSetWindow)
mWindow.window = nsnull;
mWsInfo.depth = gfxUtils::ImageFormatToDepth(img->Format());
mWsInfo.colormap = 0;
needWindowUpdate = PR_TRUE;
needWindowUpdate = true;
}
}
#endif // MAEMO
@ -2595,6 +2573,11 @@ PluginInstanceChild::UpdateWindowAttributes(bool aForceSetWindow)
}
#endif
PLUGIN_LOG_DEBUG(
("[InstanceChild][%p] UpdateWindow w=<x=%d,y=%d, w=%d,h=%d>, clip=<l=%d,t=%d,r=%d,b=%d>",
this, mWindow.x, mWindow.y, mWindow.width, mWindow.height,
mWindow.clipRect.left, mWindow.clipRect.top, mWindow.clipRect.right, mWindow.clipRect.bottom));
if (mPluginIface->setwindow) {
mPluginIface->setwindow(&mData, &mWindow);
}
@ -2604,12 +2587,6 @@ void
PluginInstanceChild::PaintRectToPlatformSurface(const nsIntRect& aRect,
gfxASurface* aSurface)
{
bool temporarilyMakeVisible = !IsVisible() && !mHasPainted;
if (temporarilyMakeVisible) {
mWindow.clipRect.right = mWindow.width;
mWindow.clipRect.bottom = mWindow.height;
}
UpdateWindowAttributes();
#ifdef MOZ_X11
@ -2698,14 +2675,6 @@ PluginInstanceChild::PaintRectToPlatformSurface(const nsIntRect& aRect,
#else
NS_RUNTIMEABORT("Surface type not implemented.");
#endif
if (temporarilyMakeVisible) {
mWindow.clipRect.right = mWindow.clipRect.bottom = 0;
if (mPluginIface->setwindow) {
mPluginIface->setwindow(&mData, &mWindow);
}
}
}
void
@ -2735,7 +2704,7 @@ PluginInstanceChild::PaintRectToSurface(const nsIntRect& aRect,
}
#endif
if (mIsTransparent) {
if (aColor.a > 0.0) {
// Clear surface content for transparent rendering
nsRefPtr<gfxContext> ctx = new gfxContext(renderSurface);
ctx->SetColor(aColor);
@ -2858,6 +2827,14 @@ PluginInstanceChild::PaintRectWithAlphaExtraction(const nsIntRect& aRect,
}
}
bool
PluginInstanceChild::CanPaintOnBackground()
{
return (mBackground &&
mCurrentSurface &&
mCurrentSurface->GetSize() == mBackground->GetSize());
}
bool
PluginInstanceChild::ShowPluginFrame()
{
@ -2872,11 +2849,20 @@ PluginInstanceChild::ShowPluginFrame()
return false;
}
// Make expose rect not bigger than clip rect
mAccumulatedInvalidRect.IntersectRect(mAccumulatedInvalidRect,
nsIntRect(mWindow.clipRect.left, mWindow.clipRect.top,
mWindow.clipRect.right - mWindow.clipRect.left,
mWindow.clipRect.bottom - mWindow.clipRect.top));
bool temporarilyMakeVisible = !IsVisible() && !mHasPainted;
if (temporarilyMakeVisible) {
mWindow.clipRect.right = mWindow.width;
mWindow.clipRect.bottom = mWindow.height;
} else if (!IsVisible()) {
// If we're not visible, don't bother painting a <0,0,0,0>
// rect. If we're eventually made visible, the visibility
// change will invalidate our window.
return true;
}
NS_ASSERTION(mWindow.width == (mWindow.clipRect.right - mWindow.clipRect.left) &&
mWindow.height == (mWindow.clipRect.bottom - mWindow.clipRect.top),
"Clip rect should be same size as window when using layers");
// Clear accRect here to be able to pass
// test_invalidate_during_plugin_paint test
@ -2884,17 +2870,54 @@ PluginInstanceChild::ShowPluginFrame()
mAccumulatedInvalidRect.Empty();
if (!ReadbackDifferenceRect(rect)) {
// Just repaint whole plugin, because we cannot read back from Shmem which is owned by another process
// We couldn't read back the pixels that differ between the
// current surface and last, so we have to invalidate the
// entire window.
rect.SetRect(0, 0, mWindow.width, mWindow.height);
}
if (mDoAlphaExtraction) {
bool haveTransparentPixels =
gfxASurface::CONTENT_COLOR_ALPHA == mCurrentSurface->GetContentType();
PLUGIN_LOG_DEBUG(
("[InstanceChild][%p] Painting%s <x=%d,y=%d, w=%d,h=%d>",
this, haveTransparentPixels ? " with alpha" : "",
rect.x, rect.y, rect.width, rect.height));
if (CanPaintOnBackground()) {
PLUGIN_LOG_DEBUG((" (on background)"));
// Source the background pixels ...
{
nsRefPtr<gfxContext> ctx = new gfxContext(mCurrentSurface);
ctx->SetSource(mBackground);
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
ctx->Rectangle(gfxRect(rect.x, rect.y, rect.width, rect.height));
ctx->Fill();
}
// ... and hand off to the plugin
// BEWARE: mBackground may die during this call
PaintRectToSurface(rect, mCurrentSurface, gfxRGBA(0.0, 0.0, 0.0, 0.0));
} else if (mDoAlphaExtraction) {
PLUGIN_LOG_DEBUG((" (with alpha recovery)"));
PaintRectWithAlphaExtraction(rect, mCurrentSurface);
} else {
PLUGIN_LOG_DEBUG((" (onto opaque surface)"));
PaintRectToSurface(rect, mCurrentSurface, gfxRGBA(0.0, 0.0, 0.0, 0.0));
}
mHasPainted = true;
if (temporarilyMakeVisible) {
mWindow.clipRect.right = mWindow.clipRect.bottom = 0;
PLUGIN_LOG_DEBUG(
("[InstanceChild][%p] Undoing temporary clipping w=<x=%d,y=%d, w=%d,h=%d>, clip=<l=%d,t=%d,r=%d,b=%d>",
this, mWindow.x, mWindow.y, mWindow.width, mWindow.height,
mWindow.clipRect.left, mWindow.clipRect.top, mWindow.clipRect.right, mWindow.clipRect.bottom));
if (mPluginIface->setwindow) {
mPluginIface->setwindow(&mData, &mWindow);
}
}
NPRect r = { (uint16_t)rect.y, (uint16_t)rect.x,
(uint16_t)rect.YMost(), (uint16_t)rect.XMost() };
SurfaceDescriptor currSurf;
@ -2918,7 +2941,7 @@ PluginInstanceChild::ShowPluginFrame()
mCurrentSurfaceActor =
SendPPluginSurfaceConstructor(handle,
mCurrentSurface->GetSize(),
mIsTransparent);
haveTransparentPixels);
}
currSurf = mCurrentSurfaceActor;
s->Flush();
@ -2962,9 +2985,17 @@ PluginInstanceChild::ReadbackDifferenceRect(const nsIntRect& rect)
return false;
#endif
if (mCurrentSurface->GetContentType() != mBackSurface->GetContentType())
return false;
if (mSurfaceDifferenceRect.IsEmpty())
return true;
PLUGIN_LOG_DEBUG(
("[InstanceChild][%p] Reading back part of <x=%d,y=%d, w=%d,h=%d>",
this, mSurfaceDifferenceRect.x, mSurfaceDifferenceRect.y,
mSurfaceDifferenceRect.width, mSurfaceDifferenceRect.height));
// Read back previous content
nsRefPtr<gfxContext> ctx = new gfxContext(mCurrentSurface);
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
@ -3041,6 +3072,110 @@ PluginInstanceChild::InvalidateRect(NPRect* aInvalidRect)
SendNPN_InvalidateRect(*aInvalidRect);
}
bool
PluginInstanceChild::RecvUpdateBackground(const SurfaceDescriptor& aBackground,
const nsIntRect& aRect)
{
NS_ABORT_IF_FALSE(mIsTransparent, "Only transparent plugins use backgrounds");
if (SurfaceDescriptor::Tnull_t == aBackground.type()) {
// null_t here means "use existing background". We're
// notified when we lose our background through
// PPluginBackgroundDestroyer. We might have already dropped
// our background from an ill-timed SetWindow, though.
if (!mBackground) {
return true;
}
} else {
NS_ABORT_IF_FALSE(!mBackground, "Shouldn't have background here");
// Now that we have a new background, our choice of surface
// format and/or size should have changed.
ClearCurrentSurface();
// XXX refactor me
switch (aBackground.type()) {
#ifdef MOZ_X11
case SurfaceDescriptor::TSurfaceDescriptorX11: {
SurfaceDescriptorX11 xdesc = aBackground.get_SurfaceDescriptorX11();
XRenderPictFormat pf;
pf.id = xdesc.xrenderPictID();
XRenderPictFormat *incFormat =
XRenderFindFormat(DefaultXDisplay(), PictFormatID, &pf, 0);
mBackground =
new gfxXlibSurface(DefaultScreenOfDisplay(DefaultXDisplay()),
xdesc.XID(), incFormat, xdesc.size());
break;
}
#endif
case SurfaceDescriptor::TShmem: {
mBackground = gfxSharedImageSurface::Open(aBackground.get_Shmem());
break;
}
default:
NS_RUNTIMEABORT("Unexpected background surface descriptor");
}
}
if (!mBackground) {
return false;
}
// XXX refactor me
mAccumulatedInvalidRect.UnionRect(aRect, mAccumulatedInvalidRect);
// The browser is limping along with a stale copy of our pixels.
// Try to repaint ASAP.
if (!ShowPluginFrame()) {
NS_WARNING("Couldn't immediately repaint plugin instance");
AsyncShowPluginFrame();
}
return true;
}
PPluginBackgroundDestroyerChild*
PluginInstanceChild::AllocPPluginBackgroundDestroyer()
{
return new PluginBackgroundDestroyerChild();
}
bool
PluginInstanceChild::RecvPPluginBackgroundDestroyerConstructor(
PPluginBackgroundDestroyerChild* aActor)
{
// Our background changed, so we have to invalidate the area
// painted with the old background. If the background was
// destroyed because we have a new background, then we expect to
// be notified of that "soon", before processing the asynchronous
// invalidation here. If we're *not* getting a new background,
// our current front surface is stale and we want to repaint
// "soon" so that we can hand the browser back a surface with
// alpha values. (We should be notified of that invalidation soon
// too, but we don't assume that here.)
if (mBackground) {
gfxIntSize bgsize = mBackground->GetSize();
mAccumulatedInvalidRect.UnionRect(
nsIntRect(0, 0, bgsize.width, bgsize.height), mAccumulatedInvalidRect);
AsyncShowPluginFrame();
// NB: we don't have to XSync here because only ShowPluginFrame()
// uses mBackground, and it always XSyncs after finishing.
mBackground = nsnull;
ClearCurrentSurface();
}
return PPluginBackgroundDestroyerChild::Send__delete__(aActor);
}
bool
PluginInstanceChild::DeallocPPluginBackgroundDestroyer(
PPluginBackgroundDestroyerChild* aActor)
{
delete aActor;
return true;
}
uint32_t
PluginInstanceChild::ScheduleTimer(uint32_t interval, bool repeat,
TimerFunc func)
@ -3130,7 +3265,8 @@ PluginInstanceChild::SwapSurfaces()
// Outdated back surface... not usable anymore due to changed plugin size.
// Dropping obsolete surface
if (mCurrentSurface && mBackSurface &&
mCurrentSurface->GetSize() != mBackSurface->GetSize()) {
(mCurrentSurface->GetSize() != mBackSurface->GetSize() ||
mCurrentSurface->GetContentType() != mBackSurface->GetContentType())) {
mCurrentSurface = nsnull;
#ifdef XP_WIN
if (mCurrentSurfaceActor) {

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

@ -236,6 +236,22 @@ private:
InternalGetNPObjectForValue(NPNVariable aValue,
NPObject** aObject);
NS_OVERRIDE
virtual bool RecvUpdateBackground(const SurfaceDescriptor& aBackground,
const nsIntRect& aRect);
NS_OVERRIDE
virtual PPluginBackgroundDestroyerChild*
AllocPPluginBackgroundDestroyer();
NS_OVERRIDE
virtual bool
RecvPPluginBackgroundDestroyerConstructor(PPluginBackgroundDestroyerChild* aActor);
NS_OVERRIDE
virtual bool
DeallocPPluginBackgroundDestroyer(PPluginBackgroundDestroyerChild* aActor);
#if defined(OS_WIN)
static bool RegisterWindowClass();
bool CreatePluginWindow();
@ -290,7 +306,6 @@ private:
int nIndex,
LONG newLong);
#endif
void HookSystemParametersInfo();
class FlashThrottleAsyncMsg : public ChildAsyncCall
{
@ -407,6 +422,8 @@ private:
const NPCocoaEvent *mCurrentEvent;
#endif
bool CanPaintOnBackground();
bool IsVisible() {
return mWindow.clipRect.top != 0 ||
mWindow.clipRect.left != 0 ||
@ -488,6 +505,13 @@ private:
// surface which is on ParentProcess side
nsRefPtr<gfxASurface> mBackSurface;
// (Not to be confused with mBackSurface). This is a recent copy
// of the opaque pixels under our object frame, if
// |mIsTransparent|. We ask the plugin render directly onto a
// copy of the background pixels if available, and fall back on
// alpha recovery otherwise.
nsRefPtr<gfxASurface> mBackground;
#ifdef XP_WIN
// These actors mirror mCurrentSurface/mBackSurface
PPluginSurfaceChild* mCurrentSurfaceActor;

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

@ -40,6 +40,7 @@
#include "PluginInstanceParent.h"
#include "BrowserStreamParent.h"
#include "PluginBackgroundDestroyer.h"
#include "PluginModuleParent.h"
#include "PluginStreamParent.h"
#include "StreamNotifyParent.h"
@ -108,6 +109,7 @@ PluginInstanceParent::PluginInstanceParent(PluginModuleParent* parent,
, mDrawingModel(NPDrawingModelCoreGraphics)
, mIOSurface(nsnull)
#endif
, mNewBackground(false)
{
InitQuirksModes(aMimeType);
}
@ -498,6 +500,12 @@ PluginInstanceParent::RecvShow(const NPRect& updatedRect,
const SurfaceDescriptor& newSurface,
SurfaceDescriptor* prevSurface)
{
PLUGIN_LOG_DEBUG(
("[InstanceParent][%p] RecvShow for <x=%d,y=%d, w=%d,h=%d>",
this, updatedRect.left, updatedRect.top,
updatedRect.right - updatedRect.left,
updatedRect.bottom - updatedRect.top));
nsRefPtr<gfxASurface> surface;
if (newSurface.type() == SurfaceDescriptor::TShmem) {
if (!newSurface.get_Shmem().IsReadable()) {
@ -529,6 +537,11 @@ PluginInstanceParent::RecvShow(const NPRect& updatedRect,
#ifdef MOZ_X11
if (mFrontSurface &&
mFrontSurface->GetType() == gfxASurface::SurfaceTypeXlib)
// This is the "old front buffer" we're about to hand back to
// the plugin. We might still have drawing operations
// referencing it, so we XSync here to let them finish before
// the plugin starts scribbling on it again, or worse,
// destroys it.
XSync(DefaultXDisplay(), False);
#endif
@ -540,6 +553,9 @@ PluginInstanceParent::RecvShow(const NPRect& updatedRect,
mFrontSurface = surface;
RecvNPN_InvalidateRect(updatedRect);
PLUGIN_LOG_DEBUG((" (RecvShow invalidated for surface %p)",
mFrontSurface.get()));
return true;
}
@ -572,6 +588,175 @@ PluginInstanceParent::GetSurface(gfxASurface** aSurface)
return NS_ERROR_NOT_AVAILABLE;
}
nsresult
PluginInstanceParent::SetBackgroundUnknown()
{
PLUGIN_LOG_DEBUG(("[InstanceParent][%p] SetBackgroundUnknown", this));
NS_ABORT_IF_FALSE(!mNewBackground, "Forgot EndUpdateBackground?");
if (mBackground) {
DestroyBackground();
NS_ABORT_IF_FALSE(!mBackground, "Background not destroyed");
}
return NS_OK;
}
nsresult
PluginInstanceParent::BeginUpdateBackground(const nsIntRect& aRect,
gfxContext** aCtx)
{
PLUGIN_LOG_DEBUG(
("[InstanceParent][%p] BeginUpdateBackground for <x=%d,y=%d, w=%d,h=%d>",
this, aRect.x, aRect.y, aRect.width, aRect.height));
NS_ABORT_IF_FALSE(!mNewBackground, "Forgot EndUpdateBackground?");
if (!mBackground) {
// XXX if we failed to create a background surface on one
// update, there's no guarantee that later updates will be for
// the entire background area until successful. We might want
// to fix that eventually.
NS_ABORT_IF_FALSE(aRect.TopLeft() == nsIntPoint(0, 0),
"Expecting rect for whole frame");
if (!CreateBackground(aRect.Size())) {
*aCtx = nsnull;
return NS_OK;
}
// The new background forwarded over in EndUpdate below.
mNewBackground = true;
}
#ifdef DEBUG
gfxIntSize sz = mBackground->GetSize();
NS_ABORT_IF_FALSE(nsIntRect(0, 0, sz.width, sz.height).Contains(aRect),
"Update outside of background area");
#endif
nsRefPtr<gfxContext> ctx = new gfxContext(mBackground);
*aCtx = ctx.forget().get();
return NS_OK;
}
nsresult
PluginInstanceParent::EndUpdateBackground(gfxContext* aCtx,
const nsIntRect& aRect)
{
PLUGIN_LOG_DEBUG(
("[InstanceParent][%p] EndUpdateBackground for <x=%d,y=%d, w=%d,h=%d>",
this, aRect.x, aRect.y, aRect.width, aRect.height));
#ifdef MOZ_X11
// Have to XSync here to avoid the plugin trying to draw with this
// surface racing with its creation in the X server. We also want
// to avoid the plugin drawing onto stale pixels, then handing us
// back a front surface from those pixels that we might
// recomposite for "a while" until the next update. This XSync
// still doesn't guarantee that the plugin draws onto a consistent
// view of its background, but it does mean that the plugin is
// drawing onto pixels no older than those in the latest
// EndUpdateBackground().
XSync(DefaultXDisplay(), False);
#endif
unused << SendUpdateBackground(
mNewBackground ? BackgroundDescriptor() : SurfaceDescriptor(null_t()),
aRect);
mNewBackground = false;
return NS_OK;
}
bool
PluginInstanceParent::CreateBackground(const nsIntSize& aSize)
{
NS_ABORT_IF_FALSE(!mBackground, "Already have a background");
// XXX refactor me
#if defined(MOZ_X11)
Screen* screen = DefaultScreenOfDisplay(DefaultXDisplay());
Visual* visual = DefaultVisualOfScreen(screen);
mBackground = gfxXlibSurface::Create(screen, visual,
gfxIntSize(aSize.width, aSize.height));
return !!mBackground;
#elif defined(XP_WIN)
// We have chosen to create an unsafe surface in which the plugin
// can read from the region while we're writing to it.
mBackground =
gfxSharedImageSurface::CreateUnsafe(
this,
gfxIntSize(aSize.width, aSize.height),
gfxASurface::ImageFormatRGB24);
return !!mBackground;
#else
return nsnull;
#endif
}
void
PluginInstanceParent::DestroyBackground()
{
if (!mBackground) {
return;
}
// Relinquish ownership of |mBackground| to its destroyer
PPluginBackgroundDestroyerParent* pbd =
new PluginBackgroundDestroyerParent(mBackground);
mBackground = nsnull;
// If this fails, there's no problem: |bd| will be destroyed along
// with the old background surface.
unused << SendPPluginBackgroundDestroyerConstructor(pbd);
}
SurfaceDescriptor
PluginInstanceParent::BackgroundDescriptor()
{
NS_ABORT_IF_FALSE(mBackground, "Need a background here");
// XXX refactor me
#ifdef MOZ_X11
gfxXlibSurface* xsurf = static_cast<gfxXlibSurface*>(mBackground.get());
return SurfaceDescriptorX11(xsurf->XDrawable(), xsurf->XRenderFormat()->id,
xsurf->GetSize());
#endif
#ifdef XP_WIN
NS_ABORT_IF_FALSE(gfxSharedImageSurface::IsSharedImage(mBackground),
"Expected shared image surface");
gfxSharedImageSurface* shmem =
static_cast<gfxSharedImageSurface*>(mBackground.get());
return shmem->GetShmem();
#endif
// If this is ever used, which it shouldn't be, it will trigger a
// hard assertion in IPDL-generated code.
return SurfaceDescriptor();
}
PPluginBackgroundDestroyerParent*
PluginInstanceParent::AllocPPluginBackgroundDestroyer()
{
NS_RUNTIMEABORT("'Power-user' ctor is used exclusively");
return nsnull;
}
bool
PluginInstanceParent::DeallocPPluginBackgroundDestroyer(
PPluginBackgroundDestroyerParent* aActor)
{
delete aActor;
return true;
}
NPError
PluginInstanceParent::NPP_SetWindow(const NPWindow* aWindow)
{

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

@ -277,13 +277,27 @@ public:
nsresult AsyncSetWindow(NPWindow* window);
nsresult GetSurface(gfxASurface** aSurface);
nsresult SetBackgroundUnknown() { return NS_OK; }
nsresult SetBackgroundUnknown();
nsresult BeginUpdateBackground(const nsIntRect& aRect,
gfxContext** aCtx) { return NS_OK; }
gfxContext** aCtx);
nsresult EndUpdateBackground(gfxContext* aCtx,
const nsIntRect& aRect) { return NS_OK; }
const nsIntRect& aRect);
private:
// Create an appropriate platform surface for a background of size
// |aSize|. Return true if successful.
bool CreateBackground(const nsIntSize& aSize);
void DestroyBackground();
SurfaceDescriptor BackgroundDescriptor() /*const*/;
NS_OVERRIDE
virtual PPluginBackgroundDestroyerParent*
AllocPPluginBackgroundDestroyer();
NS_OVERRIDE
virtual bool
DeallocPPluginBackgroundDestroyer(PPluginBackgroundDestroyerParent* aActor);
// Quirks mode support for various plugin mime types
enum PluginQuirks {
// OSX: Don't use the refresh timer for plug-ins
@ -340,6 +354,19 @@ private:
// ObjectFrame layer wrapper
nsRefPtr<gfxASurface> mFrontSurface;
// For windowless+transparent instances, this surface contains a
// "pretty recent" copy of the pixels under its <object> frame.
// On the plugin side, we use this surface to avoid doing alpha
// recovery when possible. This surface is created and owned by
// the browser, but a "read-only" reference is sent to the plugin.
//
// We have explicitly chosen not to provide any guarantees about
// the consistency of the pixels in |mBackground|. A plugin may
// be able to observe partial updates to the background.
nsRefPtr<gfxASurface> mBackground;
// True when we just created a background and it needs to be
// shared to the plugin subprocess.
bool mNewBackground;
};

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

@ -1876,7 +1876,6 @@ PluginModuleChild::InitQuirksModes(const nsCString& aMimeType)
mQuirks |= QUIRK_FLASH_THROTTLE_WMUSER_EVENTS;
mQuirks |= QUIRK_FLASH_HOOK_SETLONGPTR;
mQuirks |= QUIRK_FLASH_HOOK_GETWINDOWINFO;
mQuirks |= QUIRK_FLASH_MASK_CLEARTYPE_SETTINGS;
}
#endif
}

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

@ -246,9 +246,6 @@ public:
// results so mouse input works when flash is displaying it's settings
// window.
QUIRK_FLASH_HOOK_GETWINDOWINFO = 1 << 5,
// Win: Flash trashes the alpha channel in our buffers when cleartype
// is enabled. Mask this setting so they don't know it's enabled.
QUIRK_FLASH_MASK_CLEARTYPE_SETTINGS = 1 << 6,
};
int GetQuirks() { return mQuirks; }

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

@ -35,6 +35,7 @@
# ***** END LICENSE BLOCK *****
IPDLSRCS = \
PPluginBackgroundDestroyer.ipdl \
PPluginModule.ipdl \
PPluginIdentifier.ipdl \
PPluginInstance.ipdl \

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

@ -381,13 +381,17 @@ pluginHandleEvent(InstanceData* instanceData, void* event)
if (expose.x < clip.left || expose.y < clip.top ||
expose.x + expose.width > clip.right ||
expose.y + expose.height > clip.bottom) {
g_warning("expose rectangle not in clip rectangle");
g_warning("expose rectangle (x=%d,y=%d,w=%d,h=%d) not in clip rectangle (l=%d,t=%d,r=%d,b=%d)",
expose.x, expose.y, expose.width, expose.height,
clip.left, clip.top, clip.right, clip.bottom);
return 0;
}
if (expose.x < window.x || expose.y < window.y ||
expose.x + expose.width > window.x + int32_t(window.width) ||
expose.y + expose.height > window.y + int32_t(window.height)) {
g_warning("expose rectangle not in plugin rectangle");
g_warning("expose rectangle (x=%d,y=%d,w=%d,h=%d) not in plugin rectangle (x=%d,y=%d,w=%d,h=%d)",
expose.x, expose.y, expose.width, expose.height,
window.x, window.y, window.width, window.height);
return 0;
}