Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/layers/ImageDataSerializer.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
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 "ImageDataSerializer.h"
8
#include "gfx2DGlue.h"                  // for SurfaceFormatToImageFormat
9
#include "mozilla/gfx/Point.h"          // for IntSize
10
#include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
11
#include "mozilla/gfx/2D.h"             // for DataSourceSurface, Factory
12
#include "mozilla/gfx/Logging.h"        // for gfxDebug
13
#include "mozilla/gfx/Tools.h"          // for GetAlignedStride, etc
14
#include "mozilla/gfx/Types.h"
15
#include "mozilla/mozalloc.h"           // for operator delete, etc
16
#include "YCbCrUtils.h"                 // for YCbCr conversions
17
18
namespace mozilla {
19
namespace layers {
20
namespace ImageDataSerializer {
21
22
using namespace gfx;
23
24
int32_t
25
ComputeRGBStride(SurfaceFormat aFormat, int32_t aWidth)
26
0
{
27
0
  return GetAlignedStride<4>(aWidth, BytesPerPixel(aFormat));
28
0
}
29
30
int32_t
31
GetRGBStride(const RGBDescriptor& aDescriptor)
32
0
{
33
0
  return ComputeRGBStride(aDescriptor.format(), aDescriptor.size().width);
34
0
}
35
36
uint32_t
37
ComputeRGBBufferSize(IntSize aSize, SurfaceFormat aFormat)
38
0
{
39
0
  MOZ_ASSERT(aSize.height >= 0 && aSize.width >= 0);
40
0
41
0
  // This takes care of checking whether there could be overflow
42
0
  // with enough margin for the metadata.
43
0
  if (!gfx::Factory::AllowedSurfaceSize(aSize)) {
44
0
    return 0;
45
0
  }
46
0
47
0
  // Note we're passing height instad of the bpp parameter, but the end
48
0
  // result is the same - and the bpp was already taken care of in the
49
0
  // ComputeRGBStride function.
50
0
  int32_t bufsize = GetAlignedStride<16>(ComputeRGBStride(aFormat, aSize.width),
51
0
                                         aSize.height);
52
0
53
0
  if (bufsize < 0) {
54
0
    // This should not be possible thanks to Factory::AllowedSurfaceSize
55
0
    return 0;
56
0
  }
57
0
58
0
  return bufsize;
59
0
}
60
61
62
63
// Minimum required shmem size in bytes
64
uint32_t
65
ComputeYCbCrBufferSize(const gfx::IntSize& aYSize, int32_t aYStride,
66
                       const gfx::IntSize& aCbCrSize, int32_t aCbCrStride)
67
0
{
68
0
  MOZ_ASSERT(aYSize.height >= 0 && aYSize.width >= 0);
69
0
70
0
  if (aYSize.height < 0 || aYSize.width < 0 || aCbCrSize.height < 0 || aCbCrSize.width < 0 ||
71
0
      !gfx::Factory::AllowedSurfaceSize(IntSize(aYStride, aYSize.height)) ||
72
0
      !gfx::Factory::AllowedSurfaceSize(IntSize(aCbCrStride, aCbCrSize.height))) {
73
0
    return 0;
74
0
  }
75
0
76
0
  // Overflow checks are performed in AllowedSurfaceSize
77
0
  return GetAlignedStride<4>(aYSize.height, aYStride) +
78
0
         2 * GetAlignedStride<4>(aCbCrSize.height, aCbCrStride);
79
0
}
80
81
uint32_t
82
ComputeYCbCrBufferSize(const gfx::IntSize& aYSize, int32_t aYStride,
83
                       const gfx::IntSize& aCbCrSize, int32_t aCbCrStride,
84
                       uint32_t aYOffset, uint32_t aCbOffset,
85
                       uint32_t aCrOffset)
86
0
{
87
0
  MOZ_ASSERT(aYSize.height >= 0 && aYSize.width >= 0);
88
0
89
0
  if (aYSize.height < 0 || aYSize.width < 0 || aCbCrSize.height < 0 || aCbCrSize.width < 0 ||
90
0
      !gfx::Factory::AllowedSurfaceSize(IntSize(aYStride, aYSize.height)) ||
91
0
      !gfx::Factory::AllowedSurfaceSize(IntSize(aCbCrStride, aCbCrSize.height))) {
92
0
    return 0;
93
0
  }
94
0
95
0
  uint32_t yLength = GetAlignedStride<4>(aYStride, aYSize.height);
96
0
  uint32_t cbCrLength = GetAlignedStride<4>(aCbCrStride, aCbCrSize.height);
97
0
  if (yLength == 0 || cbCrLength == 0) {
98
0
    return 0;
99
0
  }
100
0
101
0
  CheckedInt<uint32_t> yEnd = aYOffset;
102
0
  yEnd += yLength;
103
0
  CheckedInt<uint32_t> cbEnd = aCbOffset;
104
0
  cbEnd += cbCrLength;
105
0
  CheckedInt<uint32_t> crEnd = aCrOffset;
106
0
  crEnd += cbCrLength;
107
0
108
0
  if (!yEnd.isValid() || !cbEnd.isValid() || !crEnd.isValid() ||
109
0
      yEnd.value() > aCbOffset || cbEnd.value() > aCrOffset) {
110
0
    return 0;
111
0
  }
112
0
113
0
  return crEnd.value();
114
0
}
115
116
uint32_t
117
ComputeYCbCrBufferSize(uint32_t aBufferSize)
118
0
{
119
0
  return GetAlignedStride<4>(aBufferSize, 1);
120
0
}
121
122
void ComputeYCbCrOffsets(int32_t yStride, int32_t yHeight,
123
                         int32_t cbCrStride, int32_t cbCrHeight,
124
                         uint32_t& outYOffset, uint32_t& outCbOffset,
125
                         uint32_t& outCrOffset)
126
0
{
127
0
  outYOffset = 0;
128
0
  outCbOffset = outYOffset + GetAlignedStride<4>(yStride, yHeight);
129
0
  outCrOffset = outCbOffset + GetAlignedStride<4>(cbCrStride, cbCrHeight);
130
0
}
131
132
gfx::SurfaceFormat FormatFromBufferDescriptor(const BufferDescriptor& aDescriptor)
133
0
{
134
0
  switch (aDescriptor.type()) {
135
0
    case BufferDescriptor::TRGBDescriptor:
136
0
      return aDescriptor.get_RGBDescriptor().format();
137
0
    case BufferDescriptor::TYCbCrDescriptor:
138
0
      return gfx::SurfaceFormat::YUV;
139
0
    default:
140
0
      MOZ_CRASH("GFX: FormatFromBufferDescriptor");
141
0
  }
142
0
}
143
144
gfx::IntSize SizeFromBufferDescriptor(const BufferDescriptor& aDescriptor)
145
0
{
146
0
  switch (aDescriptor.type()) {
147
0
    case BufferDescriptor::TRGBDescriptor:
148
0
      return aDescriptor.get_RGBDescriptor().size();
149
0
    case BufferDescriptor::TYCbCrDescriptor:
150
0
      return aDescriptor.get_YCbCrDescriptor().ySize();
151
0
    default:
152
0
      MOZ_CRASH("GFX: SizeFromBufferDescriptor");
153
0
  }
154
0
}
155
156
Maybe<gfx::IntSize> CbCrSizeFromBufferDescriptor(const BufferDescriptor& aDescriptor)
157
0
{
158
0
  switch (aDescriptor.type()) {
159
0
    case BufferDescriptor::TRGBDescriptor:
160
0
      return Nothing();
161
0
    case BufferDescriptor::TYCbCrDescriptor:
162
0
      return Some(aDescriptor.get_YCbCrDescriptor().cbCrSize());
163
0
    default:
164
0
      MOZ_CRASH("GFX:  CbCrSizeFromBufferDescriptor");
165
0
  }
166
0
}
167
168
Maybe<YUVColorSpace> YUVColorSpaceFromBufferDescriptor(const BufferDescriptor& aDescriptor)
169
0
{
170
0
  switch (aDescriptor.type()) {
171
0
    case BufferDescriptor::TRGBDescriptor:
172
0
      return Nothing();
173
0
    case BufferDescriptor::TYCbCrDescriptor:
174
0
      return Some(aDescriptor.get_YCbCrDescriptor().yUVColorSpace());
175
0
    default:
176
0
      MOZ_CRASH("GFX:  YUVColorSpaceFromBufferDescriptor");
177
0
  }
178
0
}
179
180
Maybe<uint32_t> BitDepthFromBufferDescriptor(const BufferDescriptor& aDescriptor)
181
0
{
182
0
  switch (aDescriptor.type()) {
183
0
    case BufferDescriptor::TRGBDescriptor:
184
0
      return Nothing();
185
0
    case BufferDescriptor::TYCbCrDescriptor:
186
0
      return Some(aDescriptor.get_YCbCrDescriptor().bitDepth());
187
0
    default:
188
0
      MOZ_CRASH("GFX:  BitDepthFromBufferDescriptor");
189
0
  }
190
0
}
191
192
Maybe<StereoMode> StereoModeFromBufferDescriptor(const BufferDescriptor& aDescriptor)
193
0
{
194
0
  switch (aDescriptor.type()) {
195
0
    case BufferDescriptor::TRGBDescriptor:
196
0
      return Nothing();
197
0
    case BufferDescriptor::TYCbCrDescriptor:
198
0
      return Some(aDescriptor.get_YCbCrDescriptor().stereoMode());
199
0
    default:
200
0
      MOZ_CRASH("GFX:  StereoModeFromBufferDescriptor");
201
0
  }
202
0
}
203
204
uint8_t* GetYChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor)
205
0
{
206
0
  return aBuffer + aDescriptor.yOffset();
207
0
}
208
209
uint8_t* GetCbChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor)
210
0
{
211
0
  return aBuffer + aDescriptor.cbOffset();
212
0
}
213
214
uint8_t* GetCrChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor)
215
0
{
216
0
  return aBuffer + aDescriptor.crOffset();
217
0
}
218
219
already_AddRefed<DataSourceSurface>
220
DataSourceSurfaceFromYCbCrDescriptor(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor, gfx::DataSourceSurface* aSurface)
221
0
{
222
0
  gfx::IntSize ySize = aDescriptor.ySize();
223
0
224
0
  RefPtr<DataSourceSurface> result;
225
0
  if (aSurface) {
226
0
    MOZ_ASSERT(aSurface->GetSize() == ySize);
227
0
    MOZ_ASSERT(aSurface->GetFormat() == gfx::SurfaceFormat::B8G8R8X8);
228
0
    if (aSurface->GetSize() == ySize &&
229
0
        aSurface->GetFormat() == gfx::SurfaceFormat::B8G8R8X8) {
230
0
      result = aSurface;
231
0
    }
232
0
  }
233
0
234
0
  if (!result) {
235
0
    result =
236
0
      Factory::CreateDataSourceSurface(ySize, gfx::SurfaceFormat::B8G8R8X8);
237
0
  }
238
0
  if (NS_WARN_IF(!result)) {
239
0
    return nullptr;
240
0
  }
241
0
242
0
  DataSourceSurface::MappedSurface map;
243
0
  if (NS_WARN_IF(!result->Map(DataSourceSurface::MapType::WRITE, &map))) {
244
0
    return nullptr;
245
0
  }
246
0
247
0
  layers::PlanarYCbCrData ycbcrData;
248
0
  ycbcrData.mYChannel     = GetYChannel(aBuffer, aDescriptor);
249
0
  ycbcrData.mYStride      = aDescriptor.yStride();
250
0
  ycbcrData.mYSize        = ySize;
251
0
  ycbcrData.mCbChannel    = GetCbChannel(aBuffer, aDescriptor);
252
0
  ycbcrData.mCrChannel    = GetCrChannel(aBuffer, aDescriptor);
253
0
  ycbcrData.mCbCrStride   = aDescriptor.cbCrStride();
254
0
  ycbcrData.mCbCrSize     = aDescriptor.cbCrSize();
255
0
  ycbcrData.mPicSize      = ySize;
256
0
  ycbcrData.mYUVColorSpace = aDescriptor.yUVColorSpace();
257
0
  ycbcrData.mBitDepth     = aDescriptor.bitDepth();
258
0
259
0
  gfx::ConvertYCbCrToRGB(ycbcrData,
260
0
                         gfx::SurfaceFormat::B8G8R8X8,
261
0
                         ySize,
262
0
                         map.mData,
263
0
                         map.mStride);
264
0
265
0
  result->Unmap();
266
0
  return result.forget();
267
0
}
268
269
void
270
ConvertAndScaleFromYCbCrDescriptor(uint8_t* aBuffer,
271
                                   const YCbCrDescriptor& aDescriptor,
272
                                   const gfx::SurfaceFormat& aDestFormat,
273
                                   const gfx::IntSize& aDestSize,
274
                                   unsigned char* aDestBuffer,
275
                                   int32_t aStride)
