michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef GFX_READBACKLAYER_H michael@0: #define GFX_READBACKLAYER_H michael@0: michael@0: #include // for uint64_t michael@0: #include "Layers.h" // for Layer, etc michael@0: #include "gfxColor.h" // for gfxRGBA michael@0: #include "gfxRect.h" // for gfxRect michael@0: #include "mozilla/mozalloc.h" // for operator delete michael@0: #include "nsAutoPtr.h" // for nsAutoPtr michael@0: #include "nsCOMPtr.h" // for already_AddRefed michael@0: #include "nsDebug.h" // for NS_ASSERTION michael@0: #include "nsPoint.h" // for nsIntPoint michael@0: #include "nsRect.h" // for nsIntRect michael@0: #include "nsSize.h" // for nsIntSize michael@0: #include "nscore.h" // for nsACString michael@0: michael@0: class gfxContext; michael@0: michael@0: namespace mozilla { michael@0: namespace layers { michael@0: michael@0: class ReadbackProcessor; michael@0: michael@0: /** michael@0: * A ReadbackSink receives a stream of updates to a rectangle of pixels. michael@0: * These update callbacks are always called on the main thread, either during michael@0: * EndTransaction or from the event loop. michael@0: */ michael@0: class ReadbackSink { michael@0: public: michael@0: ReadbackSink() {} michael@0: virtual ~ReadbackSink() {} michael@0: michael@0: /** michael@0: * Sends an update to indicate that the background is currently unknown. michael@0: */ michael@0: virtual void SetUnknown(uint64_t aSequenceNumber) = 0; michael@0: /** michael@0: * Called by the layer system to indicate that the contents of part of michael@0: * the readback area are changing. michael@0: * @param aRect is the rectangle of content that is being updated, michael@0: * in the coordinate system of the ReadbackLayer. michael@0: * @param aSequenceNumber updates issued out of order should be ignored. michael@0: * Only use updates whose sequence counter is greater than all other updates michael@0: * seen so far. Return null when a non-fresh sequence value is given. michael@0: * @return a context into which the update should be drawn. This should be michael@0: * set up to clip to aRect. Zero should never be passed as a sequence number. michael@0: * If this returns null, EndUpdate should NOT be called. If it returns michael@0: * non-null, EndUpdate must be called. michael@0: * michael@0: * We don't support partially unknown backgrounds. Therefore, the michael@0: * first BeginUpdate after a SetUnknown will have the complete background. michael@0: */ michael@0: virtual already_AddRefed michael@0: BeginUpdate(const nsIntRect& aRect, uint64_t aSequenceNumber) = 0; michael@0: /** michael@0: * EndUpdate must be called immediately after BeginUpdate, without returning michael@0: * to the event loop. michael@0: * @param aContext the context returned by BeginUpdate michael@0: * Implicitly Restore()s the state of aContext. michael@0: */ michael@0: virtual void EndUpdate(gfxContext* aContext, const nsIntRect& aRect) = 0; michael@0: }; michael@0: michael@0: /** michael@0: * A ReadbackLayer never renders anything. It enables clients to extract michael@0: * the rendered contents of the layer tree below the ReadbackLayer. michael@0: * The rendered contents are delivered asynchronously via calls to a michael@0: * ReadbackSink object supplied by the client. michael@0: * michael@0: * This is a "best effort" API; it is possible for the layer system to tell michael@0: * the ReadbackSink that the contents of the readback area are unknown. michael@0: * michael@0: * This API exists to work around the limitations of transparent windowless michael@0: * plugin rendering APIs. It should not be used for anything else. michael@0: */ michael@0: class ReadbackLayer : public Layer { michael@0: public: michael@0: MOZ_LAYER_DECL_NAME("ReadbackLayer", TYPE_READBACK) michael@0: michael@0: virtual void ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSurface) michael@0: { michael@0: // Snap our local transform first, and snap the inherited transform as well. michael@0: // This makes our snapping equivalent to what would happen if our content michael@0: // was drawn into a ThebesLayer (gfxContext would snap using the local michael@0: // transform, then we'd snap again when compositing the ThebesLayer). michael@0: mEffectiveTransform = michael@0: SnapTransform(GetLocalTransform(), gfxRect(0, 0, mSize.width, mSize.height), michael@0: nullptr)* michael@0: SnapTransformTranslation(aTransformToSurface, nullptr); michael@0: } michael@0: michael@0: /** michael@0: * CONSTRUCTION PHASE ONLY michael@0: * Set the callback object to which readback updates will be delivered. michael@0: * This also resets the "needed rectangle" so that on the next layer tree michael@0: * transaction we will try to deliver the full contents of the readback michael@0: * area to the sink. michael@0: * This layer takes ownership of the sink. It will be deleted when the michael@0: * layer is destroyed or when a new sink is set. michael@0: * Initially the contents of the readback area are completely unknown. michael@0: */ michael@0: void SetSink(ReadbackSink* aSink) michael@0: { michael@0: SetUnknown(); michael@0: mSink = aSink; michael@0: } michael@0: ReadbackSink* GetSink() { return mSink; } michael@0: michael@0: /** michael@0: * CONSTRUCTION PHASE ONLY michael@0: * Set the size of content that should be read back. The readback area michael@0: * has its top-left at 0,0 and has size aSize. michael@0: * Can only be called while the sink is null! michael@0: */ michael@0: void SetSize(const nsIntSize& aSize) michael@0: { michael@0: NS_ASSERTION(!mSink, "Should have no sink while changing size!"); michael@0: mSize = aSize; michael@0: } michael@0: const nsIntSize& GetSize() { return mSize; } michael@0: nsIntRect GetRect() { return nsIntRect(nsIntPoint(0, 0), mSize); } michael@0: michael@0: bool IsBackgroundKnown() michael@0: { michael@0: return mBackgroundLayer || mBackgroundColor.a == 1.0; michael@0: } michael@0: michael@0: void NotifyRemoved() { michael@0: SetUnknown(); michael@0: mSink = nullptr; michael@0: } michael@0: michael@0: void NotifyThebesLayerRemoved(ThebesLayer* aLayer) michael@0: { michael@0: if (mBackgroundLayer == aLayer) { michael@0: mBackgroundLayer = nullptr; michael@0: } michael@0: } michael@0: michael@0: const nsIntPoint& GetBackgroundLayerOffset() { return mBackgroundLayerOffset; } michael@0: michael@0: uint64_t AllocateSequenceNumber() { return ++mSequenceCounter; } michael@0: michael@0: void SetUnknown() michael@0: { michael@0: if (IsBackgroundKnown()) { michael@0: if (mSink) { michael@0: mSink->SetUnknown(AllocateSequenceNumber()); michael@0: } michael@0: mBackgroundLayer = nullptr; michael@0: mBackgroundColor = gfxRGBA(0,0,0,0); michael@0: } michael@0: } michael@0: michael@0: protected: michael@0: friend class ReadbackProcessor; michael@0: michael@0: ReadbackLayer(LayerManager* aManager, void* aImplData) : michael@0: Layer(aManager, aImplData), michael@0: mSequenceCounter(0), michael@0: mSize(0,0), michael@0: mBackgroundLayer(nullptr), michael@0: mBackgroundLayerOffset(0, 0), michael@0: mBackgroundColor(gfxRGBA(0,0,0,0)) michael@0: {} michael@0: michael@0: // Print interesting information about this into aTo. Internally michael@0: // used to implement Dump*() and Log*(). michael@0: virtual nsACString& PrintInfo(nsACString& aTo, const char* aPrefix); michael@0: michael@0: uint64_t mSequenceCounter; michael@0: nsAutoPtr mSink; michael@0: nsIntSize mSize; michael@0: michael@0: // This can refer to any (earlier) sibling ThebesLayer. That ThebesLayer michael@0: // must have mUsedForReadback set on it. If the ThebesLayer is removed michael@0: // for the container, this will be set to null by NotifyThebesLayerRemoved. michael@0: // This ThebesLayer contains the contents which have previously been reported michael@0: // to mSink. The ThebesLayer had only an integer translation transform, michael@0: // and it covered the entire readback area. This layer also had only an michael@0: // integer translation transform. michael@0: ThebesLayer* mBackgroundLayer; michael@0: // When mBackgroundLayer is non-null, this is the offset to add to michael@0: // convert from the coordinates of mBackgroundLayer to the coordinates michael@0: // of this layer. michael@0: nsIntPoint mBackgroundLayerOffset; michael@0: // When mBackgroundColor is opaque, this is the color of the ColorLayer michael@0: // that contained the contents we reported to mSink, which covered the michael@0: // entire readback area. michael@0: gfxRGBA mBackgroundColor; michael@0: }; michael@0: michael@0: } michael@0: } michael@0: #endif /* GFX_READBACKLAYER_H */