Bug 992486 - Part 2: Make ContentHostSingleBuffered able to handle updates that cross the rotation boundary. r=nical

This commit is contained in:
Matt Woodrow 2014-04-09 21:15:17 +12:00
parent 031f178fa9
commit 0a23f9d8f6

View File

@ -284,6 +284,16 @@ ContentHostTexture::Dump(FILE* aFile,
}
#endif
static inline void
AddWrappedRegion(const nsIntRegion& aInput, nsIntRegion& aOutput,
const nsIntSize& aSize, const nsIntPoint& aShift)
{
nsIntRegion tempRegion;
tempRegion.And(nsIntRect(aShift, aSize), aInput);
tempRegion.MoveBy(-aShift);
aOutput.Or(aOutput, tempRegion);
}
bool
ContentHostSingleBuffered::UpdateThebes(const ThebesBufferData& aData,
const nsIntRegion& aUpdated,
@ -301,26 +311,38 @@ ContentHostSingleBuffered::UpdateThebes(const ThebesBufferData& aData,
nsIntRegion destRegion(aUpdated);
destRegion.MoveBy(-aData.rect().TopLeft());
// Correct for rotation
destRegion.MoveBy(aData.rotation());
IntSize size = aData.rect().Size().ToIntSize();
nsIntRect destBounds = destRegion.GetBounds();
destRegion.MoveBy((destBounds.x >= size.width) ? -size.width : 0,
(destBounds.y >= size.height) ? -size.height : 0);
// We can get arbitrary bad regions from an untrusted client,
// which we need to be resilient to. See bug 967330.
if((destBounds.x % size.width) + destBounds.width > size.width ||
(destBounds.y % size.height) + destBounds.height > size.height)
{
NS_ERROR("updated region lies across rotation boundaries!");
if (!aData.rect().Contains(aUpdated.GetBounds()) ||
aData.rotation().x > aData.rect().width ||
aData.rotation().y > aData.rect().height) {
NS_ERROR("Invalid update data");
return false;
}
mTextureHost->Updated(&destRegion);
// destRegion is now in logical coordinates relative to the buffer, but we
// need to account for rotation. We do that by moving the region to the
// rotation offset and then wrapping any pixels that extend off the
// bottom/right edges.
// Shift to the rotation point
destRegion.MoveBy(aData.rotation());
nsIntSize bufferSize = aData.rect().Size();
// Select only the pixels that are still within the buffer.
nsIntRegion finalRegion;
finalRegion.And(nsIntRect(nsIntPoint(), bufferSize), destRegion);
// For each of the overlap areas (right, bottom-right, bottom), select those
// pixels and wrap them around to the opposite edge of the buffer rect.
AddWrappedRegion(destRegion, finalRegion, bufferSize, nsIntPoint(aData.rect().width, 0));
AddWrappedRegion(destRegion, finalRegion, bufferSize, nsIntPoint(aData.rect().width, aData.rect().height));
AddWrappedRegion(destRegion, finalRegion, bufferSize, nsIntPoint(0, aData.rect().height));
MOZ_ASSERT(nsIntRect(0, 0, aData.rect().width, aData.rect().height).Contains(finalRegion.GetBounds()));
mTextureHost->Updated(&finalRegion);
if (mTextureHostOnWhite) {
mTextureHostOnWhite->Updated(&destRegion);
mTextureHostOnWhite->Updated(&finalRegion);
}
mInitialised = true;