SourceBuffer.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. /**
  6. * SourceBuffer is a single producer, multiple consumer data structure used for
  7. * storing image source (compressed) data.
  8. */
  9. #ifndef mozilla_image_sourcebuffer_h
  10. #define mozilla_image_sourcebuffer_h
  11. #include <algorithm>
  12. #include "mozilla/Maybe.h"
  13. #include "mozilla/MemoryReporting.h"
  14. #include "mozilla/Mutex.h"
  15. #include "mozilla/Move.h"
  16. #include "mozilla/MemoryReporting.h"
  17. #include "mozilla/RefPtr.h"
  18. #include "mozilla/RefCounted.h"
  19. #include "mozilla/UniquePtr.h"
  20. #include "mozilla/RefPtr.h"
  21. #include "nsTArray.h"
  22. class nsIInputStream;
  23. namespace mozilla {
  24. namespace image {
  25. class SourceBuffer;
  26. /**
  27. * IResumable is an interface for classes that can schedule themselves to resume
  28. * their work later. An implementation of IResumable generally should post a
  29. * runnable to some event target which continues the work of the task.
  30. */
  31. struct IResumable
  32. {
  33. MOZ_DECLARE_REFCOUNTED_TYPENAME(IResumable)
  34. // Subclasses may or may not be XPCOM classes, so we just require that they
  35. // implement AddRef and Release.
  36. NS_IMETHOD_(MozExternalRefCountType) AddRef(void) = 0;
  37. NS_IMETHOD_(MozExternalRefCountType) Release(void) = 0;
  38. virtual void Resume() = 0;
  39. protected:
  40. virtual ~IResumable() { }
  41. };
  42. /**
  43. * SourceBufferIterator is a class that allows consumers of image source data to
  44. * read the contents of a SourceBuffer sequentially.
  45. *
  46. * Consumers can advance through the SourceBuffer by calling
  47. * AdvanceOrScheduleResume() repeatedly. After every advance, they should call
  48. * check the return value, which will tell them the iterator's new state.
  49. *
  50. * If WAITING is returned, AdvanceOrScheduleResume() has arranged
  51. * to call the consumer's Resume() method later, so the consumer should save its
  52. * state if needed and stop running.
  53. *
  54. * If the iterator's new state is READY, then the consumer can call Data() and
  55. * Length() to read new data from the SourceBuffer.
  56. *
  57. * Finally, in the COMPLETE state the consumer can call CompletionStatus() to
  58. * get the status passed to SourceBuffer::Complete().
  59. */
  60. class SourceBufferIterator final
  61. {
  62. public:
  63. enum State {
  64. START, // The iterator is at the beginning of the buffer.
  65. READY, // The iterator is pointing to new data.
  66. WAITING, // The iterator is blocked and the caller must yield.
  67. COMPLETE // The iterator is pointing to the end of the buffer.
  68. };
  69. explicit SourceBufferIterator(SourceBuffer* aOwner)
  70. : mOwner(aOwner)
  71. , mState(START)
  72. , mChunkCount(0)
  73. , mByteCount(0)
  74. {
  75. MOZ_ASSERT(aOwner);
  76. mData.mIterating.mChunk = 0;
  77. mData.mIterating.mData = nullptr;
  78. mData.mIterating.mOffset = 0;
  79. mData.mIterating.mAvailableLength = 0;
  80. mData.mIterating.mNextReadLength = 0;
  81. }
  82. SourceBufferIterator(SourceBufferIterator&& aOther)
  83. : mOwner(Move(aOther.mOwner))
  84. , mState(aOther.mState)
  85. , mData(aOther.mData)
  86. , mChunkCount(aOther.mChunkCount)
  87. , mByteCount(aOther.mByteCount)
  88. { }
  89. ~SourceBufferIterator();
  90. SourceBufferIterator& operator=(SourceBufferIterator&& aOther);
  91. /**
  92. * Returns true if there are no more than @aBytes remaining in the
  93. * SourceBuffer. If the SourceBuffer is not yet complete, returns false.
  94. */
  95. bool RemainingBytesIsNoMoreThan(size_t aBytes) const;
  96. /**
  97. * Advances the iterator through the SourceBuffer if possible. Advances no
  98. * more than @aRequestedBytes bytes. (Use SIZE_MAX to advance as much as
  99. * possible.)
  100. *
  101. * This is a wrapper around AdvanceOrScheduleResume() that makes it clearer at
  102. * the callsite when the no resuming is intended.
  103. *
  104. * @return State::READY if the iterator was successfully advanced.
  105. * State::WAITING if the iterator could not be advanced because it's
  106. * at the end of the underlying SourceBuffer, but the SourceBuffer
  107. * may still receive additional data.
  108. * State::COMPLETE if the iterator could not be advanced because it's
  109. * at the end of the underlying SourceBuffer and the SourceBuffer is
  110. * marked complete (i.e., it will never receive any additional
  111. * data).
  112. */
  113. State Advance(size_t aRequestedBytes)
  114. {
  115. return AdvanceOrScheduleResume(aRequestedBytes, nullptr);
  116. }
  117. /**
  118. * Advances the iterator through the SourceBuffer if possible. Advances no
  119. * more than @aRequestedBytes bytes. (Use SIZE_MAX to advance as much as
  120. * possible.) If advancing is not possible and @aConsumer is not null,
  121. * arranges to call the @aConsumer's Resume() method when more data is
  122. * available.
  123. *
  124. * @return State::READY if the iterator was successfully advanced.
  125. * State::WAITING if the iterator could not be advanced because it's
  126. * at the end of the underlying SourceBuffer, but the SourceBuffer
  127. * may still receive additional data. @aConsumer's Resume() method
  128. * will be called when additional data is available.
  129. * State::COMPLETE if the iterator could not be advanced because it's
  130. * at the end of the underlying SourceBuffer and the SourceBuffer is
  131. * marked complete (i.e., it will never receive any additional
  132. * data).
  133. */
  134. State AdvanceOrScheduleResume(size_t aRequestedBytes, IResumable* aConsumer);
  135. /// If at the end, returns the status passed to SourceBuffer::Complete().
  136. nsresult CompletionStatus() const
  137. {
  138. MOZ_ASSERT(mState == COMPLETE,
  139. "Calling CompletionStatus() in the wrong state");
  140. return mState == COMPLETE ? mData.mAtEnd.mStatus : NS_OK;
  141. }
  142. /// If we're ready to read, returns a pointer to the new data.
  143. const char* Data() const
  144. {
  145. MOZ_ASSERT(mState == READY, "Calling Data() in the wrong state");
  146. return mState == READY ? mData.mIterating.mData + mData.mIterating.mOffset
  147. : nullptr;
  148. }
  149. /// If we're ready to read, returns the length of the new data.
  150. size_t Length() const
  151. {
  152. MOZ_ASSERT(mState == READY, "Calling Length() in the wrong state");
  153. return mState == READY ? mData.mIterating.mNextReadLength : 0;
  154. }
  155. /// If we're ready to read, returns whether or not everything available thus
  156. /// far has been in the same contiguous buffer.
  157. bool IsContiguous() const {
  158. MOZ_ASSERT(mState == READY, "Calling IsContiguous() in the wrong state");
  159. return mState == READY ? mData.mIterating.mChunk == 0 : false;
  160. }
  161. /// @return a count of the chunks we've advanced through.
  162. uint32_t ChunkCount() const { return mChunkCount; }
  163. /// @return a count of the bytes in all chunks we've advanced through.
  164. size_t ByteCount() const { return mByteCount; }
  165. private:
  166. friend class SourceBuffer;
  167. SourceBufferIterator(const SourceBufferIterator&) = delete;
  168. SourceBufferIterator& operator=(const SourceBufferIterator&) = delete;
  169. bool HasMore() const { return mState != COMPLETE; }
  170. State AdvanceFromLocalBuffer(size_t aRequestedBytes)
  171. {
  172. MOZ_ASSERT(mState == READY, "Advancing in the wrong state");
  173. MOZ_ASSERT(mData.mIterating.mAvailableLength > 0,
  174. "The local buffer shouldn't be empty");
  175. MOZ_ASSERT(mData.mIterating.mNextReadLength == 0,
  176. "Advancing without consuming previous data");
  177. mData.mIterating.mNextReadLength =
  178. std::min(mData.mIterating.mAvailableLength, aRequestedBytes);
  179. return READY;
  180. }
  181. State SetReady(uint32_t aChunk, const char* aData,
  182. size_t aOffset, size_t aAvailableLength,
  183. size_t aRequestedBytes)
  184. {
  185. MOZ_ASSERT(mState != COMPLETE);
  186. mState = READY;
  187. // Update state.
  188. mData.mIterating.mChunk = aChunk;
  189. mData.mIterating.mData = aData;
  190. mData.mIterating.mOffset = aOffset;
  191. mData.mIterating.mAvailableLength = aAvailableLength;
  192. // Update metrics.
  193. mChunkCount++;
  194. mByteCount += aAvailableLength;
  195. // Attempt to advance by the requested number of bytes.
  196. return AdvanceFromLocalBuffer(aRequestedBytes);
  197. }
  198. State SetWaiting()
  199. {
  200. MOZ_ASSERT(mState != COMPLETE);
  201. MOZ_ASSERT(mState != WAITING, "Did we get a spurious wakeup somehow?");
  202. return mState = WAITING;
  203. }
  204. State SetComplete(nsresult aStatus)
  205. {
  206. mData.mAtEnd.mStatus = aStatus;
  207. return mState = COMPLETE;
  208. }
  209. RefPtr<SourceBuffer> mOwner;
  210. State mState;
  211. /**
  212. * This union contains our iteration state if we're still iterating (for
  213. * states START, READY, and WAITING) and the status the SourceBuffer was
  214. * completed with if we're in state COMPLETE.
  215. */
  216. union {
  217. struct {
  218. uint32_t mChunk;
  219. const char* mData;
  220. size_t mOffset;
  221. size_t mAvailableLength;
  222. size_t mNextReadLength;
  223. } mIterating;
  224. struct {
  225. nsresult mStatus;
  226. } mAtEnd;
  227. } mData;
  228. uint32_t mChunkCount; // Count of chunks we've advanced through.
  229. size_t mByteCount; // Count of bytes in all chunks we've advanced through.
  230. };
  231. /**
  232. * SourceBuffer is a parallel data structure used for storing image source
  233. * (compressed) data.
  234. *
  235. * SourceBuffer is a single producer, multiple consumer data structure. The
  236. * single producer calls Append() to append data to the buffer. In parallel,
  237. * multiple consumers can call Iterator(), which returns a SourceBufferIterator
  238. * that they can use to iterate through the buffer. The SourceBufferIterator
  239. * returns a series of pointers which remain stable for lifetime of the
  240. * SourceBuffer, and the data they point to is immutable, ensuring that the
  241. * producer never interferes with the consumers.
  242. *
  243. * In order to avoid blocking, SourceBuffer works with SourceBufferIterator to
  244. * keep a list of consumers which are waiting for new data, and to resume them
  245. * when the producer appends more. All consumers must implement the IResumable
  246. * interface to make this possible.
  247. */
  248. class SourceBuffer final
  249. {
  250. public:
  251. MOZ_DECLARE_REFCOUNTED_TYPENAME(image::SourceBuffer)
  252. NS_INLINE_DECL_THREADSAFE_REFCOUNTING(image::SourceBuffer)
  253. SourceBuffer();
  254. //////////////////////////////////////////////////////////////////////////////
  255. // Producer methods.
  256. //////////////////////////////////////////////////////////////////////////////
  257. /**
  258. * If the producer knows how long the source data will be, it should call
  259. * ExpectLength, which enables SourceBuffer to preallocate its buffer.
  260. */
  261. nsresult ExpectLength(size_t aExpectedLength);
  262. /// Append the provided data to the buffer.
  263. nsresult Append(const char* aData, size_t aLength);
  264. /// Append the data available on the provided nsIInputStream to the buffer.
  265. nsresult AppendFromInputStream(nsIInputStream* aInputStream, uint32_t aCount);
  266. /**
  267. * Mark the buffer complete, with a status that will be available to
  268. * consumers. Further calls to Append() are forbidden after Complete().
  269. */
  270. void Complete(nsresult aStatus);
  271. /// Returns true if the buffer is complete.
  272. bool IsComplete();
  273. /// Memory reporting.
  274. size_t SizeOfIncludingThisWithComputedFallback(MallocSizeOf) const;
  275. //////////////////////////////////////////////////////////////////////////////
  276. // Consumer methods.
  277. //////////////////////////////////////////////////////////////////////////////
  278. /// Returns an iterator to this SourceBuffer.
  279. SourceBufferIterator Iterator();
  280. //////////////////////////////////////////////////////////////////////////////
  281. // Consumer methods.
  282. //////////////////////////////////////////////////////////////////////////////
  283. /**
  284. * The minimum chunk capacity we'll allocate, if we don't know the correct
  285. * capacity (which would happen because ExpectLength() wasn't called or gave
  286. * us the wrong value). This is only exposed for use by tests; if normal code
  287. * is using this, it's doing something wrong.
  288. */
  289. static const size_t MIN_CHUNK_CAPACITY = 4096;
  290. private:
  291. friend class SourceBufferIterator;
  292. ~SourceBuffer();
  293. //////////////////////////////////////////////////////////////////////////////
  294. // Chunk type and chunk-related methods.
  295. //////////////////////////////////////////////////////////////////////////////
  296. class Chunk
  297. {
  298. public:
  299. explicit Chunk(size_t aCapacity)
  300. : mCapacity(aCapacity)
  301. , mLength(0)
  302. {
  303. MOZ_ASSERT(aCapacity > 0, "Creating zero-capacity chunk");
  304. mData.reset(new (fallible) char[mCapacity]);
  305. }
  306. Chunk(Chunk&& aOther)
  307. : mCapacity(aOther.mCapacity)
  308. , mLength(aOther.mLength)
  309. , mData(Move(aOther.mData))
  310. {
  311. aOther.mCapacity = aOther.mLength = 0;
  312. aOther.mData = nullptr;
  313. }
  314. Chunk& operator=(Chunk&& aOther)
  315. {
  316. mCapacity = aOther.mCapacity;
  317. mLength = aOther.mLength;
  318. mData = Move(aOther.mData);
  319. aOther.mCapacity = aOther.mLength = 0;
  320. aOther.mData = nullptr;
  321. return *this;
  322. }
  323. bool AllocationFailed() const { return !mData; }
  324. size_t Capacity() const { return mCapacity; }
  325. size_t Length() const { return mLength; }
  326. char* Data() const
  327. {
  328. MOZ_ASSERT(mData, "Allocation failed but nobody checked for it");
  329. return mData.get();
  330. }
  331. void AddLength(size_t aAdditionalLength)
  332. {
  333. MOZ_ASSERT(mLength + aAdditionalLength <= mCapacity);
  334. mLength += aAdditionalLength;
  335. }
  336. private:
  337. Chunk(const Chunk&) = delete;
  338. Chunk& operator=(const Chunk&) = delete;
  339. size_t mCapacity;
  340. size_t mLength;
  341. UniquePtr<char[]> mData;
  342. };
  343. nsresult AppendChunk(Maybe<Chunk>&& aChunk);
  344. Maybe<Chunk> CreateChunk(size_t aCapacity, bool aRoundUp = true);
  345. nsresult Compact();
  346. static size_t RoundedUpCapacity(size_t aCapacity);
  347. size_t FibonacciCapacityWithMinimum(size_t aMinCapacity);
  348. //////////////////////////////////////////////////////////////////////////////
  349. // Iterator / consumer methods.
  350. //////////////////////////////////////////////////////////////////////////////
  351. void AddWaitingConsumer(IResumable* aConsumer);
  352. void ResumeWaitingConsumers();
  353. typedef SourceBufferIterator::State State;
  354. State AdvanceIteratorOrScheduleResume(SourceBufferIterator& aIterator,
  355. size_t aRequestedBytes,
  356. IResumable* aConsumer);
  357. bool RemainingBytesIsNoMoreThan(const SourceBufferIterator& aIterator,
  358. size_t aBytes) const;
  359. void OnIteratorRelease();
  360. //////////////////////////////////////////////////////////////////////////////
  361. // Helper methods.
  362. //////////////////////////////////////////////////////////////////////////////
  363. nsresult HandleError(nsresult aError);
  364. bool IsEmpty();
  365. bool IsLastChunk(uint32_t aChunk);
  366. //////////////////////////////////////////////////////////////////////////////
  367. // Member variables.
  368. //////////////////////////////////////////////////////////////////////////////
  369. /// All private members are protected by mMutex.
  370. mutable Mutex mMutex;
  371. /// The data in this SourceBuffer, stored as a series of Chunks.
  372. FallibleTArray<Chunk> mChunks;
  373. /// Consumers which are waiting to be notified when new data is available.
  374. nsTArray<RefPtr<IResumable>> mWaitingConsumers;
  375. /// If present, marks this SourceBuffer complete with the given final status.
  376. Maybe<nsresult> mStatus;
  377. /// Count of active consumers.
  378. uint32_t mConsumerCount;
  379. };
  380. } // namespace image
  381. } // namespace mozilla
  382. #endif // mozilla_image_sourcebuffer_h