--- a/gfx/layers/RotatedBuffer.cpp
+++ b/gfx/layers/RotatedBuffer.cpp
@@ -19,16 +19,17 @@
#include "mozilla/gfx/BaseRect.h" // for BaseRect
#include "mozilla/gfx/BaseSize.h" // for BaseSize
#include "mozilla/gfx/Matrix.h" // for Matrix
#include "mozilla/gfx/Point.h" // for Point, IntPoint
#include "mozilla/gfx/Rect.h" // for Rect, IntRect
#include "mozilla/gfx/Types.h" // for ExtendMode::ExtendMode::CLAMP, etc
#include "mozilla/layers/ShadowLayers.h" // for ShadowableLayer
#include "mozilla/layers/TextureClient.h" // for TextureClient
+#include "mozilla/Move.h" // for Move
#include "mozilla/gfx/Point.h" // for IntSize
#include "gfx2DGlue.h"
#include "nsLayoutUtils.h" // for invalidation debugging
#include "PaintThread.h"
namespace mozilla {
using namespace gfx;
@@ -581,16 +582,116 @@ SourceRotatedBuffer::GetSourceSurface(Co
MOZ_ASSERT(aSource == BUFFER_WHITE);
surf = mSourceOnWhite;
}
MOZ_ASSERT(surf);
return surf.forget();
}
+RotatedContentBuffer::BufferDecision
+RotatedContentBuffer::CalculateBufferForPaint(PaintedLayer* aLayer,
+ uint32_t aFlags)
+{
+ ContentType layerContentType =
+ aLayer->CanUseOpaqueSurface() ? gfxContentType::COLOR :
+ gfxContentType::COLOR_ALPHA;
+
+ SurfaceMode mode;
+ ContentType contentType;
+ IntRect destBufferRect;
+ nsIntRegion neededRegion;
+ nsIntRegion validRegion = aLayer->GetValidRegion();
+
+ bool canReuseBuffer = HaveBuffer();
+ bool canKeepBufferContents = true;
+
+ while (true) {
+ mode = aLayer->GetSurfaceMode();
+ neededRegion = aLayer->GetVisibleRegion().ToUnknownRegion();
+ canReuseBuffer &= BufferSizeOkFor(neededRegion.GetBounds().Size());
+ contentType = layerContentType;
+
+ if (canReuseBuffer) {
+ if (mBufferRect.Contains(neededRegion.GetBounds())) {
+ // We don't need to adjust mBufferRect.
+ destBufferRect = mBufferRect;
+ } else if (neededRegion.GetBounds().Size() <= mBufferRect.Size()) {
+ // The buffer's big enough but doesn't contain everything that's
+ // going to be visible. We'll move it.
+ destBufferRect = IntRect(neededRegion.GetBounds().TopLeft(), mBufferRect.Size());
+ } else {
+ destBufferRect = neededRegion.GetBounds();
+ }
+ } else {
+ // We won't be reusing the buffer. Compute a new rect.
+ destBufferRect = ComputeBufferRect(neededRegion.GetBounds());
+ }
+
+ if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
+#if defined(MOZ_GFX_OPTIMIZE_MOBILE)
+ mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
+#else
+ if (!aLayer->GetParent() ||
+ !aLayer->GetParent()->SupportsComponentAlphaChildren() ||
+ !aLayer->AsShadowableLayer() ||
+ !aLayer->AsShadowableLayer()->HasShadow()) {
+ mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
+ } else {
+ contentType = gfxContentType::COLOR;
+ }
+#endif
+ }
+
+ if ((aFlags & PAINT_WILL_RESAMPLE) &&
+ (!neededRegion.GetBounds().IsEqualInterior(destBufferRect) ||
+ neededRegion.GetNumRects() > 1))
+ {
+ // The area we add to neededRegion might not be painted opaquely.
+ if (mode == SurfaceMode::SURFACE_OPAQUE) {
+ contentType = gfxContentType::COLOR_ALPHA;
+ mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
+ }
+
+ // We need to validate the entire buffer, to make sure that only valid
+ // pixels are sampled.
+ neededRegion = destBufferRect;
+ }
+
+ // If we have an existing buffer, but the content type has changed or we
+ // have transitioned into/out of component alpha, then we need to recreate it.
+ if (canReuseBuffer &&
+ (contentType != BufferContentType() ||
+ (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) != HaveBufferOnWhite()))
+ {
+ // Restart the decision process; we won't re-enter since we guard on
+ // being able to re-use the buffer.
+ canReuseBuffer = false;
+ canKeepBufferContents = false;
+ validRegion.SetEmpty();
+ continue;
+ }
+
+ break;
+ }
+
+ NS_ASSERTION(destBufferRect.Contains(neededRegion.GetBounds()),
+ "Destination rect doesn't contain what we need to paint");
+
+ BufferDecision dest;
+ dest.mNeededRegion = Move(neededRegion);
+ dest.mValidRegion = Move(validRegion);
+ dest.mBufferRect = destBufferRect;
+ dest.mBufferMode = mode;
+ dest.mBufferContentType = contentType;
+ dest.mCanReuseBuffer = canReuseBuffer;
+ dest.mCanKeepBufferContents = canKeepBufferContents;
+ return dest;
+}
+
gfxContentType
RotatedContentBuffer::BufferContentType()
{
if (mBufferProvider || (mDTBuffer && mDTBuffer->IsValid())) {
SurfaceFormat format = SurfaceFormat::B8G8R8A8;
if (mBufferProvider) {
format = mBufferProvider->GetFormat();
@@ -664,224 +765,154 @@ RotatedContentBuffer::FlushBuffers()
}
RotatedContentBuffer::PaintState
RotatedContentBuffer::BeginPaint(PaintedLayer* aLayer,
uint32_t aFlags)
{
PaintState result;
- nsIntRegion validRegion = aLayer->GetValidRegion();
-
- bool canUseOpaqueSurface = aLayer->CanUseOpaqueSurface();
- ContentType layerContentType =
- canUseOpaqueSurface ? gfxContentType::COLOR :
- gfxContentType::COLOR_ALPHA;
-
- SurfaceMode mode;
- nsIntRegion neededRegion;
- IntRect destBufferRect;
-
- bool canReuseBuffer = HaveBuffer();
-
- while (true) {
- mode = aLayer->GetSurfaceMode();
- neededRegion = aLayer->GetVisibleRegion().ToUnknownRegion();
- canReuseBuffer &= BufferSizeOkFor(neededRegion.GetBounds().Size());
- result.mContentType = layerContentType;
-
- if (canReuseBuffer) {
- if (mBufferRect.Contains(neededRegion.GetBounds())) {
- // We don't need to adjust mBufferRect.
- destBufferRect = mBufferRect;
- } else if (neededRegion.GetBounds().Size() <= mBufferRect.Size()) {
- // The buffer's big enough but doesn't contain everything that's
- // going to be visible. We'll move it.
- destBufferRect = IntRect(neededRegion.GetBounds().TopLeft(), mBufferRect.Size());
- } else {
- destBufferRect = neededRegion.GetBounds();
- }
- } else {
- // We won't be reusing the buffer. Compute a new rect.
- destBufferRect = ComputeBufferRect(neededRegion.GetBounds());
- }
+ BufferDecision dest = CalculateBufferForPaint(aLayer, aFlags);
+ result.mContentType = dest.mBufferContentType;
- if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
-#if defined(MOZ_GFX_OPTIMIZE_MOBILE)
- mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
-#else
- if (!aLayer->GetParent() ||
- !aLayer->GetParent()->SupportsComponentAlphaChildren() ||
- !aLayer->AsShadowableLayer() ||
- !aLayer->AsShadowableLayer()->HasShadow()) {
- mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
- } else {
- result.mContentType = gfxContentType::COLOR;
- }
-#endif
- }
-
- if ((aFlags & PAINT_WILL_RESAMPLE) &&
- (!neededRegion.GetBounds().IsEqualInterior(destBufferRect) ||
- neededRegion.GetNumRects() > 1))
- {
- // The area we add to neededRegion might not be painted opaquely.
- if (mode == SurfaceMode::SURFACE_OPAQUE) {
- result.mContentType = gfxContentType::COLOR_ALPHA;
- mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
- }
-
- // We need to validate the entire buffer, to make sure that only valid
- // pixels are sampled.
- neededRegion = destBufferRect;
- }
-
- // If we have an existing buffer, but the content type has changed or we
- // have transitioned into/out of component alpha, then we need to recreate it.
- if (canReuseBuffer &&
- (result.mContentType != BufferContentType() ||
- (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) != HaveBufferOnWhite()))
- {
- // Restart the decision process; we won't re-enter since we guard on
- // being able to re-use the buffer.
- canReuseBuffer = false;
- continue;
- }
-
- break;
- }
-
- if (HaveBuffer() &&
- (result.mContentType != BufferContentType() ||
- (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) != HaveBufferOnWhite()))
- {
+ if (!dest.mCanKeepBufferContents) {
// We're effectively clearing the valid region, so we need to draw
// the entire needed region now.
- canReuseBuffer = false;
+ MOZ_ASSERT(!dest.mCanReuseBuffer);
+ MOZ_ASSERT(dest.mValidRegion.IsEmpty());
+
result.mRegionToInvalidate = aLayer->GetValidRegion();
- validRegion.SetEmpty();
Clear();
#if defined(MOZ_DUMP_PAINTING)
if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
if (result.mContentType != BufferContentType()) {
printf_stderr("Invalidating entire rotated buffer (layer %p): content type changed\n", aLayer);
- } else if ((mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) != HaveBufferOnWhite()) {
+ } else if ((dest.mBufferMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) != HaveBufferOnWhite()) {
printf_stderr("Invalidating entire rotated buffer (layer %p): component alpha changed\n", aLayer);
}
}
#endif
}
- NS_ASSERTION(destBufferRect.Contains(neededRegion.GetBounds()),
- "Destination rect doesn't contain what we need to paint");
-
- result.mRegionToDraw.Sub(neededRegion, validRegion);
+ result.mRegionToDraw.Sub(dest.mNeededRegion,
+ dest.mValidRegion);
if (result.mRegionToDraw.IsEmpty())
return result;
if (HaveBuffer()) {
if (LockBuffers()) {
// Do not modify result.mRegionToDraw or result.mContentType after this call.
// Do not modify mBufferRect, mBufferRotation, or mDidSelfCopy,
// or call CreateBuffer before this call.
FinalizeFrame(result.mRegionToDraw);
} else {
// Abandon everything and redraw it all. Ideally we'd reallocate and copy
// the old to the new and then call FinalizeFrame on the new buffer so that
// we only need to draw the latest bits, but we need a big refactor to support
// that ordering.
- result.mRegionToDraw = neededRegion;
- canReuseBuffer = false;
+ result.mRegionToDraw = dest.mNeededRegion;
+ dest.mCanReuseBuffer = 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) {
+ if (dest.mBufferMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
bufferFlags |= BUFFER_COMPONENT_ALPHA;
}
- if (canReuseBuffer) {
+ if (dest.mCanReuseBuffer) {
if (!EnsureBuffer() ||
(HaveBufferOnWhite() && !EnsureBufferOnWhite())) {
return result;
}
- if (!AdjustTo(destBufferRect,
+ if (!AdjustTo(dest.mBufferRect,
drawBounds,
canHaveRotation,
canDrawRotated)) {
- destBufferRect = ComputeBufferRect(neededRegion.GetBounds());
- CreateBuffer(result.mContentType, destBufferRect, bufferFlags,
+ dest.mBufferRect = ComputeBufferRect(dest.mNeededRegion.GetBounds());
+ CreateBuffer(result.mContentType, dest.mBufferRect, 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();
+ if (Factory::ReasonableSurfaceSize(IntSize(dest.mBufferRect.Width(), dest.mBufferRect.Height()))) {
+ gfxCriticalNote << "Failed 1 buffer db=" << hexa(destDTBuffer.get())
+ << " dw=" << hexa(destDTBufferOnWhite.get())
+ << " for " << dest.mBufferRect.x << ", "
+ << dest.mBufferRect.y << ", "
+ << dest.mBufferRect.Width() << ", "
+ << dest.mBufferRect.Height();
}
return result;
}
}
} else {
// The buffer's not big enough, so allocate a new one
- CreateBuffer(result.mContentType, destBufferRect, bufferFlags,
+ CreateBuffer(result.mContentType, dest.mBufferRect, bufferFlags,
&destDTBuffer, &destDTBufferOnWhite);
if (!destDTBuffer ||
(!destDTBufferOnWhite && (bufferFlags & BUFFER_COMPONENT_ALPHA))) {
- if (Factory::ReasonableSurfaceSize(IntSize(destBufferRect.Width(), destBufferRect.Height()))) {
- gfxCriticalNote << "Failed 2 buffer db=" << hexa(destDTBuffer.get()) << " dw=" << hexa(destDTBufferOnWhite.get()) << " for " << destBufferRect.x << ", " << destBufferRect.y << ", " << destBufferRect.Width() << ", " << destBufferRect.Height();
+ if (Factory::ReasonableSurfaceSize(IntSize(dest.mBufferRect.Width(), dest.mBufferRect.Height()))) {
+ gfxCriticalNote << "Failed 2 buffer db=" << hexa(destDTBuffer.get())
+ << " dw=" << hexa(destDTBufferOnWhite.get())
+ << " for " << dest.mBufferRect.x << ", "
+ << dest.mBufferRect.y << ", "
+ << dest.mBufferRect.Width() << ", "
+ << dest.mBufferRect.Height();
}
return result;
}
}
- NS_ASSERTION(!(aFlags & PAINT_WILL_RESAMPLE) || destBufferRect == neededRegion.GetBounds(),
+ NS_ASSERTION(!(aFlags & PAINT_WILL_RESAMPLE) || dest.mBufferRect == dest.mNeededRegion.GetBounds(),
"If we're resampling, we need to validate the entire buffer");
// If needed, copy the old buffer over to the new one
if (destDTBuffer) {
if ((HaveBuffer() && EnsureBuffer()) &&
- (mode != SurfaceMode::SURFACE_COMPONENT_ALPHA || (HaveBufferOnWhite() && EnsureBufferOnWhite()))) {
+ (dest.mBufferMode != SurfaceMode::SURFACE_COMPONENT_ALPHA || (HaveBufferOnWhite() && EnsureBufferOnWhite()))) {
DrawTargetRotatedBuffer oldBuffer = DrawTargetRotatedBuffer(mDTBuffer, mDTBufferOnWhite,
mBufferRect, mBufferRotation);
mDTBuffer = destDTBuffer.forget();
mDTBufferOnWhite = destDTBufferOnWhite.forget();
- mBufferRect = destBufferRect;
+ mBufferRect = dest.mBufferRect;
mBufferRotation = IntPoint(0,0);
UpdateDestinationFrom(oldBuffer, nsIntRegion(mBufferRect));
} else {
mDTBuffer = destDTBuffer.forget();
mDTBufferOnWhite = destDTBufferOnWhite.forget();
- mBufferRect = destBufferRect;
+ mBufferRect = dest.mBufferRect;
mBufferRotation = IntPoint(0,0);
}
}
NS_ASSERTION(canHaveRotation || mBufferRotation == IntPoint(0,0),
"Rotation disabled, but we have nonzero rotation?");
nsIntRegion invalidate;
- invalidate.Sub(aLayer->GetValidRegion(), destBufferRect);
+ invalidate.Sub(aLayer->GetValidRegion(), dest.mBufferRect);
result.mRegionToInvalidate.Or(result.mRegionToInvalidate, invalidate);
+
result.mClip = DrawRegionClip::DRAW;
- result.mMode = mode;
+ result.mMode = dest.mBufferMode;
return result;
}
RefPtr<CapturedPaintState>
RotatedContentBuffer::BorrowDrawTargetForRecording(PaintState& aPaintState,
DrawIterator* aIter,
bool aSetTransform)