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/AlreadyAddRefed.h"
12 #include "mozilla/ErrorResult.h"
13 #include "mozilla/dom/ImageBitmapBinding.h"
15 using namespace mozilla::layers
;
16 using namespace mozilla::gfx
;
18 namespace mozilla::dom
{
20 static ImageBitmapFormat
GetImageBitmapFormatFromSurfaceFromat(
21 SurfaceFormat aSurfaceFormat
) {
22 switch (aSurfaceFormat
) {
23 case SurfaceFormat::B8G8R8A8
:
24 case SurfaceFormat::B8G8R8X8
:
25 return ImageBitmapFormat::BGRA32
;
26 case SurfaceFormat::R8G8B8A8
:
27 case SurfaceFormat::R8G8B8X8
:
28 return ImageBitmapFormat::RGBA32
;
29 case SurfaceFormat::R8G8B8
:
30 return ImageBitmapFormat::RGB24
;
31 case SurfaceFormat::B8G8R8
:
32 return ImageBitmapFormat::BGR24
;
33 case SurfaceFormat::HSV
:
34 return ImageBitmapFormat::HSV
;
35 case SurfaceFormat::Lab
:
36 return ImageBitmapFormat::Lab
;
37 case SurfaceFormat::Depth
:
38 return ImageBitmapFormat::DEPTH
;
39 case SurfaceFormat::A8
:
40 return ImageBitmapFormat::GRAY8
;
41 case SurfaceFormat::R5G6B5_UINT16
:
42 case SurfaceFormat::YUV
:
43 case SurfaceFormat::NV12
:
44 case SurfaceFormat::P010
:
45 case SurfaceFormat::P016
:
46 case SurfaceFormat::UNKNOWN
:
48 return ImageBitmapFormat::EndGuard_
;
52 static ImageBitmapFormat
GetImageBitmapFormatFromPlanarYCbCrData(
53 layers::PlanarYCbCrData
const* aData
) {
56 media::Interval
<uintptr_t> YInterval(
57 uintptr_t(aData
->mYChannel
),
58 uintptr_t(aData
->mYChannel
) + aData
->mYSize
.height
* aData
->mYStride
),
59 CbInterval(uintptr_t(aData
->mCbChannel
),
60 uintptr_t(aData
->mCbChannel
) +
61 aData
->mCbCrSize
.height
* aData
->mCbCrStride
),
62 CrInterval(uintptr_t(aData
->mCrChannel
),
63 uintptr_t(aData
->mCrChannel
) +
64 aData
->mCbCrSize
.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 if (aData
->mYSize
.height
== aData
->mCbCrSize
.height
) {
70 if (aData
->mYSize
.width
== aData
->mCbCrSize
.width
) {
71 return ImageBitmapFormat::YUV444P
;
73 if (((aData
->mYSize
.width
+ 1) / 2) == aData
->mCbCrSize
.width
) {
74 return ImageBitmapFormat::YUV422P
;
76 } else if (((aData
->mYSize
.height
+ 1) / 2) == aData
->mCbCrSize
.height
) {
77 if (((aData
->mYSize
.width
+ 1) / 2) == aData
->mCbCrSize
.width
) {
78 return ImageBitmapFormat::YUV420P
;
82 } else if (aData
->mYSkip
== 0 && aData
->mCbSkip
== 1 &&
83 aData
->mCrSkip
== 1) { // Possibly two planes.
84 if (!YInterval
.Intersects(CbInterval
) &&
85 aData
->mCbChannel
== aData
->mCrChannel
- 1) { // Two planes.
86 if (((aData
->mYSize
.height
+ 1) / 2) == aData
->mCbCrSize
.height
&&
87 ((aData
->mYSize
.width
+ 1) / 2) == aData
->mCbCrSize
.width
) {
88 return ImageBitmapFormat::YUV420SP_NV12
; // Y-Cb-Cr
90 } else if (!YInterval
.Intersects(CrInterval
) &&
91 aData
->mCrChannel
== aData
->mCbChannel
- 1) { // Two planes.
92 if (((aData
->mYSize
.height
+ 1) / 2) == aData
->mCbCrSize
.height
&&
93 ((aData
->mYSize
.width
+ 1) / 2) == aData
->mCbCrSize
.width
) {
94 return ImageBitmapFormat::YUV420SP_NV21
; // Y-Cr-Cb
99 return ImageBitmapFormat::EndGuard_
;
102 // ImageUtils::Impl implements the _generic_ algorithm which always readback
103 // data in RGBA format into CPU memory.
104 // Since layers::CairoImage is just a warpper to a DataSourceSurface, the
105 // implementation of CairoSurfaceImpl is nothing different to the generic
107 class ImageUtils::Impl
{
109 explicit Impl(layers::Image
* aImage
) : mImage(aImage
), mSurface(nullptr) {}
111 virtual ~Impl() = default;
113 virtual ImageBitmapFormat
GetFormat() const {
114 return GetImageBitmapFormatFromSurfaceFromat(Surface()->GetFormat());
117 virtual uint32_t GetBufferLength() const {
118 DataSourceSurface::ScopedMap
map(Surface(), DataSourceSurface::READ
);
119 const uint32_t stride
= map
.GetStride();
120 const IntSize size
= Surface()->GetSize();
121 return (uint32_t)(size
.height
* stride
);
127 DataSourceSurface
* Surface() const {
129 RefPtr
<SourceSurface
> surface
= mImage
->GetAsSourceSurface();
132 mSurface
= surface
->GetDataSurface();
133 MOZ_ASSERT(mSurface
);
136 return mSurface
.get();
139 RefPtr
<layers::Image
> mImage
;
140 mutable RefPtr
<DataSourceSurface
> mSurface
;
143 // YUVImpl is optimized for the layers::PlanarYCbCrImage and layers::NVImage.
144 // This implementation does not readback data in RGBA format but keep it in YUV
146 class YUVImpl final
: public ImageUtils::Impl
{
148 explicit YUVImpl(layers::Image
* aImage
) : Impl(aImage
) {
149 MOZ_ASSERT(aImage
->GetFormat() == ImageFormat::PLANAR_YCBCR
||
150 aImage
->GetFormat() == ImageFormat::NV_IMAGE
);
153 ImageBitmapFormat
GetFormat() const override
{
154 return GetImageBitmapFormatFromPlanarYCbCrData(GetPlanarYCbCrData());
157 uint32_t GetBufferLength() const override
{
158 if (mImage
->GetFormat() == ImageFormat::PLANAR_YCBCR
) {
159 return mImage
->AsPlanarYCbCrImage()->GetDataSize();
161 return mImage
->AsNVImage()->GetBufferSize();
165 const PlanarYCbCrData
* GetPlanarYCbCrData() const {
166 if (mImage
->GetFormat() == ImageFormat::PLANAR_YCBCR
) {
167 return mImage
->AsPlanarYCbCrImage()->GetData();
169 return mImage
->AsNVImage()->GetData();
173 // TODO: optimize for other platforms.
174 // For Windows: implement D3D9RGB32TextureImpl and D3D11ShareHandleTextureImpl.
175 // Others: SharedBGRImpl, MACIOSrufaceImpl, GLImageImpl, SurfaceTextureImpl
176 // EGLImageImpl and OverlayImegImpl.
178 ImageUtils::ImageUtils(layers::Image
* aImage
) : mImpl(nullptr) {
179 MOZ_ASSERT(aImage
, "Create ImageUtils with nullptr.");
180 switch (aImage
->GetFormat()) {
181 case mozilla::ImageFormat::PLANAR_YCBCR
:
182 case mozilla::ImageFormat::NV_IMAGE
:
183 mImpl
= new YUVImpl(aImage
);
185 case mozilla::ImageFormat::CAIRO_SURFACE
:
187 mImpl
= new Impl(aImage
);
191 ImageUtils::~ImageUtils() {
198 ImageBitmapFormat
ImageUtils::GetFormat() const {
200 return mImpl
->GetFormat();
203 uint32_t ImageUtils::GetBufferLength() const {
205 return mImpl
->GetBufferLength();
208 } // namespace mozilla::dom