From 0a23f9d8f620388e0df219bc57b7334431fccc36 Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Wed, 9 Apr 2014 21:15:17 +1200 Subject: [PATCH] Bug 992486 - Part 2: Make ContentHostSingleBuffered able to handle updates that cross the rotation boundary. r=nical --- gfx/layers/composite/ContentHost.cpp | 54 +++++++++++++++++++--------- 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/gfx/layers/composite/ContentHost.cpp b/gfx/layers/composite/ContentHost.cpp index 5a06eaa1706..3a956e13250 100644 --- a/gfx/layers/composite/ContentHost.cpp +++ b/gfx/layers/composite/ContentHost.cpp @@ -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;