Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.

Commit 88e2751

Browse files
committed
Bug 1315554 - Part 6. Reuse the same SourceBuffer when decoding a resource within an ICO. r=tnikkel
1 parent 1404a84 commit 88e2751

4 files changed

Lines changed: 49 additions & 46 deletions

File tree

image/DecoderFactory.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ DecoderFactory::CreateMetadataDecoder(DecoderType aType,
234234

235235
/* static */ already_AddRefed<Decoder>
236236
DecoderFactory::CreateDecoderForICOResource(DecoderType aType,
237-
NotNull<SourceBuffer*> aSourceBuffer,
237+
SourceBufferIterator&& aIterator,
238238
NotNull<nsICODecoder*> aICODecoder,
239239
const Maybe<IntSize>& aExpectedSize,
240240
const Maybe<uint32_t>& aDataOffset
@@ -263,7 +263,7 @@ DecoderFactory::CreateDecoderForICOResource(DecoderType aType,
263263
// Initialize the decoder, copying settings from @aICODecoder.
264264
MOZ_ASSERT(!aICODecoder->IsMetadataDecode());
265265
decoder->SetMetadataDecode(aICODecoder->IsMetadataDecode());
266-
decoder->SetIterator(aSourceBuffer->Iterator());
266+
decoder->SetIterator(Forward<SourceBufferIterator>(aIterator));
267267
decoder->SetOutputSize(aICODecoder->OutputSize());
268268
if (aExpectedSize) {
269269
decoder->SetExpectedSize(*aExpectedSize);

image/DecoderFactory.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ class IDecodingTask;
2323
class nsICODecoder;
2424
class RasterImage;
2525
class SourceBuffer;
26+
class SourceBufferIterator;
2627

2728
/**
2829
* The type of decoder; this is usually determined from a MIME type using
@@ -119,8 +120,8 @@ class DecoderFactory
119120
*
120121
* @param aType Which type of decoder to create. This must be either BMP or
121122
* PNG.
122-
* @param aSourceBuffer The SourceBuffer which the decoder will read its data
123-
* from.
123+
* @param aIterator The SourceBufferIterator which the decoder will read its
124+
* data from.
124125
* @param aICODecoder The ICO decoder which is controlling this resource
125126
* decoder. @aICODecoder's settings will be copied to the
126127
* resource decoder, so the two decoders will have the
@@ -133,7 +134,7 @@ class DecoderFactory
133134
*/
134135
static already_AddRefed<Decoder>
135136
CreateDecoderForICOResource(DecoderType aType,
136-
NotNull<SourceBuffer*> aSourceBuffer,
137+
SourceBufferIterator&& aIterator,
137138
NotNull<nsICODecoder*> aICODecoder,
138139
const Maybe<gfx::IntSize>& aExpectedSize,
139140
const Maybe<uint32_t>& aDataOffset = Nothing());

image/decoders/nsICODecoder.cpp

Lines changed: 38 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -91,14 +91,8 @@ nsICODecoder::GetFinalStateFromContainedDecoder()
9191
return NS_OK;
9292
}
9393

94-
MOZ_ASSERT(mContainedSourceBuffer,
95-
"Should have a SourceBuffer if we have a decoder");
96-
9794
// Let the contained decoder finish up if necessary.
98-
if (!mContainedSourceBuffer->IsComplete()) {
99-
mContainedSourceBuffer->Complete(NS_OK);
100-
mContainedDecoder->Decode();
101-
}
95+
FlushContainedDecoder();
10296

10397
// Make our state the same as the state of the contained decoder.
10498
mDecodeDone = mContainedDecoder->GetDecodeDone();
@@ -255,28 +249,26 @@ nsICODecoder::ReadDirEntry(const char* aData)
255249
LexerTransition<ICOState>
256250
nsICODecoder::SniffResource(const char* aData)
257251
{
252+
// Prepare a new iterator for the contained decoder to advance as it wills.
253+
// Cloning at the point ensures it will begin at the resource offset.
254+
mContainedIterator.emplace(mLexer.Clone(*mIterator, mDirEntry.mBytesInRes));
255+
258256
// We use the first PNGSIGNATURESIZE bytes to determine whether this resource
259257
// is a PNG or a BMP.
260258
bool isPNG = !memcmp(aData, nsPNGDecoder::pngSignatureBytes,
261259
PNGSIGNATURESIZE);
262260
if (isPNG) {
261+
if (mDirEntry.mBytesInRes <= PNGSIGNATURESIZE) {
262+
return Transition::TerminateFailure();
263+
}
264+
263265
// Create a PNG decoder which will do the rest of the work for us.
264-
mContainedSourceBuffer = new SourceBuffer();
265-
mContainedSourceBuffer->ExpectLength(mDirEntry.mBytesInRes);
266266
mContainedDecoder =
267267
DecoderFactory::CreateDecoderForICOResource(DecoderType::PNG,
268-
WrapNotNull(mContainedSourceBuffer),
268+
Move(*mContainedIterator),
269269
WrapNotNull(this),
270270
Some(GetRealSize()));
271271

272-
if (!WriteToContainedDecoder(aData, PNGSIGNATURESIZE)) {
273-
return Transition::TerminateFailure();
274-
}
275-
276-
if (mDirEntry.mBytesInRes <= PNGSIGNATURESIZE) {
277-
return Transition::TerminateFailure();
278-
}
279-
280272
// Read in the rest of the PNG unbuffered.
281273
size_t toRead = mDirEntry.mBytesInRes - PNGSIGNATURESIZE;
282274
return Transition::ToUnbuffered(ICOState::FINISHED_RESOURCE,
@@ -299,9 +291,9 @@ nsICODecoder::SniffResource(const char* aData)
299291
}
300292

301293
LexerTransition<ICOState>
302-
nsICODecoder::ReadResource(const char* aData, uint32_t aLen)
294+
nsICODecoder::ReadResource()
303295
{
304-
if (!WriteToContainedDecoder(aData, aLen)) {
296+
if (!FlushContainedDecoder()) {
305297
return Transition::TerminateFailure();
306298
}
307299

@@ -334,19 +326,18 @@ nsICODecoder::ReadBIH(const char* aData)
334326

335327
// Create a BMP decoder which will do most of the work for us; the exception
336328
// is the AND mask, which isn't present in standalone BMPs.
337-
mContainedSourceBuffer = new SourceBuffer();
338-
mContainedSourceBuffer->ExpectLength(mDirEntry.mBytesInRes);
339329
mContainedDecoder =
340330
DecoderFactory::CreateDecoderForICOResource(DecoderType::BMP,
341-
WrapNotNull(mContainedSourceBuffer),
331+
Move(*mContainedIterator),
342332
WrapNotNull(this),
343333
Some(GetRealSize()),
344334
Some(dataOffset));
335+
345336
RefPtr<nsBMPDecoder> bmpDecoder =
346337
static_cast<nsBMPDecoder*>(mContainedDecoder.get());
347338

348-
// Write out the BMP's bitmap info header.
349-
if (!WriteToContainedDecoder(mBIHraw, sizeof(mBIHraw))) {
339+
// Ensure the decoder has parsed at least the BMP's bitmap info header.
340+
if (!FlushContainedDecoder()) {
350341
return Transition::TerminateFailure();
351342
}
352343

@@ -372,6 +363,14 @@ nsICODecoder::ReadBIH(const char* aData)
372363
LexerTransition<ICOState>
373364
nsICODecoder::PrepareForMask()
374365
{
366+
// We have received all of the data required by the BMP decoder so flushing
367+
// here guarantees the decode has finished.
368+
if (!FlushContainedDecoder()) {
369+
return Transition::TerminateFailure();
370+
}
371+
372+
MOZ_ASSERT(mContainedDecoder->GetDecodeDone());
373+
375374
RefPtr<nsBMPDecoder> bmpDecoder =
376375
static_cast<nsBMPDecoder*>(mContainedDecoder.get());
377376

@@ -517,6 +516,14 @@ nsICODecoder::FinishMask()
517516
LexerTransition<ICOState>
518517
nsICODecoder::FinishResource()
519518
{
519+
// We have received all of the data required by the PNG/BMP decoder so
520+
// flushing here guarantees the decode has finished.
521+
if (!FlushContainedDecoder()) {
522+
return Transition::TerminateFailure();
523+
}
524+
525+
MOZ_ASSERT(mContainedDecoder->GetDecodeDone());
526+
520527
// Make sure the actual size of the resource matches the size in the directory
521528
// entry. If not, we consider the image corrupt.
522529
if (mContainedDecoder->HasSize() &&
@@ -559,7 +566,7 @@ nsICODecoder::DoDecode(SourceBufferIterator& aIterator, IResumable* aOnResume)
559566
case ICOState::SNIFF_RESOURCE:
560567
return SniffResource(aData);
561568
case ICOState::READ_RESOURCE:
562-
return ReadResource(aData, aLength);
569+
return ReadResource();
563570
case ICOState::READ_BIH:
564571
return ReadBIH(aData);
565572
case ICOState::PREPARE_FOR_MASK:
@@ -579,21 +586,16 @@ nsICODecoder::DoDecode(SourceBufferIterator& aIterator, IResumable* aOnResume)
579586
}
580587

581588
bool
582-
nsICODecoder::WriteToContainedDecoder(const char* aBuffer, uint32_t aCount)
589+
nsICODecoder::FlushContainedDecoder()
583590
{
584591
MOZ_ASSERT(mContainedDecoder);
585-
MOZ_ASSERT(mContainedSourceBuffer);
586-
587-
// Append the provided data to the SourceBuffer that the contained decoder is
588-
// reading from.
589-
mContainedSourceBuffer->Append(aBuffer, aCount);
590592

591593
bool succeeded = true;
592594

593-
// Write to the contained decoder. If we run out of data, the ICO decoder will
594-
// get resumed when there's more data available, as usual, so we don't need
595-
// the contained decoder to get resumed too. To avoid that, we provide an
596-
// IResumable which just does nothing.
595+
// If we run out of data, the ICO decoder will get resumed when there's more
596+
// data available, as usual, so we don't need the contained decoder to get
597+
// resumed too. To avoid that, we provide an IResumable which just does
598+
// nothing. All the caller needs to do is flush when there is new data.
597599
LexerResult result = mContainedDecoder->Decode();
598600
if (result == LexerResult(TerminalState::FAILURE)) {
599601
succeeded = false;

image/decoders/nsICODecoder.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,9 @@ class nsICODecoder : public Decoder
7979
// Decoders should only be instantiated via DecoderFactory.
8080
explicit nsICODecoder(RasterImage* aImage);
8181

82-
// Writes to the contained decoder and sets the appropriate errors
83-
// Returns true if there are no errors.
84-
bool WriteToContainedDecoder(const char* aBuffer, uint32_t aCount);
82+
// Flushes the contained decoder to read all available data and sets the
83+
// appropriate errors. Returns true if there are no errors.
84+
bool FlushContainedDecoder();
8585

8686
// Gets decoder state from the contained decoder so it's visible externally.
8787
nsresult GetFinalStateFromContainedDecoder();
@@ -92,7 +92,7 @@ class nsICODecoder : public Decoder
9292
LexerTransition<ICOState> ReadHeader(const char* aData);
9393
LexerTransition<ICOState> ReadDirEntry(const char* aData);
9494
LexerTransition<ICOState> SniffResource(const char* aData);
95-
LexerTransition<ICOState> ReadResource(const char* aData, uint32_t aLen);
95+
LexerTransition<ICOState> ReadResource();
9696
LexerTransition<ICOState> ReadBIH(const char* aData);
9797
LexerTransition<ICOState> PrepareForMask();
9898
LexerTransition<ICOState> ReadMaskRow(const char* aData);
@@ -101,7 +101,7 @@ class nsICODecoder : public Decoder
101101

102102
StreamingLexer<ICOState, 32> mLexer; // The lexer.
103103
RefPtr<Decoder> mContainedDecoder; // Either a BMP or PNG decoder.
104-
RefPtr<SourceBuffer> mContainedSourceBuffer; // SourceBuffer for mContainedDecoder.
104+
Maybe<SourceBufferIterator> mContainedIterator; // Iterator for the subdecoder.
105105
UniquePtr<uint8_t[]> mMaskBuffer; // A temporary buffer for the alpha mask.
106106
char mBIHraw[bmp::InfoHeaderLength::WIN_ICO]; // The bitmap information header.
107107
IconDirEntry mDirEntry; // The dir entry for the selected resource.

0 commit comments

Comments
 (0)