Bug 1105834 - Part 1: Add CreateDataSourceSurfaceByCloning to moz2d. r=mstange,bas

--HG--
extra : rebase_source : 361ea428e03d80c31d9041809afcdab7ae3a32e6
This commit is contained in:
Benoit Girard 2014-11-28 18:11:03 -05:00
parent 340c56ea1f
commit 3cd71202c6
4 changed files with 133 additions and 98 deletions

View File

@ -9,11 +9,41 @@
#include "DataSurfaceHelpers.h"
#include "Logging.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/PodOperations.h"
#include "Tools.h"
namespace mozilla {
namespace gfx {
uint8_t*
DataAtOffset(DataSourceSurface* aSurface, IntPoint aPoint)
{
if (!SurfaceContainsPoint(aSurface, aPoint)) {
MOZ_CRASH("sample position needs to be inside surface!");
}
MOZ_ASSERT(Factory::CheckSurfaceSize(aSurface->GetSize()),
"surface size overflows - this should have been prevented when the surface was created");
uint8_t* data = aSurface->GetData() + aPoint.y * aSurface->Stride() +
aPoint.x * BytesPerPixel(aSurface->GetFormat());
if (data < aSurface->GetData()) {
MOZ_CRASH("out-of-range data access");
}
return data;
}
// This check is safe against integer overflow.
bool
SurfaceContainsPoint(SourceSurface* aSurface, const IntPoint& aPoint)
{
IntSize size = aSurface->GetSize();
return aPoint.x >= 0 && aPoint.x < size.width &&
aPoint.y >= 0 && aPoint.y < size.height;
}
void
ConvertBGRXToBGRA(uint8_t* aData, const IntSize &aSize, int32_t aStride)
{
@ -196,5 +226,57 @@ BufferSizeFromStrideAndHeight(int32_t aStride,
return requiredBytes.value();
}
/**
* aSrcRect: Rect relative to the aSrc surface
* aDestPoint: Point inside aDest surface
*/
void
CopyRect(DataSourceSurface* aSrc, DataSourceSurface* aDest,
IntRect aSrcRect, IntPoint aDestPoint)
{
if (aSrcRect.Overflows() ||
IntRect(aDestPoint, aSrcRect.Size()).Overflows()) {
MOZ_CRASH("we should never be getting invalid rects at this point");
}
MOZ_ASSERT(aSrc->GetFormat() == aDest->GetFormat(), "different surface formats");
MOZ_ASSERT(IntRect(IntPoint(), aSrc->GetSize()).Contains(aSrcRect), "source rect too big for source surface");
MOZ_ASSERT(IntRect(IntPoint(), aDest->GetSize()).Contains(aSrcRect - aSrcRect.TopLeft() + aDestPoint), "dest surface too small");
if (aSrcRect.IsEmpty()) {
return;
}
uint8_t* sourceData = DataAtOffset(aSrc, aSrcRect.TopLeft());
uint32_t sourceStride = aSrc->Stride();
uint8_t* destData = DataAtOffset(aDest, aDestPoint);
uint32_t destStride = aDest->Stride();
if (BytesPerPixel(aSrc->GetFormat()) == 4) {
for (int32_t y = 0; y < aSrcRect.height; y++) {
PodCopy((int32_t*)destData, (int32_t*)sourceData, aSrcRect.width);
sourceData += sourceStride;
destData += destStride;
}
} else if (BytesPerPixel(aSrc->GetFormat()) == 1) {
for (int32_t y = 0; y < aSrcRect.height; y++) {
PodCopy(destData, sourceData, aSrcRect.width);
sourceData += sourceStride;
destData += destStride;
}
}
}
TemporaryRef<DataSourceSurface>
CreateDataSourceSurfaceByCloning(DataSourceSurface* aSource)
{
RefPtr<DataSourceSurface> copy =
Factory::CreateDataSourceSurface(aSource->GetSize(), aSource->GetFormat(), true);
if (copy) {
CopyRect(aSource, copy, IntRect(IntPoint(), aSource->GetSize()), IntPoint());
}
return copy.forget();
}
}
}

View File

@ -70,6 +70,36 @@ BufferSizeFromStrideAndHeight(int32_t aStride,
int32_t aHeight,
int32_t aExtraBytes = 0);
/**
* Copy aSrcRect from aSrc to aDest starting at aDestPoint.
*/
void
CopyRect(DataSourceSurface* aSrc, DataSourceSurface* aDest,
IntRect aSrcRect, IntPoint aDestPoint);
/**
* Create a non aliasing copy of aSource. This creates a new DataSourceSurface
* using the factory and copies the bits.
*
* @return a dss allocated by Factory that contains a copy a aSource.
*/
TemporaryRef<DataSourceSurface>
CreateDataSourceSurfaceByCloning(DataSourceSurface* aSource);
/**
* Return the byte at aPoint.
*/
uint8_t*
DataAtOffset(DataSourceSurface* aSurface, IntPoint aPoint);
/**
* Check if aPoint is contained by the surface.
*
* @returns true if and only if aPoint is inside the surface.
*/
bool
SurfaceContainsPoint(SourceSurface* aSurface, const IntPoint& aPoint);
}
}

