Bug 1892041 - Part 1: Update test262 features. r=spidermonkey-reviewers,dminor
[gecko.git] / dom / canvas / ImageUtils.cpp
blob432fa3355e8c0208a2242e436a61aa45c03996de
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
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 "ImageUtils.h"
9 #include "ImageContainer.h"
10 #include "Intervals.h"
11 #include "mozilla/dom/ImageBitmapBinding.h"
13 using namespace mozilla::layers;
14 using namespace mozilla::gfx;
16 namespace mozilla::dom {
18 static Maybe<ImageBitmapFormat> GetImageBitmapFormatFromSurfaceFromat(
19 SurfaceFormat aSurfaceFormat) {
20 switch (aSurfaceFormat) {
21 case SurfaceFormat::B8G8R8A8:
22 case SurfaceFormat::B8G8R8X8:
23 return Some(ImageBitmapFormat::BGRA32);
24 case SurfaceFormat::R8G8B8A8:
25 case SurfaceFormat::R8G8B8X8:
26 return Some(ImageBitmapFormat::RGBA32);
27 case SurfaceFormat::R8G8B8:
28 return Some(ImageBitmapFormat::RGB24);
29 case SurfaceFormat::B8G8R8:
30 return Some(ImageBitmapFormat::BGR24);
31 case SurfaceFormat::HSV:
32 return Some(ImageBitmapFormat::HSV);
33 case SurfaceFormat::Lab:
34 return Some(ImageBitmapFormat::Lab);
35 case SurfaceFormat::Depth:
36 return Some(ImageBitmapFormat::DEPTH);
37 case SurfaceFormat::A8:
38 return Some(ImageBitmapFormat::GRAY8);
39 case SurfaceFormat::R5G6B5_UINT16:
40 case SurfaceFormat::YUV:
41 case SurfaceFormat::NV12:
42 case SurfaceFormat::P010:
43 case SurfaceFormat::P016:
44 case SurfaceFormat::UNKNOWN:
45 default:
46 return Nothing();
50 static Maybe<ImageBitmapFormat> GetImageBitmapFormatFromPlanarYCbCrData(
51 layers::PlanarYCbCrData const* aData) {
52 MOZ_ASSERT(aData);
54 auto ySize = aData->YDataSize();
55 auto cbcrSize = aData->CbCrDataSize();
56 media::Interval<uintptr_t> YInterval(
57 uintptr_t(aData->mYChannel),
58 uintptr_t(aData->mYChannel) + ySize.height * aData->mYStride),
59 CbInterval(
60 uintptr_t(aData->mCbChannel),
61 uintptr_t(aData->mCbChannel) + cbcrSize.height * aData->mCbCrStride),
62 CrInterval(
63 uintptr_t(aData->mCrChannel),
64 uintptr_t(aData->mCrChannel) + cbcrSize.height * aData->mCbCrStride);
65 if (aData->mYSkip == 0 && aData->mCbSkip == 0 &&
66 aData->mCrSkip == 0) { // Possibly three planes.
67 if (!YInterval.Intersects(CbInterval) &&
68 !CbInterval.Intersects(CrInterval)) { // Three planes.
69 switch (aData->mChromaSubsampling) {
70 case ChromaSubsampling::FULL:
71 return Some(ImageBitmapFormat::YUV444P);
72 case ChromaSubsampling::HALF_WIDTH:
73 return Some(ImageBitmapFormat::YUV422P);
74 case ChromaSubsampling::HALF_WIDTH_AND_HEIGHT:
75 return Some(ImageBitmapFormat::YUV420P);
76 default:
77 break;
80 } else if (aData->mYSkip == 0 && aData->mCbSkip == 1 && aData->mCrSkip == 1 &&
81 aData->mChromaSubsampling ==
82 ChromaSubsampling::HALF_WIDTH_AND_HEIGHT) { // Possibly two
83 // planes.
84 if (!YInterval.Intersects(CbInterval) &&
85 aData->mCbChannel == aData->mCrChannel - 1) { // Two planes.
86 return Some(ImageBitmapFormat::YUV420SP_NV12); // Y-Cb-Cr
87 } else if (!YInterval.Intersects(CrInterval) &&
88 aData->mCrChannel == aData->mCbChannel - 1) { // Two planes.
89 return Some(ImageBitmapFormat::YUV420SP_NV21); // Y-Cr-Cb
93 return Nothing();
96 // ImageUtils::Impl implements the _generic_ algorithm which always readback
97 // data in RGBA format into CPU memory.
98 // Since layers::CairoImage is just a warpper to a DataSourceSurface, the
99 // implementation of CairoSurfaceImpl is nothing different to the generic
100 // version.
101 class ImageUtils::Impl {
102 public:
103 explicit Impl(layers::Image* aImage) : mImage(aImage), mSurface(nullptr) {}
105 virtual ~Impl() = default;
107 virtual Maybe<ImageBitmapFormat> GetFormat() const {
108 return GetImageBitmapFormatFromSurfaceFromat(Surface()->GetFormat());
111 virtual uint32_t GetBufferLength() const {
112 DataSourceSurface::ScopedMap map(Surface(), DataSourceSurface::READ);
113 const uint32_t stride = map.GetStride();
114 const IntSize size = Surface()->GetSize();
115 return (uint32_t)(size.height * stride);
118 protected:
119 Impl() = default;
121 DataSourceSurface* Surface() const {
122 if (!mSurface) {
123 RefPtr<SourceSurface> surface = mImage->GetAsSourceSurface();
124 MOZ_ASSERT(surface);
126 mSurface = surface->GetDataSurface();
127 MOZ_ASSERT(mSurface);
130 return mSurface.get();
133 RefPtr<layers::Image> mImage;
134 mutable RefPtr<DataSourceSurface> mSurface;
137 // YUVImpl is optimized for the layers::PlanarYCbCrImage and layers::NVImage.
138 // This implementation does not readback data in RGBA format but keep it in YUV
139 // format family.
140 class YUVImpl final : public ImageUtils::Impl {
141 public:
142 explicit YUVImpl(layers::Image* aImage) : Impl(aImage) {
143 MOZ_ASSERT(aImage->GetFormat() == ImageFormat::PLANAR_YCBCR ||
144 aImage->GetFormat() == ImageFormat::NV_IMAGE);
147 Maybe<ImageBitmapFormat> GetFormat() const override {
148 return GetImageBitmapFormatFromPlanarYCbCrData(GetPlanarYCbCrData());
151 uint32_t GetBufferLength() const override {
152 if (mImage->GetFormat() == ImageFormat::PLANAR_YCBCR) {
153 return mImage->AsPlanarYCbCrImage()->GetDataSize();
155 return mImage->AsNVImage()->GetBufferSize();
158 private:
159 const PlanarYCbCrData* GetPlanarYCbCrData() const {
160 if (mImage->GetFormat() == ImageFormat::PLANAR_YCBCR) {
161 return mImage->AsPlanarYCbCrImage()->GetData();
163 return mImage->AsNVImage()->GetData();
167 // TODO: optimize for other platforms.
168 // For Windows: implement D3D9RGB32TextureImpl and D3D11ShareHandleTextureImpl.
169 // Others: SharedBGRImpl, MACIOSrufaceImpl, GLImageImpl, SurfaceTextureImpl
170 // EGLImageImpl and OverlayImegImpl.
172 ImageUtils::ImageUtils(layers::Image* aImage) : mImpl(nullptr) {
173 MOZ_ASSERT(aImage, "Create ImageUtils with nullptr.");
174 switch (aImage->GetFormat()) {
175 case mozilla::ImageFormat::PLANAR_YCBCR:
176 case mozilla::ImageFormat::NV_IMAGE:
177 mImpl = new YUVImpl(aImage);
178 break;
179 case mozilla::ImageFormat::MOZ2D_SURFACE:
180 default:
181 mImpl = new Impl(aImage);
185 ImageUtils::~ImageUtils() {
186 if (mImpl) {
187 delete mImpl;
188 mImpl = nullptr;
192 Maybe<ImageBitmapFormat> ImageUtils::GetFormat() const {
193 MOZ_ASSERT(mImpl);
194 return mImpl->GetFormat();
197 uint32_t ImageUtils::GetBufferLength() const {
198 MOZ_ASSERT(mImpl);
199 return mImpl->GetBufferLength();
202 } // namespace mozilla::dom