diff options
Diffstat (limited to 'image/SurfacePipe.cpp')
-rw-r--r-- | image/SurfacePipe.cpp | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/image/SurfacePipe.cpp b/image/SurfacePipe.cpp new file mode 100644 index 000000000..5c306144a --- /dev/null +++ b/image/SurfacePipe.cpp @@ -0,0 +1,199 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#include "SurfacePipe.h" + +#include <utility> + +#include "mozilla/ClearOnShutdown.h" +#include "mozilla/DebugOnly.h" +#include "Decoder.h" + +namespace mozilla { +namespace image { + +using namespace gfx; + +using std::min; + +/* static */ UniquePtr<NullSurfaceSink> NullSurfaceSink::sSingleton; + +/* static */ NullSurfaceSink* +NullSurfaceSink::Singleton() +{ + if (!sSingleton) { + MOZ_ASSERT(NS_IsMainThread()); + sSingleton = MakeUnique<NullSurfaceSink>(); + ClearOnShutdown(&sSingleton); + + DebugOnly<nsresult> rv = sSingleton->Configure(NullSurfaceConfig { }); + MOZ_ASSERT(NS_SUCCEEDED(rv), "Couldn't configure a NullSurfaceSink?"); + } + + return sSingleton.get(); +} + +nsresult +NullSurfaceSink::Configure(const NullSurfaceConfig& aConfig) +{ + // Note that the choice of uint32_t as the pixel size here is more or less + // arbitrary, since you cannot write to a NullSurfaceSink anyway, but uint32_t + // is a natural choice since most SurfacePipes will be for BGRA/BGRX surfaces. + ConfigureFilter(IntSize(), sizeof(uint32_t)); + return NS_OK; +} + +Maybe<SurfaceInvalidRect> +AbstractSurfaceSink::TakeInvalidRect() +{ + if (mInvalidRect.IsEmpty()) { + return Nothing(); + } + + SurfaceInvalidRect invalidRect; + invalidRect.mInputSpaceRect = invalidRect.mOutputSpaceRect = mInvalidRect; + + // Forget about the invalid rect we're returning. + mInvalidRect = IntRect(); + + return Some(invalidRect); +} + +uint8_t* +AbstractSurfaceSink::DoResetToFirstRow() +{ + mRow = 0; + return GetRowPointer(); +} + +uint8_t* +AbstractSurfaceSink::DoAdvanceRow() +{ + if (mRow >= uint32_t(InputSize().height)) { + return nullptr; + } + + // If we're vertically flipping the output, we need to flip the invalid rect. Since we're + // dealing with an axis-aligned rect, only the y coordinate needs to change. + int32_t invalidY = mFlipVertically + ? InputSize().height - (mRow + 1) + : mRow; + mInvalidRect.UnionRect(mInvalidRect, + IntRect(0, invalidY, InputSize().width, 1)); + + mRow = min(uint32_t(InputSize().height), mRow + 1); + + return mRow < uint32_t(InputSize().height) ? GetRowPointer() + : nullptr; +} + +nsresult +SurfaceSink::Configure(const SurfaceConfig& aConfig) +{ + // For non-paletted surfaces, the surface size is just the output size. + IntSize surfaceSize = aConfig.mOutputSize; + + // Non-paletted surfaces should not have frame rects, so we just pass + // AllocateFrame() a frame rect which covers the entire surface. + IntRect frameRect(0, 0, surfaceSize.width, surfaceSize.height); + + // Allocate the frame. + // XXX(seth): Once every Decoder subclass uses SurfacePipe, we probably want + // to allocate the frame directly here and get rid of Decoder::AllocateFrame + // altogether. + nsresult rv = aConfig.mDecoder->AllocateFrame(aConfig.mFrameNum, + surfaceSize, + frameRect, + aConfig.mFormat); + if (NS_FAILED(rv)) { + return rv; + } + + mImageData = aConfig.mDecoder->mImageData; + mImageDataLength = aConfig.mDecoder->mImageDataLength; + mFlipVertically = aConfig.mFlipVertically; + + MOZ_ASSERT(mImageData); + MOZ_ASSERT(mImageDataLength == + uint32_t(surfaceSize.width * surfaceSize.height * sizeof(uint32_t))); + + ConfigureFilter(surfaceSize, sizeof(uint32_t)); + return NS_OK; +} + +uint8_t* +SurfaceSink::GetRowPointer() const +{ + // If we're flipping vertically, reverse the order in which we traverse the + // rows. + uint32_t row = mFlipVertically + ? InputSize().height - (mRow + 1) + : mRow; + + uint8_t* rowPtr = mImageData + row * InputSize().width * sizeof(uint32_t); + + MOZ_ASSERT(rowPtr >= mImageData); + MOZ_ASSERT(rowPtr < mImageData + mImageDataLength); + MOZ_ASSERT(rowPtr + InputSize().width * sizeof(uint32_t) <= + mImageData + mImageDataLength); + + return rowPtr; +} + + +nsresult +PalettedSurfaceSink::Configure(const PalettedSurfaceConfig& aConfig) +{ + // For paletted surfaces, the surface size is the size of the frame rect. + IntSize surfaceSize = aConfig.mFrameRect.Size(); + + // Allocate the frame. + // XXX(seth): Once every Decoder subclass uses SurfacePipe, we probably want + // to allocate the frame directly here and get rid of Decoder::AllocateFrame + // altogether. + nsresult rv = aConfig.mDecoder->AllocateFrame(aConfig.mFrameNum, + aConfig.mOutputSize, + aConfig.mFrameRect, + aConfig.mFormat, + aConfig.mPaletteDepth); + if (NS_FAILED(rv)) { + return rv; + } + + mImageData = aConfig.mDecoder->mImageData; + mImageDataLength = aConfig.mDecoder->mImageDataLength; + mFlipVertically = aConfig.mFlipVertically; + mFrameRect = aConfig.mFrameRect; + + MOZ_ASSERT(mImageData); + MOZ_ASSERT(mImageDataLength == + uint32_t(mFrameRect.width * mFrameRect.height * sizeof(uint8_t))); + + ConfigureFilter(surfaceSize, sizeof(uint8_t)); + return NS_OK; +} + +uint8_t* +PalettedSurfaceSink::GetRowPointer() const +{ + // If we're flipping vertically, reverse the order in which we traverse the + // rows. + uint32_t row = mFlipVertically + ? InputSize().height - (mRow + 1) + : mRow; + + uint8_t* rowPtr = mImageData + row * InputSize().width * sizeof(uint8_t); + + MOZ_ASSERT(rowPtr >= mImageData); + MOZ_ASSERT(rowPtr < mImageData + mImageDataLength); + MOZ_ASSERT(rowPtr + InputSize().width * sizeof(uint8_t) <= + mImageData + mImageDataLength); + + return rowPtr; +} + +} // namespace image +} // namespace mozilla |