Backed out changeset ada34cba0052 (bug 1348941) for image-related bustages

CLOSED TREE
This commit is contained in:
Phil Ringnalda 2017-03-30 19:28:00 -07:00
parent 4cb08c4110
commit 57f1484fe3
4 changed files with 33 additions and 96 deletions

View file

@ -10,7 +10,6 @@
#include "nsString.h" #include "nsString.h"
#include "nsStreamUtils.h" #include "nsStreamUtils.h"
#include "nsTArray.h" #include "nsTArray.h"
#include "mozilla/CheckedInt.h"
using namespace mozilla; using namespace mozilla;
using namespace mozilla::image; using namespace mozilla::image;
@ -59,11 +58,6 @@ nsBMPEncoder::InitFromData(const uint8_t* aData,
return NS_ERROR_INVALID_ARG; return NS_ERROR_INVALID_ARG;
} }
CheckedInt32 check = CheckedInt32(aWidth) * 4;
if (MOZ_UNLIKELY(!check.isValid())) {
return NS_ERROR_INVALID_ARG;
}
// Stride is the padded width of each row, so it better be longer // Stride is the padded width of each row, so it better be longer
if ((aInputFormat == INPUT_FORMAT_RGB && if ((aInputFormat == INPUT_FORMAT_RGB &&
aStride < aWidth * 3) || aStride < aWidth * 3) ||
@ -92,15 +86,15 @@ nsBMPEncoder::InitFromData(const uint8_t* aData,
// Just a helper method to make it explicit in calculations that we are dealing // Just a helper method to make it explicit in calculations that we are dealing
// with bytes and not bits // with bytes and not bits
static inline uint16_t static inline uint32_t
BytesPerPixel(uint16_t aBPP) BytesPerPixel(uint32_t aBPP)
{ {
return aBPP / 8; return aBPP / 8;
} }
// Calculates the number of padding bytes that are needed per row of image data // Calculates the number of padding bytes that are needed per row of image data
static inline uint32_t static inline uint32_t
PaddingBytes(uint16_t aBPP, uint32_t aWidth) PaddingBytes(uint32_t aBPP, uint32_t aWidth)
{ {
uint32_t rowSize = aWidth * BytesPerPixel(aBPP); uint32_t rowSize = aWidth * BytesPerPixel(aBPP);
uint8_t paddingSize = 0; uint8_t paddingSize = 0;
@ -131,21 +125,14 @@ nsBMPEncoder::StartImageEncode(uint32_t aWidth,
// parse and check any provided output options // parse and check any provided output options
Version version; Version version;
uint16_t bpp; uint32_t bpp;
nsresult rv = ParseOptions(aOutputOptions, version, bpp); nsresult rv = ParseOptions(aOutputOptions, version, bpp);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
return rv; return rv;
} }
MOZ_ASSERT(bpp <= 32);
rv = InitFileHeader(version, bpp, aWidth, aHeight); InitFileHeader(version, bpp, aWidth, aHeight);
if (NS_FAILED(rv)) { InitInfoHeader(version, bpp, aWidth, aHeight);
return rv;
}
rv = InitInfoHeader(version, bpp, aWidth, aHeight);
if (NS_FAILED(rv)) {
return rv;
}
mImageBufferSize = mBMPFileHeader.filesize; mImageBufferSize = mBMPFileHeader.filesize;
mImageBufferStart = static_cast<uint8_t*>(malloc(mImageBufferSize)); mImageBufferStart = static_cast<uint8_t*>(malloc(mImageBufferSize));
@ -200,26 +187,12 @@ nsBMPEncoder::AddImageFrame(const uint8_t* aData,
return NS_ERROR_INVALID_ARG; return NS_ERROR_INVALID_ARG;
} }
if (mBMPInfoHeader.width < 0) { auto row = MakeUniqueFallible<uint8_t[]>(mBMPInfoHeader.width *
return NS_ERROR_ILLEGAL_VALUE; BytesPerPixel(mBMPInfoHeader.bpp));
}
CheckedUint32 size =
CheckedUint32(mBMPInfoHeader.width) * CheckedUint32(BytesPerPixel(mBMPInfoHeader.bpp));
if (MOZ_UNLIKELY(!size.isValid())) {
return NS_ERROR_FAILURE;
}
auto row = MakeUniqueFallible<uint8_t[]>(size.value());
if (!row) { if (!row) {
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
} }
CheckedUint32 check = CheckedUint32(mBMPInfoHeader.height) * aStride;
if (MOZ_UNLIKELY(!check.isValid())) {
return NS_ERROR_FAILURE;
}
// write each row: if we add more input formats, we may want to // write each row: if we add more input formats, we may want to
// generalize the conversions // generalize the conversions
if (aInputFormat == INPUT_FORMAT_HOSTARGB) { if (aInputFormat == INPUT_FORMAT_HOSTARGB) {
@ -283,7 +256,7 @@ nsBMPEncoder::EndImageEncode()
// See InitFromData for a description of the parse options // See InitFromData for a description of the parse options
nsresult nsresult
nsBMPEncoder::ParseOptions(const nsAString& aOptions, Version& aVersionOut, nsBMPEncoder::ParseOptions(const nsAString& aOptions, Version& aVersionOut,
uint16_t& aBppOut) uint32_t& aBppOut)
{ {
aVersionOut = VERSION_3; aVersionOut = VERSION_3;
aBppOut = 24; aBppOut = 24;
@ -451,7 +424,7 @@ nsBMPEncoder::ConvertHostARGBRow(const uint8_t* aSrc,
const UniquePtr<uint8_t[]>& aDest, const UniquePtr<uint8_t[]>& aDest,
uint32_t aPixelWidth) uint32_t aPixelWidth)
{ {
uint16_t bytes = BytesPerPixel(mBMPInfoHeader.bpp); int bytes = BytesPerPixel(mBMPInfoHeader.bpp);
if (mBMPInfoHeader.bpp == 32) { if (mBMPInfoHeader.bpp == 32) {
for (uint32_t x = 0; x < aPixelWidth; x++) { for (uint32_t x = 0; x < aPixelWidth; x++) {
@ -500,8 +473,8 @@ nsBMPEncoder::NotifyListener()
} }
// Initializes the BMP file header mBMPFileHeader to the passed in values // Initializes the BMP file header mBMPFileHeader to the passed in values
nsresult void
nsBMPEncoder::InitFileHeader(Version aVersion, uint16_t aBPP, uint32_t aWidth, nsBMPEncoder::InitFileHeader(Version aVersion, uint32_t aBPP, uint32_t aWidth,
uint32_t aHeight) uint32_t aHeight)
{ {
memset(&mBMPFileHeader, 0, sizeof(mBMPFileHeader)); memset(&mBMPFileHeader, 0, sizeof(mBMPFileHeader));
@ -518,25 +491,13 @@ nsBMPEncoder::InitFileHeader(Version aVersion, uint16_t aBPP, uint32_t aWidth,
if (aBPP <= 8) { if (aBPP <= 8) {
uint32_t numColors = 1 << aBPP; uint32_t numColors = 1 << aBPP;
mBMPFileHeader.dataoffset += 4 * numColors; mBMPFileHeader.dataoffset += 4 * numColors;
CheckedUint32 filesize = mBMPFileHeader.filesize = mBMPFileHeader.dataoffset + aWidth * aHeight;
CheckedUint32(mBMPFileHeader.dataoffset) + CheckedUint32(aWidth) * aHeight;
if (MOZ_UNLIKELY(!filesize.isValid())) {
return NS_ERROR_INVALID_ARG;
}
mBMPFileHeader.filesize = filesize.value();
} else { } else {
CheckedUint32 filesize = mBMPFileHeader.filesize = mBMPFileHeader.dataoffset +
CheckedUint32(mBMPFileHeader.dataoffset) + (aWidth * BytesPerPixel(aBPP) + PaddingBytes(aBPP, aWidth)) * aHeight;
(CheckedUint32(aWidth) * BytesPerPixel(aBPP) + PaddingBytes(aBPP, aWidth)) * aHeight;
if (MOZ_UNLIKELY(!filesize.isValid())) {
return NS_ERROR_INVALID_ARG;
}
mBMPFileHeader.filesize = filesize.value();
} }
mBMPFileHeader.reserved = 0; mBMPFileHeader.reserved = 0;
return NS_OK;
} }
#define ENCODE(pImageBufferCurr, value) \ #define ENCODE(pImageBufferCurr, value) \
@ -544,8 +505,8 @@ nsBMPEncoder::InitFileHeader(Version aVersion, uint16_t aBPP, uint32_t aWidth,
*pImageBufferCurr += sizeof value; *pImageBufferCurr += sizeof value;
// Initializes the bitmap info header mBMPInfoHeader to the passed in values // Initializes the bitmap info header mBMPInfoHeader to the passed in values
nsresult void
nsBMPEncoder::InitInfoHeader(Version aVersion, uint16_t aBPP, uint32_t aWidth, nsBMPEncoder::InitInfoHeader(Version aVersion, uint32_t aBPP, uint32_t aWidth,
uint32_t aHeight) uint32_t aHeight)
{ {
memset(&mBMPInfoHeader, 0, sizeof(mBMPInfoHeader)); memset(&mBMPInfoHeader, 0, sizeof(mBMPInfoHeader));
@ -555,39 +516,18 @@ nsBMPEncoder::InitInfoHeader(Version aVersion, uint16_t aBPP, uint32_t aWidth,
MOZ_ASSERT(aVersion == VERSION_5); MOZ_ASSERT(aVersion == VERSION_5);
mBMPInfoHeader.bihsize = InfoHeaderLength::WIN_V5; mBMPInfoHeader.bihsize = InfoHeaderLength::WIN_V5;
} }
mBMPInfoHeader.width = aWidth;
CheckedInt32 width(aWidth); mBMPInfoHeader.height = aHeight;
CheckedInt32 height(aHeight);
if (MOZ_UNLIKELY(!width.isValid() || !height.isValid())) {
return NS_ERROR_INVALID_ARG;
}
mBMPInfoHeader.width = width.value();
mBMPInfoHeader.height = height.value();
mBMPInfoHeader.planes = 1; mBMPInfoHeader.planes = 1;
mBMPInfoHeader.bpp = aBPP; mBMPInfoHeader.bpp = aBPP;
mBMPInfoHeader.compression = 0; mBMPInfoHeader.compression = 0;
mBMPInfoHeader.colors = 0; mBMPInfoHeader.colors = 0;
mBMPInfoHeader.important_colors = 0; mBMPInfoHeader.important_colors = 0;
CheckedUint32 check = CheckedUint32(aWidth) * BytesPerPixel(aBPP);
if (MOZ_UNLIKELY(check.isValid())) {
return NS_ERROR_INVALID_ARG;
}
if (aBPP <= 8) { if (aBPP <= 8) {
CheckedUint32 imagesize = CheckedUint32(aWidth) * aHeight; mBMPInfoHeader.image_size = aWidth * aHeight;
if (MOZ_UNLIKELY(imagesize.isValid())) {
return NS_ERROR_INVALID_ARG;
}
mBMPInfoHeader.image_size = imagesize.value();
} else { } else {
CheckedUint32 imagesize = mBMPInfoHeader.image_size =
CheckedUint32(aWidth) * BytesPerPixel(aBPP) + PaddingBytes(aBPP, aWidth) * CheckedUint32(aHeight); (aWidth * BytesPerPixel(aBPP) + PaddingBytes(aBPP, aWidth)) * aHeight;
if (MOZ_UNLIKELY(imagesize.isValid())) {
return NS_ERROR_INVALID_ARG;
}
mBMPInfoHeader.image_size = imagesize.value();
} }
mBMPInfoHeader.xppm = 0; mBMPInfoHeader.xppm = 0;
mBMPInfoHeader.yppm = 0; mBMPInfoHeader.yppm = 0;
@ -614,8 +554,6 @@ nsBMPEncoder::InitInfoHeader(Version aVersion, uint16_t aBPP, uint32_t aWidth,
mBMPInfoHeader.profile_size = 0; mBMPInfoHeader.profile_size = 0;
mBMPInfoHeader.reserved = 0; mBMPInfoHeader.reserved = 0;
} }
return NS_OK;
} }
// Encodes the BMP file header mBMPFileHeader // Encodes the BMP file header mBMPFileHeader

View file

@ -104,7 +104,7 @@ protected:
// See InitData in the cpp for valid parse options // See InitData in the cpp for valid parse options
nsresult ParseOptions(const nsAString& aOptions, Version& aVersionOut, nsresult ParseOptions(const nsAString& aOptions, Version& aVersionOut,
uint16_t& aBppOut); uint32_t& aBppOut);
// Obtains data with no alpha in machine-independent byte order // Obtains data with no alpha in machine-independent byte order
void ConvertHostARGBRow(const uint8_t* aSrc, void ConvertHostARGBRow(const uint8_t* aSrc,
const mozilla::UniquePtr<uint8_t[]>& aDest, const mozilla::UniquePtr<uint8_t[]>& aDest,
@ -113,10 +113,10 @@ protected:
void NotifyListener(); void NotifyListener();
// Initializes the bitmap file header member mBMPFileHeader // Initializes the bitmap file header member mBMPFileHeader
nsresult InitFileHeader(Version aVersion, uint16_t aBPP, uint32_t aWidth, void InitFileHeader(Version aVersion, uint32_t aBPP, uint32_t aWidth,
uint32_t aHeight); uint32_t aHeight);
// Initializes the bitmap info header member mBMPInfoHeader // Initializes the bitmap info header member mBMPInfoHeader
nsresult InitInfoHeader(Version aVersion, uint16_t aBPP, uint32_t aWidth, void InitInfoHeader(Version aVersion, uint32_t aBPP, uint32_t aWidth,
uint32_t aHeight); uint32_t aHeight);
// Encodes the bitmap file header member mBMPFileHeader // Encodes the bitmap file header member mBMPFileHeader

View file

@ -228,11 +228,10 @@ nsICOEncoder::StartImageEncode(uint32_t aWidth,
} }
// parse and check any provided output options // parse and check any provided output options
uint16_t bpp = 24; uint32_t bpp = 24;
bool usePNG = true; bool usePNG = true;
nsresult rv = ParseOptions(aOutputOptions, bpp, usePNG); nsresult rv = ParseOptions(aOutputOptions, bpp, usePNG);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
MOZ_ASSERT(bpp <= 32);
mUsePNG = usePNG; mUsePNG = usePNG;
@ -266,7 +265,7 @@ nsICOEncoder::EndImageEncode()
// Parses the encoder options and sets the bits per pixel to use and PNG or BMP // Parses the encoder options and sets the bits per pixel to use and PNG or BMP
// See InitFromData for a description of the parse options // See InitFromData for a description of the parse options
nsresult nsresult
nsICOEncoder::ParseOptions(const nsAString& aOptions, uint16_t& aBppOut, nsICOEncoder::ParseOptions(const nsAString& aOptions, uint32_t& aBppOut,
bool& aUsePNGOut) bool& aUsePNGOut)
{ {
// If no parsing options just use the default of 24BPP and PNG yes // If no parsing options just use the default of 24BPP and PNG yes
@ -470,7 +469,7 @@ nsICOEncoder::InitFileHeader()
// Initializes the icon directory info header mICODirEntry // Initializes the icon directory info header mICODirEntry
void void
nsICOEncoder::InitInfoHeader(uint16_t aBPP, uint8_t aWidth, uint8_t aHeight) nsICOEncoder::InitInfoHeader(uint32_t aBPP, uint8_t aWidth, uint8_t aHeight)
{ {
memset(&mICODirEntry, 0, sizeof(mICODirEntry)); memset(&mICODirEntry, 0, sizeof(mICODirEntry));
mICODirEntry.mBitCount = aBPP; mICODirEntry.mBitCount = aBPP;

View file

@ -50,14 +50,14 @@ public:
protected: protected:
~nsICOEncoder(); ~nsICOEncoder();
nsresult ParseOptions(const nsAString& aOptions, uint16_t& aBppOut, nsresult ParseOptions(const nsAString& aOptions, uint32_t& aBppOut,
bool& aUsePNGOut); bool& aUsePNGOut);
void NotifyListener(); void NotifyListener();
// Initializes the icon file header mICOFileHeader // Initializes the icon file header mICOFileHeader
void InitFileHeader(); void InitFileHeader();
// Initializes the icon directory info header mICODirEntry // Initializes the icon directory info header mICODirEntry
void InitInfoHeader(uint16_t aBPP, uint8_t aWidth, uint8_t aHeight); void InitInfoHeader(uint32_t aBPP, uint8_t aWidth, uint8_t aHeight);
// Encodes the icon file header mICOFileHeader // Encodes the icon file header mICOFileHeader
void EncodeFileHeader(); void EncodeFileHeader();
// Encodes the icon directory info header mICODirEntry // Encodes the icon directory info header mICODirEntry