Bug 1869043 assert that graph set access is main thread only r=padenot
[gecko.git] / image / SurfacePipe.cpp
blob2e4a86daefd1f25452bdb8e73a491f43bc73854b
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/. */
7 #include "SurfacePipe.h"
9 #include <algorithm> // for min
11 #include "Decoder.h"
13 namespace mozilla {
14 namespace image {
16 using namespace gfx;
18 using std::min;
20 Maybe<SurfaceInvalidRect> AbstractSurfaceSink::TakeInvalidRect() {
21 if (mInvalidRect.IsEmpty()) {
22 return Nothing();
25 SurfaceInvalidRect invalidRect;
26 invalidRect.mInputSpaceRect = invalidRect.mOutputSpaceRect = mInvalidRect;
28 // Forget about the invalid rect we're returning.
29 mInvalidRect = OrientedIntRect();
31 return Some(invalidRect);
34 uint8_t* AbstractSurfaceSink::DoResetToFirstRow() {
35 mRow = 0;
36 return GetRowPointer();
39 uint8_t* SurfaceSink::DoAdvanceRowFromBuffer(const uint8_t* aInputRow) {
40 CopyInputRow(aInputRow);
41 return DoAdvanceRow();
44 uint8_t* SurfaceSink::DoAdvanceRow() {
45 if (mRow >= uint32_t(InputSize().height)) {
46 return nullptr;
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));
56 mRow = min(uint32_t(InputSize().height), mRow + 1);
58 return mRow < uint32_t(InputSize().height) ? GetRowPointer() : nullptr;
61 nsresult SurfaceSink::Configure(const SurfaceConfig& aConfig) {
62 IntSize surfaceSize = aConfig.mOutputSize;
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;
74 mImageData = aConfig.mDecoder->mImageData;
75 mImageDataLength = aConfig.mDecoder->mImageDataLength;
76 mFlipVertically = aConfig.mFlipVertically;
78 MOZ_ASSERT(mImageData);
79 MOZ_ASSERT(uint64_t(mImageDataLength) == uint64_t(surfaceSize.width) *
80 uint64_t(surfaceSize.height) *
81 sizeof(uint32_t));
83 ConfigureFilter(surfaceSize, sizeof(uint32_t));
84 return NS_OK;
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;
92 uint8_t* rowPtr = mImageData + row * InputSize().width * sizeof(uint32_t);
94 MOZ_ASSERT(rowPtr >= mImageData);
95 MOZ_ASSERT(rowPtr < mImageData + mImageDataLength);
96 MOZ_ASSERT(rowPtr + InputSize().width * sizeof(uint32_t) <=
97 mImageData + mImageDataLength);
99 return rowPtr;
102 uint8_t* ReorientSurfaceSink::DoAdvanceRowFromBuffer(const uint8_t* aInputRow) {
103 if (mRow >= uint32_t(InputSize().height)) {
104 return nullptr;
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);
112 mRow = min(uint32_t(InputSize().height), mRow + 1);
114 return mRow < uint32_t(InputSize().height) ? GetRowPointer() : nullptr;
117 uint8_t* ReorientSurfaceSink::DoAdvanceRow() {
118 return DoAdvanceRowFromBuffer(mBuffer.get());
121 nsresult ReorientSurfaceSink::Configure(const ReorientSurfaceConfig& aConfig) {
122 mSurfaceSize = aConfig.mOutputSize.ToUnknownSize();
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;
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;
142 memset(mBuffer.get(), 0xFF, inputSize.width * sizeof(uint32_t));
144 mReorientFn = ReorientRow(aConfig.mOrientation);
145 MOZ_ASSERT(mReorientFn);
147 mImageData = aConfig.mDecoder->mImageData;
148 mImageDataLength = aConfig.mDecoder->mImageDataLength;
150 MOZ_ASSERT(mImageData);
151 MOZ_ASSERT(uint64_t(mImageDataLength) == uint64_t(mSurfaceSize.width) *
152 uint64_t(mSurfaceSize.height) *
153 sizeof(uint32_t));
155 ConfigureFilter(inputSize, sizeof(uint32_t));
156 return NS_OK;
159 uint8_t* ReorientSurfaceSink::GetRowPointer() const { return mBuffer.get(); }
161 } // namespace image
162 } // namespace mozilla