View File

@ -180,101 +180,16 @@ NS_lround(double x)
return x >= 0.0 ? int32_t(x + 0.5) : int32_t(x - 0.5);
}
// This check is safe against integer overflow.
static bool
SurfaceContainsPoint(SourceSurface* aSurface, const IntPoint& aPoint)
{
IntSize size = aSurface->GetSize();
return aPoint.x >= 0 && aPoint.x < size.width &&
aPoint.y >= 0 && aPoint.y < size.height;
}
static uint8_t*
DataAtOffset(DataSourceSurface* aSurface, IntPoint aPoint)
{
if (!SurfaceContainsPoint(aSurface, aPoint)) {
MOZ_CRASH("sample position needs to be inside surface!");
}
MOZ_ASSERT(Factory::CheckSurfaceSize(aSurface->GetSize()),
"surface size overflows - this should have been prevented when the surface was created");
uint8_t* data = aSurface->GetData() + aPoint.y * aSurface->Stride() +
aPoint.x * BytesPerPixel(aSurface->GetFormat());
if (data < aSurface->GetData()) {
MOZ_CRASH("out-of-range data access");
}
return data;
}
static bool
IntRectOverflows(const IntRect& aRect)
{
CheckedInt<int32_t> xMost = aRect.x;
xMost += aRect.width;
CheckedInt<int32_t> yMost = aRect.y;
yMost += aRect.height;
return !xMost.isValid() || !yMost.isValid();
}
/**
* aSrcRect: Rect relative to the aSrc surface
* aDestPoint: Point inside aDest surface
*/
static void
CopyRect(DataSourceSurface* aSrc, DataSourceSurface* aDest,
IntRect aSrcRect, IntPoint aDestPoint)
{
if (IntRectOverflows(aSrcRect) ||
IntRectOverflows(IntRect(aDestPoint, aSrcRect.Size()))) {
MOZ_CRASH("we should never be getting invalid rects at this point");
}
MOZ_ASSERT(aSrc->GetFormat() == aDest->GetFormat(), "different surface formats");
MOZ_ASSERT(IntRect(IntPoint(), aSrc->GetSize()).Contains(aSrcRect), "source rect too big for source surface");
MOZ_ASSERT(IntRect(IntPoint(), aDest->GetSize()).Contains(aSrcRect - aSrcRect.TopLeft() + aDestPoint), "dest surface too small");
if (aSrcRect.IsEmpty()) {
return;
}
uint8_t* sourceData = DataAtOffset(aSrc, aSrcRect.TopLeft());
uint32_t sourceStride = aSrc->Stride();
uint8_t* destData = DataAtOffset(aDest, aDestPoint);
uint32_t destStride = aDest->Stride();
if (BytesPerPixel(aSrc->GetFormat()) == 4) {
for (int32_t y = 0; y < aSrcRect.height; y++) {
PodCopy((int32_t*)destData, (int32_t*)sourceData, aSrcRect.width);
sourceData += sourceStride;
destData += destStride;
}
} else if (BytesPerPixel(aSrc->GetFormat()) == 1) {
for (int32_t y = 0; y < aSrcRect.height; y++) {
PodCopy(destData, sourceData, aSrcRect.width);
sourceData += sourceStride;
destData += destStride;
}
}
}
TemporaryRef<DataSourceSurface>
CloneAligned(DataSourceSurface* aSource)
{
RefPtr<DataSourceSurface> copy =
Factory::CreateDataSourceSurface(aSource->GetSize(), aSource->GetFormat(), true);
if (copy) {
CopyRect(aSource, copy, IntRect(IntPoint(), aSource->GetSize()), IntPoint());
}
return copy.forget();
return CreateDataSourceSurfaceByCloning(aSource);
}
static void
FillRectWithPixel(DataSourceSurface *aSurface, const IntRect &aFillRect, IntPoint aPixelPos)
{
MOZ_ASSERT(!IntRectOverflows(aFillRect));
MOZ_ASSERT(!aFillRect.Overflows());
MOZ_ASSERT(IntRect(IntPoint(), aSurface->GetSize()).Contains(aFillRect),
"aFillRect needs to be completely inside the surface");
MOZ_ASSERT(SurfaceContainsPoint(aSurface, aPixelPos),
@ -307,8 +222,8 @@ FillRectWithVerticallyRepeatingHorizontalStrip(DataSourceSurface *aSurface,
const IntRect &aFillRect,
const IntRect &aSampleRect)
{
MOZ_ASSERT(!IntRectOverflows(aFillRect));
MOZ_ASSERT(!IntRectOverflows(aSampleRect));
MOZ_ASSERT(!aFillRect.Overflows());
MOZ_ASSERT(!aSampleRect.Overflows());
MOZ_ASSERT(IntRect(IntPoint(), aSurface->GetSize()).Contains(aFillRect),
"aFillRect needs to be completely inside the surface");
MOZ_ASSERT(IntRect(IntPoint(), aSurface->GetSize()).Contains(aSampleRect),
@ -335,8 +250,8 @@ FillRectWithHorizontallyRepeatingVerticalStrip(DataSourceSurface *aSurface,
const IntRect &aFillRect,
const IntRect &aSampleRect)
{
MOZ_ASSERT(!IntRectOverflows(aFillRect));
MOZ_ASSERT(!IntRectOverflows(aSampleRect));
MOZ_ASSERT(!aFillRect.Overflows());
MOZ_ASSERT(!aSampleRect.Overflows());
MOZ_ASSERT(IntRect(IntPoint(), aSurface->GetSize()).Contains(aFillRect),
"aFillRect needs to be completely inside the surface");
MOZ_ASSERT(IntRect(IntPoint(), aSurface->GetSize()).Contains(aSampleRect),
@ -367,7 +282,7 @@ FillRectWithHorizontallyRepeatingVerticalStrip(DataSourceSurface *aSurface,
static void
DuplicateEdges(DataSourceSurface* aSurface, const IntRect &aFromRect)
{
MOZ_ASSERT(!IntRectOverflows(aFromRect));
MOZ_ASSERT(!aFromRect.Overflows());
MOZ_ASSERT(IntRect(IntPoint(), aSurface->GetSize()).Contains(aFromRect),
"aFromRect needs to be completely inside the surface");
@ -475,7 +390,7 @@ GetDataSurfaceInRect(SourceSurface *aSurface,
{
MOZ_ASSERT(aSurface ? aSurfaceRect.Size() == aSurface->GetSize() : aSurfaceRect.IsEmpty());
if (IntRectOverflows(aSurfaceRect) || IntRectOverflows(aDestRect)) {
if (aSurfaceRect.Overflows() || aDestRect.Overflows()) {
// We can't rely on the intersection calculations below to make sense when
// XMost() or YMost() overflow. Bail out.
return nullptr;
@ -629,7 +544,7 @@ FilterNodeSoftware::Draw(DrawTarget* aDrawTarget,
}
IntRect outputRect = GetOutputRectInRect(renderIntRect);
if (IntRectOverflows(outputRect)) {
if (outputRect.Overflows()) {
#ifdef DEBUG_DUMP_SURFACES
printf("output rect overflowed, not painting anything\n");
printf("</pre>\n");
@ -680,7 +595,7 @@ FilterNodeSoftware::GetOutput(const IntRect &aRect)
{
MOZ_ASSERT(GetOutputRectInRect(aRect).Contains(aRect));
if (IntRectOverflows(aRect)) {
if (aRect.Overflows()) {
return nullptr;
}
@ -710,7 +625,7 @@ FilterNodeSoftware::RequestRect(const IntRect &aRect)
void
FilterNodeSoftware::RequestInputRect(uint32_t aInputEnumIndex, const IntRect &aRect)
{
if (IntRectOverflows(aRect)) {
if (aRect.Overflows()) {
return;
}
@ -743,7 +658,7 @@ FilterNodeSoftware::GetInputDataSourceSurface(uint32_t aInputEnumIndex,
ConvolveMatrixEdgeMode aEdgeMode,
const IntRect *aTransparencyPaddedSourceRect)
{
if (IntRectOverflows(aRect)) {
if (aRect.Overflows()) {
return nullptr;
}
@ -858,7 +773,7 @@ IntRect
FilterNodeSoftware::GetInputRectInRect(uint32_t aInputEnumIndex,
const IntRect &aInRect)
{
if (IntRectOverflows(aInRect)) {
if (aInRect.Overflows()) {
return IntRect();
}

View File

@ -91,6 +91,14 @@ struct IntRectTyped :
IntRectTyped<UnknownUnits> ToUnknownRect() const {
return IntRectTyped<UnknownUnits>(this->x, this->y, this->width, this->height);
}
bool Overflows() const {
CheckedInt<int32_t> xMost = this->x;
xMost += this->width;
CheckedInt<int32_t> yMost = this->y;
yMost += this->height;
return !xMost.isValid() || !yMost.isValid();
}
};
typedef IntRectTyped<UnknownUnits> IntRect;