mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-08 20:47:44 +00:00
db2ca75447
--HG-- rename : image/src/BMPFileHeaders.h => image/BMPFileHeaders.h rename : image/src/ClippedImage.cpp => image/ClippedImage.cpp rename : image/src/ClippedImage.h => image/ClippedImage.h rename : image/src/DecodePool.cpp => image/DecodePool.cpp rename : image/src/DecodePool.h => image/DecodePool.h rename : image/src/Decoder.cpp => image/Decoder.cpp rename : image/src/Decoder.h => image/Decoder.h rename : image/src/Downscaler.cpp => image/Downscaler.cpp rename : image/src/Downscaler.h => image/Downscaler.h rename : image/src/DynamicImage.cpp => image/DynamicImage.cpp rename : image/src/DynamicImage.h => image/DynamicImage.h rename : image/src/FrameAnimator.cpp => image/FrameAnimator.cpp rename : image/src/FrameAnimator.h => image/FrameAnimator.h rename : image/src/FrozenImage.cpp => image/FrozenImage.cpp rename : image/src/FrozenImage.h => image/FrozenImage.h rename : image/src/ICOFileHeaders.h => image/ICOFileHeaders.h rename : image/src/IProgressObserver.h => image/IProgressObserver.h rename : image/src/Image.cpp => image/Image.cpp rename : image/src/Image.h => image/Image.h rename : image/src/ImageFactory.cpp => image/ImageFactory.cpp rename : image/src/ImageFactory.h => image/ImageFactory.h rename : image/src/ImageMetadata.cpp => image/ImageMetadata.cpp rename : image/src/ImageMetadata.h => image/ImageMetadata.h rename : image/src/ImageOps.cpp => image/ImageOps.cpp rename : image/src/ImageOps.h => image/ImageOps.h rename : image/src/ImageRegion.h => image/ImageRegion.h rename : image/src/ImageURL.h => image/ImageURL.h rename : image/src/ImageWrapper.cpp => image/ImageWrapper.cpp rename : image/src/ImageWrapper.h => image/ImageWrapper.h rename : image/src/MultipartImage.cpp => image/MultipartImage.cpp rename : image/src/MultipartImage.h => image/MultipartImage.h rename : image/src/Orientation.h => image/Orientation.h rename : image/src/OrientedImage.cpp => image/OrientedImage.cpp rename : image/src/OrientedImage.h => image/OrientedImage.h rename : image/src/ProgressTracker.cpp => image/ProgressTracker.cpp rename : image/src/ProgressTracker.h => image/ProgressTracker.h rename : image/src/RasterImage.cpp => image/RasterImage.cpp rename : image/src/RasterImage.h => image/RasterImage.h rename : image/src/SVGDocumentWrapper.cpp => image/SVGDocumentWrapper.cpp rename : image/src/SVGDocumentWrapper.h => image/SVGDocumentWrapper.h rename : image/src/ScriptedNotificationObserver.cpp => image/ScriptedNotificationObserver.cpp rename : image/src/ScriptedNotificationObserver.h => image/ScriptedNotificationObserver.h rename : image/src/ShutdownTracker.cpp => image/ShutdownTracker.cpp rename : image/src/ShutdownTracker.h => image/ShutdownTracker.h rename : image/src/SourceBuffer.cpp => image/SourceBuffer.cpp rename : image/src/SourceBuffer.h => image/SourceBuffer.h rename : image/src/SurfaceCache.cpp => image/SurfaceCache.cpp rename : image/src/SurfaceCache.h => image/SurfaceCache.h rename : image/src/VectorImage.cpp => image/VectorImage.cpp rename : image/src/VectorImage.h => image/VectorImage.h rename : image/src/imgFrame.cpp => image/imgFrame.cpp rename : image/src/imgFrame.h => image/imgFrame.h rename : image/src/imgLoader.cpp => image/imgLoader.cpp rename : image/src/imgLoader.h => image/imgLoader.h rename : image/src/imgRequest.cpp => image/imgRequest.cpp rename : image/src/imgRequest.h => image/imgRequest.h rename : image/src/imgRequestProxy.cpp => image/imgRequestProxy.cpp rename : image/src/imgRequestProxy.h => image/imgRequestProxy.h rename : image/src/imgTools.cpp => image/imgTools.cpp rename : image/src/imgTools.h => image/imgTools.h
383 lines
12 KiB
C++
383 lines
12 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
/**
|
|
* SourceBuffer is a single producer, multiple consumer data structure used for
|
|
* storing image source (compressed) data.
|
|
*/
|
|
|
|
#ifndef mozilla_image_sourcebuffer_h
|
|
#define mozilla_image_sourcebuffer_h
|
|
|
|
#include "mozilla/Maybe.h"
|
|
#include "mozilla/MemoryReporting.h"
|
|
#include "mozilla/Mutex.h"
|
|
#include "mozilla/Move.h"
|
|
#include "mozilla/MemoryReporting.h"
|
|
#include "mozilla/RefPtr.h"
|
|
#include "mozilla/UniquePtr.h"
|
|
#include "nsRefPtr.h"
|
|
#include "nsTArray.h"
|
|
|
|
namespace mozilla {
|
|
namespace image {
|
|
|
|
class SourceBuffer;
|
|
|
|
/**
|
|
* IResumable is an interface for classes that can schedule themselves to resume
|
|
* their work later. An implementation of IResumable generally should post a
|
|
* runnable to some event target which continues the work of the task.
|
|
*/
|
|
struct IResumable
|
|
{
|
|
MOZ_DECLARE_REFCOUNTED_TYPENAME(IResumable)
|
|
|
|
// Subclasses may or may not be XPCOM classes, so we just require that they
|
|
// implement AddRef and Release.
|
|
NS_IMETHOD_(MozExternalRefCountType) AddRef(void) = 0;
|
|
NS_IMETHOD_(MozExternalRefCountType) Release(void) = 0;
|
|
|
|
virtual void Resume() = 0;
|
|
|
|
protected:
|
|
virtual ~IResumable() { }
|
|
};
|
|
|
|
/**
|
|
* SourceBufferIterator is a class that allows consumers of image source data to
|
|
* read the contents of a SourceBuffer sequentially.
|
|
*
|
|
* Consumers can advance through the SourceBuffer by calling
|
|
* AdvanceOrScheduleResume() repeatedly. After every advance, they should call
|
|
* check the return value, which will tell them the iterator's new state.
|
|
*
|
|
* If WAITING is returned, AdvanceOrScheduleResume() has arranged
|
|
* to call the consumer's Resume() method later, so the consumer should save its
|
|
* state if needed and stop running.
|
|
*
|
|
* If the iterator's new state is READY, then the consumer can call Data() and
|
|
* Length() to read new data from the SourceBuffer.
|
|
*
|
|
* Finally, in the COMPLETE state the consumer can call CompletionStatus() to
|
|
* get the status passed to SourceBuffer::Complete().
|
|
*/
|
|
class SourceBufferIterator final
|
|
{
|
|
public:
|
|
enum State {
|
|
START, // The iterator is at the beginning of the buffer.
|
|
READY, // The iterator is pointing to new data.
|
|
WAITING, // The iterator is blocked and the caller must yield.
|
|
COMPLETE // The iterator is pointing to the end of the buffer.
|
|
};
|
|
|
|
explicit SourceBufferIterator(SourceBuffer* aOwner)
|
|
: mOwner(aOwner)
|
|
, mState(START)
|
|
{
|
|
MOZ_ASSERT(aOwner);
|
|
mData.mIterating.mChunk = 0;
|
|
mData.mIterating.mData = nullptr;
|
|
mData.mIterating.mOffset = 0;
|
|
mData.mIterating.mLength = 0;
|
|
}
|
|
|
|
SourceBufferIterator(SourceBufferIterator&& aOther)
|
|
: mOwner(Move(aOther.mOwner))
|
|
, mState(aOther.mState)
|
|
, mData(aOther.mData)
|
|
{ }
|
|
|
|
~SourceBufferIterator();
|
|
|
|
SourceBufferIterator& operator=(SourceBufferIterator&& aOther)
|
|
{
|
|
mOwner = Move(aOther.mOwner);
|
|
mState = aOther.mState;
|
|
mData = aOther.mData;
|
|
return *this;
|
|
}
|
|
|
|
/**
|
|
* Returns true if there are no more than @aBytes remaining in the
|
|
* SourceBuffer. If the SourceBuffer is not yet complete, returns false.
|
|
*/
|
|
bool RemainingBytesIsNoMoreThan(size_t aBytes) const;
|
|
|
|
/**
|
|
* Advances the iterator through the SourceBuffer if possible. If not,
|
|
* arranges to call the @aConsumer's Resume() method when more data is
|
|
* available.
|
|
*/
|
|
State AdvanceOrScheduleResume(IResumable* aConsumer);
|
|
|
|
/// If at the end, returns the status passed to SourceBuffer::Complete().
|
|
nsresult CompletionStatus() const
|
|
{
|
|
MOZ_ASSERT(mState == COMPLETE,
|
|
"Calling CompletionStatus() in the wrong state");
|
|
return mState == COMPLETE ? mData.mAtEnd.mStatus : NS_OK;
|
|
}
|
|
|
|
/// If we're ready to read, returns a pointer to the new data.
|
|
const char* Data() const
|
|
{
|
|
MOZ_ASSERT(mState == READY, "Calling Data() in the wrong state");
|
|
return mState == READY ? mData.mIterating.mData + mData.mIterating.mOffset
|
|
: nullptr;
|
|
}
|
|
|
|
/// If we're ready to read, returns the length of the new data.
|
|
size_t Length() const
|
|
{
|
|
MOZ_ASSERT(mState == READY, "Calling Length() in the wrong state");
|
|
return mState == READY ? mData.mIterating.mLength : 0;
|
|
}
|
|
|
|
private:
|
|
friend class SourceBuffer;
|
|
|
|
SourceBufferIterator(const SourceBufferIterator&) = delete;
|
|
SourceBufferIterator& operator=(const SourceBufferIterator&) = delete;
|
|
|
|
bool HasMore() const { return mState != COMPLETE; }
|
|
|
|
State SetReady(uint32_t aChunk, const char* aData,
|
|
size_t aOffset, size_t aLength)
|
|
{
|
|
MOZ_ASSERT(mState != COMPLETE);
|
|
mData.mIterating.mChunk = aChunk;
|
|
mData.mIterating.mData = aData;
|
|
mData.mIterating.mOffset = aOffset;
|
|
mData.mIterating.mLength = aLength;
|
|
return mState = READY;
|
|
}
|
|
|
|
State SetWaiting()
|
|
{
|
|
MOZ_ASSERT(mState != COMPLETE);
|
|
MOZ_ASSERT(mState != WAITING, "Did we get a spurious wakeup somehow?");
|
|
return mState = WAITING;
|
|
}
|
|
|
|
State SetComplete(nsresult aStatus)
|
|
{
|
|
mData.mAtEnd.mStatus = aStatus;
|
|
return mState = COMPLETE;
|
|
}
|
|
|
|
nsRefPtr<SourceBuffer> mOwner;
|
|
|
|
State mState;
|
|
|
|
/**
|
|
* This union contains our iteration state if we're still iterating (for
|
|
* states START, READY, and WAITING) and the status the SourceBuffer was
|
|
* completed with if we're in state COMPLETE.
|
|
*/
|
|
union {
|
|
struct {
|
|
uint32_t mChunk;
|
|
const char* mData;
|
|
size_t mOffset;
|
|
size_t mLength;
|
|
} mIterating;
|
|
struct {
|
|
nsresult mStatus;
|
|
} mAtEnd;
|
|
} mData;
|
|
};
|
|
|
|
/**
|
|
* SourceBuffer is a parallel data structure used for storing image source
|
|
* (compressed) data.
|
|
*
|
|
* SourceBuffer is a single producer, multiple consumer data structure. The
|
|
* single producer calls Append() to append data to the buffer. In parallel,
|
|
* multiple consumers can call Iterator(), which returns a SourceBufferIterator
|
|
* that they can use to iterate through the buffer. The SourceBufferIterator
|
|
* returns a series of pointers which remain stable for lifetime of the
|
|
* SourceBuffer, and the data they point to is immutable, ensuring that the
|
|
* producer never interferes with the consumers.
|
|
*
|
|
* In order to avoid blocking, SourceBuffer works with SourceBufferIterator to
|
|
* keep a list of consumers which are waiting for new data, and to resume them
|
|
* when the producer appends more. All consumers must implement the IResumable
|
|
* interface to make this possible.
|
|
*
|
|
* XXX(seth): We should add support for compacting a SourceBuffer. To do this,
|
|
* we need to have SourceBuffer keep track of how many live
|
|
* SourceBufferIterator's point to it. When the SourceBuffer is complete and no
|
|
* live SourceBufferIterator's for it remain, we can compact its contents into a
|
|
* single chunk.
|
|
*/
|
|
class SourceBuffer final
|
|
{
|
|
public:
|
|
MOZ_DECLARE_REFCOUNTED_TYPENAME(image::SourceBuffer)
|
|
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(image::SourceBuffer)
|
|
|
|
SourceBuffer();
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Producer methods.
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* If the producer knows how long the source data will be, it should call
|
|
* ExpectLength, which enables SourceBuffer to preallocate its buffer.
|
|
*/
|
|
nsresult ExpectLength(size_t aExpectedLength);
|
|
|
|
/// Append the provided data to the buffer.
|
|
nsresult Append(const char* aData, size_t aLength);
|
|
|
|
/**
|
|
* Mark the buffer complete, with a status that will be available to
|
|
* consumers. Further calls to Append() are forbidden after Complete().
|
|
*/
|
|
void Complete(nsresult aStatus);
|
|
|
|
/// Returns true if the buffer is complete.
|
|
bool IsComplete();
|
|
|
|
/// Memory reporting.
|
|
size_t SizeOfIncludingThisWithComputedFallback(MallocSizeOf) const;
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Consumer methods.
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
/// Returns an iterator to this SourceBuffer.
|
|
SourceBufferIterator Iterator();
|
|
|
|
|
|
private:
|
|
friend class SourceBufferIterator;
|
|
|
|
~SourceBuffer();
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Chunk type and chunk-related methods.
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
class Chunk
|
|
{
|
|
public:
|
|
explicit Chunk(size_t aCapacity)
|
|
: mCapacity(aCapacity)
|
|
, mLength(0)
|
|
{
|
|
MOZ_ASSERT(aCapacity > 0, "Creating zero-capacity chunk");
|
|
mData = new (fallible) char[mCapacity];
|
|
}
|
|
|
|
~Chunk() { delete[] mData; }
|
|
|
|
Chunk(Chunk&& aOther)
|
|
: mCapacity(aOther.mCapacity)
|
|
, mLength(aOther.mLength)
|
|
, mData(aOther.mData)
|
|
{
|
|
aOther.mCapacity = aOther.mLength = 0;
|
|
aOther.mData = nullptr;
|
|
}
|
|
|
|
Chunk& operator=(Chunk&& aOther)
|
|
{
|
|
mCapacity = aOther.mCapacity;
|
|
mLength = aOther.mLength;
|
|
mData = aOther.mData;
|
|
aOther.mCapacity = aOther.mLength = 0;
|
|
aOther.mData = nullptr;
|
|
return *this;
|
|
}
|
|
|
|
bool AllocationFailed() const { return !mData; }
|
|
size_t Capacity() const { return mCapacity; }
|
|
size_t Length() const { return mLength; }
|
|
|
|
char* Data() const
|
|
{
|
|
MOZ_ASSERT(mData, "Allocation failed but nobody checked for it");
|
|
return mData;
|
|
}
|
|
|
|
void AddLength(size_t aAdditionalLength)
|
|
{
|
|
MOZ_ASSERT(mLength + aAdditionalLength <= mCapacity);
|
|
mLength += aAdditionalLength;
|
|
}
|
|
|
|
private:
|
|
Chunk(const Chunk&) = delete;
|
|
Chunk& operator=(const Chunk&) = delete;
|
|
|
|
size_t mCapacity;
|
|
size_t mLength;
|
|
char* mData;
|
|
};
|
|
|
|
nsresult AppendChunk(Maybe<Chunk>&& aChunk);
|
|
Maybe<Chunk> CreateChunk(size_t aCapacity, bool aRoundUp = true);
|
|
nsresult Compact();
|
|
static size_t RoundedUpCapacity(size_t aCapacity);
|
|
size_t FibonacciCapacityWithMinimum(size_t aMinCapacity);
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Iterator / consumer methods.
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
void AddWaitingConsumer(IResumable* aConsumer);
|
|
void ResumeWaitingConsumers();
|
|
|
|
typedef SourceBufferIterator::State State;
|
|
|
|
State AdvanceIteratorOrScheduleResume(SourceBufferIterator& aIterator,
|
|
IResumable* aConsumer);
|
|
bool RemainingBytesIsNoMoreThan(const SourceBufferIterator& aIterator,
|
|
size_t aBytes) const;
|
|
|
|
void OnIteratorRelease();
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Helper methods.
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
nsresult HandleError(nsresult aError);
|
|
bool IsEmpty();
|
|
bool IsLastChunk(uint32_t aChunk);
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Member variables.
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
static const size_t MIN_CHUNK_CAPACITY = 4096;
|
|
|
|
/// All private members are protected by mMutex.
|
|
mutable Mutex mMutex;
|
|
|
|
/// The data in this SourceBuffer, stored as a series of Chunks.
|
|
FallibleTArray<Chunk> mChunks;
|
|
|
|
/// Consumers which are waiting to be notified when new data is available.
|
|
nsTArray<nsRefPtr<IResumable>> mWaitingConsumers;
|
|
|
|
/// If present, marks this SourceBuffer complete with the given final status.
|
|
Maybe<nsresult> mStatus;
|
|
|
|
/// Count of active consumers.
|
|
uint32_t mConsumerCount;
|
|
};
|
|
|
|
} // namespace image
|
|
} // namespace mozilla
|
|
|
|
#endif // mozilla_image_sourcebuffer_h
|