summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--image/decoders/nsBMPDecoder.cpp45
-rw-r--r--image/decoders/nsBMPDecoder.h7
2 files changed, 36 insertions, 16 deletions
diff --git a/image/decoders/nsBMPDecoder.cpp b/image/decoders/nsBMPDecoder.cpp
index fc79c223d..b93eb42b6 100644
--- a/image/decoders/nsBMPDecoder.cpp
+++ b/image/decoders/nsBMPDecoder.cpp
@@ -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.
diff --git a/image/decoders/nsBMPDecoder.h b/image/decoders/nsBMPDecoder.h
index 258381649..4b9568487 100644
--- a/image/decoders/nsBMPDecoder.h
+++ b/image/decoders/nsBMPDecoder.h
@@ -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