276
0
{
277
0
  MOZ_ASSERT(aBuffer);
278
0
279
0
  layers::PlanarYCbCrData ycbcrData;
280
0
  ycbcrData.mYChannel     = GetYChannel(aBuffer, aDescriptor);
281
0
  ycbcrData.mYStride      = aDescriptor.yStride();;
282
0
  ycbcrData.mYSize        = aDescriptor.ySize();
283
0
  ycbcrData.mCbChannel    = GetCbChannel(aBuffer, aDescriptor);
284
0
  ycbcrData.mCrChannel    = GetCrChannel(aBuffer, aDescriptor);
285
0
  ycbcrData.mCbCrStride   = aDescriptor.cbCrStride();
286
0
  ycbcrData.mCbCrSize     = aDescriptor.cbCrSize();
287
0
  ycbcrData.mPicSize      = aDescriptor.ySize();
288
0
  ycbcrData.mYUVColorSpace = aDescriptor.yUVColorSpace();
289
0
  ycbcrData.mBitDepth     = aDescriptor.bitDepth();
290
0
291
0
  gfx::ConvertYCbCrToRGB(ycbcrData, aDestFormat, aDestSize, aDestBuffer, aStride);
292
0
}
293
294
} // namespace ImageDataSerializer
295
} // namespace layers
296
} // namespace mozilla