mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-17 23:35:34 +00:00
Bug 1232181
- Add support for capturing plugin windows on Windows. r=aklotz
This commit is contained in:
parent
002407fe45
commit
71b61067c1
@ -60,6 +60,7 @@
|
|||||||
#include "nsIWidget.h"
|
#include "nsIWidget.h"
|
||||||
#include "nsPluginNativeWindow.h"
|
#include "nsPluginNativeWindow.h"
|
||||||
#include "PluginQuirks.h"
|
#include "PluginQuirks.h"
|
||||||
|
#include "nsWindowsHelpers.h"
|
||||||
extern const wchar_t* kFlashFullscreenClass;
|
extern const wchar_t* kFlashFullscreenClass;
|
||||||
#elif defined(MOZ_WIDGET_GTK)
|
#elif defined(MOZ_WIDGET_GTK)
|
||||||
#include "mozilla/dom/ContentChild.h"
|
#include "mozilla/dom/ContentChild.h"
|
||||||
@ -76,6 +77,13 @@ using namespace mozilla::plugins;
|
|||||||
using namespace mozilla::layers;
|
using namespace mozilla::layers;
|
||||||
using namespace mozilla::gl;
|
using namespace mozilla::gl;
|
||||||
|
|
||||||
|
#if defined(XP_WIN)
|
||||||
|
// Delays associated with attempting an e10s window capture for scrolling.
|
||||||
|
const int kScrollCaptureDelayMs = 100;
|
||||||
|
const int kInitScrollCaptureDelayMs = 1000;
|
||||||
|
const uint32_t kScrollCaptureFillColor = 0xFFa0a0a0; // gray
|
||||||
|
#endif
|
||||||
|
|
||||||
void
|
void
|
||||||
StreamNotifyParent::ActorDestroy(ActorDestroyReason aWhy)
|
StreamNotifyParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||||
{
|
{
|
||||||
@ -113,6 +121,13 @@ PluginInstanceParent::LookupPluginInstanceByID(uintptr_t aId)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct RunnableMethodTraits<PluginInstanceParent>
|
||||||
|
{
|
||||||
|
static void RetainCallee(PluginInstanceParent* obj) { }
|
||||||
|
static void ReleaseCallee(PluginInstanceParent* obj) { }
|
||||||
|
};
|
||||||
|
|
||||||
PluginInstanceParent::PluginInstanceParent(PluginModuleParent* parent,
|
PluginInstanceParent::PluginInstanceParent(PluginModuleParent* parent,
|
||||||
NPP npp,
|
NPP npp,
|
||||||
const nsCString& aMimeType,
|
const nsCString& aMimeType,
|
||||||
@ -139,6 +154,11 @@ PluginInstanceParent::PluginInstanceParent(PluginModuleParent* parent,
|
|||||||
, mShHeight(0)
|
, mShHeight(0)
|
||||||
, mShColorSpace(nullptr)
|
, mShColorSpace(nullptr)
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(XP_WIN)
|
||||||
|
, mCaptureRefreshTask(nullptr)
|
||||||
|
, mValidFirstCapture(false)
|
||||||
|
, mIsScrolling(false)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
#if defined(OS_WIN)
|
#if defined(OS_WIN)
|
||||||
if (!sPluginInstanceList) {
|
if (!sPluginInstanceList) {
|
||||||
@ -163,6 +183,9 @@ PluginInstanceParent::~PluginInstanceParent()
|
|||||||
if (mShColorSpace)
|
if (mShColorSpace)
|
||||||
::CGColorSpaceRelease(mShColorSpace);
|
::CGColorSpaceRelease(mShColorSpace);
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(XP_WIN)
|
||||||
|
CancelScheduledScrollCapture();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -440,6 +463,12 @@ PluginInstanceParent::AnswerNPN_SetValue_NPPVpluginWindow(
|
|||||||
// non-pointer-sized integer.
|
// non-pointer-sized integer.
|
||||||
*result = mNPNIface->setvalue(mNPP, NPPVpluginWindowBool,
|
*result = mNPNIface->setvalue(mNPP, NPPVpluginWindowBool,
|
||||||
(void*)(intptr_t)windowed);
|
(void*)(intptr_t)windowed);
|
||||||
|
|
||||||
|
#if defined(XP_WIN)
|
||||||
|
if (windowed) {
|
||||||
|
ScheduleScrollCapture(kScrollCaptureDelayMs);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1187,6 +1216,203 @@ PluginInstanceParent::EndUpdateBackground(const nsIntRect& aRect)
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(XP_WIN)
|
||||||
|
//#define CAPTURE_LOG(...) printf_stderr("CAPTURE [%X]: ", this);printf_stderr(__VA_ARGS__);printf_stderr("\n");
|
||||||
|
#define CAPTURE_LOG(...)
|
||||||
|
|
||||||
|
void
|
||||||
|
PluginInstanceParent::ScheduleScrollCapture(int aTimeout)
|
||||||
|
{
|
||||||
|
if (mCaptureRefreshTask) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CAPTURE_LOG("delayed scroll capture requested.");
|
||||||
|
mCaptureRefreshTask =
|
||||||
|
NewRunnableMethod(this, &PluginInstanceParent::ScheduledUpdateScrollCaptureCallback);
|
||||||
|
MessageLoop::current()->PostDelayedTask(FROM_HERE, mCaptureRefreshTask,
|
||||||
|
kScrollCaptureDelayMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PluginInstanceParent::ScheduledUpdateScrollCaptureCallback()
|
||||||
|
{
|
||||||
|
CAPTURE_LOG("taking delayed scrollcapture.");
|
||||||
|
mCaptureRefreshTask = nullptr;
|
||||||
|
bool retrigger = false;
|
||||||
|
UpdateScrollCapture(retrigger);
|
||||||
|
if (retrigger) {
|
||||||
|
// reset the async request
|
||||||
|
ScheduleScrollCapture(kScrollCaptureDelayMs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PluginInstanceParent::CancelScheduledScrollCapture()
|
||||||
|
{
|
||||||
|
CAPTURE_LOG("delayed scroll capture cancelled.");
|
||||||
|
if (mCaptureRefreshTask) {
|
||||||
|
mCaptureRefreshTask->Cancel();
|
||||||
|
mCaptureRefreshTask = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
PluginInstanceParent::UpdateScrollCapture(bool& aRequestNewCapture)
|
||||||
|
{
|
||||||
|
aRequestNewCapture = false;
|
||||||
|
if (!::IsWindow(mChildPluginHWND)) {
|
||||||
|
CAPTURE_LOG("invalid window");
|
||||||
|
aRequestNewCapture = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsAutoHDC windowDC(::GetDC(mChildPluginHWND));
|
||||||
|
if (!windowDC) {
|
||||||
|
CAPTURE_LOG("no windowdc");
|
||||||
|
aRequestNewCapture = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
RECT bounds = {0};
|
||||||
|
::GetWindowRect(mChildPluginHWND, &bounds);
|
||||||
|
if ((bounds.left == bounds.right && bounds.top == bounds.bottom) ||
|
||||||
|
(!mWindowSize.width && !mWindowSize.height)) {
|
||||||
|
CAPTURE_LOG("empty bounds");
|
||||||
|
// Lots of null window plugins in content, don't capture.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we need to init mScrollCapture do so, also reset it if the size of the
|
||||||
|
// plugin window changes.
|
||||||
|
if (!mScrollCapture || mScrollCapture->GetSize() != mWindowSize) {
|
||||||
|
mValidFirstCapture = false;
|
||||||
|
mScrollCapture =
|
||||||
|
gfxPlatform::GetPlatform()->CreateOffscreenSurface(mWindowSize,
|
||||||
|
SurfaceFormat::X8R8G8B8_UINT32);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check clipping, we don't want to capture windows that are clipped by
|
||||||
|
// the viewport.
|
||||||
|
RECT clip = {0};
|
||||||
|
int rgnType = ::GetWindowRgnBox(mPluginHWND, &clip);
|
||||||
|
bool clipCorrect = !clip.left && !clip.top &&
|
||||||
|
clip.right == mWindowSize.width &&
|
||||||
|
clip.bottom == mWindowSize.height;
|
||||||
|
|
||||||
|
bool isVisible = ::IsWindowVisible(mChildPluginHWND);
|
||||||
|
|
||||||
|
CAPTURE_LOG("validcap=%d visible=%d region=%d clip=%d:%dx%dx%dx%d",
|
||||||
|
mValidFirstCapture, isVisible, rgnType, clipCorrect
|
||||||
|
clip.left, clip.top, clip.right, clip.bottom);
|
||||||
|
|
||||||
|
// We have a good capture and can't update so keep using the existing
|
||||||
|
// capture image. Otherwise fall through so we paint the fill color to
|
||||||
|
// the layer.
|
||||||
|
if (mValidFirstCapture && (!isVisible || !clipCorrect)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// On Windows we'll need a native bitmap for BitBlt.
|
||||||
|
RefPtr<gfxWindowsSurface> nativeScrollCapture;
|
||||||
|
|
||||||
|
// Copy the plugin window if it's visible and there's no clipping, otherwise
|
||||||
|
// use a default fill color.
|
||||||
|
if (isVisible && clipCorrect) {
|
||||||
|
CAPTURE_LOG("capturing window");
|
||||||
|
nativeScrollCapture =
|
||||||
|
new gfxWindowsSurface(mWindowSize, SurfaceFormat::X8R8G8B8_UINT32);
|
||||||
|
if (!::BitBlt(nativeScrollCapture->GetDC(), 0, 0, mWindowSize.width,
|
||||||
|
mWindowSize.height, windowDC, 0, 0, SRCCOPY)) {
|
||||||
|
CAPTURE_LOG("blt failure??");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
::GdiFlush();
|
||||||
|
mValidFirstCapture = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
IntSize targetSize = mScrollCapture->GetSize();
|
||||||
|
RefPtr<gfx::DrawTarget> dt =
|
||||||
|
gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(mScrollCapture,
|
||||||
|
targetSize);
|
||||||
|
|
||||||
|
if (nativeScrollCapture) {
|
||||||
|
// Copy the native capture image over to a remotable gfx surface.
|
||||||
|
RefPtr<gfx::SourceSurface> sourceSurface =
|
||||||
|
gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(nullptr,
|
||||||
|
nativeScrollCapture);
|
||||||
|
dt->CopySurface(sourceSurface,
|
||||||
|
IntRect(0, 0, targetSize.width, targetSize.height),
|
||||||
|
IntPoint());
|
||||||
|
} else {
|
||||||
|
CAPTURE_LOG("using fill color");
|
||||||
|
dt->FillRect(gfx::Rect(0, 0, targetSize.width, targetSize.height),
|
||||||
|
gfx::ColorPattern(gfx::Color::FromABGR(kScrollCaptureFillColor)),
|
||||||
|
gfx::DrawOptions(1.f, CompositionOp::OP_SOURCE));
|
||||||
|
aRequestNewCapture = true;
|
||||||
|
}
|
||||||
|
dt->Flush();
|
||||||
|
|
||||||
|
// Get a source for mScrollCapture and load it into the image container.
|
||||||
|
RefPtr<gfx::SourceSurface> cachedSource =
|
||||||
|
gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt,
|
||||||
|
mScrollCapture);
|
||||||
|
RefPtr<SourceSurfaceImage> image =
|
||||||
|
new SourceSurfaceImage(cachedSource->GetSize(), cachedSource);
|
||||||
|
|
||||||
|
ImageContainer::NonOwningImage holder(image);
|
||||||
|
holder.mFrameID = ++mFrameID;
|
||||||
|
|
||||||
|
AutoTArray<ImageContainer::NonOwningImage,1> imageList;
|
||||||
|
imageList.AppendElement(holder);
|
||||||
|
|
||||||
|
// inits mImageContainer
|
||||||
|
ImageContainer *container = GetImageContainer();
|
||||||
|
container->SetCurrentImages(imageList);
|
||||||
|
|
||||||
|
// Invalidate our area in the page so the image gets flushed.
|
||||||
|
NPRect nprect = {0, 0, targetSize.width, targetSize.height};
|
||||||
|
RecvNPN_InvalidateRect(nprect);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
PluginInstanceParent::GetScrollCaptureContainer(ImageContainer** aContainer)
|
||||||
|
{
|
||||||
|
if (!aContainer || !::IsWindow(mPluginHWND)) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mImageContainer) {
|
||||||
|
ScheduleScrollCapture(kInitScrollCaptureDelayMs);
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageContainer *container = GetImageContainer();
|
||||||
|
NS_IF_ADDREF(container);
|
||||||
|
*aContainer = container;
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
PluginInstanceParent::UpdateScrollState(bool aIsScrolling)
|
||||||
|
{
|
||||||
|
bool scrollStateChanged = (mIsScrolling != aIsScrolling);
|
||||||
|
mIsScrolling = aIsScrolling;
|
||||||
|
if (scrollStateChanged && !aIsScrolling) {
|
||||||
|
// At the end of a dom scroll operation capturing now will attempt to
|
||||||
|
// capture a window that is still hidden due to the current scroll
|
||||||
|
// operation. (The browser process will update visibility after layer
|
||||||
|
// updates get pushed over.) So we delay our attempt for a bit. This
|
||||||
|
// shouldn't hurt our chances of capturing with APZ scroll since the
|
||||||
|
// delay is short.
|
||||||
|
ScheduleScrollCapture(kScrollCaptureDelayMs);
|
||||||
|
}
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
#endif // XP_WIN
|
||||||
|
|
||||||
PluginAsyncSurrogate*
|
PluginAsyncSurrogate*
|
||||||
PluginInstanceParent::GetAsyncSurrogate()
|
PluginInstanceParent::GetAsyncSurrogate()
|
||||||
{
|
{
|
||||||
@ -1339,6 +1565,9 @@ PluginInstanceParent::NPP_SetWindow(const NPWindow* aWindow)
|
|||||||
window.type = aWindow->type;
|
window.type = aWindow->type;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
mWindowSize.width = window.width;
|
||||||
|
mWindowSize.height = window.height;
|
||||||
|
|
||||||
#if defined(XP_MACOSX)
|
#if defined(XP_MACOSX)
|
||||||
double floatScaleFactor = 1.0;
|
double floatScaleFactor = 1.0;
|
||||||
mNPNIface->getvalue(mNPP, NPNVcontentsScaleFactor, &floatScaleFactor);
|
mNPNIface->getvalue(mNPP, NPNVcontentsScaleFactor, &floatScaleFactor);
|
||||||
@ -1383,6 +1612,12 @@ PluginInstanceParent::NPP_SetWindow(const NPWindow* aWindow)
|
|||||||
}
|
}
|
||||||
|
|
||||||
RecordDrawingModel();
|
RecordDrawingModel();
|
||||||
|
|
||||||
|
#if defined(XP_WIN)
|
||||||
|
if (!mCaptureRefreshTask) {
|
||||||
|
ScheduleScrollCapture(kScrollCaptureDelayMs);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return NPERR_NO_ERROR;
|
return NPERR_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,6 +342,10 @@ public:
|
|||||||
nsresult BeginUpdateBackground(const nsIntRect& aRect,
|
nsresult BeginUpdateBackground(const nsIntRect& aRect,
|
||||||
DrawTarget** aDrawTarget);
|
DrawTarget** aDrawTarget);
|
||||||
nsresult EndUpdateBackground(const nsIntRect& aRect);
|
nsresult EndUpdateBackground(const nsIntRect& aRect);
|
||||||
|
#if defined(XP_WIN)
|
||||||
|
nsresult GetScrollCaptureContainer(mozilla::layers::ImageContainer** aContainer);
|
||||||
|
nsresult UpdateScrollState(bool aIsScrolling);
|
||||||
|
#endif
|
||||||
void DidComposite();
|
void DidComposite();
|
||||||
|
|
||||||
bool IsUsingDirectDrawing();
|
bool IsUsingDirectDrawing();
|
||||||
@ -401,6 +405,7 @@ private:
|
|||||||
bool mIsWhitelistedForShumway;
|
bool mIsWhitelistedForShumway;
|
||||||
NPWindowType mWindowType;
|
NPWindowType mWindowType;
|
||||||
int16_t mDrawingModel;
|
int16_t mDrawingModel;
|
||||||
|
IntSize mWindowSize;
|
||||||
|
|
||||||
// Since plugins may request different drawing models to find a compatible
|
// Since plugins may request different drawing models to find a compatible
|
||||||
// one, we only record the drawing model after a SetWindow call and if the
|
// one, we only record the drawing model after a SetWindow call and if the
|
||||||
@ -465,6 +470,18 @@ private:
|
|||||||
RefPtr<gfxASurface> mBackground;
|
RefPtr<gfxASurface> mBackground;
|
||||||
|
|
||||||
RefPtr<ImageContainer> mImageContainer;
|
RefPtr<ImageContainer> mImageContainer;
|
||||||
|
|
||||||
|
#if defined(XP_WIN)
|
||||||
|
void ScheduleScrollCapture(int aTimeout);
|
||||||
|
void ScheduledUpdateScrollCaptureCallback();
|
||||||
|
bool UpdateScrollCapture(bool& aRequestNewCapture);
|
||||||
|
void CancelScheduledScrollCapture();
|
||||||
|
|
||||||
|
RefPtr<gfxASurface> mScrollCapture;
|
||||||
|
CancelableTask* mCaptureRefreshTask;
|
||||||
|
bool mValidFirstCapture;
|
||||||
|
bool mIsScrolling;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user