Bug 1936278 - Prevent search mode chiclet from being dismissed when clicking in page...
[gecko.git] / dom / canvas / ImageUtils.cpp
blob7808b209a90bcc946ea95e7f6a6e48f5f9d2ddfd
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 "mozilla/dom/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::YUV420:
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 if (DataSourceSurface* surface = Surface()) {
109 return GetImageBitmapFormatFromSurfaceFromat(surface->GetFormat());
111 return Nothing();
114 virtual uint32_t GetBufferLength() const {
115 if (DataSourceSurface* surface = Surface()) {
116 DataSourceSurface::ScopedMap map(surface, DataSourceSurface::READ);
117 const uint32_t stride = map.GetStride();
118 const IntSize size = surface->GetSize();
119 return (uint32_t)(size.height * stride);
121 return 0;
124 protected:
125 Impl() = default;
127 DataSourceSurface* Surface() const {
128 if (mSurface) {
129 return mSurface.get();
132 RefPtr<SourceSurface> surface = mImage->GetAsSourceSurface();
133 if (NS_WARN_IF(!surface)) {
134 return nullptr;
137 mSurface = surface->GetDataSurface();
138 MOZ_ASSERT(mSurface);
139 return mSurface.get();
142 RefPtr<layers::Image> mImage;
143 mutable RefPtr<DataSourceSurface> mSurface;
146 // YUVImpl is optimized for the layers::PlanarYCbCrImage and layers::NVImage.
147 // This implementation does not readback data in RGBA format but keep it in YUV
148 // format family.
149 class YUVImpl final : public ImageUtils::Impl {
150 public:
151 explicit YUVImpl(layers::Image* aImage) : Impl(aImage) {
152 MOZ_ASSERT(aImage->GetFormat() == ImageFormat::PLANAR_YCBCR ||
153 aImage->GetFormat() == ImageFormat::NV_IMAGE);
156 Maybe<ImageBitmapFormat> GetFormat() const override {
157 return GetImageBitmapFormatFromPlanarYCbCrData(GetPlanarYCbCrData());
160 uint32_t GetBufferLength() const override {
161 if (mImage->GetFormat() == ImageFormat::PLANAR_YCBCR) {
162 return mImage->AsPlanarYCbCrImage()->GetDataSize();
164 return mImage->AsNVImage()->GetBufferSize();
167 private:
168 const PlanarYCbCrData* GetPlanarYCbCrData() const {
169 if (mImage->GetFormat() == ImageFormat::PLANAR_YCBCR) {
170 return mImage->AsPlanarYCbCrImage()->GetData();
172 return mImage->AsNVImage()->GetData();
176 // TODO: optimize for other platforms.
177 // For Windows: implement D3D9RGB32TextureImpl and D3D11ShareHandleTextureImpl.
178 // Others: SharedBGRImpl, MACIOSrufaceImpl, GLImageImpl, SurfaceTextureImpl
179 // EGLImageImpl and OverlayImegImpl.
181 ImageUtils::ImageUtils(layers::Image* aImage) : mImpl(nullptr) {
182 MOZ_ASSERT(aImage, "Create ImageUtils with nullptr.");
183 switch (aImage->GetFormat()) {
184 case mozilla::ImageFormat::PLANAR_YCBCR:
185 case mozilla::ImageFormat::NV_IMAGE:
186 mImpl = new YUVImpl(aImage);
187 break;
188 case mozilla::ImageFormat::MOZ2D_SURFACE:
189 default:
190 mImpl = new Impl(aImage);
194 ImageUtils::~ImageUtils() {
195 if (mImpl) {
196 delete mImpl;
197 mImpl = nullptr;
201 Maybe<ImageBitmapFormat> ImageUtils::GetFormat() const {
202 MOZ_ASSERT(mImpl);
203 return mImpl->GetFormat();
206 uint32_t ImageUtils::GetBufferLength() const {
207 MOZ_ASSERT(mImpl);
208 return mImpl->GetBufferLength();
211 } // namespace mozilla::dom