From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- image/ImageOps.cpp | 248 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 248 insertions(+) create mode 100644 image/ImageOps.cpp (limited to 'image/ImageOps.cpp') diff --git a/image/ImageOps.cpp b/image/ImageOps.cpp new file mode 100644 index 0000000000..875dc7b985 --- /dev/null +++ b/image/ImageOps.cpp @@ -0,0 +1,248 @@ +/* -*- 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/. */ + +#include "ImageOps.h" + +#include "ClippedImage.h" +#include "Decoder.h" +#include "DecoderFactory.h" +#include "DynamicImage.h" +#include "FrozenImage.h" +#include "IDecodingTask.h" +#include "Image.h" +#include "ImageMetadata.h" +#include "imgIContainer.h" +#include "mozilla/gfx/2D.h" +#include "nsNetUtil.h" // for NS_NewBufferedInputStream +#include "nsStreamUtils.h" +#include "OrientedImage.h" +#include "SourceBuffer.h" + +using namespace mozilla::gfx; + +namespace mozilla::image { + +/* static */ +already_AddRefed ImageOps::Freeze(Image* aImage) { + RefPtr frozenImage = new FrozenImage(aImage); + return frozenImage.forget(); +} + +/* static */ +already_AddRefed ImageOps::Freeze(imgIContainer* aImage) { + nsCOMPtr frozenImage = + new FrozenImage(static_cast(aImage)); + return frozenImage.forget(); +} + +/* static */ +already_AddRefed ImageOps::Clip(Image* aImage, nsIntRect aClip, + const Maybe& aSVGViewportSize) { + RefPtr clippedImage = + new ClippedImage(aImage, aClip, aSVGViewportSize); + return clippedImage.forget(); +} + +/* static */ +already_AddRefed ImageOps::Clip( + imgIContainer* aImage, nsIntRect aClip, + const Maybe& aSVGViewportSize) { + nsCOMPtr clippedImage = + new ClippedImage(static_cast(aImage), aClip, aSVGViewportSize); + return clippedImage.forget(); +} + +/* static */ +already_AddRefed ImageOps::Orient(Image* aImage, + Orientation aOrientation) { + if (aOrientation.IsIdentity()) { + return do_AddRef(aImage); + } + RefPtr image = new OrientedImage(aImage, aOrientation); + return image.forget(); +} + +/* static */ +already_AddRefed ImageOps::Orient(imgIContainer* aImage, + Orientation aOrientation) { + return Orient(static_cast(aImage), aOrientation); +} + +/* static */ +already_AddRefed ImageOps::Unorient(imgIContainer* aImage) { + return Orient(aImage, aImage->GetOrientation().Reversed()); +} + +/* static */ +already_AddRefed ImageOps::CreateFromDrawable( + gfxDrawable* aDrawable) { + nsCOMPtr drawableImage = new DynamicImage(aDrawable); + return drawableImage.forget(); +} + +class ImageOps::ImageBufferImpl final : public ImageOps::ImageBuffer { + public: + explicit ImageBufferImpl(already_AddRefed aSourceBuffer) + : mSourceBuffer(aSourceBuffer) {} + + protected: + ~ImageBufferImpl() override {} + + already_AddRefed GetSourceBuffer() const override { + RefPtr sourceBuffer = mSourceBuffer; + return sourceBuffer.forget(); + } + + private: + RefPtr mSourceBuffer; +}; + +/* static */ already_AddRefed +ImageOps::CreateImageBuffer(already_AddRefed aInputStream) { + nsCOMPtr inputStream = std::move(aInputStream); + MOZ_ASSERT(inputStream); + + nsresult rv; + + // Prepare the input stream. + if (!NS_InputStreamIsBuffered(inputStream)) { + nsCOMPtr bufStream; + rv = NS_NewBufferedInputStream(getter_AddRefs(bufStream), + inputStream.forget(), 1024); + if (NS_WARN_IF(NS_FAILED(rv))) { + return nullptr; + } + inputStream = std::move(bufStream); + } + + // Figure out how much data we've been passed. + uint64_t length; + rv = inputStream->Available(&length); + if (NS_FAILED(rv) || length > UINT32_MAX) { + return nullptr; + } + + // Write the data into a SourceBuffer. + RefPtr sourceBuffer = new SourceBuffer(); + sourceBuffer->ExpectLength(length); + rv = sourceBuffer->AppendFromInputStream(inputStream, length); + if (NS_FAILED(rv)) { + return nullptr; + } + // Make sure our sourceBuffer is marked as complete. + if (sourceBuffer->IsComplete()) { + NS_WARNING( + "The SourceBuffer was unexpectedly marked as complete. This may " + "indicate either an OOM condition, or that imagelib was not " + "initialized properly."); + return nullptr; + } + sourceBuffer->Complete(NS_OK); + + RefPtr imageBuffer = new ImageBufferImpl(sourceBuffer.forget()); + return imageBuffer.forget(); +} + +/* static */ +nsresult ImageOps::DecodeMetadata(already_AddRefed aInputStream, + const nsACString& aMimeType, + ImageMetadata& aMetadata) { + nsCOMPtr inputStream = std::move(aInputStream); + RefPtr buffer = CreateImageBuffer(inputStream.forget()); + return DecodeMetadata(buffer, aMimeType, aMetadata); +} + +/* static */ +nsresult ImageOps::DecodeMetadata(ImageBuffer* aBuffer, + const nsACString& aMimeType, + ImageMetadata& aMetadata) { + if (!aBuffer) { + return NS_ERROR_FAILURE; + } + + RefPtr sourceBuffer = aBuffer->GetSourceBuffer(); + if (NS_WARN_IF(!sourceBuffer)) { + return NS_ERROR_FAILURE; + } + + // Create a decoder. + DecoderType decoderType = + DecoderFactory::GetDecoderType(PromiseFlatCString(aMimeType).get()); + RefPtr decoder = DecoderFactory::CreateAnonymousMetadataDecoder( + decoderType, WrapNotNull(sourceBuffer)); + if (!decoder) { + return NS_ERROR_FAILURE; + } + + // Run the decoder synchronously. + RefPtr task = + new AnonymousDecodingTask(WrapNotNull(decoder), /* aResumable */ false); + task->Run(); + if (!decoder->GetDecodeDone() || decoder->HasError()) { + return NS_ERROR_FAILURE; + } + + aMetadata = decoder->GetImageMetadata(); + if (aMetadata.GetNativeSizes().IsEmpty() && aMetadata.HasSize()) { + aMetadata.AddNativeSize(aMetadata.GetSize()); + } + + return NS_OK; +} + +/* static */ already_AddRefed ImageOps::DecodeToSurface( + already_AddRefed aInputStream, const nsACString& aMimeType, + uint32_t aFlags, const Maybe& aSize /* = Nothing() */) { + nsCOMPtr inputStream = std::move(aInputStream); + RefPtr buffer = CreateImageBuffer(inputStream.forget()); + return DecodeToSurface(buffer, aMimeType, aFlags, aSize); +} + +/* static */ already_AddRefed ImageOps::DecodeToSurface( + ImageBuffer* aBuffer, const nsACString& aMimeType, uint32_t aFlags, + const Maybe& aSize /* = Nothing() */) { + if (!aBuffer) { + return nullptr; + } + + RefPtr sourceBuffer = aBuffer->GetSourceBuffer(); + if (NS_WARN_IF(!sourceBuffer)) { + return nullptr; + } + + // Create a decoder. + DecoderType decoderType = + DecoderFactory::GetDecoderType(PromiseFlatCString(aMimeType).get()); + RefPtr decoder = DecoderFactory::CreateAnonymousDecoder( + decoderType, WrapNotNull(sourceBuffer), aSize, + DecoderFlags::FIRST_FRAME_ONLY, ToSurfaceFlags(aFlags)); + if (!decoder) { + return nullptr; + } + + // Run the decoder synchronously. + RefPtr task = + new AnonymousDecodingTask(WrapNotNull(decoder), /* aResumable */ false); + task->Run(); + if (!decoder->GetDecodeDone() || decoder->HasError()) { + return nullptr; + } + + // Pull out the surface. + RawAccessFrameRef frame = decoder->GetCurrentFrameRef(); + if (!frame) { + return nullptr; + } + + RefPtr surface = frame->GetSourceSurface(); + if (!surface) { + return nullptr; + } + + return surface.forget(); +} + +} // namespace mozilla::image -- cgit v1.2.3