Bug 1383916 Prep a DrawTarget to be drawn to on the paint thread. r=dvander

This commit is contained in:
Mason Chang
2017-08-03 08:50:32 -07:00
parent 57379b2557
commit c749bb558e
7 changed files with 226 additions and 49 deletions

View File

@@ -27,6 +27,7 @@
#include "mozilla/gfx/Point.h" // for IntSize
#include "gfx2DGlue.h"
#include "nsLayoutUtils.h" // for invalidation debugging
#include "PaintThread.h"
namespace mozilla {
@@ -730,6 +731,77 @@ RotatedContentBuffer::BeginPaint(PaintedLayer* aLayer,
return result;
}
DrawTarget*
RotatedContentBuffer::BorrowDrawTargetForRecording(PaintState& aPaintState,
DrawIterator* aIter /* = nullptr */)
{
if (aPaintState.mMode == SurfaceMode::SURFACE_NONE) {
return nullptr;
}
DrawTarget* result = BorrowDrawTargetForQuadrantUpdate(aPaintState.mRegionToDraw.GetBounds(),
BUFFER_BOTH, aIter);
if (!result) {
return nullptr;
}
ExpandDrawRegion(aPaintState, aIter, result->GetBackendType());
return result;
}
/*static */ bool
RotatedContentBuffer::PrepareDrawTargetForPainting(CapturedPaintState* aState)
{
RefPtr<DrawTarget> target = aState->mTarget;
RefPtr<DrawTarget> whiteTarget = aState->mTargetOnWhite;
if (aState->mSurfaceMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
if (!target || !target->IsValid() ||
!aState->mTargetOnWhite || !aState->mTargetOnWhite->IsValid()) {
// This can happen in release builds if allocating one of the two buffers
// failed. This in turn can happen if unreasonably large textures are
// requested.
return false;
}
for (auto iter = aState->mRegionToDraw.RectIter(); !iter.Done(); iter.Next()) {
const IntRect& rect = iter.Get();
target->FillRect(Rect(rect.x, rect.y, rect.width, rect.height),
ColorPattern(Color(0.0, 0.0, 0.0, 1.0)));
whiteTarget->FillRect(Rect(rect.x, rect.y, rect.width, rect.height),
ColorPattern(Color(1.0, 1.0, 1.0, 1.0)));
}
} else if (aState->mContentType == gfxContentType::COLOR_ALPHA &&
target->IsValid()) {
// HaveBuffer() => we have an existing buffer that we must clear
for (auto iter = aState->mRegionToDraw.RectIter(); !iter.Done(); iter.Next()) {
const IntRect& rect = iter.Get();
target->ClearRect(Rect(rect.x, rect.y, rect.width, rect.height));
}
}
return true;
}
void
RotatedContentBuffer::ExpandDrawRegion(PaintState& aPaintState,
DrawIterator* aIter,
BackendType aBackendType)
{
nsIntRegion* drawPtr = &aPaintState.mRegionToDraw;
if (aIter) {
// The iterators draw region currently only contains the bounds of the region,
// this makes it the precise region.
aIter->mDrawRegion.And(aIter->mDrawRegion, aPaintState.mRegionToDraw);
drawPtr = &aIter->mDrawRegion;
}
if (aBackendType == BackendType::DIRECT2D ||
aBackendType == BackendType::DIRECT2D1_1) {
// Simplify the draw region to avoid hitting expensive drawing paths
// for complex regions.
drawPtr->SimplifyOutwardByArea(100 * 100);
}
}
DrawTarget*
RotatedContentBuffer::BorrowDrawTargetForPainting(PaintState& aPaintState,
DrawIterator* aIter /* = nullptr */)
@@ -744,41 +816,22 @@ RotatedContentBuffer::BorrowDrawTargetForPainting(PaintState& aPaintState,
return nullptr;
}
nsIntRegion* drawPtr = &aPaintState.mRegionToDraw;
if (aIter) {
// The iterators draw region currently only contains the bounds of the region,
// this makes it the precise region.
aIter->mDrawRegion.And(aIter->mDrawRegion, aPaintState.mRegionToDraw);
drawPtr = &aIter->mDrawRegion;
}
if (result->GetBackendType() == BackendType::DIRECT2D ||
result->GetBackendType() == BackendType::DIRECT2D1_1) {
// Simplify the draw region to avoid hitting expensive drawing paths
// for complex regions.
drawPtr->SimplifyOutwardByArea(100 * 100);
}
ExpandDrawRegion(aPaintState, aIter, result->GetBackendType());
if (aPaintState.mMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
if (!mDTBuffer || !mDTBuffer->IsValid() ||
!mDTBufferOnWhite || !mDTBufferOnWhite->IsValid()) {
// This can happen in release builds if allocating one of the two buffers
// failed. This in turn can happen if unreasonably large textures are
// requested.
return nullptr;
}
for (auto iter = drawPtr->RectIter(); !iter.Done(); iter.Next()) {
const IntRect& rect = iter.Get();
mDTBuffer->FillRect(Rect(rect.x, rect.y, rect.width, rect.height),
ColorPattern(Color(0.0, 0.0, 0.0, 1.0)));
mDTBufferOnWhite->FillRect(Rect(rect.x, rect.y, rect.width, rect.height),
ColorPattern(Color(1.0, 1.0, 1.0, 1.0)));
}
} else if (aPaintState.mContentType == gfxContentType::COLOR_ALPHA && HaveBuffer()) {
// HaveBuffer() => we have an existing buffer that we must clear
for (auto iter = drawPtr->RectIter(); !iter.Done(); iter.Next()) {
const IntRect& rect = iter.Get();
result->ClearRect(Rect(rect.x, rect.y, rect.width, rect.height));
}
nsIntRegion regionToDraw = aIter ? aIter->mDrawRegion
: aPaintState.mRegionToDraw;
// Can't stack allocate refcounted objects.
RefPtr<CapturedPaintState> capturedPaintState =
MakeAndAddRef<CapturedPaintState>(regionToDraw,
mDTBuffer,
mDTBufferOnWhite,
Matrix(),
aPaintState.mMode,
aPaintState.mContentType);
if (!RotatedContentBuffer::PrepareDrawTargetForPainting(capturedPaintState)) {
return nullptr;
}
return result;