Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/canvas/ImageUtils.cpp
Line
Count
Source (jump to first uncovered line)
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/. */
6
7
#include "ImageUtils.h"
8
#include "ImageBitmapUtils.h"
9
#include "ImageContainer.h"
10
#include "mozilla/AlreadyAddRefed.h"
11
#include "mozilla/dom/ImageBitmapBinding.h"
12
#include "mozilla/ErrorResult.h"
13
14
using namespace mozilla::layers;
15
using namespace mozilla::gfx;
16
17
namespace mozilla {
18
namespace dom {
19
20
static ImageBitmapFormat
21
GetImageBitmapFormatFromSurfaceFromat(SurfaceFormat aSurfaceFormat)
22
{
23
  switch (aSurfaceFormat) {
24
  case SurfaceFormat::B8G8R8A8:
25
  case SurfaceFormat::B8G8R8X8:
26
    return ImageBitmapFormat::BGRA32;
27
  case SurfaceFormat::R8G8B8A8:
28
  case SurfaceFormat::R8G8B8X8:
29
    return ImageBitmapFormat::RGBA32;
30
  case SurfaceFormat::R8G8B8:
31
    return ImageBitmapFormat::RGB24;
32
  case SurfaceFormat::B8G8R8:
33
    return ImageBitmapFormat::BGR24;
34
  case SurfaceFormat::HSV:
35
    return ImageBitmapFormat::HSV;
36
  case SurfaceFormat::Lab:
37
    return ImageBitmapFormat::Lab;
38
  case SurfaceFormat::Depth:
39
    return ImageBitmapFormat::DEPTH;
40
  case SurfaceFormat::A8:
41
    return ImageBitmapFormat::GRAY8;
42
  case SurfaceFormat::R5G6B5_UINT16:
43
  case SurfaceFormat::YUV:
44
  case SurfaceFormat::NV12:
45
  case SurfaceFormat::UNKNOWN:
46
  default:
47
    return ImageBitmapFormat::EndGuard_;
48
  }
49
}
50
51
static ImageBitmapFormat
52
GetImageBitmapFormatFromPlanarYCbCrData(layers::PlanarYCbCrData const *aData)
53
0
{
54
0
  MOZ_ASSERT(aData);
55
0
56
0
  if (aData->mYSkip == 0 && aData->mCbSkip == 0 &&
57
0
      aData->mCrSkip == 0) { // Possibly three planes.
58
0
    if (aData->mCbChannel >=
59
0
          aData->mYChannel + aData->mYSize.height * aData->mYStride &&
60
0
        aData->mCrChannel >=
61
0
          aData->mCbChannel +
62
0
            aData->mCbCrSize.height * aData->mCbCrStride) { // Three planes.
63
0
      if (aData->mYSize.height == aData->mCbCrSize.height) {
64
0
        if (aData->mYSize.width == aData->mCbCrSize.width) {
65
0
          return ImageBitmapFormat::YUV444P;
66
0
        }
67
0
        if (((aData->mYSize.width + 1) / 2) == aData->mCbCrSize.width) {
68
0
          return ImageBitmapFormat::YUV422P;
69
0
        }
70
0
      } else if (((aData->mYSize.height + 1) / 2) == aData->mCbCrSize.height) {
71
0
        if (((aData->mYSize.width + 1) / 2) == aData->mCbCrSize.width) {
72
0
          return ImageBitmapFormat::YUV420P;
73
0
        }
74
0
      }
75
0
    }
76
0
  } else if (aData->mYSkip == 0 && aData->mCbSkip == 1 && aData->mCrSkip == 1) { // Possibly two planes.
77
0
    if (aData->mCbChannel >= aData->mYChannel + aData->mYSize.height * aData->mYStride &&
78
0
        aData->mCbChannel == aData->mCrChannel - 1) { // Two planes.
79
0
      if (((aData->mYSize.height + 1) / 2) == aData->mCbCrSize.height &&
80
0
          ((aData->mYSize.width + 1) / 2) == aData->mCbCrSize.width) {
81
0
        return ImageBitmapFormat::YUV420SP_NV12;  // Y-Cb-Cr
82
0
      }
83
0
    } else if (aData->mCrChannel >= aData->mYChannel + aData->mYSize.height * aData->mYStride &&
84
0
               aData->mCrChannel == aData->mCbChannel - 1) { // Two planes.
85
0
      if (((aData->mYSize.height + 1) / 2) == aData->mCbCrSize.height &&
86
0
          ((aData->mYSize.width + 1) / 2) == aData->mCbCrSize.width) {
87
0
        return ImageBitmapFormat::YUV420SP_NV21;  // Y-Cr-Cb
88
0
      }
89
0
    }
90
0
  }
91
0
92
0
  return ImageBitmapFormat::EndGuard_;
93
0
}
94
95
// ImageUtils::Impl implements the _generic_ algorithm which always readback
96
// data in RGBA format into CPU memory.
97
// Since layers::CairoImage is just a warpper to a DataSourceSurface, the
98
// implementation of CairoSurfaceImpl is nothing different to the generic
99
// version.
100
class ImageUtils::Impl
101
{
102
public:
103
  explicit Impl(layers::Image* aImage)
104
  : mImage(aImage)
105
  , mSurface(nullptr)
106
0
  {
107
0
  }
108
109
0
  virtual ~Impl() = default;
110
111
  virtual ImageBitmapFormat
112
  GetFormat() const
113
0
  {
114
0
    return GetImageBitmapFormatFromSurfaceFromat(Surface()->GetFormat());
115
0
  }
116
117
  virtual uint32_t
118
  GetBufferLength() const
119
0
  {
120
0
    DataSourceSurface::ScopedMap map(Surface(), DataSourceSurface::READ);
121
0
    const uint32_t stride = map.GetStride();
122
0
    const IntSize size = Surface()->GetSize();
123
0
    return (uint32_t)(size.height * stride);
124
0
  }
125
126
  virtual UniquePtr<ImagePixelLayout>
127
  MapDataInto(uint8_t* aBuffer,
128
              uint32_t aOffset,
129
              uint32_t aBufferLength,
130
              ImageBitmapFormat aFormat,
131
              ErrorResult& aRv) const
132
0
  {
133
0
    DataSourceSurface::ScopedMap map(Surface(), DataSourceSurface::READ);
134
0
    if (!map.IsMapped()) {
135
0
      aRv.Throw(NS_ERROR_ILLEGAL_VALUE);
136
0
      return nullptr;
137
0
    }
138
0
139
0
    // Copy or convert data.
140
0
    UniquePtr<ImagePixelLayout> srcLayout =
141
0
      CreateDefaultPixelLayout(GetFormat(), Surface()->GetSize().width,
142
0
                               Surface()->GetSize().height, map.GetStride());
143
0
144
0
    // Prepare destination buffer.
145
0
    uint8_t* dstBuffer = aBuffer + aOffset;
146
0
    UniquePtr<ImagePixelLayout> dstLayout =
147
0
      CopyAndConvertImageData(GetFormat(), map.GetData(), srcLayout.get(),
148
0
                              aFormat, dstBuffer);
149
0
150
0
    if (!dstLayout) {
151
0
      aRv.Throw(NS_ERROR_NOT_AVAILABLE);
152
0
      return nullptr;
153
0
    }
154
0
155
0
    return dstLayout;
156
0
  }
157
158
protected:
159
0
  Impl() {}
160
161
  DataSourceSurface* Surface() const
162
0
  {
163
0
    if (!mSurface) {
164
0
      RefPtr<SourceSurface> surface = mImage->GetAsSourceSurface();
165
0
      MOZ_ASSERT(surface);
166
0
167
0
      mSurface = surface->GetDataSurface();
168
0
      MOZ_ASSERT(mSurface);
169
0
    }
170
0
171
0
    return mSurface.get();
172
0
  }
173
174
  RefPtr<layers::Image> mImage;
175
  mutable RefPtr<DataSourceSurface> mSurface;
176
};
177
178
// YUVImpl is optimized for the layers::PlanarYCbCrImage and layers::NVImage.
179
// This implementation does not readback data in RGBA format but keep it in YUV
180
// format family.
181
class YUVImpl final : public ImageUtils::Impl
182
{
183
public:
184
  explicit YUVImpl(layers::Image* aImage)
185
  : Impl(aImage)
186
0
  {
187
0
    MOZ_ASSERT(aImage->GetFormat() == ImageFormat::PLANAR_YCBCR ||
188
0
               aImage->GetFormat() == ImageFormat::NV_IMAGE);
189
0
  }
190
191
  ImageBitmapFormat GetFormat() const override
192
0
  {
193
0
    return GetImageBitmapFormatFromPlanarYCbCrData(GetPlanarYCbCrData());
194
0
  }
195
196
  uint32_t GetBufferLength() const override
197
0
  {
198
0
    if (mImage->GetFormat() == ImageFormat::PLANAR_YCBCR) {
199
0
      return mImage->AsPlanarYCbCrImage()->GetDataSize();
200
0
    }
201
0
    return mImage->AsNVImage()->GetBufferSize();
202
0
  }
203
204
  UniquePtr<ImagePixelLayout> MapDataInto(uint8_t* aBuffer,
205
                                          uint32_t aOffset,
206
                                          uint32_t aBufferLength,
207
                                          ImageBitmapFormat aFormat,
208
                                          ErrorResult& aRv) const override
209
0
  {
210
0
    // Prepare source buffer and pixel layout.
211
0
    const PlanarYCbCrData* data = GetPlanarYCbCrData();
212
0
213
0
    UniquePtr<ImagePixelLayout> srcLayout =
214
0
      CreatePixelLayoutFromPlanarYCbCrData(data);
215
0
216
0
    // Do conversion.
217
0
    UniquePtr<ImagePixelLayout> dstLayout =
218
0
      CopyAndConvertImageData(GetFormat(), data->mYChannel, srcLayout.get(),
219
0
                              aFormat, aBuffer+aOffset);
220
0
221
0
    if (!dstLayout) {
222
0
      aRv.Throw(NS_ERROR_NOT_AVAILABLE);
223
0
      return nullptr;
224
0
    }
225
0
226
0
    return dstLayout;
227
0
  }
228
229
private:
230
  const PlanarYCbCrData* GetPlanarYCbCrData() const
231
0
  {
232
0
    if (mImage->GetFormat() == ImageFormat::PLANAR_YCBCR) {
233
0
      return mImage->AsPlanarYCbCrImage()->GetData();
234
0
    }
235
0
    return mImage->AsNVImage()->GetData();
236
0
  }
237
};
238
239
// TODO: optimize for other platforms.
240
// For Windows: implement D3D9RGB32TextureImpl and D3D11ShareHandleTextureImpl.
241
// Others: SharedBGRImpl, MACIOSrufaceImpl, GLImageImpl, SurfaceTextureImpl
242
//         EGLImageImpl and OverlayImegImpl.
243
244
ImageUtils::ImageUtils(layers::Image* aImage)
245
: mImpl(nullptr)
246
0
{
247
0
  MOZ_ASSERT(aImage, "Create ImageUtils with nullptr.");
248
0
  switch(aImage->GetFormat()) {
249
0
  case mozilla::ImageFormat::PLANAR_YCBCR:
250
0
  case mozilla::ImageFormat::NV_IMAGE:
251
0
    mImpl = new YUVImpl(aImage);
252
0
    break;
253
0
  case mozilla::ImageFormat::CAIRO_SURFACE:
254
0
  default:
255
0
    mImpl = new Impl(aImage);
256
0
  }
257
0
}
258
259
ImageUtils::~ImageUtils()
260
0
{
261
0
  if (mImpl) { delete mImpl; mImpl = nullptr; }
262
0
}
263
264
ImageBitmapFormat
265
ImageUtils::GetFormat() const
266
0
{
267
0
  MOZ_ASSERT(mImpl);
268
0
  return mImpl->GetFormat();
269
0
}
270
271
uint32_t
272
ImageUtils::GetBufferLength() const
273
0
{
274
0
  MOZ_ASSERT(mImpl);
275
0
  return mImpl->GetBufferLength();
276
0
}
277
278
UniquePtr<ImagePixelLayout>
279
ImageUtils::MapDataInto(uint8_t* aBuffer,
280
                        uint32_t aOffset,
281
                        uint32_t aBufferLength,
282
                        ImageBitmapFormat aFormat,
283
                        ErrorResult& aRv) const
284
0
{
285
0
  MOZ_ASSERT(mImpl);
286
0
  MOZ_ASSERT(aBuffer, "Map data into a null buffer.");
287
0
  return mImpl->MapDataInto(aBuffer, aOffset, aBufferLength, aFormat, aRv);
288
0
}
289
290
} // namespace dom
291
} // namespace mozilla