Move UpdateDestinationFrom to RotatedBuffer. (
bug 1409871 part 2, r=nical)
UpdateDestinationFrom is a useful method for any rotated buffer. This will be
needed when content clients are no longer rotated buffers.
Note: EnsureBuffer and EnsureBufferOnWhite were moved out of
UpdateDestinationFrom because I'd like to kill those methods, and so the calls
were moved to all users of UpdateDestinationFrom.
MozReview-Commit-ID: 2e3HhUsZ6iw
--- a/gfx/layers/RotatedBuffer.cpp
+++ b/gfx/layers/RotatedBuffer.cpp
@@ -30,16 +30,30 @@
#include "PaintThread.h"
namespace mozilla {
using namespace gfx;
namespace layers {
+void
+BorrowDrawTarget::ReturnDrawTarget(gfx::DrawTarget*& aReturned)
+{
+ MOZ_ASSERT(mLoanedDrawTarget);
+ MOZ_ASSERT(aReturned == mLoanedDrawTarget);
+ if (mLoanedDrawTarget) {
+ if (mSetTransform) {
+ mLoanedDrawTarget->SetTransform(mLoanedTransform);
+ }
+ mLoanedDrawTarget = nullptr;
+ }
+ aReturned = nullptr;
+}
+
IntRect
RotatedBuffer::GetQuadrantRectangle(XSide aXSide, YSide aYSide) const
{
// quadrantTranslation is the amount we translate the top-left
// of the quadrant by to get coordinates relative to the layer
IntPoint quadrantTranslation = -mBufferRotation;
quadrantTranslation.x += aXSide == LEFT ? mBufferRect.Width() : 0;
quadrantTranslation.y += aYSide == TOP ? mBufferRect.Height() : 0;
@@ -177,40 +191,149 @@ RotatedBuffer::DrawBufferWithRotation(gf
// though! Particularly on D2D Repeat should be a lot faster, need to look
// into that. TODO[Bas]
DrawBufferQuadrant(aTarget, LEFT, TOP, aSource, aOpacity, aOperator, aMask, aMaskTransform);
DrawBufferQuadrant(aTarget, RIGHT, TOP, aSource, aOpacity, aOperator, aMask, aMaskTransform);
DrawBufferQuadrant(aTarget, LEFT, BOTTOM, aSource, aOpacity, aOperator, aMask, aMaskTransform);
DrawBufferQuadrant(aTarget, RIGHT, BOTTOM, aSource, aOpacity, aOperator,aMask, aMaskTransform);
}
+bool IsClippingCheap(gfx::DrawTarget* aTarget, const nsIntRegion& aRegion)
+{
+ // Assume clipping is cheap if the draw target just has an integer
+ // translation, and the visible region is simple.
+ return !aTarget->GetTransform().HasNonIntegerTranslation() &&
+ aRegion.GetNumRects() <= 1;
+}
+
+void
+RotatedBuffer::UpdateDestinationFrom(const RotatedBuffer& aSource,
+ const nsIntRegion& aUpdateRegion)
+{
+ DrawIterator iter;
+ while (DrawTarget* destDT =
+ BorrowDrawTargetForQuadrantUpdate(aUpdateRegion.GetBounds(), BUFFER_BLACK, &iter)) {
+ bool isClippingCheap = IsClippingCheap(destDT, iter.mDrawRegion);
+ if (isClippingCheap) {
+ gfxUtils::ClipToRegion(destDT, iter.mDrawRegion);
+ }
+
+ aSource.DrawBufferWithRotation(destDT, BUFFER_BLACK, 1.0, CompositionOp::OP_SOURCE);
+ if (isClippingCheap) {
+ destDT->PopClip();
+ }
+ // Flush the destination before the sources become inaccessible (Unlock).
+ destDT->Flush();
+ ReturnDrawTarget(destDT);
+ }
+
+ if (aSource.HaveBufferOnWhite()) {
+ MOZ_ASSERT(HaveBufferOnWhite());
+ DrawIterator whiteIter;
+ while (DrawTarget* destDT =
+ BorrowDrawTargetForQuadrantUpdate(aUpdateRegion.GetBounds(), BUFFER_WHITE, &whiteIter)) {
+ bool isClippingCheap = IsClippingCheap(destDT, whiteIter.mDrawRegion);
+ if (isClippingCheap) {
+ gfxUtils::ClipToRegion(destDT, whiteIter.mDrawRegion);
+ }
+
+ aSource.DrawBufferWithRotation(destDT, BUFFER_WHITE, 1.0, CompositionOp::OP_SOURCE);
+ if (isClippingCheap) {
+ destDT->PopClip();
+ }
+ // Flush the destination before the sources become inaccessible (Unlock).
+ destDT->Flush();
+ ReturnDrawTarget(destDT);
+ }
+ }
+}
+
+DrawTarget*
+RotatedBuffer::BorrowDrawTargetForQuadrantUpdate(const IntRect& aBounds,
+ ContextSource aSource,
+ DrawIterator* aIter,
+ bool aSetTransform,
+ Matrix* aOutMatrix)
+{
+ IntRect bounds = aBounds;
+ if (aIter) {
+ // If an iterator was provided, then BeginPaint must have been run with
+ // PAINT_CAN_DRAW_ROTATED, and the draw region might cover multiple quadrants.
+ // Iterate over each of them, and return an appropriate buffer each time we find
+ // one that intersects the draw region. The iterator mCount value tracks which
+ // quadrants we have considered across multiple calls to this function.
+ aIter->mDrawRegion.SetEmpty();
+ while (aIter->mCount < 4) {
+ IntRect quadrant = GetQuadrantRectangle((aIter->mCount & 1) ? LEFT : RIGHT,
+ (aIter->mCount & 2) ? TOP : BOTTOM);
+ aIter->mDrawRegion.And(aBounds, quadrant);
+ aIter->mCount++;
+ if (!aIter->mDrawRegion.IsEmpty()) {
+ break;
+ }
+ }
+ if (aIter->mDrawRegion.IsEmpty()) {
+ return nullptr;
+ }
+ bounds = aIter->mDrawRegion.GetBounds();
+ }
+
+ gfx::DrawTarget* dtBuffer = GetDTBuffer();
+ gfx::DrawTarget* dtBufferOnWhite = GetDTBufferOnWhite();
+
+ MOZ_ASSERT(!mLoanedDrawTarget, "draw target has been borrowed and not returned");
+ if (aSource == BUFFER_BOTH && HaveBufferOnWhite()) {
+ MOZ_ASSERT(dtBuffer && dtBuffer->IsValid() && dtBufferOnWhite && dtBufferOnWhite->IsValid());
+ mLoanedDrawTarget = Factory::CreateDualDrawTarget(dtBuffer, dtBufferOnWhite);
+ } else if (aSource == BUFFER_WHITE) {
+ mLoanedDrawTarget = dtBufferOnWhite;
+ } else {
+ // BUFFER_BLACK, or BUFFER_BOTH with a single buffer.
+ mLoanedDrawTarget = dtBuffer;
+ }
+
+ // Figure out which quadrant to draw in
+ int32_t xBoundary = mBufferRect.XMost() - mBufferRotation.x;
+ int32_t yBoundary = mBufferRect.YMost() - mBufferRotation.y;
+ XSide sideX = bounds.XMost() <= xBoundary ? RIGHT : LEFT;
+ YSide sideY = bounds.YMost() <= yBoundary ? BOTTOM : TOP;
+ IntRect quadrantRect = GetQuadrantRectangle(sideX, sideY);
+ NS_ASSERTION(quadrantRect.Contains(bounds), "Messed up quadrants");
+
+ if (aSetTransform) {
+ mLoanedTransform = mLoanedDrawTarget->GetTransform();
+ Matrix transform = Matrix(mLoanedTransform)
+ .PreTranslate(-quadrantRect.x,
+ -quadrantRect.y);
+ mLoanedDrawTarget->SetTransform(transform);
+ mSetTransform = true;
+ } else {
+ MOZ_ASSERT(aOutMatrix);
+ *aOutMatrix = Matrix::Translation(-quadrantRect.x, -quadrantRect.y);
+ mSetTransform = false;
+ }
+
+ return mLoanedDrawTarget;
+}
+
already_AddRefed<SourceSurface>
SourceRotatedBuffer::GetSourceSurface(ContextSource aSource) const
{
RefPtr<SourceSurface> surf;
if (aSource == BUFFER_BLACK) {
surf = mSource;
} else {
MOZ_ASSERT(aSource == BUFFER_WHITE);
surf = mSourceOnWhite;
}
MOZ_ASSERT(surf);
return surf.forget();
}
-/* static */ bool
-RotatedContentBuffer::IsClippingCheap(DrawTarget* aTarget, const nsIntRegion& aRegion)
-{
- // Assume clipping is cheap if the draw target just has an integer
- // translation, and the visible region is simple.
- return !aTarget->GetTransform().HasNonIntegerTranslation() &&
- aRegion.GetNumRects() <= 1;
-}
-
void
RotatedContentBuffer::DrawTo(PaintedLayer* aLayer,
DrawTarget* aTarget,
float aOpacity,
CompositionOp aOp,
SourceSurface* aMask,
const Matrix* aMaskTransform)
{
@@ -238,105 +361,16 @@ RotatedContentBuffer::DrawTo(PaintedLaye
}
DrawBufferWithRotation(aTarget, BUFFER_BLACK, aOpacity, aOp, aMask, aMaskTransform);
if (clipped) {
aTarget->PopClip();
}
}
-DrawTarget*
-RotatedContentBuffer::BorrowDrawTargetForQuadrantUpdate(const IntRect& aBounds,
- ContextSource aSource,
- DrawIterator* aIter,
- bool aSetTransform,
- Matrix* aOutMatrix)
-{
- IntRect bounds = aBounds;
- if (aIter) {
- // If an iterator was provided, then BeginPaint must have been run with
- // PAINT_CAN_DRAW_ROTATED, and the draw region might cover multiple quadrants.
- // Iterate over each of them, and return an appropriate buffer each time we find
- // one that intersects the draw region. The iterator mCount value tracks which
- // quadrants we have considered across multiple calls to this function.
- aIter->mDrawRegion.SetEmpty();
- while (aIter->mCount < 4) {
- IntRect quadrant = GetQuadrantRectangle((aIter->mCount & 1) ? LEFT : RIGHT,
- (aIter->mCount & 2) ? TOP : BOTTOM);
- aIter->mDrawRegion.And(aBounds, quadrant);
- aIter->mCount++;
- if (!aIter->mDrawRegion.IsEmpty()) {
- break;
- }
- }
- if (aIter->mDrawRegion.IsEmpty()) {
- return nullptr;
- }
- bounds = aIter->mDrawRegion.GetBounds();
- }
-
- if (!EnsureBuffer()) {
- return nullptr;
- }
-
- MOZ_ASSERT(!mLoanedDrawTarget, "draw target has been borrowed and not returned");
- if (aSource == BUFFER_BOTH && HaveBufferOnWhite()) {
- if (!EnsureBufferOnWhite()) {
- return nullptr;
- }
- MOZ_ASSERT(mDTBuffer && mDTBuffer->IsValid() && mDTBufferOnWhite && mDTBufferOnWhite->IsValid());
- mLoanedDrawTarget = Factory::CreateDualDrawTarget(mDTBuffer, mDTBufferOnWhite);
- } else if (aSource == BUFFER_WHITE) {
- if (!EnsureBufferOnWhite()) {
- return nullptr;
- }
- mLoanedDrawTarget = mDTBufferOnWhite;
- } else {
- // BUFFER_BLACK, or BUFFER_BOTH with a single buffer.
- mLoanedDrawTarget = mDTBuffer;
- }
-
- // Figure out which quadrant to draw in
- int32_t xBoundary = mBufferRect.XMost() - mBufferRotation.x;
- int32_t yBoundary = mBufferRect.YMost() - mBufferRotation.y;
- XSide sideX = bounds.XMost() <= xBoundary ? RIGHT : LEFT;
- YSide sideY = bounds.YMost() <= yBoundary ? BOTTOM : TOP;
- IntRect quadrantRect = GetQuadrantRectangle(sideX, sideY);
- NS_ASSERTION(quadrantRect.Contains(bounds), "Messed up quadrants");
-
- if (aSetTransform) {
- mLoanedTransform = mLoanedDrawTarget->GetTransform();
- Matrix transform = Matrix(mLoanedTransform)
- .PreTranslate(-quadrantRect.x,
- -quadrantRect.y);
- mLoanedDrawTarget->SetTransform(transform);
- mSetTransform = true;
- } else {
- MOZ_ASSERT(aOutMatrix);
- *aOutMatrix = Matrix::Translation(-quadrantRect.x, -quadrantRect.y);
- mSetTransform = false;
- }
-
- return mLoanedDrawTarget;
-}
-
-void
-BorrowDrawTarget::ReturnDrawTarget(gfx::DrawTarget*& aReturned)
-{
- MOZ_ASSERT(mLoanedDrawTarget);
- MOZ_ASSERT(aReturned == mLoanedDrawTarget);
- if (mLoanedDrawTarget) {
- if (mSetTransform) {
- mLoanedDrawTarget->SetTransform(mLoanedTransform);
- }
- mLoanedDrawTarget = nullptr;
- }
- aReturned = nullptr;
-}
-
gfxContentType
RotatedContentBuffer::BufferContentType()
{
if (mBufferProvider || (mDTBuffer && mDTBuffer->IsValid())) {
SurfaceFormat format = SurfaceFormat::B8G8R8A8;
if (mBufferProvider) {
format = mBufferProvider->GetFormat();
@@ -743,17 +777,19 @@ RotatedContentBuffer::BeginPaint(Painted
return result;
}
RefPtr<CapturedPaintState>
RotatedContentBuffer::BorrowDrawTargetForRecording(PaintState& aPaintState,
DrawIterator* aIter,
bool aSetTransform)
{
- if (aPaintState.mMode == SurfaceMode::SURFACE_NONE) {
+ if (aPaintState.mMode == SurfaceMode::SURFACE_NONE ||
+ !EnsureBuffer() ||
+ (HaveBufferOnWhite() && !EnsureBufferOnWhite())) {
return nullptr;
}
Matrix transform;
DrawTarget* result = BorrowDrawTargetForQuadrantUpdate(aPaintState.mRegionToDraw.GetBounds(),
BUFFER_BOTH, aIter,
aSetTransform,
&transform);
--- a/gfx/layers/RotatedBuffer.h
+++ b/gfx/layers/RotatedBuffer.h
@@ -24,76 +24,114 @@ namespace layers {
class CapturedPaintState;
typedef bool (*PrepDrawTargetForPaintingCallback)(CapturedPaintState*);
class TextureClient;
class PaintedLayer;
+// Mixin class for classes which need logic for loaning out a draw target.
+// See comments on BorrowDrawTargetForQuadrantUpdate.
+class BorrowDrawTarget
+{
+protected:
+ void ReturnDrawTarget(gfx::DrawTarget*& aReturned);
+
+ // The draw target loaned by BorrowDrawTargetForQuadrantUpdate. It should not
+ // be used, we just keep a reference to ensure it is kept alive and so we can
+ // correctly restore state when it is returned.
+ RefPtr<gfx::DrawTarget> mLoanedDrawTarget;
+ gfx::Matrix mLoanedTransform;
+
+ // This flag denotes whether or not a transform was already applied
+ // to mLoanedDrawTarget and thus needs to be reset to mLoanedTransform
+ // upon returning the drawtarget.
+ bool mSetTransform;
+};
+
/**
* This is a cairo/Thebes surface, but with a literal twist. Scrolling
* causes the layer's visible region to move. We want to keep
* reusing the same surface if the region size hasn't changed, but we don't
* want to keep moving the contents of the surface around in memory. So
* we use a trick.
* Consider just the vertical case, and suppose the buffer is H pixels
* high and we're scrolling down by N pixels. Instead of copying the
* buffer contents up by N pixels, we leave the buffer contents in place,
* and paint content rows H to H+N-1 into rows 0 to N-1 of the buffer.
* Then we can refresh the screen by painting rows N to H-1 of the buffer
* at row 0 on the screen, and then painting rows 0 to N-1 of the buffer
* at row H-N on the screen.
* mBufferRotation.y would be N in this example.
*/
-class RotatedBuffer {
+class RotatedBuffer : public BorrowDrawTarget
+{
public:
typedef gfxContentType ContentType;
RotatedBuffer(const gfx::IntRect& aBufferRect,
const gfx::IntPoint& aBufferRotation)
: mBufferRect(aBufferRect)
, mBufferRotation(aBufferRotation)
, mDidSelfCopy(false)
{ }
RotatedBuffer()
: mDidSelfCopy(false)
{ }
+ struct DrawIterator {
+ friend class RotatedBuffer;
+ DrawIterator()
+ : mCount(0)
+ {}
+
+ nsIntRegion mDrawRegion;
+
+ private:
+ uint32_t mCount;
+ };
+
/*
* Which buffer should be drawn to/read from.
*/
enum ContextSource {
BUFFER_BLACK, // The normal buffer, or buffer with black background when using component alpha.
BUFFER_WHITE, // The buffer with white background, only valid with component alpha.
BUFFER_BOTH // The combined black/white buffers, only valid for writing operations, not reading.
};
// It is the callers repsonsibility to ensure aTarget is flushed after calling
// this method.
void DrawBufferWithRotation(gfx::DrawTarget* aTarget, ContextSource aSource,
float aOpacity = 1.0,
gfx::CompositionOp aOperator = gfx::CompositionOp::OP_OVER,
gfx::SourceSurface* aMask = nullptr,
const gfx::Matrix* aMaskTransform = nullptr) const;
+ void UpdateDestinationFrom(const RotatedBuffer& aSource,
+ const nsIntRegion& aUpdateRegion);
+
/**
* |BufferRect()| is the rect of device pixels that this
* RotatedBuffer covers. That is what DrawBufferWithRotation()
* will paint when it's called.
*/
const gfx::IntRect& BufferRect() const { return mBufferRect; }
const gfx::IntPoint& BufferRotation() const { return mBufferRotation; }
virtual bool HaveBuffer() const = 0;
virtual bool HaveBufferOnWhite() const = 0;
virtual already_AddRefed<gfx::SourceSurface> GetSourceSurface(ContextSource aSource) const = 0;
protected:
+ virtual gfx::DrawTarget* GetDTBuffer() const = 0;
+ virtual gfx::DrawTarget* GetDTBufferOnWhite() const = 0;
+
enum XSide {
LEFT, RIGHT
};
enum YSide {
TOP, BOTTOM
};
gfx::IntRect GetQuadrantRectangle(XSide aXSide, YSide aYSide) const;
@@ -106,16 +144,37 @@ protected:
*/
void DrawBufferQuadrant(gfx::DrawTarget* aTarget, XSide aXSide, YSide aYSide,
ContextSource aSource,
float aOpacity,
gfx::CompositionOp aOperator,
gfx::SourceSurface* aMask,
const gfx::Matrix* aMaskTransform) const;
+ /**
+ * Get a draw target at the specified resolution for updating |aBounds|,
+ * which must be contained within a single quadrant.
+ *
+ * The result should only be held temporarily by the caller (it will be kept
+ * alive by this). Once used it should be returned using ReturnDrawTarget.
+ * BorrowDrawTargetForQuadrantUpdate may not be called more than once without
+ * first calling ReturnDrawTarget.
+ *
+ * ReturnDrawTarget will by default restore the transform on the draw target.
+ * But it is the callers responsibility to restore the clip.
+ * The caller should flush the draw target, if necessary.
+ * If aSetTransform is false, the required transform will be set in aOutTransform.
+ */
+ gfx::DrawTarget*
+ BorrowDrawTargetForQuadrantUpdate(const gfx::IntRect& aBounds,
+ ContextSource aSource,
+ DrawIterator* aIter,
+ bool aSetTransform = true,
+ gfx::Matrix* aOutTransform = nullptr);
+
/** The area of the PaintedLayer that is covered by the buffer as a whole */
gfx::IntRect mBufferRect;
/**
* The x and y rotation of the buffer. Conceptually the buffer
* has its origin translated to mBufferRect.TopLeft() - mBufferRotation,
* is tiled to fill the plane, and the result is clipped to mBufferRect.
* So the pixel at mBufferRotation within the buffer is what gets painted at
* mBufferRect.TopLeft().
@@ -140,46 +199,30 @@ public:
, mSourceOnWhite(aSourceOnWhite)
{ }
virtual already_AddRefed<gfx::SourceSurface> GetSourceSurface(ContextSource aSource) const;
virtual bool HaveBuffer() const { return !!mSource; }
virtual bool HaveBufferOnWhite() const { return !!mSourceOnWhite; }
+protected:
+ virtual gfx::DrawTarget* GetDTBuffer() const { return nullptr; }
+ virtual gfx::DrawTarget* GetDTBufferOnWhite() const { return nullptr; }
+
private:
RefPtr<gfx::SourceSurface> mSource;
RefPtr<gfx::SourceSurface> mSourceOnWhite;
};
-// Mixin class for classes which need logic for loaning out a draw target.
-// See comments on BorrowDrawTargetForQuadrantUpdate.
-class BorrowDrawTarget
-{
-protected:
- void ReturnDrawTarget(gfx::DrawTarget*& aReturned);
-
- // The draw target loaned by BorrowDrawTargetForQuadrantUpdate. It should not
- // be used, we just keep a reference to ensure it is kept alive and so we can
- // correctly restore state when it is returned.
- RefPtr<gfx::DrawTarget> mLoanedDrawTarget;
- gfx::Matrix mLoanedTransform;
-
- // This flag denotes whether or not a transform was already applied
- // to mLoanedDrawTarget and thus needs to be reset to mLoanedTransform
- // upon returning the drawtarget.
- bool mSetTransform;
-};
-
/**
* This class encapsulates the buffer used to retain PaintedLayer contents,
* i.e., the contents of the layer's GetVisibleRegion().
*/
class RotatedContentBuffer : public RotatedBuffer
- , public BorrowDrawTarget
{
public:
typedef gfxContentType ContentType;
/**
* Controls the size of the backing buffer of this.
* - SizedToVisibleBounds: the backing buffer is exactly the same
* size as the bounds of PaintedLayer's visible region
@@ -267,28 +310,16 @@ public:
* PAINT_CAN_DRAW_ROTATED can be passed if the caller supports drawing
* rotated content that crosses the physical buffer boundary. The caller
* will need to call BorrowDrawTargetForPainting multiple times to achieve
* this.
*/
PaintState BeginPaint(PaintedLayer* aLayer,
uint32_t aFlags);
- struct DrawIterator {
- friend class RotatedContentBuffer;
- DrawIterator()
- : mCount(0)
- {}
-
- nsIntRegion mDrawRegion;
-
- private:
- uint32_t mCount;
- };
-
/**
* Fetch a DrawTarget for rendering. The DrawTarget remains owned by
* this. See notes on BorrowDrawTargetForQuadrantUpdate.
* May return null. If the return value is non-null, it must be
* 'un-borrowed' using ReturnDrawTarget.
*
* If PAINT_CAN_DRAW_ROTATED was specified for BeginPaint, then the caller
* must call this function repeatedly (with an iterator) until it returns
@@ -326,24 +357,16 @@ public:
* If the created buffer supports azure content, then the result(s) will
* be returned in aBlackDT/aWhiteDT, otherwise aBlackSurface/aWhiteSurface
* will be used.
*/
virtual void
CreateBuffer(ContentType aType, const gfx::IntRect& aRect, uint32_t aFlags,
RefPtr<gfx::DrawTarget>* aBlackDT, RefPtr<gfx::DrawTarget>* aWhiteDT) = 0;
- /**
- * Get the underlying buffer, if any. This is useful because we can pass
- * in the buffer as the default "reference surface" if there is one.
- * Don't use it for anything else!
- */
- gfx::DrawTarget* GetDTBuffer() { return mDTBuffer; }
- gfx::DrawTarget* GetDTBufferOnWhite() { return mDTBufferOnWhite; }
-
virtual already_AddRefed<gfx::SourceSurface> GetSourceSurface(ContextSource aSource) const;
/**
* Complete the drawing operation. The region to draw must have been
* drawn before this is called. The contents of the buffer are drawn
* to aTarget.
*/
void DrawTo(PaintedLayer* aLayer,
@@ -374,39 +397,16 @@ protected:
MOZ_ASSERT(!aClient || !mDTBufferOnWhite || !mDTBufferOnWhite->IsValid());
mBufferProviderOnWhite = aClient;
if (!mBufferProviderOnWhite) {
mDTBufferOnWhite = nullptr;
}
}
- /**
- * Get a draw target at the specified resolution for updating |aBounds|,
- * which must be contained within a single quadrant.
- *
- * The result should only be held temporarily by the caller (it will be kept
- * alive by this). Once used it should be returned using ReturnDrawTarget.
- * BorrowDrawTargetForQuadrantUpdate may not be called more than once without
- * first calling ReturnDrawTarget.
- *
- * ReturnDrawTarget will by default restore the transform on the draw target.
- * But it is the callers responsibility to restore the clip.
- * The caller should flush the draw target, if necessary.
- * If aSetTransform is false, the required transform will be set in aOutTransform.
- */
- gfx::DrawTarget*
- BorrowDrawTargetForQuadrantUpdate(const gfx::IntRect& aBounds,
- ContextSource aSource,
- DrawIterator* aIter,
- bool aSetTransform = true,
- gfx::Matrix* aOutTransform = nullptr);
-
- static bool IsClippingCheap(gfx::DrawTarget* aTarget, const nsIntRegion& aRegion);
-
protected:
/**
* Return the buffer's content type. Requires a valid buffer or
* buffer provider.
*/
gfxContentType BufferContentType();
bool BufferSizeOkFor(const gfx::IntSize& aSize);
/**
@@ -414,16 +414,24 @@ protected:
*/
bool EnsureBuffer();
bool EnsureBufferOnWhite();
// Flush our buffers if they are mapped.
void FlushBuffers();
/**
+ * Get the underlying buffer, if any. This is useful because we can pass
+ * in the buffer as the default "reference surface" if there is one.
+ * Don't use it for anything else!
+ */
+ virtual gfx::DrawTarget* GetDTBuffer() const { return mDTBuffer; }
+ virtual gfx::DrawTarget* GetDTBufferOnWhite() const { return mDTBufferOnWhite; }
+
+ /**
* True if we have a buffer where we can get it (but not necessarily
* mapped currently).
*/
virtual bool HaveBuffer() const;
virtual bool HaveBufferOnWhite() const;
/**
* Any actions that should be performed at the last moment before we begin
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -631,16 +631,21 @@ ContentClientDoubleBuffered::FinalizeFra
// No point in sync'ing what we are going to draw over anyway. And if there is
// nothing to sync at all, there is nothing to do and we can go home early.
updateRegion.Sub(updateRegion, aRegionToDraw);
if (updateRegion.IsEmpty()) {
return;
}
+ if (!EnsureBuffer() ||
+ (HaveBufferOnWhite() && !EnsureBufferOnWhite())) {
+ return;
+ }
+
// We need to ensure that we lock these two buffers in the same
// order as the compositor to prevent deadlocks.
TextureClientAutoLock frontLock(mFrontClient, OpenMode::OPEN_READ_ONLY);
if (!frontLock.Succeeded()) {
return;
}
Maybe<TextureClientAutoLock> frontOnWhiteLock;
if (mFrontClientOnWhite) {
@@ -676,52 +681,10 @@ ContentClientDoubleBuffered::EnsureBackB
if (!mTextureClient && mFrontClient) {
CreateBackBuffer(mFrontBufferRect);
mBufferRect = mFrontBufferRect;
mBufferRotation = mFrontBufferRotation;
}
}
-void
-ContentClientDoubleBuffered::UpdateDestinationFrom(const RotatedBuffer& aSource,
- const nsIntRegion& aUpdateRegion)
-{
- DrawIterator iter;
- while (DrawTarget* destDT =
- BorrowDrawTargetForQuadrantUpdate(aUpdateRegion.GetBounds(), BUFFER_BLACK, &iter)) {
- bool isClippingCheap = IsClippingCheap(destDT, iter.mDrawRegion);
- if (isClippingCheap) {
- gfxUtils::ClipToRegion(destDT, iter.mDrawRegion);
- }
-
- aSource.DrawBufferWithRotation(destDT, BUFFER_BLACK, 1.0, CompositionOp::OP_SOURCE);
- if (isClippingCheap) {
- destDT->PopClip();
- }
- // Flush the destination before the sources become inaccessible (Unlock).
- destDT->Flush();
- ReturnDrawTargetToBuffer(destDT);
- }
-
- if (aSource.HaveBufferOnWhite()) {
- MOZ_ASSERT(HaveBufferOnWhite());
- DrawIterator whiteIter;
- while (DrawTarget* destDT =
- BorrowDrawTargetForQuadrantUpdate(aUpdateRegion.GetBounds(), BUFFER_WHITE, &whiteIter)) {
- bool isClippingCheap = IsClippingCheap(destDT, whiteIter.mDrawRegion);
- if (isClippingCheap) {
- gfxUtils::ClipToRegion(destDT, whiteIter.mDrawRegion);
- }
-
- aSource.DrawBufferWithRotation(destDT, BUFFER_WHITE, 1.0, CompositionOp::OP_SOURCE);
- if (isClippingCheap) {
- destDT->PopClip();
- }
- // Flush the destination before the sources become inaccessible (Unlock).
- destDT->Flush();
- ReturnDrawTargetToBuffer(destDT);
- }
- }
-}
-
} // namespace layers
} // namespace mozilla
--- a/gfx/layers/client/ContentClient.h
+++ b/gfx/layers/client/ContentClient.h
@@ -358,18 +358,16 @@ public:
virtual void Dump(std::stringstream& aStream,
const char* aPrefix="",
bool aDumpHtml=false,
TextureDumpMode aCompress=TextureDumpMode::Compress) override;
protected:
virtual void DestroyFrontBuffer() override;
private:
- void UpdateDestinationFrom(const RotatedBuffer& aSource,
- const nsIntRegion& aUpdateRegion);
virtual void AbortTextureClientCreation() override
{
mTextureClient = nullptr;
mTextureClientOnWhite = nullptr;
mFrontClient = nullptr;
mFrontClientOnWhite = nullptr;
}