Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/2d/SourceSurfaceCapture.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 "SourceSurfaceCapture.h"
8
#include "DrawCommand.h"
9
#include "DrawTargetCapture.h"
10
#include "MainThreadUtils.h"
11
#include "mozilla/gfx/Logging.h"
12
13
namespace mozilla {
14
namespace gfx {
15
16
SourceSurfaceCapture::SourceSurfaceCapture(DrawTargetCaptureImpl* aOwner)
17
 : mOwner(aOwner),
18
   mHasCommandList(false),
19
   mShouldResolveToLuminance{false},
20
   mLuminanceType{LuminanceType::LUMINANCE},
21
   mOpacity{1.0f},
22
   mLock("SourceSurfaceCapture.mLock")
23
0
{
24
0
  mSize = mOwner->GetSize();
25
0
  mFormat = mOwner->GetFormat();
26
0
  mRefDT = mOwner->mRefDT;
27
0
  mStride = mOwner->mStride;
28
0
  mSurfaceAllocationSize = mOwner->mSurfaceAllocationSize;
29
0
}
30
31
SourceSurfaceCapture::SourceSurfaceCapture(DrawTargetCaptureImpl* aOwner,
32
                                           LuminanceType aLuminanceType /* = LuminanceType::LINEARRGB */,
33
                                           Float aOpacity /* = 1.0f */)
34
  : mOwner{aOwner}
35
  , mHasCommandList{false}
36
  , mShouldResolveToLuminance{true}
37
  , mLuminanceType{aLuminanceType}
38
  , mOpacity{aOpacity}
39
  , mLock{"SourceSurfaceCapture.mLock"}
40
0
{
41
0
  mSize = mOwner->GetSize();
42
0
  mFormat = mOwner->GetFormat();
43
0
  mRefDT = mOwner->mRefDT;
44
0
  mStride = mOwner->mStride;
45
0
  mSurfaceAllocationSize = mOwner->mSurfaceAllocationSize;
46
0
47
0
  // In this case our DrawTarget will not track us, so copy its drawing commands.
48
0
  DrawTargetWillChange();
49
0
}
50
51
SourceSurfaceCapture::~SourceSurfaceCapture()
52
0
{
53
0
}
54
55
bool
56
SourceSurfaceCapture::IsValid() const
57
0
{
58
0
  // We must either be able to source a command list, or we must have a cached
59
0
  // and rasterized surface.
60
0
  MutexAutoLock lock(mLock);
61
0
  return (mOwner || mHasCommandList) || mResolved;
62
0
}
63
64
RefPtr<SourceSurface>
65
SourceSurfaceCapture::Resolve(BackendType aBackendType)
66
0
{
67
0
  MutexAutoLock lock(mLock);
68
0
69
0
  if (!mOwner && !mHasCommandList) {
70
0
    // There is no way we can rasterize anything, we don't have a source
71
0
    // DrawTarget and we don't have a command list. Return whatever our
72
0
    // cached surface is.
73
0
    return mResolved;
74
0
  }
75
0
76
0
  BackendType backendType = aBackendType;
77
0
  if (backendType == BackendType::NONE) {
78
0
    backendType = mRefDT->GetBackendType();
79
0
  }
80
0
81
0
  // If on the paint thread, we require that the owning DrawTarget be detached
82
0
  // from this snapshot. This roughly approximates an assert that nothing can
83
0
  // mutate the snapshot.
84
0
  MOZ_RELEASE_ASSERT(NS_IsMainThread() || !mOwner);
85
0
86
0
  // Note: SurfaceType is not 1:1 with BackendType, so we can't easily decide
87
0
  // that they match. Instead we just cache the first thing to be requested.
88
0
  if (!mResolved) {
89
0
    mResolved = ResolveImpl(backendType);
90
0
  }
91
0
  return mResolved;
92
0
}
93
94
RefPtr<SourceSurface>
95
SourceSurfaceCapture::ResolveImpl(BackendType aBackendType)
96
0
{
97
0
  RefPtr<DrawTarget> dt;
98
0
  uint8_t* data = nullptr;
99
0
  if (!mSurfaceAllocationSize) {
100
0
    if (aBackendType == mRefDT->GetBackendType()) {
101
0
      dt = mRefDT->CreateSimilarDrawTarget(mSize, mFormat);
102
0
    } else {
103
0
      dt = Factory::CreateDrawTarget(aBackendType, mSize, mFormat);
104
0
    }
105
0
  } else {
106
0
    data = static_cast<uint8_t*>(calloc(1, mSurfaceAllocationSize));
107
0
    if (!data) {
108
0
      return nullptr;
109
0
    }
110
0
    BackendType type = Factory::DoesBackendSupportDataDrawtarget(aBackendType)
111
0
                       ? aBackendType
112
0
                       : BackendType::SKIA;
113
0
    dt = Factory::CreateDrawTargetForData(type, data, mSize, mStride, mFormat);
114
0
    if (!dt) {
115
0
      free(data);
116
0
      return nullptr;
117
0
    }
118
0
  }
119
0
120
0
  if (!dt) {
121
0
    // Make sure we haven't allocated and aren't leaking something, the code right
122
0
    // anove here should have guaranteed that.
123
0
    MOZ_ASSERT(!data);
124
0
    return nullptr;
125
0
  }
126
0
127
0
  // If we're still attached to a DrawTarget, use its command list rather than
128
0
  // our own (which will be empty).
129
0
  CaptureCommandList& commands = mHasCommandList
130
0
                                 ? mCommands
131
0
                                 : mOwner->mCommands;
132
0
  for (CaptureCommandList::iterator iter(commands); !iter.Done(); iter.Next()) {
133
0
    DrawingCommand* cmd = iter.Get();
134
0
    cmd->ExecuteOnDT(dt, nullptr);
135
0
  }
136
0
137
0
  RefPtr<SourceSurface> surf;
138
0
  if (!mShouldResolveToLuminance) {
139
0
    surf = dt->Snapshot();
140
0
  } else {
141
0
    surf = dt->IntoLuminanceSource(mLuminanceType, mOpacity);
142
0
  }
143
0
144
0
  if (data) {
145
0
    surf->AddUserData(reinterpret_cast<UserDataKey*>(dt.get()), data, free);
146
0
  }
147
0
148
0
  return surf.forget();
149
0
}
150
151
already_AddRefed<DataSourceSurface>
152
SourceSurfaceCapture::GetDataSurface()
153
0
{
154
0
  RefPtr<SourceSurface> surface = Resolve();
155
0
  if (!surface) {
156
0
    return nullptr;
157
0
  }
158
0
  return surface->GetDataSurface();
159
0
}
160
161
void
162
SourceSurfaceCapture::DrawTargetWillDestroy()
163
0
{
164
0
  MutexAutoLock lock(mLock);
165
0
166
0
  // The source DrawTarget is going away, so we can just steal its commands.
167
0
  mCommands = std::move(mOwner->mCommands);
168
0
  mHasCommandList = true;
169
0
  mOwner = nullptr;
170
0
}
171
172
void
173
SourceSurfaceCapture::DrawTargetWillChange()
174
0
{
175
0
  MutexAutoLock lock(mLock);
176
0
177
0
  for (CaptureCommandList::iterator iter(mOwner->mCommands); !iter.Done(); iter.Next()) {
178
0
    DrawingCommand* cmd = iter.Get();
179
0
    cmd->CloneInto(&mCommands);
180
0
  }
181
0
182
0
  mHasCommandList = true;
183
0
  mOwner = nullptr;
184
0
}
185
186
} // namespace gfx
187
} // namespace mozilla