Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/layers/basic/BasicImages.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 <stdint.h>                     // for uint8_t, uint32_t
8
#include "BasicLayers.h"                // for BasicLayerManager
9
#include "ImageContainer.h"             // for PlanarYCbCrImage, etc
10
#include "ImageTypes.h"                 // for ImageFormat, etc
11
#include "cairo.h"                      // for cairo_user_data_key_t
12
#include "gfxASurface.h"                // for gfxASurface, etc
13
#include "gfxPlatform.h"                // for gfxPlatform, gfxImageFormat
14
#include "gfxUtils.h"                   // for gfxUtils
15
#include "mozilla/CheckedInt.h"
16
#include "mozilla/mozalloc.h"           // for operator delete[], etc
17
#include "mozilla/RefPtr.h"
18
#include "mozilla/UniquePtr.h"
19
#include "nsAutoRef.h"                  // for nsCountedRef
20
#include "nsCOMPtr.h"                   // for already_AddRefed
21
#include "nsDebug.h"                    // for NS_ERROR, NS_ASSERTION
22
#include "nsISupportsImpl.h"            // for Image::Release, etc
23
#include "nsThreadUtils.h"              // for NS_IsMainThread
24
#include "mozilla/gfx/Point.h"          // for IntSize
25
#include "mozilla/gfx/DataSurfaceHelpers.h"
26
#include "gfx2DGlue.h"
27
#include "YCbCrUtils.h"                 // for YCbCr conversions
28
29
namespace mozilla {
30
namespace layers {
31
32
class BasicPlanarYCbCrImage : public RecyclingPlanarYCbCrImage
33
{
34
public:
35
  BasicPlanarYCbCrImage(const gfx::IntSize& aScaleHint, gfxImageFormat aOffscreenFormat, BufferRecycleBin *aRecycleBin)
36
    : RecyclingPlanarYCbCrImage(aRecycleBin)
37
    , mScaleHint(aScaleHint)
38
    , mStride(0)
39
    , mDelayedConversion(false)
40
0
  {
41
0
    SetOffscreenFormat(aOffscreenFormat);
42
0
  }
43
44
  ~BasicPlanarYCbCrImage()
45
0
  {
46
0
    if (mDecodedBuffer) {
47
0
      // Right now this only happens if the Image was never drawn, otherwise
48
0
      // this will have been tossed away at surface destruction.
49
0
      mRecycleBin->RecycleBuffer(std::move(mDecodedBuffer), mSize.height * mStride);
50
0
    }
51
0
  }
52
53
  virtual bool CopyData(const Data& aData) override;
54
0
  virtual void SetDelayedConversion(bool aDelayed) override { mDelayedConversion = aDelayed; }
55
56
  already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() override;
57
58
  virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override
59
0
  {
60
0
    return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
61
0
  }
62
63
  virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override
64
0
  {
65
0
    size_t size = RecyclingPlanarYCbCrImage::SizeOfExcludingThis(aMallocSizeOf);
66
0
    size += aMallocSizeOf(mDecodedBuffer.get());
67
0
    return size;
68
0
  }
69
70
private:
71
  UniquePtr<uint8_t[]> mDecodedBuffer;
72
  gfx::IntSize mScaleHint;
73
  int mStride;
74
  bool mDelayedConversion;
75
};
76
77
class BasicImageFactory : public ImageFactory
78
{
79
public:
80
0
  BasicImageFactory() {}
81
82
  virtual RefPtr<PlanarYCbCrImage>
83
  CreatePlanarYCbCrImage(const gfx::IntSize& aScaleHint, BufferRecycleBin* aRecycleBin) override
84
0
  {
85
0
    return new BasicPlanarYCbCrImage(aScaleHint, gfxPlatform::GetPlatform()->GetOffscreenFormat(), aRecycleBin);
86
0
  }
87
};
88
89
bool
90
BasicPlanarYCbCrImage::CopyData(const Data& aData)
91
0
{
92
0
  RecyclingPlanarYCbCrImage::CopyData(aData);
93
0
94
0
  if (mDelayedConversion) {
95
0
    return false;
96
0
  }
97
0
98
0
  // Do some sanity checks to prevent integer overflow
99
0
  if (aData.mYSize.width > PlanarYCbCrImage::MAX_DIMENSION ||
100
0
      aData.mYSize.height > PlanarYCbCrImage::MAX_DIMENSION) {
101
0
    NS_ERROR("Illegal image source width or height");
102
0
    return false;
103
0
  }
104
0
105
0
  gfx::SurfaceFormat format = gfx::ImageFormatToSurfaceFormat(GetOffscreenFormat());
106
0
107
0
  gfx::IntSize size(mScaleHint);
108
0
  gfx::GetYCbCrToRGBDestFormatAndSize(aData, format, size);
109
0
  if (size.width > PlanarYCbCrImage::MAX_DIMENSION ||
110
0
      size.height > PlanarYCbCrImage::MAX_DIMENSION) {
111
0
    NS_ERROR("Illegal image dest width or height");
112
0
    return false;
113
0
  }
114
0
115
0
  mStride = gfx::StrideForFormatAndWidth(format, size.width);
116
0
  mozilla::CheckedInt32 requiredBytes =
117
0
    mozilla::CheckedInt32(size.height) * mozilla::CheckedInt32(mStride);
118
0
  if (!requiredBytes.isValid()) {
119
0
    // invalid size
120
0
    return false;
121
0
  }
122
0
  mDecodedBuffer = AllocateBuffer(requiredBytes.value());
123
0
  if (!mDecodedBuffer) {
124
0
    // out of memory
125
0
    return false;
126
0
  }
127
0
128
0
  gfx::ConvertYCbCrToRGB(aData, format, size, mDecodedBuffer.get(), mStride);
129
0
  SetOffscreenFormat(gfx::SurfaceFormatToImageFormat(format));
130
0
  mSize = size;
131
0
132
0
  return true;
133
0
}
134
135
already_AddRefed<gfx::SourceSurface>
136
BasicPlanarYCbCrImage::GetAsSourceSurface()
137
0
{
138
0
  NS_ASSERTION(NS_IsMainThread(), "Must be main thread");
139
0
140
0
  if (mSourceSurface) {
141
0
    RefPtr<gfx::SourceSurface> surface(mSourceSurface);
142
0
    return surface.forget();
143
0
  }
144
0
145
0
  if (!mDecodedBuffer) {
146
0
    return PlanarYCbCrImage::GetAsSourceSurface();
147
0
  }
148
0
149
0
  gfxImageFormat format = GetOffscreenFormat();
150
0
151
0
  RefPtr<gfx::SourceSurface> surface;
152
0
  {
153
0
    // Create a DrawTarget so that we can own the data inside mDecodeBuffer.
154
0
    // We create the target out of mDecodedBuffer, and get a snapshot from it.
155
0
    // The draw target is destroyed on scope exit and the surface owns the data.
156
0
    RefPtr<gfx::DrawTarget> drawTarget
157
0
      = gfxPlatform::CreateDrawTargetForData(mDecodedBuffer.get(),
158
0
                                             mSize,
159
0
                                             mStride,
160
0
                                             gfx::ImageFormatToSurfaceFormat(format));
161
0
    if (!drawTarget) {
162
0
      return nullptr;
163
0
    }
164
0
165
0
    surface = drawTarget->Snapshot();
166
0
  }
167
0
168
0
  mRecycleBin->RecycleBuffer(std::move(mDecodedBuffer), mSize.height * mStride);
169
0
170
0
  mSourceSurface = surface;
171
0
  return surface.forget();
172
0
}
173
174
175
ImageFactory*
176
BasicLayerManager::GetImageFactory()
177
0
{
178
0
  if (!mFactory) {
179
0
    mFactory = new BasicImageFactory();
180
0
  }
181
0
182
0
  return mFactory.get();
183
0
}
184
185
} // namespace layers
186
} // namespace mozilla