mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-27 12:50:09 +00:00
Bug 1252877 Part 2: On Windows capture an image for windowed plugins to be displayed during APZ scroll. r=jimm, r=mattwoodrow
MozReview-Commit-ID: ElE0GD3tLah
This commit is contained in:
parent
b2b638175c
commit
25fe73cb68
@ -47,6 +47,16 @@ parent:
|
||||
* on the chrome side. This is only currently used on Windows.
|
||||
*/
|
||||
sync SetNativeChildWindow(uintptr_t childWindow);
|
||||
|
||||
child:
|
||||
/**
|
||||
* Used to set the ID of a scroll capture container from the parent process,
|
||||
* so that we can create a proxy container in the layer tree.
|
||||
* @param aScrollCaptureId async container ID of the parent container
|
||||
* @param aPluginInstanceId plugin ID on which to set the scroll capture ID
|
||||
*/
|
||||
async SetScrollCaptureId(uint64_t aScrollCaptureId,
|
||||
uintptr_t aPluginInstanceId);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -1372,23 +1372,28 @@ PluginInstanceParent::UpdateScrollCapture(bool& aRequestNewCapture)
|
||||
return true;
|
||||
}
|
||||
|
||||
nsresult
|
||||
PluginInstanceParent::SetScrollCaptureId(uint64_t aScrollCaptureId)
|
||||
{
|
||||
if (aScrollCaptureId == ImageContainer::sInvalidAsyncContainerId) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mImageContainer = new ImageContainer(aScrollCaptureId);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
PluginInstanceParent::GetScrollCaptureContainer(ImageContainer** aContainer)
|
||||
{
|
||||
if (!aContainer || !::IsWindow(mPluginHWND)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (!aContainer || !mImageContainer) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (!mImageContainer) {
|
||||
ScheduleScrollCapture(kInitScrollCaptureDelayMs);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
RefPtr<ImageContainer> container = GetImageContainer();
|
||||
container.forget(aContainer);
|
||||
|
||||
ImageContainer *container = GetImageContainer();
|
||||
NS_IF_ADDREF(container);
|
||||
*aContainer = container;
|
||||
|
||||
return NS_OK;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -331,6 +331,7 @@ public:
|
||||
DrawTarget** aDrawTarget);
|
||||
nsresult EndUpdateBackground(const nsIntRect& aRect);
|
||||
#if defined(XP_WIN)
|
||||
nsresult SetScrollCaptureId(uint64_t aScrollCaptureId);
|
||||
nsresult GetScrollCaptureContainer(mozilla::layers::ImageContainer** aContainer);
|
||||
nsresult UpdateScrollState(bool aIsScrolling);
|
||||
#endif
|
||||
|
@ -12,6 +12,10 @@
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "nsDebug.h"
|
||||
|
||||
#if defined(XP_WIN)
|
||||
#include "mozilla/plugins/PluginInstanceParent.h"
|
||||
#endif
|
||||
|
||||
#define PWLOG(...)
|
||||
//#define PWLOG(...) printf_stderr(__VA_ARGS__)
|
||||
|
||||
@ -31,6 +35,25 @@ PluginWidgetChild::~PluginWidgetChild()
|
||||
MOZ_COUNT_DTOR(PluginWidgetChild);
|
||||
}
|
||||
|
||||
bool
|
||||
PluginWidgetChild::RecvSetScrollCaptureId(const uint64_t& aScrollCaptureId,
|
||||
const uintptr_t& aPluginInstanceId)
|
||||
{
|
||||
#if defined(XP_WIN)
|
||||
PluginInstanceParent* instance =
|
||||
PluginInstanceParent::LookupPluginInstanceByID(aPluginInstanceId);
|
||||
if (instance) {
|
||||
NS_WARN_IF(NS_FAILED(instance->SetScrollCaptureId(aScrollCaptureId)));
|
||||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
MOZ_ASSERT_UNREACHABLE(
|
||||
"PluginWidgetChild::RecvSetScrollCaptureId calls not expected.");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Called by the proxy widget when it is destroyed by layout. Only gets
|
||||
// called once.
|
||||
void
|
||||
|
@ -19,6 +19,9 @@ public:
|
||||
PluginWidgetChild();
|
||||
virtual ~PluginWidgetChild();
|
||||
|
||||
bool RecvSetScrollCaptureId(const uint64_t& aScrollCaptureId,
|
||||
const uintptr_t& aPluginInstanceId) override;
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
void SetWidget(mozilla::widget::PluginWidgetProxy* aWidget) {
|
||||
|
@ -143,6 +143,11 @@ PluginWidgetParent::RecvCreate(nsresult* aResult)
|
||||
mozilla::dom::kPluginWidgetContentParentProperty,
|
||||
GetTabParent()->Manager()->AsContentParent());
|
||||
NS_ASSERTION(winres, "SetPropW call failure");
|
||||
|
||||
uint64_t scrollCaptureId = mWidget->CreateScrollCaptureContainer();
|
||||
uintptr_t pluginId =
|
||||
reinterpret_cast<uintptr_t>(mWidget->GetNativeData(NS_NATIVE_PLUGIN_ID));
|
||||
Unused << SendSetScrollCaptureId(scrollCaptureId, pluginId);
|
||||
#endif
|
||||
|
||||
// This is a special call we make to nsBaseWidget to register this
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "mozilla/unused.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#if defined(XP_WIN)
|
||||
#include "mozilla/layers/ImageBridgeChild.h"
|
||||
#include "WinUtils.h"
|
||||
#endif
|
||||
#include "mozilla/widget/CompositorWidget.h"
|
||||
@ -425,6 +426,35 @@ CompositorBridgeChild::RecvUpdatePluginConfigurations(const LayoutDeviceIntPoint
|
||||
#endif // !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK)
|
||||
}
|
||||
|
||||
#if defined(XP_WIN)
|
||||
static void
|
||||
ScheduleSendAllPluginsCaptured(CompositorBridgeChild* aThis, MessageLoop* aLoop)
|
||||
{
|
||||
aLoop->PostTask(NewNonOwningRunnableMethod(
|
||||
aThis, &CompositorBridgeChild::SendAllPluginsCaptured));
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
CompositorBridgeChild::RecvCaptureAllPlugins(const uintptr_t& aParentWidget)
|
||||
{
|
||||
#if defined(XP_WIN)
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
nsIWidget::CaptureRegisteredPlugins(aParentWidget);
|
||||
|
||||
// Bounce the call to SendAllPluginsCaptured off the ImageBridgeChild loop,
|
||||
// to make sure that the image updates on that thread have been processed.
|
||||
ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(
|
||||
NewRunnableFunction(&ScheduleSendAllPluginsCaptured, this,
|
||||
MessageLoop::current()));
|
||||
return true;
|
||||
#else
|
||||
MOZ_ASSERT_UNREACHABLE(
|
||||
"CompositorBridgeChild::RecvCaptureAllPlugins calls unexpected.");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
CompositorBridgeChild::RecvHideAllPlugins(const uintptr_t& aParentWidget)
|
||||
{
|
||||
@ -436,9 +466,7 @@ CompositorBridgeChild::RecvHideAllPlugins(const uintptr_t& aParentWidget)
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
nsTArray<uintptr_t> list;
|
||||
nsIWidget::UpdateRegisteredPluginWindowVisibility(aParentWidget, list);
|
||||
#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
|
||||
SendRemotePluginsReady();
|
||||
#endif
|
||||
return true;
|
||||
#endif // !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK)
|
||||
}
|
||||
|
@ -109,6 +109,9 @@ public:
|
||||
const LayoutDeviceIntRegion& aVisibleRegion,
|
||||
nsTArray<PluginWindowData>&& aPlugins) override;
|
||||
|
||||
virtual bool
|
||||
RecvCaptureAllPlugins(const uintptr_t& aParentWidget) override;
|
||||
|
||||
virtual bool
|
||||
RecvHideAllPlugins(const uintptr_t& aParentWidget) override;
|
||||
|
||||
|
@ -1973,6 +1973,8 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool RecvAllPluginsCaptured() override { return true; }
|
||||
|
||||
virtual bool RecvGetTileSize(int32_t* aWidth, int32_t* aHeight) override
|
||||
{
|
||||
*aWidth = gfxPlatform::GetPlatform()->GetTileWidth();
|
||||
@ -2638,11 +2640,30 @@ CompositorBridgeParent::HideAllPluginWindows()
|
||||
|
||||
mDeferPluginWindows = true;
|
||||
mPluginWindowsHidden = true;
|
||||
|
||||
#if defined(XP_WIN)
|
||||
// We will get an async reply that this has happened and then send hide.
|
||||
Unused << SendCaptureAllPlugins(parentWidget);
|
||||
#else
|
||||
Unused << SendHideAllPlugins(parentWidget);
|
||||
ScheduleComposition();
|
||||
#endif
|
||||
}
|
||||
#endif // #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
|
||||
|
||||
bool
|
||||
CompositorBridgeParent::RecvAllPluginsCaptured()
|
||||
{
|
||||
#if defined(XP_WIN)
|
||||
ForceComposeToTarget(nullptr);
|
||||
Unused << SendHideAllPlugins(GetWidget()->GetWidgetKey());
|
||||
return true;
|
||||
#else
|
||||
MOZ_ASSERT_UNREACHABLE(
|
||||
"CompositorBridgeParent::RecvAllPluginsCaptured calls unexpected.");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
void
|
||||
CrossProcessCompositorBridgeParent::DidComposite(
|
||||
uint64_t aId,
|
||||
|
@ -269,6 +269,8 @@ public:
|
||||
const ScrollableLayerGuid& aGuid,
|
||||
const CSSIntRegion& aRegion);
|
||||
|
||||
virtual bool RecvAllPluginsCaptured() override;
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason why) override;
|
||||
|
||||
virtual void ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
|
||||
|
@ -91,6 +91,13 @@ child:
|
||||
LayoutDeviceIntRegion aVisibleRegion,
|
||||
PluginWindowData[] aPlugins);
|
||||
|
||||
/**
|
||||
* Captures an image for all visible child plugins of a given widget for use
|
||||
* during scrolling.
|
||||
* @param aParentWidget parent of widgets to be captured
|
||||
*/
|
||||
async CaptureAllPlugins(uintptr_t aParentWidget);
|
||||
|
||||
/**
|
||||
* Hides all registered plugin widgets associated with a particular chrome
|
||||
* widget.
|
||||
@ -203,6 +210,11 @@ parent:
|
||||
ScrollableLayerGuid guid,
|
||||
CSSIntRegion region);
|
||||
|
||||
/**
|
||||
* Sent when the child has finished CaptureAllPlugins.
|
||||
*/
|
||||
async AllPluginsCaptured();
|
||||
|
||||
async PTexture(SurfaceDescriptor aSharedData, LayersBackend aBackend, TextureFlags aTextureFlags, uint64_t id, uint64_t aSerial);
|
||||
|
||||
child:
|
||||
|
@ -522,6 +522,11 @@ NS_METHOD nsBaseWidget::Destroy()
|
||||
parent->RemoveChild(this);
|
||||
}
|
||||
|
||||
#if defined(XP_WIN)
|
||||
// Allow our scroll capture container to be cleaned up, if we have one.
|
||||
mScrollCaptureContainer = nullptr;
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -2144,6 +2149,81 @@ nsIWidget::UpdateRegisteredPluginWindowVisibility(uintptr_t aOwnerWidget,
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(XP_WIN)
|
||||
// static
|
||||
void
|
||||
nsIWidget::CaptureRegisteredPlugins(uintptr_t aOwnerWidget)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(sPluginWidgetList);
|
||||
|
||||
// Our visible list is associated with a compositor which is associated with
|
||||
// a specific top level window. We use the parent widget during iteration
|
||||
// to skip the plugin widgets owned by other top level windows.
|
||||
for (auto iter = sPluginWidgetList->Iter(); !iter.Done(); iter.Next()) {
|
||||
const void* windowId = iter.Key();
|
||||
nsIWidget* widget = iter.UserData();
|
||||
|
||||
MOZ_ASSERT(windowId);
|
||||
MOZ_ASSERT(widget);
|
||||
|
||||
if (!widget->Destroyed() && widget->IsVisible()) {
|
||||
if ((uintptr_t)widget->GetParent() == aOwnerWidget) {
|
||||
widget->UpdateScrollCapture();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t
|
||||
nsBaseWidget::CreateScrollCaptureContainer()
|
||||
{
|
||||
mScrollCaptureContainer =
|
||||
LayerManager::CreateImageContainer(ImageContainer::ASYNCHRONOUS);
|
||||
if (!mScrollCaptureContainer) {
|
||||
NS_WARNING("Failed to create ImageContainer for widget image capture.");
|
||||
return ImageContainer::sInvalidAsyncContainerId;
|
||||
}
|
||||
|
||||
return mScrollCaptureContainer->GetAsyncContainerID();
|
||||
}
|
||||
|
||||
void
|
||||
nsBaseWidget::UpdateScrollCapture()
|
||||
{
|
||||
// Don't capture if no container or no size.
|
||||
if (!mScrollCaptureContainer || mBounds.width <= 0 || mBounds.height <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the derived class cannot take a snapshot, for example due to clipping,
|
||||
// then it is responsible for creating a fallback. If null is returned, this
|
||||
// means that we want to keep the existing snapshot.
|
||||
RefPtr<gfx::SourceSurface> snapshot = CreateScrollSnapshot();
|
||||
if (!snapshot) {
|
||||
return;
|
||||
}
|
||||
|
||||
ImageContainer::NonOwningImage holder(new SourceSurfaceImage(snapshot));
|
||||
|
||||
AutoTArray<ImageContainer::NonOwningImage, 1> imageList;
|
||||
imageList.AppendElement(holder);
|
||||
|
||||
mScrollCaptureContainer->SetCurrentImages(imageList);
|
||||
}
|
||||
|
||||
void
|
||||
nsBaseWidget::DefaultFillScrollCapture(DrawTarget* aSnapshotDrawTarget)
|
||||
{
|
||||
gfx::IntSize dtSize = aSnapshotDrawTarget->GetSize();
|
||||
aSnapshotDrawTarget->FillRect(
|
||||
gfx::Rect(0, 0, dtSize.width, dtSize.height),
|
||||
gfx::ColorPattern(gfx::Color::FromABGR(kScrollCaptureFillColor)),
|
||||
gfx::DrawOptions(1.f, gfx::CompositionOp::OP_SOURCE));
|
||||
aSnapshotDrawTarget->Flush();
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_IMETHODIMP_(nsIWidget::NativeIMEContext)
|
||||
nsIWidget::GetNativeIMEContext()
|
||||
{
|
||||
|
@ -22,6 +22,14 @@
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include <algorithm>
|
||||
|
||||
#if defined(XP_WIN)
|
||||
// Scroll capture constants
|
||||
const uint32_t kScrollCaptureFillColor = 0xFFa0a0a0; // gray
|
||||
const mozilla::gfx::SurfaceFormat kScrollCaptureFormat =
|
||||
mozilla::gfx::SurfaceFormat::X8R8G8B8_UINT32;
|
||||
#endif
|
||||
|
||||
class nsIContent;
|
||||
class nsAutoRollup;
|
||||
class gfxContext;
|
||||
@ -36,6 +44,7 @@ class Accessible;
|
||||
|
||||
namespace gfx {
|
||||
class DrawTarget;
|
||||
class SourceSurface;
|
||||
} // namespace gfx
|
||||
|
||||
namespace layers {
|
||||
@ -46,6 +55,7 @@ class APZCTreeManager;
|
||||
class GeckoContentController;
|
||||
class APZEventState;
|
||||
class CompositorSession;
|
||||
class ImageContainer;
|
||||
struct ScrollableLayerGuid;
|
||||
} // namespace layers
|
||||
|
||||
@ -104,6 +114,7 @@ class nsBaseWidget : public nsIWidget, public nsSupportsWeakReference
|
||||
protected:
|
||||
typedef base::Thread Thread;
|
||||
typedef mozilla::gfx::DrawTarget DrawTarget;
|
||||
typedef mozilla::gfx::SourceSurface SourceSurface;
|
||||
typedef mozilla::layers::BasicLayerManager BasicLayerManager;
|
||||
typedef mozilla::layers::BufferMode BufferMode;
|
||||
typedef mozilla::layers::CompositorBridgeChild CompositorBridgeChild;
|
||||
@ -118,6 +129,7 @@ protected:
|
||||
typedef mozilla::ScreenRotation ScreenRotation;
|
||||
typedef mozilla::widget::CompositorWidgetDelegate CompositorWidgetDelegate;
|
||||
typedef mozilla::layers::CompositorSession CompositorSession;
|
||||
typedef mozilla::layers::ImageContainer ImageContainer;
|
||||
|
||||
virtual ~nsBaseWidget();
|
||||
|
||||
@ -354,6 +366,10 @@ public:
|
||||
|
||||
void Shutdown();
|
||||
|
||||
#if defined(XP_WIN)
|
||||
uint64_t CreateScrollCaptureContainer() override;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// These are methods for CompositorWidgetWrapper, and should only be
|
||||
// accessed from that class. Derived widgets can choose which methods to
|
||||
@ -542,6 +558,29 @@ protected:
|
||||
|
||||
bool UseAPZ();
|
||||
|
||||
|
||||
#if defined(XP_WIN)
|
||||
void UpdateScrollCapture() override;
|
||||
|
||||
/**
|
||||
* To be overridden by derived classes to return a snapshot that can be used
|
||||
* during scrolling. Returning null means we won't update the container.
|
||||
* @return an already AddRefed SourceSurface containing the snapshot
|
||||
*/
|
||||
virtual already_AddRefed<SourceSurface> CreateScrollSnapshot()
|
||||
{
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
/**
|
||||
* Used by derived classes to create a fallback scroll image.
|
||||
* @param aSnapshotDrawTarget DrawTarget to fill with fallback image.
|
||||
*/
|
||||
void DefaultFillScrollCapture(DrawTarget* aSnapshotDrawTarget);
|
||||
|
||||
RefPtr<ImageContainer> mScrollCaptureContainer;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// Returns whether compositing should use an external surface size.
|
||||
virtual bool UseExternalCompositingSurface() const {
|
||||
|
@ -1085,6 +1085,28 @@ class nsIWidget : public nsISupports
|
||||
static void UpdateRegisteredPluginWindowVisibility(uintptr_t aOwnerWidget,
|
||||
nsTArray<uintptr_t>& aPluginIds);
|
||||
|
||||
#if defined(XP_WIN)
|
||||
/**
|
||||
* Iterates over the list of registered plugins and for any that are owned
|
||||
* by aOwnerWidget and visible it takes a snapshot.
|
||||
*
|
||||
* @param aOwnerWidget only captures visible widgets owned by this
|
||||
*/
|
||||
static void CaptureRegisteredPlugins(uintptr_t aOwnerWidget);
|
||||
|
||||
/**
|
||||
* Take a scroll capture for this widget if possible.
|
||||
*/
|
||||
virtual void UpdateScrollCapture() = 0;
|
||||
|
||||
/**
|
||||
* Creates an async ImageContainer to hold scroll capture images that can be
|
||||
* used if the plugin is hidden during scroll.
|
||||
* @return the async container ID of the created ImageContainer.
|
||||
*/
|
||||
virtual uint64_t CreateScrollCaptureContainer() = 0;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Set the shadow style of the window.
|
||||
*
|
||||
|
@ -188,6 +188,11 @@
|
||||
|
||||
#include "InkCollector.h"
|
||||
|
||||
// ERROR from wingdi.h (below) gets undefined by some code.
|
||||
// #define ERROR 0
|
||||
// #define RGN_ERROR ERROR
|
||||
#define ERROR 0
|
||||
|
||||
#if !defined(SM_CONVERTIBLESLATEMODE)
|
||||
#define SM_CONVERTIBLESLATEMODE 0x2003
|
||||
#endif
|
||||
@ -1181,6 +1186,107 @@ nsWindow::EnumAllWindows(WindowEnumCallback aCallback)
|
||||
(LPARAM)aCallback);
|
||||
}
|
||||
|
||||
static already_AddRefed<SourceSurface>
|
||||
CreateSourceSurfaceForGfxSurface(gfxASurface* aSurface)
|
||||
{
|
||||
MOZ_ASSERT(aSurface);
|
||||
return Factory::CreateSourceSurfaceForCairoSurface(
|
||||
aSurface->CairoSurface(), aSurface->GetSize(),
|
||||
aSurface->GetSurfaceFormat());
|
||||
}
|
||||
|
||||
nsWindow::ScrollSnapshot*
|
||||
nsWindow::EnsureSnapshotSurface(ScrollSnapshot& aSnapshotData,
|
||||
const mozilla::gfx::IntSize& aSize)
|
||||
{
|
||||
// If the surface doesn't exist or is the wrong size then create new one.
|
||||
if (!aSnapshotData.surface || aSnapshotData.surface->GetSize() != aSize) {
|
||||
aSnapshotData.surface = new gfxWindowsSurface(aSize, kScrollCaptureFormat);
|
||||
aSnapshotData.surfaceHasSnapshot = false;
|
||||
}
|
||||
|
||||
return &aSnapshotData;
|
||||
}
|
||||
|
||||
already_AddRefed<SourceSurface>
|
||||
nsWindow::CreateScrollSnapshot()
|
||||
{
|
||||
RECT clip = { 0 };
|
||||
int rgnType = ::GetWindowRgnBox(mWnd, &clip);
|
||||
if (rgnType == RGN_ERROR) {
|
||||
// We failed to get the clip assume that we need a full fallback.
|
||||
clip.left = 0;
|
||||
clip.top = 0;
|
||||
clip.right = mBounds.width;
|
||||
clip.bottom = mBounds.height;
|
||||
return GetFallbackScrollSnapshot(clip);
|
||||
}
|
||||
|
||||
// Check that the window is in a position to snapshot. We don't check for
|
||||
// clipped width as that doesn't currently matter for APZ scrolling.
|
||||
if (clip.top || clip.bottom != mBounds.height) {
|
||||
return GetFallbackScrollSnapshot(clip);
|
||||
}
|
||||
|
||||
nsAutoHDC windowDC(::GetDC(mWnd));
|
||||
if (!windowDC) {
|
||||
return GetFallbackScrollSnapshot(clip);
|
||||
}
|
||||
|
||||
gfx::IntSize snapshotSize(mBounds.width, mBounds.height);
|
||||
ScrollSnapshot* snapshot;
|
||||
if (clip.left || clip.right != mBounds.width) {
|
||||
// Can't do a full snapshot, so use the partial snapshot.
|
||||
snapshot = EnsureSnapshotSurface(mPartialSnapshot, snapshotSize);
|
||||
} else {
|
||||
snapshot = EnsureSnapshotSurface(mFullSnapshot, snapshotSize);
|
||||
}
|
||||
|
||||
// Note that we know that the clip is full height.
|
||||
if (!::BitBlt(snapshot->surface->GetDC(), clip.left, 0, clip.right - clip.left,
|
||||
clip.bottom, windowDC, clip.left, 0, SRCCOPY)) {
|
||||
return GetFallbackScrollSnapshot(clip);
|
||||
}
|
||||
::GdiFlush();
|
||||
snapshot->surface->Flush();
|
||||
snapshot->surfaceHasSnapshot = true;
|
||||
snapshot->clip = clip;
|
||||
mCurrentSnapshot = snapshot;
|
||||
|
||||
return CreateSourceSurfaceForGfxSurface(mCurrentSnapshot->surface);
|
||||
}
|
||||
|
||||
already_AddRefed<SourceSurface>
|
||||
nsWindow::GetFallbackScrollSnapshot(const RECT& aRequiredClip)
|
||||
{
|
||||
gfx::IntSize snapshotSize(mBounds.width, mBounds.height);
|
||||
|
||||
// If the current snapshot is the correct size and covers the required clip,
|
||||
// just keep that by returning null.
|
||||
// Note: we know the clip is always full height.
|
||||
if (mCurrentSnapshot &&
|
||||
mCurrentSnapshot->surface->GetSize() == snapshotSize &&
|
||||
mCurrentSnapshot->clip.left <= aRequiredClip.left &&
|
||||
mCurrentSnapshot->clip.right >= aRequiredClip.right) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Otherwise we'll use the full snapshot, making sure it is big enough first.
|
||||
mCurrentSnapshot = EnsureSnapshotSurface(mFullSnapshot, snapshotSize);
|
||||
|
||||
// If there is no snapshot, create a default.
|
||||
if (!mCurrentSnapshot->surfaceHasSnapshot) {
|
||||
gfx::SurfaceFormat format = mCurrentSnapshot->surface->GetSurfaceFormat();
|
||||
RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForCairoSurface(
|
||||
mCurrentSnapshot->surface->CairoSurface(),
|
||||
mCurrentSnapshot->surface->GetSize(), &format);
|
||||
|
||||
DefaultFillScrollCapture(dt);
|
||||
}
|
||||
|
||||
return CreateSourceSurfaceForGfxSurface(mCurrentSnapshot->surface);
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
*
|
||||
* SECTION: nsIWidget::Show
|
||||
|
@ -487,6 +487,25 @@ protected:
|
||||
void ClearCachedResources();
|
||||
nsIWidgetListener* GetPaintListener();
|
||||
|
||||
already_AddRefed<SourceSurface> CreateScrollSnapshot() override;
|
||||
|
||||
struct ScrollSnapshot
|
||||
{
|
||||
RefPtr<gfxWindowsSurface> surface;
|
||||
bool surfaceHasSnapshot = false;
|
||||
RECT clip;
|
||||
};
|
||||
|
||||
ScrollSnapshot* EnsureSnapshotSurface(ScrollSnapshot& aSnapshotData,
|
||||
const mozilla::gfx::IntSize& aSize);
|
||||
|
||||
ScrollSnapshot mFullSnapshot;
|
||||
ScrollSnapshot mPartialSnapshot;
|
||||
ScrollSnapshot* mCurrentSnapshot = nullptr;
|
||||
|
||||
already_AddRefed<SourceSurface>
|
||||
GetFallbackScrollSnapshot(const RECT& aRequiredClip);
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIWidget> mParent;
|
||||
nsIntSize mLastSize;
|
||||
|
Loading…
x
Reference in New Issue
Block a user