/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * 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/. */
void Downscaler::ReleaseWindow() { if (!mWindow) { return;
}
for (int32_t i = 0; i < mWindowCapacity; ++i) { delete[] mWindow[i];
}
mWindow = nullptr;
mWindowCapacity = 0;
}
nsresult Downscaler::BeginFrame(const nsIntSize& aOriginalSize, const Maybe<nsIntRect>& aFrameRect,
uint8_t* aOutputBuffer, bool aHasAlpha, bool aFlipVertically /* = false */) {
MOZ_ASSERT(aOutputBuffer);
MOZ_ASSERT(mTargetSize != aOriginalSize, "Created a downscaler, but not downscaling?");
MOZ_ASSERT(mTargetSize.width <= aOriginalSize.width, "Created a downscaler, but width is larger");
MOZ_ASSERT(mTargetSize.height <= aOriginalSize.height, "Created a downscaler, but height is larger");
MOZ_ASSERT(aOriginalSize.width > 0 && aOriginalSize.height > 0, "Invalid original size");
// Only downscale from reasonable sizes to avoid using too much memory/cpu // downscaling and decoding. 1 << 20 == 1,048,576 seems a reasonable limit. if (aOriginalSize.width > (1 << 20) || aOriginalSize.height > (1 << 20)) {
NS_WARNING("Trying to downscale image frame that is too large"); return NS_ERROR_INVALID_ARG;
}
mFrameRect = aFrameRect.valueOr(nsIntRect(nsIntPoint(), aOriginalSize));
MOZ_ASSERT(mFrameRect.X() >= 0 && mFrameRect.Y() >= 0 &&
mFrameRect.Width() >= 0 && mFrameRect.Height() >= 0, "Frame rect must have non-negative components");
MOZ_ASSERT(nsIntRect(0, 0, aOriginalSize.width, aOriginalSize.height)
.Contains(mFrameRect), "Frame rect must fit inside image");
MOZ_ASSERT_IF(!nsIntRect(0, 0, aOriginalSize.width, aOriginalSize.height)
.IsEqualEdges(mFrameRect),
aHasAlpha);
auto resizeMethod = gfx::ConvolutionFilter::ResizeMethod::LANCZOS3; if (!mXFilter.ComputeResizeFilter(resizeMethod, mOriginalSize.width,
mTargetSize.width) ||
!mYFilter.ComputeResizeFilter(resizeMethod, mOriginalSize.height,
mTargetSize.height)) {
NS_WARNING("Failed to compute filters for image downscaling"); return NS_ERROR_OUT_OF_MEMORY;
}
// Allocate the buffer, which contains scanlines of the original image. // pad to handle overreads by the simd code
size_t bufferLen = gfx::ConvolutionFilter::PadBytesForSIMD(
mOriginalSize.width * sizeof(uint32_t));
mRowBuffer.reset(new (fallible) uint8_t[bufferLen]); if (MOZ_UNLIKELY(!mRowBuffer)) { return NS_ERROR_OUT_OF_MEMORY;
}
// Zero buffer to keep valgrind happy.
memset(mRowBuffer.get(), 0, bufferLen);
// Allocate the window, which contains horizontally downscaled scanlines. (We // can store scanlines which are already downscale because our downscaling // filter is separable.)
mWindowCapacity = mYFilter.MaxFilter();
mWindow.reset(new (fallible) uint8_t*[mWindowCapacity]); if (MOZ_UNLIKELY(!mWindow)) { return NS_ERROR_OUT_OF_MEMORY;
}
bool anyAllocationFailed = false; // pad to handle overreads by the simd code const size_t rowSize = gfx::ConvolutionFilter::PadBytesForSIMD(
mTargetSize.width * sizeof(uint32_t)); for (int32_t i = 0; i < mWindowCapacity; ++i) {
mWindow[i] = new (fallible) uint8_t[rowSize];
anyAllocationFailed = anyAllocationFailed || mWindow[i] == nullptr;
}
if (MOZ_UNLIKELY(anyAllocationFailed)) { // We intentionally iterate through the entire array even if an allocation // fails, to ensure that all the pointers in it are either valid or nullptr. // That in turn ensures that ReleaseWindow() can clean up correctly. return NS_ERROR_OUT_OF_MEMORY;
}
ResetForNextProgressivePass();
return NS_OK;
}
void Downscaler::SkipToRow(int32_t aRow) { if (mCurrentInLine < aRow) {
ClearRow(); do {
CommitRow();
} while (mCurrentInLine < aRow);
}
}
if (mFrameRect.IsEmpty()) { // Our frame rect is zero size; commit rows until the end of the image.
SkipToRow(mOriginalSize.height - 1);
} else { // If we have a vertical offset, commit rows to shift us past it.
SkipToRow(mFrameRect.Y());
}
}
void Downscaler::CommitRow() {
MOZ_ASSERT(mOutputBuffer, "Should have a current frame");
MOZ_ASSERT(mCurrentInLine < mOriginalSize.height, "Past end of input");
// If we're at the end of the part of the original image that has data, commit // rows to shift us to the end. if (mCurrentInLine == (mFrameRect.Y() + mFrameRect.Height())) {
SkipToRow(mOriginalSize.height - 1);
}
}
DownscalerInvalidRect Downscaler::TakeInvalidRect() { if (MOZ_UNLIKELY(!HasInvalidation())) { return DownscalerInvalidRect();
}
DownscalerInvalidRect invalidRect;
// Compute the target size invalid rect. if (mFlipVertically) { // We need to flip it. This will implicitly flip the original size invalid // rect, since we compute it by scaling this rect.
invalidRect.mTargetSizeRect =
IntRect(0, mTargetSize.height - mCurrentOutLine, mTargetSize.width,
mCurrentOutLine - mPrevInvalidatedLine);
} else {
invalidRect.mTargetSizeRect =
IntRect(0, mPrevInvalidatedLine, mTargetSize.width,
mCurrentOutLine - mPrevInvalidatedLine);
}
mPrevInvalidatedLine = mCurrentOutLine;
// Compute the original size invalid rect.
invalidRect.mOriginalSizeRect = invalidRect.mTargetSizeRect;
invalidRect.mOriginalSizeRect.ScaleRoundOut(mScale.xScale, mScale.yScale);
return invalidRect;
}
void Downscaler::DownscaleInputLine() {
MOZ_ASSERT(mOutputBuffer);
MOZ_ASSERT(mCurrentOutLine < mTargetSize.height, "Writing past end of output");
int diff = newFilterOffset - filterOffset;
MOZ_ASSERT(diff >= 0, "Moving backwards in the filter?");
// Shift the buffer. We're just moving pointers here, so this is cheap.
mLinesInBuffer -= diff;
mLinesInBuffer = std::clamp(mLinesInBuffer, 0, mWindowCapacity);
// If we already have enough rows to satisfy the filter, there is no need // to swap as we won't be writing more before the next convolution. if (filterLength > mLinesInBuffer) { for (int32_t i = 0; i < mLinesInBuffer; ++i) {
swap(mWindow[i], mWindow[filterLength - mLinesInBuffer + i]);
}
}
}
} // namespace image
} // namespace mozilla
¤ Dauer der Verarbeitung: 0.22 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.