--- a/gfx/layers/RotatedBuffer.cpp
+++ b/gfx/layers/RotatedBuffer.cpp
@@ -273,16 +273,138 @@ RotatedBuffer::UpdateDestinationFrom(con
}
// Flush the destination before the sources become inaccessible (Unlock).
destDT->Flush();
ReturnDrawTarget(destDT);
}
}
}
+static void
+WrapRotationAxis(int32_t* aRotationPoint, int32_t aSize)
+{
+ if (*aRotationPoint < 0) {
+ *aRotationPoint += aSize;
+ } else if (*aRotationPoint >= aSize) {
+ *aRotationPoint -= aSize;
+ }
+}
+
+static IntRect
+ComputeBufferRect(const IntRect& aRequestedRect)
+{
+ IntRect rect(aRequestedRect);
+ // Set a minimum width to guarantee a minimum size of buffers we
+ // allocate (and work around problems on some platforms with smaller
+ // dimensions). 64 used to be the magic number needed to work around
+ // a rendering glitch on b2g (see bug 788411). Now that we don't support
+ // this device anymore we should be fine with 8 pixels as the minimum.
+ rect.SetWidth(std::max(aRequestedRect.Width(), 8));
+ return rect;
+}
+
+bool
+RotatedBuffer::AdjustTo(const gfx::IntRect& aDestBufferRect,
+ const gfx::IntRect& aDrawBounds,
+ bool aCanHaveRotation,
+ bool aCanDrawRotated)
+{
+ IntRect keepArea;
+ if (keepArea.IntersectRect(aDestBufferRect, mBufferRect)) {
+ // Set mBufferRotation so that the pixels currently in mDTBuffer
+ // will still be rendered in the right place when mBufferRect
+ // changes to aDestBufferRect.
+ IntPoint newRotation = mBufferRotation +
+ (aDestBufferRect.TopLeft() - mBufferRect.TopLeft());
+ WrapRotationAxis(&newRotation.x, mBufferRect.Width());
+ WrapRotationAxis(&newRotation.y, mBufferRect.Height());
+ NS_ASSERTION(gfx::IntRect(gfx::IntPoint(0,0), mBufferRect.Size()).Contains(newRotation),
+ "newRotation out of bounds");
+
+ int32_t xBoundary = aDestBufferRect.XMost() - newRotation.x;
+ int32_t yBoundary = aDestBufferRect.YMost() - newRotation.y;
+ bool drawWrapsBuffer = (aDrawBounds.x < xBoundary && xBoundary < aDrawBounds.XMost()) ||
+ (aDrawBounds.y < yBoundary && yBoundary < aDrawBounds.YMost());
+
+ if ((drawWrapsBuffer && !aCanDrawRotated) ||
+ (newRotation != IntPoint(0,0) && !aCanHaveRotation)) {
+ // The stuff we need to redraw will wrap around an edge of the
+ // 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.
+ RefPtr<gfx::DrawTarget> dtBuffer = GetDTBuffer();
+ RefPtr<gfx::DrawTarget> dtBufferOnWhite = GetDTBufferOnWhite();
+
+ if (mBufferRotation == IntPoint(0,0)) {
+ IntRect srcRect(IntPoint(0, 0), mBufferRect.Size());
+ IntPoint dest = mBufferRect.TopLeft() - aDestBufferRect.TopLeft();
+
+ MOZ_ASSERT(dtBuffer && dtBuffer->IsValid());
+ dtBuffer->CopyRect(srcRect, dest);
+ if (HaveBufferOnWhite()) {
+ MOZ_ASSERT(dtBufferOnWhite && dtBufferOnWhite->IsValid());
+ dtBufferOnWhite->CopyRect(srcRect, dest);
+ }
+
+ mDidSelfCopy = true;
+ mBufferRect = aDestBufferRect;
+ } else {
+ // With azure and a data surface perform an buffer unrotate
+ // (SelfCopy).
+ unsigned char* data;
+ IntSize size;
+ int32_t stride;
+ SurfaceFormat format;
+
+ if (dtBuffer->LockBits(&data, &size, &stride, &format)) {
+ uint8_t bytesPerPixel = BytesPerPixel(format);
+ BufferUnrotate(data,
+ size.width * bytesPerPixel,
+ size.height, stride,
+ newRotation.x * bytesPerPixel, newRotation.y);
+ dtBuffer->ReleaseBits(data);
+
+ if (HaveBufferOnWhite()) {
+ MOZ_ASSERT(dtBufferOnWhite && dtBufferOnWhite->IsValid());
+ dtBufferOnWhite->LockBits(&data, &size, &stride, &format);
+ uint8_t bytesPerPixel = BytesPerPixel(format);
+ BufferUnrotate(data,
+ size.width * bytesPerPixel,
+ size.height, stride,
+ newRotation.x * bytesPerPixel, newRotation.y);
+ dtBufferOnWhite->ReleaseBits(data);
+ }
+
+ // Buffer unrotate moves all the pixels
+ mDidSelfCopy = true;
+ mBufferRect = aDestBufferRect;
+ mBufferRotation = IntPoint(0, 0);
+ }
+
+ if (!mDidSelfCopy) {
+ // We couldn't unrotate the buffer, so we need to create a
+ // new one and start from scratch
+ return false;
+ }
+ }
+ } else {
+ mBufferRect = aDestBufferRect;
+ mBufferRotation = newRotation;
+ }
+ } else {
+ // No pixels are going to be kept. The whole visible region
+ // will be redrawn, so we don't need to copy anything, so we don't
+ // set destBuffer.
+ mBufferRect = aDestBufferRect;
+ mBufferRotation = IntPoint(0,0);
+ }
+
+ return true;
+}
+
DrawTarget*
RotatedBuffer::BorrowDrawTargetForQuadrantUpdate(const IntRect& aBounds,
ContextSource aSource,
DrawIterator* aIter,
bool aSetTransform,
Matrix* aOutMatrix)
{
IntRect bounds = aBounds;
@@ -525,61 +647,32 @@ RotatedContentBuffer::HaveBuffer() const
}
bool
RotatedContentBuffer::HaveBufferOnWhite() const
{
return mBufferProviderOnWhite || (mDTBufferOnWhite && mDTBufferOnWhite->IsValid());
}
-static void
-WrapRotationAxis(int32_t* aRotationPoint, int32_t aSize)
-{
- if (*aRotationPoint < 0) {
- *aRotationPoint += aSize;
- } else if (*aRotationPoint >= aSize) {
- *aRotationPoint -= aSize;
- }
-}
-
-static IntRect
-ComputeBufferRect(const IntRect& aRequestedRect)
-{
- IntRect rect(aRequestedRect);
- // Set a minimum width to guarantee a minimum size of buffers we
- // allocate (and work around problems on some platforms with smaller
- // dimensions). 64 used to be the magic number needed to work around
- // a rendering glitch on b2g (see bug 788411). Now that we don't support
- // this device anymore we should be fine with 8 pixels as the minimum.
- rect.SetWidth(std::max(aRequestedRect.Width(), 8));
- return rect;
-}
-
void
RotatedContentBuffer::FlushBuffers()
{
if (mDTBuffer) {
mDTBuffer->Flush();
}
if (mDTBufferOnWhite) {
mDTBufferOnWhite->Flush();
}
}
RotatedContentBuffer::PaintState
RotatedContentBuffer::BeginPaint(PaintedLayer* aLayer,
uint32_t aFlags)
{
PaintState result;
- // We need to disable rotation if we're going to be resampled when
- // drawing, because we might sample across the rotation boundary.
- // Also disable buffer rotation when using webrender.
- bool canHaveRotation = gfxPlatform::BufferRotationEnabled() &&
- !(aFlags & (PAINT_WILL_RESAMPLE | PAINT_NO_ROTATION)) &&
- !(aLayer->Manager()->AsWebRenderLayerManager());
nsIntRegion validRegion = aLayer->GetValidRegion();
bool canUseOpaqueSurface = aLayer->CanUseOpaqueSurface();
ContentType layerContentType =
canUseOpaqueSurface ? gfxContentType::COLOR :
gfxContentType::COLOR_ALPHA;
@@ -698,124 +791,52 @@ RotatedContentBuffer::BeginPaint(Painted
// we only need to draw the latest bits, but we need a big refactor to support
// that ordering.
result.mRegionToDraw = neededRegion;
canReuseBuffer = false;
Clear();
}
}
+ // We need to disable rotation if we're going to be resampled when
+ // drawing, because we might sample across the rotation boundary.
+ // Also disable buffer rotation when using webrender.
+ bool canHaveRotation = gfxPlatform::BufferRotationEnabled() &&
+ !(aFlags & (PAINT_WILL_RESAMPLE | PAINT_NO_ROTATION)) &&
+ !(aLayer->Manager()->AsWebRenderLayerManager());
+ bool canDrawRotated = aFlags & PAINT_CAN_DRAW_ROTATED;
+
IntRect drawBounds = result.mRegionToDraw.GetBounds();
RefPtr<DrawTarget> destDTBuffer;
RefPtr<DrawTarget> destDTBufferOnWhite;
uint32_t bufferFlags = 0;
if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
bufferFlags |= BUFFER_COMPONENT_ALPHA;
}
if (canReuseBuffer) {
- if (!EnsureBuffer()) {
+ if (!EnsureBuffer() ||
+ (HaveBufferOnWhite() && !EnsureBufferOnWhite())) {
return result;
}
- IntRect keepArea;
- if (keepArea.IntersectRect(destBufferRect, mBufferRect)) {
- // Set mBufferRotation so that the pixels currently in mDTBuffer
- // will still be rendered in the right place when mBufferRect
- // changes to destBufferRect.
- IntPoint newRotation = mBufferRotation +
- (destBufferRect.TopLeft() - mBufferRect.TopLeft());
- WrapRotationAxis(&newRotation.x, mBufferRect.Width());
- WrapRotationAxis(&newRotation.y, mBufferRect.Height());
- NS_ASSERTION(gfx::IntRect(gfx::IntPoint(0,0), mBufferRect.Size()).Contains(newRotation),
- "newRotation out of bounds");
- int32_t xBoundary = destBufferRect.XMost() - newRotation.x;
- int32_t yBoundary = destBufferRect.YMost() - newRotation.y;
- bool drawWrapsBuffer = (drawBounds.x < xBoundary && xBoundary < drawBounds.XMost()) ||
- (drawBounds.y < yBoundary && yBoundary < drawBounds.YMost());
- if ((drawWrapsBuffer && !(aFlags & PAINT_CAN_DRAW_ROTATED)) ||
- (newRotation != IntPoint(0,0) && !canHaveRotation)) {
- // The stuff we need to redraw will wrap around an edge of the
- // 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 == IntPoint(0,0)) {
- IntRect srcRect(IntPoint(0, 0), mBufferRect.Size());
- IntPoint dest = mBufferRect.TopLeft() - destBufferRect.TopLeft();
- MOZ_ASSERT(mDTBuffer && mDTBuffer->IsValid());
- mDTBuffer->CopyRect(srcRect, dest);
- if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
- if (!EnsureBufferOnWhite()) {
- return result;
- }
- MOZ_ASSERT(mDTBufferOnWhite && mDTBufferOnWhite->IsValid());
- mDTBufferOnWhite->CopyRect(srcRect, dest);
- }
- mDidSelfCopy = true;
- // Don't set destBuffer; we special-case self-copies, and
- // just did the necessary work above.
- mBufferRect = destBufferRect;
- } else {
- // With azure and a data surface perform an buffer unrotate
- // (SelfCopy).
- unsigned char* data;
- IntSize size;
- int32_t stride;
- SurfaceFormat format;
- if (mDTBuffer->LockBits(&data, &size, &stride, &format)) {
- uint8_t bytesPerPixel = BytesPerPixel(format);
- BufferUnrotate(data,
- size.width * bytesPerPixel,
- size.height, stride,
- newRotation.x * bytesPerPixel, newRotation.y);
- mDTBuffer->ReleaseBits(data);
-
- if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
- if (!EnsureBufferOnWhite()) {
- return result;
- }
- MOZ_ASSERT(mDTBufferOnWhite && mDTBufferOnWhite->IsValid());
- mDTBufferOnWhite->LockBits(&data, &size, &stride, &format);
- uint8_t bytesPerPixel = BytesPerPixel(format);
- BufferUnrotate(data,
- size.width * bytesPerPixel,
- size.height, stride,
- newRotation.x * bytesPerPixel, newRotation.y);
- mDTBufferOnWhite->ReleaseBits(data);
- }
+ if (!AdjustTo(destBufferRect,
+ drawBounds,
+ canHaveRotation,
+ canDrawRotated)) {
+ destBufferRect = ComputeBufferRect(neededRegion.GetBounds());
+ CreateBuffer(result.mContentType, destBufferRect, bufferFlags,
+ &destDTBuffer, &destDTBufferOnWhite);
- // Buffer unrotate moves all the pixels, note that
- // we self copied for SyncBackToFrontBuffer
- mDidSelfCopy = true;
- mBufferRect = destBufferRect;
- mBufferRotation = IntPoint(0, 0);
- }
-
- if (!mDidSelfCopy) {
- destBufferRect = ComputeBufferRect(neededRegion.GetBounds());
- CreateBuffer(result.mContentType, destBufferRect, bufferFlags,
- &destDTBuffer, &destDTBufferOnWhite);
- if (!destDTBuffer ||
- (!destDTBufferOnWhite && (bufferFlags & BUFFER_COMPONENT_ALPHA))) {
- if (Factory::ReasonableSurfaceSize(IntSize(destBufferRect.Width(), destBufferRect.Height()))) {
- gfxCriticalNote << "Failed 1 buffer db=" << hexa(destDTBuffer.get()) << " dw=" << hexa(destDTBufferOnWhite.get()) << " for " << destBufferRect.x << ", " << destBufferRect.y << ", " << destBufferRect.Width() << ", " << destBufferRect.Height();
- }
- return result;
- }
- }
+ if (!destDTBuffer ||
+ (!destDTBufferOnWhite && (bufferFlags & BUFFER_COMPONENT_ALPHA))) {
+ if (Factory::ReasonableSurfaceSize(IntSize(destBufferRect.Width(), destBufferRect.Height()))) {
+ gfxCriticalNote << "Failed 1 buffer db=" << hexa(destDTBuffer.get()) << " dw=" << hexa(destDTBufferOnWhite.get()) << " for " << destBufferRect.x << ", " << destBufferRect.y << ", " << destBufferRect.Width() << ", " << destBufferRect.Height();
}
- } else {
- mBufferRect = destBufferRect;
- mBufferRotation = newRotation;
+ return result;
}
- } else {
- // No pixels are going to be kept. The whole visible region
- // will be redrawn, so we don't need to copy anything, so we don't
- // set destBuffer.
- mBufferRect = destBufferRect;
- mBufferRotation = IntPoint(0,0);
}
} else {
// The buffer's not big enough, so allocate a new one
CreateBuffer(result.mContentType, destBufferRect, bufferFlags,
&destDTBuffer, &destDTBufferOnWhite);
if (!destDTBuffer ||
(!destDTBufferOnWhite && (bufferFlags & BUFFER_COMPONENT_ALPHA))) {
if (Factory::ReasonableSurfaceSize(IntSize(destBufferRect.Width(), destBufferRect.Height()))) {