Bug 626602. Part 3: Hook up ReadbackLayers in nsObjectFrame. r=cjones

This commit is contained in:
Robert O'Callahan 2011-02-16 16:43:30 -06:00
Родитель 1619ca83d2
Коммит ac0601703a
3 изменённых файлов: 242 добавлений и 46 удалений

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

@ -78,6 +78,7 @@ enum Type {
TYPE_PAGE_CONTENT,
TYPE_PAGE_SEQUENCE,
TYPE_PLUGIN,
TYPE_PLUGIN_READBACK,
TYPE_PRINT_PREVIEW_BACKGROUND,
TYPE_PRINT_PLUGIN,
TYPE_REMOTE,

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

@ -164,6 +164,7 @@ enum { XKeyPress = KeyPress };
#include "gfxImageSurface.h"
#include "gfxUtils.h"
#include "Layers.h"
#include "ReadbackLayer.h"
// accessibility support
#ifdef ACCESSIBILITY
@ -238,6 +239,8 @@ static PRLogModuleInfo *nsObjectFrameLM = PR_NewLogModule("nsObjectFrame");
#define MAC_CARBON_PLUGINS
#endif
using namespace mozilla;
using namespace mozilla::plugins;
using namespace mozilla::layers;
// special class for handeling DOM context menu events because for
@ -467,6 +470,11 @@ public:
// Return true if we set image with valid surface
PRBool SetCurrentImage(ImageContainer* aContainer);
// Methods to update the background image we send to async plugins
void SetBackgroundUnknown() {}
already_AddRefed<gfxContext> BeginUpdateBackground(const nsIntRect& aRect) { return nsnull; }
void EndUpdateBackground(gfxContext* aContext, const nsIntRect& aRect) {}
PRBool UseAsyncRendering()
{
PRBool useAsyncRendering;
@ -624,6 +632,53 @@ private:
PRPackedBool mWaitingForPaint;
};
class PluginBackgroundSink : public ReadbackSink {
public:
PluginBackgroundSink(nsObjectFrame* aFrame, PRUint64 aStartSequenceNumber)
: mLastSequenceNumber(aStartSequenceNumber), mFrame(aFrame) {}
~PluginBackgroundSink()
{
if (mFrame) {
mFrame->mBackgroundSink = nsnull;
}
}
virtual void SetUnknown(PRUint64 aSequenceNumber)
{
if (!AcceptUpdate(aSequenceNumber))
return;
mFrame->mInstanceOwner->SetBackgroundUnknown();
}
virtual already_AddRefed<gfxContext>
BeginUpdate(const nsIntRect& aRect, PRUint64 aSequenceNumber)
{
if (!AcceptUpdate(aSequenceNumber))
return nsnull;
return mFrame->mInstanceOwner->BeginUpdateBackground(aRect);
}
virtual void EndUpdate(gfxContext* aContext, const nsIntRect& aRect)
{
return mFrame->mInstanceOwner->EndUpdateBackground(aContext, aRect);
}
void Destroy() { mFrame = nsnull; }
protected:
PRBool AcceptUpdate(PRUint64 aSequenceNumber) {
if (aSequenceNumber > mLastSequenceNumber && mFrame &&
mFrame->mInstanceOwner) {
mLastSequenceNumber = aSequenceNumber;
return PR_TRUE;
}
return PR_FALSE;
}
PRUint64 mLastSequenceNumber;
nsObjectFrame* mFrame;
};
// Mac specific code to fix up port position and clip
#ifdef XP_MACOSX
@ -669,7 +724,6 @@ NS_IMETHODIMP nsObjectFrame::GetPluginPort(HWND *aPort)
#endif
#endif
static NS_DEFINE_CID(kWidgetCID, NS_CHILD_CID);
NS_IMETHODIMP
@ -707,6 +761,10 @@ nsObjectFrame::DestroyFrom(nsIFrame* aDestructRoot)
mWidget->Destroy();
}
if (mBackgroundSink) {
mBackgroundSink->Destroy();
}
nsObjectFrameSuper::DestroyFrom(aDestructRoot);
}
@ -1277,20 +1335,56 @@ nsObjectFrame::PaintPrintPlugin(nsIFrame* aFrame, nsIRenderingContext* aCtx,
static_cast<nsObjectFrame*>(aFrame)->PrintPlugin(*aCtx, aDirtyRect);
}
nsRect
nsDisplayPlugin::GetBounds(nsDisplayListBuilder* aBuilder)
{
nsRect r = mFrame->GetContentRect() - mFrame->GetPosition() +
ToReferenceFrame();
if (aBuilder->IsForPluginGeometry()) {
// Return the geometry we want, not the geometry we have (which is based
// on the surface the plugin last gave us)
return r;
class nsDisplayPluginReadback : public nsDisplayItem {
public:
nsDisplayPluginReadback(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
: nsDisplayItem(aBuilder, aFrame)
{
MOZ_COUNT_CTOR(nsDisplayPluginReadback);
}
#ifdef NS_BUILD_REFCNT_LOGGING
virtual ~nsDisplayPluginReadback() {
MOZ_COUNT_DTOR(nsDisplayPluginReadback);
}
#endif
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder);
virtual PRBool ComputeVisibility(nsDisplayListBuilder* aBuilder,
nsRegion* aVisibleRegion,
PRBool& aContainsRootContentDocBG);
NS_DISPLAY_DECL_NAME("PluginReadback", TYPE_PLUGIN_READBACK)
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager)
{
return static_cast<nsObjectFrame*>(mFrame)->BuildLayer(aBuilder, aManager, this);
}
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager)
{
return LAYER_ACTIVE;
}
};
static nsRect
GetDesiredDisplayItemBounds(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem, nsIFrame* aFrame)
{
nsRect r = aFrame->GetContentRect() - aFrame->GetPosition() +
aItem->ToReferenceFrame();
return r;
}
static nsRect
GetDrawnDisplayItemBounds(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem, nsIFrame* aFrame)
{
nsRect r = aFrame->GetContentRect() - aFrame->GetPosition() +
aItem->ToReferenceFrame();
#ifndef XP_MACOSX
nsObjectFrame* f = static_cast<nsObjectFrame*>(mFrame);
if (mozilla::LAYER_ACTIVE == f->GetLayerState(aBuilder, nsnull)) {
nsObjectFrame* f = static_cast<nsObjectFrame*>(aFrame);
if (LAYER_ACTIVE == f->GetLayerState(aBuilder, nsnull)) {
ImageContainer* c = f->GetImageContainer();
if (c) {
gfxIntSize size = c->GetCurrentSize();
@ -1305,6 +1399,40 @@ nsDisplayPlugin::GetBounds(nsDisplayListBuilder* aBuilder)
return r;
}
nsRect
nsDisplayPluginReadback::GetBounds(nsDisplayListBuilder* aBuilder)
{
return GetDesiredDisplayItemBounds(aBuilder, this, mFrame);
}
PRBool
nsDisplayPluginReadback::ComputeVisibility(nsDisplayListBuilder* aBuilder,
nsRegion* aVisibleRegion,
PRBool& aContainsRootContentDocBG)
{
if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion, aContainsRootContentDocBG))
return PR_FALSE;
// *Add* our bounds to the visible region so that stuff underneath us is
// likely to be made visible, so we can use it for a background! This is
// a bit crazy since we normally only subtract from the visible region.
aVisibleRegion->Or(*aVisibleRegion, GetBounds(aBuilder));
return PR_TRUE;
}
nsRect
nsDisplayPlugin::GetBounds(nsDisplayListBuilder* aBuilder)
{
// We use display lists to notify plugins of visibility. But we
// also need to return the "real" visible bounds, possibly those of
// our Image, when actually painting. Usually those will be the
// same, but for the plugin to paint initially, something needs to
// notify it that it's visible. So return whichever the appropriate
// rect here.
return aBuilder->IsForPluginGeometry() ?
GetDesiredDisplayItemBounds(aBuilder, this, mFrame) :
GetDrawnDisplayItemBounds(aBuilder, this, mFrame);
}
void
nsDisplayPlugin::Paint(nsDisplayListBuilder* aBuilder,
nsIRenderingContext* aCtx)
@ -1455,6 +1583,18 @@ PRBool
nsObjectFrame::IsOpaque() const
{
#if defined(XP_MACOSX)
// ???
return PR_FALSE;
#else
return !IsTransparentMode();
#endif
}
PRBool
nsObjectFrame::IsTransparentMode() const
{
#if defined(XP_MACOSX)
// ???
return PR_FALSE;
#else
if (!mInstanceOwner)
@ -1463,7 +1603,7 @@ nsObjectFrame::IsOpaque() const
NPWindow *window;
mInstanceOwner->GetWindow(window);
if (window->type != NPWindowTypeDrawable)
return PR_TRUE;
return PR_FALSE;
nsresult rv;
nsCOMPtr<nsIPluginInstance> pi;
@ -1473,7 +1613,7 @@ nsObjectFrame::IsOpaque() const
PRBool transparent = PR_FALSE;
pi->IsTransparent(&transparent);
return !transparent;
return transparent;
#endif
}
@ -1482,10 +1622,12 @@ nsObjectFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists)
{
AddStateBits(NS_OBJECT_NEEDS_SET_IMAGE);
// XXX why are we painting collapsed object frames?
if (!IsVisibleOrCollapsedForPainting(aBuilder))
return NS_OK;
nsresult rv = DisplayBorderBackgroundOutline(aBuilder, aLists);
NS_ENSURE_SUCCESS(rv, rv);
@ -1530,6 +1672,14 @@ nsObjectFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
nsDisplayGeneric(aBuilder, this, PaintPrintPlugin, "PrintPlugin",
nsDisplayItem::TYPE_PRINT_PLUGIN));
} else {
if (aBuilder->IsPaintingToWindow() &&
GetLayerState(aBuilder, nsnull) == LAYER_ACTIVE &&
IsTransparentMode()) {
rv = replacedContent.AppendNewToTop(new (aBuilder)
nsDisplayPluginReadback(aBuilder, this));
NS_ENSURE_SUCCESS(rv, rv);
}
rv = replacedContent.AppendNewToTop(new (aBuilder)
nsDisplayPlugin(aBuilder, this));
}
@ -1831,7 +1981,8 @@ nsObjectFrame::GetLayerState(nsDisplayListBuilder* aBuilder,
return mozilla::LAYER_NONE;
#ifdef XP_MACOSX
if (aManager->GetBackendType() == LayerManager::LAYERS_OPENGL &&
if (aManager &&
aManager->GetBackendType() == LayerManager::LAYERS_OPENGL &&
mInstanceOwner->GetEventModel() == NPEventModelCocoa &&
mInstanceOwner->GetDrawingModel() == NPDrawingModelCoreGraphics &&
mInstanceOwner->IsRemoteDrawingCoreAnimation())
@ -1862,6 +2013,18 @@ nsObjectFrame::BuildLayer(nsDisplayListBuilder* aBuilder,
if (window->width <= 0 || window->height <= 0)
return nsnull;
// Create image
nsRefPtr<ImageContainer> container = GetImageContainer(aManager);
if (!container)
return nsnull;
if (GetStateBits() & NS_OBJECT_NEEDS_SET_IMAGE) {
RemoveStateBits(NS_OBJECT_NEEDS_SET_IMAGE);
if (!mInstanceOwner->SetCurrentImage(container)) {
return nsnull;
}
}
gfxIntSize size = container->GetCurrentSize();
nsRect area = GetContentRect() + aBuilder->ToReferenceFrame(GetParent());
gfxRect r = nsLayoutUtils::RectToGfxRect(area, PresContext()->AppUnitsPerDevPixel());
// to provide crisper and faster drawing.
@ -1869,49 +2032,66 @@ nsObjectFrame::BuildLayer(nsDisplayListBuilder* aBuilder,
nsRefPtr<Layer> layer =
(aBuilder->LayerBuilder()->GetLeafLayerFor(aBuilder, aManager, aItem));
if (!layer) {
if (mInstanceOwner->UseAsyncRendering()) {
if (aItem->GetType() == nsDisplayItem::TYPE_PLUGIN) {
if (!layer) {
mInstanceOwner->NotifyPaintWaiter(aBuilder);
// Initialize ImageLayer
layer = aManager->CreateImageLayer();
if (!layer)
return nsnull;
}
// Initialize ImageLayer
layer = aManager->CreateImageLayer();
}
if (!layer)
return nsnull;
#ifdef XP_MACOSX
// Until we get async plugins on mac we need to manually trigger the DrawRect event
mInstanceOwner->DoCocoaEventDrawRect(r, nsnull);
// Until we get async plugins on mac we need to manually trigger the DrawRect event
mInstanceOwner->DoCocoaEventDrawRect(r, nsnull);
#endif
NS_ASSERTION(layer->GetType() == Layer::TYPE_IMAGE, "ObjectFrame works only with ImageLayer");
// Create image
nsRefPtr<ImageContainer> container = GetImageContainer(aManager);
if (!container)
return nsnull;
NS_ASSERTION(layer->GetType() == Layer::TYPE_IMAGE, "Bad layer type");
if (!mInstanceOwner->SetCurrentImage(container)) {
return nsnull;
ImageLayer* imglayer = static_cast<ImageLayer*>(layer.get());
imglayer->SetContainer(container);
imglayer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(this));
layer->SetContentFlags(IsOpaque() ? Layer::CONTENT_OPAQUE : 0);
} else {
NS_ASSERTION(aItem->GetType() == nsDisplayItem::TYPE_PLUGIN_READBACK,
"Unknown item type");
NS_ABORT_IF_FALSE(!IsOpaque(), "Opaque plugins don't use backgrounds");
if (!layer) {
layer = aManager->CreateReadbackLayer();
if (!layer)
return nsnull;
}
NS_ASSERTION(layer->GetType() == Layer::TYPE_READBACK, "Bad layer type");
ReadbackLayer* readback = static_cast<ReadbackLayer*>(layer.get());
if (readback->GetSize() != nsIntSize(size.width, size.height)) {
// This will destroy any old background sink and notify us that the
// background is now unknown
readback->SetSink(nsnull);
NS_ASSERTION(!mBackgroundSink, "Should have been cleared");
readback->SetSize(nsIntSize(size.width, size.height));
mBackgroundSink =
new PluginBackgroundSink(this,
readback->AllocateSequenceNumber());
readback->SetSink(mBackgroundSink);
// The layer has taken ownership of our sink. When either the sink dies
// or the frame dies, the connection from the surviving object is nulled out.
}
}
ImageLayer* imglayer = static_cast<ImageLayer*>(layer.get());
imglayer->SetContainer(container);
imglayer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(this));
layer->SetContentFlags(IsOpaque() ? Layer::CONTENT_OPAQUE : 0);
// Set a transform on the layer to draw the plugin in the right place
gfxMatrix transform;
// Center plugin if layer size != frame rect
r.pos.x += (r.Width() - container->GetCurrentSize().width) / 2;
r.pos.y += (r.Height() - container->GetCurrentSize().height) / 2;
r.pos.x += (r.Width() - size.width) / 2;
r.pos.y += (r.Height() - size.height) / 2;
transform.Translate(r.pos);
layer->SetTransform(gfx3DMatrix::From2D(transform));
nsRefPtr<Layer> result = layer.forget();
return result.forget();
return layer.forget();
}
void
@ -2076,7 +2256,7 @@ nsObjectFrame::PaintPlugin(nsDisplayListBuilder* aBuilder,
// double pass render. If this plugin isn't oop, the register window message
// will be ignored.
NPEvent pluginEvent;
pluginEvent.event = mozilla::plugins::DoublePassRenderingEvent();
pluginEvent.event = DoublePassRenderingEvent();
pluginEvent.wParam = 0;
pluginEvent.lParam = 0;
if (pluginEvent.event)

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

@ -63,9 +63,12 @@ class nsPresContext;
class nsDisplayPlugin;
class nsIDOMElement;
class nsIOSurface;
class PluginBackgroundSink;
#define nsObjectFrameSuper nsFrame
#define NS_OBJECT_NEEDS_SET_IMAGE NS_FRAME_STATE_BIT(31)
class nsObjectFrame : public nsObjectFrameSuper,
public nsIObjectFrame,
public nsIReflowCallback {
@ -177,6 +180,10 @@ public:
virtual PRBool ReflowFinished();
virtual void ReflowCallbackCanceled();
/**
* Builds either an ImageLayer or a ReadbackLayer, depending on the type
* of aItem (TYPE_PLUGIN or TYPE_PLUGIN_READBACK respectively).
*/
already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
nsDisplayItem* aItem);
@ -230,6 +237,7 @@ protected:
PRBool IsHidden(PRBool aCheckVisibilityStyle = PR_TRUE) const;
PRBool IsOpaque() const;
PRBool IsTransparentMode() const;
void NotifyContentObjectWrapper();
@ -273,6 +281,7 @@ protected:
friend class nsPluginInstanceOwner;
friend class nsDisplayPlugin;
friend class PluginBackgroundSink;
private:
@ -290,6 +299,11 @@ private:
nsIView* mInnerView;
nsCOMPtr<nsIWidget> mWidget;
nsIntRect mWindowlessRect;
/**
* This is owned by the ReadbackLayer for this nsObjectFrame. It is
* automatically cleared if the PluginBackgroundSink is destroyed.
*/
PluginBackgroundSink* mBackgroundSink;
// For assertions that make it easier to determine if a crash is due
// to the underlying problem described in bug 136927, and to prevent
@ -348,7 +362,8 @@ public:
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager)
{
return static_cast<nsObjectFrame*>(mFrame)->GetLayerState(aBuilder, aManager);
return static_cast<nsObjectFrame*>(mFrame)->GetLayerState(aBuilder,
aManager);
}
private: