Bug 992486 - Part 1: Add API to RotatedContentBuffer for drawing in multiple passes. r=roc

This commit is contained in:
Matt Woodrow 2014-04-09 21:15:17 +12:00
parent 166126a333
commit 031f178fa9
6 changed files with 87 additions and 26 deletions

View File

@ -531,12 +531,14 @@ RotatedContentBuffer::BeginPaint(ThebesLayer* aLayer,
"newRotation out of bounds");
int32_t xBoundary = destBufferRect.XMost() - newRotation.x;
int32_t yBoundary = destBufferRect.YMost() - newRotation.y;
if ((drawBounds.x < xBoundary && xBoundary < drawBounds.XMost()) ||
(drawBounds.y < yBoundary && yBoundary < drawBounds.YMost()) ||
bool drawWrapsBuffer = (drawBounds.x < xBoundary && xBoundary < drawBounds.XMost()) ||
(drawBounds.y < yBoundary && yBoundary < drawBounds.YMost());
if ((drawWrapsBuffer && !(aFlags & PAINT_CAN_DRAW_ROTATED)) ||
(newRotation != nsIntPoint(0,0) && !canHaveRotation)) {
// The stuff we need to redraw will wrap around an edge of the
// buffer, so move the pixels we can keep into a position that
// lets us redraw in just one quadrant.
// buffer (and the caller doesn't know how to support that), so
// move the pixels we can keep into a position that lets us
// redraw in just one quadrant.
if (mBufferRotation == nsIntPoint(0,0)) {
nsIntRect srcRect(nsIntPoint(0, 0), mBufferRect.Size());
nsIntPoint dest = mBufferRect.TopLeft() - destBufferRect.TopLeft();
@ -674,19 +676,44 @@ RotatedContentBuffer::BeginPaint(ThebesLayer* aLayer,
}
DrawTarget*
RotatedContentBuffer::BorrowDrawTargetForPainting(ThebesLayer* aLayer,
const PaintState& aPaintState)
RotatedContentBuffer::BorrowDrawTargetForPainting(const PaintState& aPaintState,
DrawIterator* aIter /* = nullptr */)
{
if (aPaintState.mMode == SurfaceMode::SURFACE_NONE) {
return nullptr;
}
DrawTarget* result = BorrowDrawTargetForQuadrantUpdate(aPaintState.mRegionToDraw.GetBounds(),
const nsIntRegion* drawPtr;
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) {
nsIntRect quadrant = GetQuadrantRectangle((aIter->mCount & 1) ? LEFT : RIGHT,
(aIter->mCount & 2) ? TOP : BOTTOM);
aIter->mDrawRegion.And(aPaintState.mRegionToDraw, quadrant);
aIter->mCount++;
if (!aIter->mDrawRegion.IsEmpty()) {
break;
}
}
if (aIter->mDrawRegion.IsEmpty()) {
return nullptr;
}
drawPtr = &aIter->mDrawRegion;
} else {
drawPtr = &aPaintState.mRegionToDraw;
}
DrawTarget* result = BorrowDrawTargetForQuadrantUpdate(drawPtr->GetBounds(),
BUFFER_BOTH);
if (aPaintState.mMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
MOZ_ASSERT(mDTBuffer && mDTBufferOnWhite);
nsIntRegionRectIterator iter(aPaintState.mRegionToDraw);
nsIntRegionRectIterator iter(*drawPtr);
const nsIntRect *iterRect;
while ((iterRect = iter.Next())) {
mDTBuffer->FillRect(Rect(iterRect->x, iterRect->y, iterRect->width, iterRect->height),
@ -696,7 +723,7 @@ RotatedContentBuffer::BorrowDrawTargetForPainting(ThebesLayer* aLayer,
}
} else if (aPaintState.mContentType == gfxContentType::COLOR_ALPHA && HaveBuffer()) {
// HaveBuffer() => we have an existing buffer that we must clear
nsIntRegionRectIterator iter(aPaintState.mRegionToDraw);
nsIntRegionRectIterator iter(*drawPtr);
const nsIntRect *iterRect;
while ((iterRect = iter.Next())) {
result->ClearRect(Rect(iterRect->x, iterRect->y, iterRect->width, iterRect->height));

View File

@ -223,7 +223,8 @@ public:
enum {
PAINT_WILL_RESAMPLE = 0x01,
PAINT_NO_ROTATION = 0x02
PAINT_NO_ROTATION = 0x02,
PAINT_CAN_DRAW_ROTATED = 0x04
};
/**
* Start a drawing operation. This returns a PaintState describing what
@ -240,18 +241,44 @@ public:
* make the entire buffer contents valid (since we don't want to sample
* invalid pixels outside the visible region, if the visible region doesn't
* fill the buffer bounds).
* 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(ThebesLayer* aLayer,
uint32_t aFlags);
struct DrawIterator {
friend class RotatedContentBuffer;
friend class ContentClientIncremental;
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
* nullptr. The caller should draw the mDrawRegion of the iterator instead
* of mRegionToDraw in the PaintState.
*
* @param aPaintState Paint state data returned by a call to BeginPaint
* @param aIter Paint state iterator. Only required if PAINT_CAN_DRAW_ROTATED
* was specified to BeginPaint.
*/
gfx::DrawTarget* BorrowDrawTargetForPainting(ThebesLayer* aLayer,
const PaintState& aPaintState);
gfx::DrawTarget* BorrowDrawTargetForPainting(const PaintState& aPaintState,
DrawIterator* aIter = nullptr);
enum {
ALLOW_REPEAT = 0x01,

View File

@ -186,7 +186,7 @@ BasicThebesLayer::Validate(LayerManager::DrawThebesLayerCallback aCallback,
mContentClient->BeginPaintBuffer(this, flags);
mValidRegion.Sub(mValidRegion, state.mRegionToInvalidate);
if (DrawTarget* target = mContentClient->BorrowDrawTargetForPainting(this, state)) {
if (DrawTarget* target = mContentClient->BorrowDrawTargetForPainting(state)) {
// The area that became invalid and is visible needs to be repainted
// (this could be the whole visible area if our buffer switched
// from RGB to RGBA, because we might need to repaint with

View File

@ -56,7 +56,7 @@ ClientThebesLayer::PaintThebes()
mContentClient->BeginPaintBuffer(this, flags);
mValidRegion.Sub(mValidRegion, state.mRegionToInvalidate);
if (DrawTarget* target = mContentClient->BorrowDrawTargetForPainting(this, state)) {
if (DrawTarget* target = mContentClient->BorrowDrawTargetForPainting(state)) {
// The area that became invalid and is visible needs to be repainted
// (this could be the whole visible area if our buffer switched
// from RGB to RGBA, because we might need to repaint with

View File

@ -785,13 +785,20 @@ ContentClientIncremental::BeginPaintBuffer(ThebesLayer* aLayer,
}
DrawTarget*
ContentClientIncremental::BorrowDrawTargetForPainting(ThebesLayer* aLayer,
const PaintState& aPaintState)
ContentClientIncremental::BorrowDrawTargetForPainting(const PaintState& aPaintState,
RotatedContentBuffer::DrawIterator* aIter)
{
if (aPaintState.mMode == SurfaceMode::SURFACE_NONE) {
return nullptr;
}
if (aIter) {
if (aIter->mCount++ > 0) {
return nullptr;
}
aIter->mDrawRegion = aPaintState.mRegionToDraw;
}
DrawTarget* result = nullptr;
nsIntRect drawBounds = aPaintState.mRegionToDraw.GetBounds();

View File

@ -95,8 +95,8 @@ public:
virtual void Clear() = 0;
virtual RotatedContentBuffer::PaintState BeginPaintBuffer(ThebesLayer* aLayer,
uint32_t aFlags) = 0;
virtual gfx::DrawTarget* BorrowDrawTargetForPainting(ThebesLayer* aLayer,
const RotatedContentBuffer::PaintState& aPaintState) = 0;
virtual gfx::DrawTarget* BorrowDrawTargetForPainting(const RotatedContentBuffer::PaintState& aPaintState,
RotatedContentBuffer::DrawIterator* aIter = nullptr) = 0;
virtual void ReturnDrawTargetToBuffer(gfx::DrawTarget*& aReturned) = 0;
virtual void PrepareFrame() {}
@ -143,10 +143,10 @@ public:
{
return RotatedContentBuffer::BeginPaint(aLayer, aFlags);
}
virtual gfx::DrawTarget* BorrowDrawTargetForPainting(ThebesLayer* aLayer,
const PaintState& aPaintState) MOZ_OVERRIDE
virtual gfx::DrawTarget* BorrowDrawTargetForPainting(const PaintState& aPaintState,
RotatedContentBuffer::DrawIterator* aIter = nullptr) MOZ_OVERRIDE
{
return RotatedContentBuffer::BorrowDrawTargetForPainting(aLayer, aPaintState);
return RotatedContentBuffer::BorrowDrawTargetForPainting(aPaintState, aIter);
}
virtual void ReturnDrawTargetToBuffer(gfx::DrawTarget*& aReturned) MOZ_OVERRIDE
{
@ -218,10 +218,10 @@ public:
{
return RotatedContentBuffer::BeginPaint(aLayer, aFlags);
}
virtual gfx::DrawTarget* BorrowDrawTargetForPainting(ThebesLayer* aLayer,
const PaintState& aPaintState) MOZ_OVERRIDE
virtual gfx::DrawTarget* BorrowDrawTargetForPainting(const PaintState& aPaintState,
RotatedContentBuffer::DrawIterator* aIter = nullptr) MOZ_OVERRIDE
{
return RotatedContentBuffer::BorrowDrawTargetForPainting(aLayer, aPaintState);
return RotatedContentBuffer::BorrowDrawTargetForPainting(aPaintState, aIter);
}
virtual void ReturnDrawTargetToBuffer(gfx::DrawTarget*& aReturned) MOZ_OVERRIDE
{
@ -420,8 +420,8 @@ public:
virtual PaintState BeginPaintBuffer(ThebesLayer* aLayer,
uint32_t aFlags) MOZ_OVERRIDE;
virtual gfx::DrawTarget* BorrowDrawTargetForPainting(ThebesLayer* aLayer,
const PaintState& aPaintState) MOZ_OVERRIDE;
virtual gfx::DrawTarget* BorrowDrawTargetForPainting(const PaintState& aPaintState,
RotatedContentBuffer::DrawIterator* aIter = nullptr) MOZ_OVERRIDE;
virtual void ReturnDrawTargetToBuffer(gfx::DrawTarget*& aReturned) MOZ_OVERRIDE
{
BorrowDrawTarget::ReturnDrawTarget(aReturned);