SurfacePipe.cpp (5269B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "SurfacePipe.h" 8 9 #include <algorithm> // for min 10 11 #include "Decoder.h" 12 13 namespace mozilla { 14 namespace image { 15 16 using namespace gfx; 17 18 using std::min; 19 20 Maybe<SurfaceInvalidRect> AbstractSurfaceSink::TakeInvalidRect() { 21 if (mInvalidRect.IsEmpty()) { 22 return Nothing(); 23 } 24 25 SurfaceInvalidRect invalidRect; 26 invalidRect.mInputSpaceRect = invalidRect.mOutputSpaceRect = mInvalidRect; 27 28 // Forget about the invalid rect we're returning. 29 mInvalidRect = OrientedIntRect(); 30 31 return Some(invalidRect); 32 } 33 34 uint8_t* AbstractSurfaceSink::DoResetToFirstRow() { 35 mRow = 0; 36 return GetRowPointer(); 37 } 38 39 uint8_t* SurfaceSink::DoAdvanceRowFromBuffer(const uint8_t* aInputRow) { 40 CopyInputRow(aInputRow); 41 return DoAdvanceRow(); 42 } 43 44 uint8_t* SurfaceSink::DoAdvanceRow() { 45 if (mRow >= uint32_t(InputSize().height)) { 46 return nullptr; 47 } 48 49 // If we're vertically flipping the output, we need to flip the invalid rect. 50 // Since we're dealing with an axis-aligned rect, only the y coordinate needs 51 // to change. 52 int32_t invalidY = mFlipVertically ? InputSize().height - (mRow + 1) : mRow; 53 mInvalidRect.UnionRect(mInvalidRect, 54 OrientedIntRect(0, invalidY, InputSize().width, 1)); 55 56 mRow = min(uint32_t(InputSize().height), mRow + 1); 57 58 return mRow < uint32_t(InputSize().height) ? GetRowPointer() : nullptr; 59 } 60 61 nsresult SurfaceSink::Configure(const SurfaceConfig& aConfig) { 62 IntSize surfaceSize = aConfig.mOutputSize; 63 64 // Allocate the frame. 65 // XXX(seth): Once every Decoder subclass uses SurfacePipe, we probably want 66 // to allocate the frame directly here and get rid of Decoder::AllocateFrame 67 // altogether. 68 nsresult rv = aConfig.mDecoder->AllocateFrame(surfaceSize, aConfig.mFormat, 69 aConfig.mAnimParams); 70 if (NS_FAILED(rv)) { 71 return rv; 72 } 73 74 mImageData = aConfig.mDecoder->mImageData; 75 mImageDataLength = aConfig.mDecoder->mImageDataLength; 76 mFlipVertically = aConfig.mFlipVertically; 77 78 MOZ_ASSERT(mImageData); 79 MOZ_ASSERT(uint64_t(mImageDataLength) == uint64_t(surfaceSize.width) * 80 uint64_t(surfaceSize.height) * 81 sizeof(uint32_t)); 82 83 ConfigureFilter(surfaceSize, sizeof(uint32_t)); 84 return NS_OK; 85 } 86 87 uint8_t* SurfaceSink::GetRowPointer() const { 88 // If we're flipping vertically, reverse the order in which we traverse the 89 // rows. 90 uint32_t row = mFlipVertically ? InputSize().height - (mRow + 1) : mRow; 91 92 uint8_t* rowPtr = mImageData + row * InputSize().width * sizeof(uint32_t); 93 94 MOZ_ASSERT(rowPtr >= mImageData); 95 MOZ_ASSERT(rowPtr < mImageData + mImageDataLength); 96 MOZ_ASSERT(rowPtr + InputSize().width * sizeof(uint32_t) <= 97 mImageData + mImageDataLength); 98 99 return rowPtr; 100 } 101 102 uint8_t* ReorientSurfaceSink::DoAdvanceRowFromBuffer(const uint8_t* aInputRow) { 103 if (mRow >= uint32_t(InputSize().height)) { 104 return nullptr; 105 } 106 107 IntRect dirty = mReorientFn(aInputRow, mRow, mImageData, mSurfaceSize, 108 mSurfaceSize.width * sizeof(uint32_t)); 109 auto orientedDirty = OrientedIntRect::FromUnknownRect(dirty); 110 mInvalidRect.UnionRect(mInvalidRect, orientedDirty); 111 112 mRow = min(uint32_t(InputSize().height), mRow + 1); 113 114 return mRow < uint32_t(InputSize().height) ? GetRowPointer() : nullptr; 115 } 116 117 uint8_t* ReorientSurfaceSink::DoAdvanceRow() { 118 return DoAdvanceRowFromBuffer(mBuffer.get()); 119 } 120 121 nsresult ReorientSurfaceSink::Configure(const ReorientSurfaceConfig& aConfig) { 122 mSurfaceSize = aConfig.mOutputSize.ToUnknownSize(); 123 124 // Allocate the frame. 125 // XXX(seth): Once every Decoder subclass uses SurfacePipe, we probably want 126 // to allocate the frame directly here and get rid of Decoder::AllocateFrame 127 // altogether. 128 nsresult rv = 129 aConfig.mDecoder->AllocateFrame(mSurfaceSize, aConfig.mFormat, Nothing()); 130 if (NS_FAILED(rv)) { 131 return rv; 132 } 133 134 // The filters above us need the unoriented size as the input. 135 auto inputSize = 136 aConfig.mOrientation.ToUnoriented(aConfig.mOutputSize).ToUnknownSize(); 137 mBuffer.reset(new (fallible) uint8_t[inputSize.width * sizeof(uint32_t)]); 138 if (MOZ_UNLIKELY(!mBuffer)) { 139 return NS_ERROR_OUT_OF_MEMORY; 140 } 141 142 memset(mBuffer.get(), 0xFF, inputSize.width * sizeof(uint32_t)); 143 144 mReorientFn = ReorientRow(aConfig.mOrientation); 145 MOZ_ASSERT(mReorientFn); 146 147 mImageData = aConfig.mDecoder->mImageData; 148 mImageDataLength = aConfig.mDecoder->mImageDataLength; 149 150 MOZ_ASSERT(mImageData); 151 MOZ_ASSERT(uint64_t(mImageDataLength) == uint64_t(mSurfaceSize.width) * 152 uint64_t(mSurfaceSize.height) * 153 sizeof(uint32_t)); 154 155 ConfigureFilter(inputSize, sizeof(uint32_t)); 156 return NS_OK; 157 } 158 159 uint8_t* ReorientSurfaceSink::GetRowPointer() const { return mBuffer.get(); } 160 161 } // namespace image 162 } // namespace mozilla