mirror of
https://github.com/roytam1/basilisk55.git
synced 2026-05-26 15:02:46 +00:00
import from UXP: BMPs from the clipboard may include extra padding. (4f5c2d5a)
This commit is contained in:
@@ -66,6 +66,17 @@
|
||||
// compression, then instead of treating the pixel data as 0RGB it is treated
|
||||
// as ARGB, but only if one or more of the A values are non-zero.
|
||||
//
|
||||
// Clipboard variants.
|
||||
// - It's the BMP format used for BMP images captured from the clipboard.
|
||||
// - It is missing the file header, containing the BM signature and the data
|
||||
// offset. Instead the data begins after the header.
|
||||
// - If it uses BITFIELDS compression, then there is always an additional 12
|
||||
// bytes of data after the header that must be read. In WinBMPv4+, the masks
|
||||
// are supposed to be included in the header size, which are the values we use
|
||||
// for decoding purposes, but there is additional three masks following the
|
||||
// header which must be skipped to get to the pixel data.
|
||||
//
|
||||
//
|
||||
// OS/2 VERSIONS OF THE BMP FORMAT
|
||||
// -------------------------------
|
||||
// OS2-BMPv1.
|
||||
@@ -168,10 +179,12 @@ static mozilla::LazyLogModule sBMPLog("BMPDecoder");
|
||||
// The length of the mBIHSize field in the info header.
|
||||
static const uint32_t BIHSIZE_FIELD_LENGTH = 4;
|
||||
|
||||
nsBMPDecoder::nsBMPDecoder(RasterImage* aImage, State aState, size_t aLength)
|
||||
nsBMPDecoder::nsBMPDecoder(RasterImage* aImage, State aState, size_t aLength,
|
||||
bool aForClipboard)
|
||||
: Decoder(aImage)
|
||||
, mLexer(Transition::To(aState, aLength), Transition::TerminateSuccess())
|
||||
, mIsWithinICO(false)
|
||||
, mIsForClipboard(aForClipboard)
|
||||
, mMayHaveTransparency(false)
|
||||
, mDoesHaveTransparency(false)
|
||||
, mNumColors(0)
|
||||
@@ -188,14 +201,16 @@ nsBMPDecoder::nsBMPDecoder(RasterImage* aImage, State aState, size_t aLength)
|
||||
// Constructor for normal BMP files or from the clipboard.
|
||||
nsBMPDecoder::nsBMPDecoder(RasterImage* aImage, bool aForClipboard)
|
||||
: nsBMPDecoder(aImage,
|
||||
aForClipboard ? State::CLIPBOARD_HEADER : State::FILE_HEADER,
|
||||
aForClipboard ? BIHSIZE_FIELD_LENGTH : FILE_HEADER_LENGTH)
|
||||
aForClipboard ? State::INFO_HEADER_SIZE : State::FILE_HEADER,
|
||||
aForClipboard ? BIHSIZE_FIELD_LENGTH : FILE_HEADER_LENGTH,
|
||||
aForClipboard)
|
||||
{
|
||||
}
|
||||
|
||||
// Constructor used for WinBMPv3-ICO files, which lack a file header.
|
||||
nsBMPDecoder::nsBMPDecoder(RasterImage* aImage, uint32_t aDataOffset)
|
||||
: nsBMPDecoder(aImage, State::INFO_HEADER_SIZE, BIHSIZE_FIELD_LENGTH)
|
||||
: nsBMPDecoder(aImage, State::INFO_HEADER_SIZE, BIHSIZE_FIELD_LENGTH,
|
||||
/* aForClipboard */ false)
|
||||
{
|
||||
SetIsWithinICO();
|
||||
|
||||
@@ -457,7 +472,6 @@ nsBMPDecoder::DoDecode(SourceBufferIterator& aIterator, IResumable* aOnResume)
|
||||
[=](State aState, const char* aData, size_t aLength) {
|
||||
switch (aState) {
|
||||
case State::FILE_HEADER: return ReadFileHeader(aData, aLength);
|
||||
case State::CLIPBOARD_HEADER: return ReadClipboardHeader(aData, aLength);
|
||||
case State::INFO_HEADER_SIZE: return ReadInfoHeaderSize(aData, aLength);
|
||||
case State::INFO_HEADER_REST: return ReadInfoHeaderRest(aData, aLength);
|
||||
case State::BITFIELDS: return ReadBitfields(aData, aLength);
|
||||
@@ -491,14 +505,6 @@ nsBMPDecoder::ReadFileHeader(const char* aData, size_t aLength)
|
||||
return Transition::To(State::INFO_HEADER_SIZE, BIHSIZE_FIELD_LENGTH);
|
||||
}
|
||||
|
||||
LexerTransition<nsBMPDecoder::State>
|
||||
nsBMPDecoder::ReadClipboardHeader(const char* aData, size_t aLength)
|
||||
{
|
||||
// With the clipboard, the data offset is the header length.
|
||||
mH.mDataOffset = LittleEndian::readUint32(aData);
|
||||
return ReadInfoHeaderSize(aData, aLength);
|
||||
}
|
||||
|
||||
// We read the info header in two steps: (a) read the mBIHSize field to
|
||||
// determine how long the header is; (b) read the rest of the header.
|
||||
LexerTransition<nsBMPDecoder::State>
|
||||
@@ -609,6 +615,13 @@ nsBMPDecoder::ReadInfoHeaderRest(const char* aData, size_t aLength)
|
||||
// Bitfields are present in the info header, so we can read them
|
||||
// immediately.
|
||||
mBitFields.ReadFromHeader(aData + 36, /* aReadAlpha = */ true);
|
||||
|
||||
// If this came from the clipboard, then we know that even if the header
|
||||
// explicitly includes the bitfield masks, we need to add an additional
|
||||
// offset for the start of the RGB data.
|
||||
if (mIsForClipboard) {
|
||||
mH.mDataOffset += BitFields::LENGTH;
|
||||
}
|
||||
} else {
|
||||
// Bitfields are present after the info header, so we will read them in
|
||||
// ReadBitfields().
|
||||
@@ -723,6 +736,12 @@ nsBMPDecoder::ReadColorTable(const char* aData, size_t aLength)
|
||||
aData += mBytesPerColor;
|
||||
}
|
||||
|
||||
// If we are decoding a BMP from the clipboard, we did not know the data
|
||||
// offset in advance. It is defined as just after the header and color table.
|
||||
if (mIsForClipboard) {
|
||||
mH.mDataOffset += mPreGapLength;
|
||||
}
|
||||
|
||||
// We know how many bytes we've read so far (mPreGapLength) and we know the
|
||||
// offset of the pixel data (mH.mDataOffset), so we can determine the length
|
||||
// of the gap (possibly zero) between the color table and the pixel data.
|
||||
|
||||
@@ -152,7 +152,6 @@ private:
|
||||
|
||||
enum class State {
|
||||
FILE_HEADER,
|
||||
CLIPBOARD_HEADER,
|
||||
INFO_HEADER_SIZE,
|
||||
INFO_HEADER_REST,
|
||||
BITFIELDS,
|
||||
@@ -172,7 +171,7 @@ private:
|
||||
nsBMPDecoder(RasterImage* aImage, uint32_t aDataOffset);
|
||||
|
||||
// Helper constructor called by the other two.
|
||||
nsBMPDecoder(RasterImage* aImage, State aState, size_t aLength);
|
||||
nsBMPDecoder(RasterImage* aImage, State aState, size_t aLength, bool aForClipboard);
|
||||
|
||||
int32_t AbsoluteHeight() const { return abs(mH.mHeight); }
|
||||
|
||||
@@ -181,7 +180,6 @@ private:
|
||||
void FinishRow();
|
||||
|
||||
LexerTransition<State> ReadFileHeader(const char* aData, size_t aLength);
|
||||
LexerTransition<State> ReadClipboardHeader(const char* aData, size_t aLength);
|
||||
LexerTransition<State> ReadInfoHeaderSize(const char* aData, size_t aLength);
|
||||
LexerTransition<State> ReadInfoHeaderRest(const char* aData, size_t aLength);
|
||||
LexerTransition<State> ReadBitfields(const char* aData, size_t aLength);
|
||||
@@ -200,6 +198,9 @@ private:
|
||||
// If the BMP is within an ICO file our treatment of it differs slightly.
|
||||
bool mIsWithinICO;
|
||||
|
||||
// If the BMP is decoded from the clipboard, we start with a data offset.
|
||||
bool mIsForClipboard;
|
||||
|
||||
bmp::BitFields mBitFields;
|
||||
|
||||
// Might the image have transparency? Determined from the headers during
|
||||
|
||||
Reference in New Issue
Block a user