diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /dom/canvas/ImageUtils.cpp | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/canvas/ImageUtils.cpp')
-rw-r--r-- | dom/canvas/ImageUtils.cpp | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/dom/canvas/ImageUtils.cpp b/dom/canvas/ImageUtils.cpp new file mode 100644 index 0000000000..485b87c162 --- /dev/null +++ b/dom/canvas/ImageUtils.cpp @@ -0,0 +1,202 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* 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 "ImageUtils.h" + +#include "ImageContainer.h" +#include "Intervals.h" +#include "mozilla/dom/ImageBitmapBinding.h" + +using namespace mozilla::layers; +using namespace mozilla::gfx; + +namespace mozilla::dom { + +static ImageBitmapFormat GetImageBitmapFormatFromSurfaceFromat( + SurfaceFormat aSurfaceFormat) { + switch (aSurfaceFormat) { + case SurfaceFormat::B8G8R8A8: + case SurfaceFormat::B8G8R8X8: + return ImageBitmapFormat::BGRA32; + case SurfaceFormat::R8G8B8A8: + case SurfaceFormat::R8G8B8X8: + return ImageBitmapFormat::RGBA32; + case SurfaceFormat::R8G8B8: + return ImageBitmapFormat::RGB24; + case SurfaceFormat::B8G8R8: + return ImageBitmapFormat::BGR24; + case SurfaceFormat::HSV: + return ImageBitmapFormat::HSV; + case SurfaceFormat::Lab: + return ImageBitmapFormat::Lab; + case SurfaceFormat::Depth: + return ImageBitmapFormat::DEPTH; + case SurfaceFormat::A8: + return ImageBitmapFormat::GRAY8; + case SurfaceFormat::R5G6B5_UINT16: + case SurfaceFormat::YUV: + case SurfaceFormat::NV12: + case SurfaceFormat::P010: + case SurfaceFormat::P016: + case SurfaceFormat::UNKNOWN: + default: + return ImageBitmapFormat::EndGuard_; + } +} + +static ImageBitmapFormat GetImageBitmapFormatFromPlanarYCbCrData( + layers::PlanarYCbCrData const* aData) { + MOZ_ASSERT(aData); + + auto ySize = aData->YDataSize(); + auto cbcrSize = aData->CbCrDataSize(); + media::Interval<uintptr_t> YInterval( + uintptr_t(aData->mYChannel), + uintptr_t(aData->mYChannel) + ySize.height * aData->mYStride), + CbInterval( + uintptr_t(aData->mCbChannel), + uintptr_t(aData->mCbChannel) + cbcrSize.height * aData->mCbCrStride), + CrInterval( + uintptr_t(aData->mCrChannel), + uintptr_t(aData->mCrChannel) + cbcrSize.height * aData->mCbCrStride); + if (aData->mYSkip == 0 && aData->mCbSkip == 0 && + aData->mCrSkip == 0) { // Possibly three planes. + if (!YInterval.Intersects(CbInterval) && + !CbInterval.Intersects(CrInterval)) { // Three planes. + switch (aData->mChromaSubsampling) { + case ChromaSubsampling::FULL: + return ImageBitmapFormat::YUV444P; + case ChromaSubsampling::HALF_WIDTH: + return ImageBitmapFormat::YUV422P; + case ChromaSubsampling::HALF_WIDTH_AND_HEIGHT: + return ImageBitmapFormat::YUV420P; + default: + break; + } + } + } else if (aData->mYSkip == 0 && aData->mCbSkip == 1 && aData->mCrSkip == 1 && + aData->mChromaSubsampling == + ChromaSubsampling::HALF_WIDTH_AND_HEIGHT) { // Possibly two + // planes. + if (!YInterval.Intersects(CbInterval) && + aData->mCbChannel == aData->mCrChannel - 1) { // Two planes. + return ImageBitmapFormat::YUV420SP_NV12; // Y-Cb-Cr + } else if (!YInterval.Intersects(CrInterval) && + aData->mCrChannel == aData->mCbChannel - 1) { // Two planes. + return ImageBitmapFormat::YUV420SP_NV21; // Y-Cr-Cb + } + } + + return ImageBitmapFormat::EndGuard_; +} + +// ImageUtils::Impl implements the _generic_ algorithm which always readback +// data in RGBA format into CPU memory. +// Since layers::CairoImage is just a warpper to a DataSourceSurface, the +// implementation of CairoSurfaceImpl is nothing different to the generic +// version. +class ImageUtils::Impl { + public: + explicit Impl(layers::Image* aImage) : mImage(aImage), mSurface(nullptr) {} + + virtual ~Impl() = default; + + virtual ImageBitmapFormat GetFormat() const { + return GetImageBitmapFormatFromSurfaceFromat(Surface()->GetFormat()); + } + + virtual uint32_t GetBufferLength() const { + DataSourceSurface::ScopedMap map(Surface(), DataSourceSurface::READ); + const uint32_t stride = map.GetStride(); + const IntSize size = Surface()->GetSize(); + return (uint32_t)(size.height * stride); + } + + protected: + Impl() = default; + + DataSourceSurface* Surface() const { + if (!mSurface) { + RefPtr<SourceSurface> surface = mImage->GetAsSourceSurface(); + MOZ_ASSERT(surface); + + mSurface = surface->GetDataSurface(); + MOZ_ASSERT(mSurface); + } + + return mSurface.get(); + } + + RefPtr<layers::Image> mImage; + mutable RefPtr<DataSourceSurface> mSurface; +}; + +// YUVImpl is optimized for the layers::PlanarYCbCrImage and layers::NVImage. +// This implementation does not readback data in RGBA format but keep it in YUV +// format family. +class YUVImpl final : public ImageUtils::Impl { + public: + explicit YUVImpl(layers::Image* aImage) : Impl(aImage) { + MOZ_ASSERT(aImage->GetFormat() == ImageFormat::PLANAR_YCBCR || + aImage->GetFormat() == ImageFormat::NV_IMAGE); + } + + ImageBitmapFormat GetFormat() const override { + return GetImageBitmapFormatFromPlanarYCbCrData(GetPlanarYCbCrData()); + } + + uint32_t GetBufferLength() const override { + if (mImage->GetFormat() == ImageFormat::PLANAR_YCBCR) { + return mImage->AsPlanarYCbCrImage()->GetDataSize(); + } + return mImage->AsNVImage()->GetBufferSize(); + } + + private: + const PlanarYCbCrData* GetPlanarYCbCrData() const { + if (mImage->GetFormat() == ImageFormat::PLANAR_YCBCR) { + return mImage->AsPlanarYCbCrImage()->GetData(); + } + return mImage->AsNVImage()->GetData(); + } +}; + +// TODO: optimize for other platforms. +// For Windows: implement D3D9RGB32TextureImpl and D3D11ShareHandleTextureImpl. +// Others: SharedBGRImpl, MACIOSrufaceImpl, GLImageImpl, SurfaceTextureImpl +// EGLImageImpl and OverlayImegImpl. + +ImageUtils::ImageUtils(layers::Image* aImage) : mImpl(nullptr) { + MOZ_ASSERT(aImage, "Create ImageUtils with nullptr."); + switch (aImage->GetFormat()) { + case mozilla::ImageFormat::PLANAR_YCBCR: + case mozilla::ImageFormat::NV_IMAGE: + mImpl = new YUVImpl(aImage); + break; + case mozilla::ImageFormat::MOZ2D_SURFACE: + default: + mImpl = new Impl(aImage); + } +} + +ImageUtils::~ImageUtils() { + if (mImpl) { + delete mImpl; + mImpl = nullptr; + } +} + +ImageBitmapFormat ImageUtils::GetFormat() const { + MOZ_ASSERT(mImpl); + return mImpl->GetFormat(); +} + +uint32_t ImageUtils::GetBufferLength() const { + MOZ_ASSERT(mImpl); + return mImpl->GetBufferLength(); +} + +} // namespace mozilla::dom |