diff --git a/image/DownscalingFilter.h b/image/DownscalingFilter.h index 6a2b93c69d5b..41d796f45057 100644 --- a/image/DownscalingFilter.h +++ b/image/DownscalingFilter.h @@ -78,6 +78,10 @@ class DownscalingFilter final : public SurfaceFilter { MOZ_CRASH(); return nullptr; } + uint8_t* DoAdvanceRowFromBuffer(const uint8_t* aInputRow) override { + MOZ_CRASH(); + return nullptr; + } uint8_t* DoAdvanceRow() override { MOZ_CRASH(); return nullptr; @@ -206,7 +210,7 @@ class DownscalingFilter final : public SurfaceFilter { return GetRowPointer(); } - uint8_t* DoAdvanceRow() override { + uint8_t* DoAdvanceRowFromBuffer(const uint8_t* aInputRow) override { if (mInputRow >= mInputSize.height) { NS_WARNING("Advancing DownscalingFilter past the end of the input"); return nullptr; @@ -226,7 +230,7 @@ class DownscalingFilter final : public SurfaceFilter { if (mInputRow == inputRowToRead) { MOZ_RELEASE_ASSERT(mRowsInWindow < mWindowCapacity, "Need more rows than capacity!"); - mXFilter.ConvolveHorizontally(mRowBuffer.get(), mWindow[mRowsInWindow++], + mXFilter.ConvolveHorizontally(aInputRow, mWindow[mRowsInWindow++], mHasAlpha); } @@ -249,6 +253,10 @@ class DownscalingFilter final : public SurfaceFilter { return mInputRow < mInputSize.height ? GetRowPointer() : nullptr; } + uint8_t* DoAdvanceRow() override { + return DoAdvanceRowFromBuffer(mRowBuffer.get()); + } + private: uint8_t* GetRowPointer() const { return mRowBuffer.get(); } diff --git a/image/SurfaceFilters.h b/image/SurfaceFilters.h index a3aff1e6955c..7a8bdbdefcc0 100644 --- a/image/SurfaceFilters.h +++ b/image/SurfaceFilters.h @@ -80,12 +80,16 @@ class ColorManagementFilter final : public SurfaceFilter { protected: uint8_t* DoResetToFirstRow() override { return mNext.ResetToFirstRow(); } - uint8_t* DoAdvanceRow() override { - uint8_t* rowPtr = mNext.CurrentRowPointer(); - qcms_transform_data(mTransform, rowPtr, rowPtr, mNext.InputSize().width); + uint8_t* DoAdvanceRowFromBuffer(const uint8_t* aInputRow) override { + qcms_transform_data(mTransform, aInputRow, mNext.CurrentRowPointer(), + mNext.InputSize().width); return mNext.AdvanceRow(); } + uint8_t* DoAdvanceRow() override { + return DoAdvanceRowFromBuffer(mNext.CurrentRowPointer()); + } + Next mNext; /// The next SurfaceFilter in the chain. qcms_transform* mTransform; @@ -182,6 +186,11 @@ class DeinterlacingFilter final : public SurfaceFilter { return GetRowPointer(mOutputRow); } + uint8_t* DoAdvanceRowFromBuffer(const uint8_t* aInputRow) override { + CopyInputRow(aInputRow); + return DoAdvanceRow(); + } + uint8_t* DoAdvanceRow() override { if (mPass >= 4) { return nullptr; // We already finished all passes. @@ -638,6 +647,11 @@ class BlendAnimationFilter final : public SurfaceFilter { return nullptr; // We're done. } + uint8_t* DoAdvanceRowFromBuffer(const uint8_t* aInputRow) override { + CopyInputRow(aInputRow); + return DoAdvanceRow(); + } + uint8_t* DoAdvanceRow() override { uint8_t* rowPtr = nullptr; @@ -912,6 +926,11 @@ class RemoveFrameRectFilter final : public SurfaceFilter { return nullptr; // We're done. } + uint8_t* DoAdvanceRowFromBuffer(const uint8_t* aInputRow) override { + CopyInputRow(aInputRow); + return DoAdvanceRow(); + } + uint8_t* DoAdvanceRow() override { uint8_t* rowPtr = nullptr; @@ -1097,6 +1116,11 @@ class ADAM7InterpolatingFilter final : public SurfaceFilter { return mCurrentRow.get(); } + uint8_t* DoAdvanceRowFromBuffer(const uint8_t* aInputRow) override { + CopyInputRow(aInputRow); + return DoAdvanceRow(); + } + uint8_t* DoAdvanceRow() override { MOZ_ASSERT(0 < mPass && mPass <= 7, "Invalid pass"); diff --git a/image/SurfacePipe.cpp b/image/SurfacePipe.cpp index f5595e2d5c7b..1fbb25470d40 100644 --- a/image/SurfacePipe.cpp +++ b/image/SurfacePipe.cpp @@ -36,6 +36,11 @@ uint8_t* AbstractSurfaceSink::DoResetToFirstRow() { return GetRowPointer(); } +uint8_t* AbstractSurfaceSink::DoAdvanceRowFromBuffer(const uint8_t* aInputRow) { + CopyInputRow(aInputRow); + return DoAdvanceRow(); +} + uint8_t* AbstractSurfaceSink::DoAdvanceRow() { if (mRow >= uint32_t(InputSize().height)) { return nullptr; diff --git a/image/SurfacePipe.h b/image/SurfacePipe.h index 224680f29c0e..7bcadf050b39 100644 --- a/image/SurfacePipe.h +++ b/image/SurfacePipe.h @@ -127,6 +127,19 @@ class SurfaceFilter { return mRowPointer; } + /** + * Called by WriteBuffer() to advance this filter to the next row, if the + * supplied row is a full row. + * + * @return a pointer to the buffer for the next row, or nullptr to indicate + * that we've finished the entire surface. + */ + uint8_t* AdvanceRow(const uint8_t* aInputRow) { + mCol = 0; + mRowPointer = DoAdvanceRowFromBuffer(aInputRow); + return mRowPointer; + } + /// @return a pointer to the buffer for the current row. uint8_t* CurrentRowPointer() const { return mRowPointer; } @@ -269,7 +282,22 @@ class SurfaceFilter { */ template WriteState WriteBuffer(const PixelType* aSource) { - return WriteBuffer(aSource, 0, mInputSize.width); + MOZ_ASSERT(mPixelSize == 1 || mPixelSize == 4); + MOZ_ASSERT_IF(mPixelSize == 1, sizeof(PixelType) == sizeof(uint8_t)); + MOZ_ASSERT_IF(mPixelSize == 4, sizeof(PixelType) == sizeof(uint32_t)); + + if (IsSurfaceFinished()) { + return WriteState::FINISHED; // Already done. + } + + if (MOZ_UNLIKELY(!aSource)) { + NS_WARNING("Passed a null pointer to WriteBuffer"); + return WriteState::FAILURE; + } + + AdvanceRow(reinterpret_cast(aSource)); + return IsSurfaceFinished() ? WriteState::FINISHED + : WriteState::NEED_MORE_DATA; } /** @@ -440,6 +468,16 @@ class SurfaceFilter { */ virtual uint8_t* DoResetToFirstRow() = 0; + /** + * Called by AdvanceRow() to actually advance this filter to the next row. + * + * @param aInputRow The input row supplied by the decoder. + * + * @return a pointer to the buffer for the next row, or nullptr to indicate + * that we've finished the entire surface. + */ + virtual uint8_t* DoAdvanceRowFromBuffer(const uint8_t* aInputRow) = 0; + /** * Called by AdvanceRow() to actually advance this filter to the next row. * @@ -470,6 +508,20 @@ class SurfaceFilter { ResetToFirstRow(); } + /** + * Called by subclasses' DoAdvanceRowFromBuffer() methods to copy a decoder + * supplied row buffer into its internal row pointer. Ideally filters at the + * top of the filter pipeline are able to consume the decoder row buffer + * directly without the extra copy prior to performing its transformation. + * + * @param aInputRow The input row supplied by the decoder. + */ + void CopyInputRow(const uint8_t* aInputRow) { + MOZ_ASSERT(aInputRow); + MOZ_ASSERT(mCol == 0); + memcpy(mRowPointer, aInputRow, mPixelSize * mInputSize.width); + } + private: /** * An internal method used to implement WritePixelBlocks. This method writes @@ -719,6 +771,7 @@ class AbstractSurfaceSink : public SurfaceFilter { protected: uint8_t* DoResetToFirstRow() final; + uint8_t* DoAdvanceRowFromBuffer(const uint8_t* aInputRow) final; uint8_t* DoAdvanceRow() final; virtual uint8_t* GetRowPointer() const = 0;