1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
|
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/renderer/pepper_plugin_delegate_impl.h"
#include "app/surface/transport_dib.h"
#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "chrome/common/render_messages.h"
#include "chrome/renderer/audio_message_filter.h"
#include "chrome/renderer/render_view.h"
#include "webkit/glue/plugins/pepper_plugin_instance.h"
#if defined(OS_MACOSX)
#include "chrome/common/render_messages.h"
#include "chrome/renderer/render_thread.h"
#endif
namespace {
// Implements the Image2D using a TransportDIB.
class PlatformImage2DImpl : public pepper::PluginDelegate::PlatformImage2D {
public:
// This constructor will take ownership of the dib pointer.
PlatformImage2DImpl(int width, int height, TransportDIB* dib)
: width_(width),
height_(height),
dib_(dib) {
}
virtual skia::PlatformCanvas* Map() {
return dib_->GetPlatformCanvas(width_, height_);
}
virtual intptr_t GetSharedMemoryHandle() const {
return reinterpret_cast<intptr_t>(dib_.get());
}
private:
int width_;
int height_;
scoped_ptr<TransportDIB> dib_;
DISALLOW_COPY_AND_ASSIGN(PlatformImage2DImpl);
};
class PlatformAudioImpl
: public pepper::PluginDelegate::PlatformAudio,
public AudioMessageFilter::Delegate {
public:
explicit PlatformAudioImpl(scoped_refptr<AudioMessageFilter> filter)
: client_(NULL), filter_(filter), stream_id_(0) {
DCHECK(filter_);
}
virtual ~PlatformAudioImpl() {
// Make sure we have been shut down.
DCHECK_EQ(0, stream_id_);
DCHECK(!client_);
}
// Initialize this audio context. StreamCreated() will be called when the
// stream is created.
bool Initialize(uint32_t sample_rate, uint32_t sample_count,
pepper::PluginDelegate::PlatformAudio::Client* client);
virtual bool StartPlayback() {
return filter_ && filter_->Send(
new ViewHostMsg_PlayAudioStream(0, stream_id_));
}
virtual bool StopPlayback() {
return filter_ && filter_->Send(
new ViewHostMsg_PauseAudioStream(0, stream_id_));
}
virtual void ShutDown();
private:
virtual void OnRequestPacket(uint32 bytes_in_buffer,
const base::Time& message_timestamp) {
LOG(FATAL) << "Should never get OnRequestPacket in PlatformAudioImpl";
}
virtual void OnStateChanged(const ViewMsg_AudioStreamState_Params& state) { }
virtual void OnCreated(base::SharedMemoryHandle handle, uint32 length) {
LOG(FATAL) << "Should never get OnCreated in PlatformAudioImpl";
}
virtual void OnLowLatencyCreated(base::SharedMemoryHandle handle,
base::SyncSocket::Handle socket_handle,
uint32 length);
virtual void OnVolume(double volume) { }
// The client to notify when the stream is created.
pepper::PluginDelegate::PlatformAudio::Client* client_;
// MessageFilter used to send/receive IPC.
scoped_refptr<AudioMessageFilter> filter_;
// Our ID on the MessageFilter.
int32 stream_id_;
DISALLOW_COPY_AND_ASSIGN(PlatformAudioImpl);
};
bool PlatformAudioImpl::Initialize(
uint32_t sample_rate, uint32_t sample_count,
pepper::PluginDelegate::PlatformAudio::Client* client) {
DCHECK(client);
// Make sure we don't call init more than once.
DCHECK_EQ(0, stream_id_);
client_ = client;
ViewHostMsg_Audio_CreateStream_Params params;
params.format = AudioManager::AUDIO_PCM_LINEAR;
params.channels = 2;
params.sample_rate = sample_rate;
params.bits_per_sample = 16;
params.packet_size = sample_count * params.channels *
(params.bits_per_sample >> 3);
stream_id_ = filter_->AddDelegate(this);
return filter_->Send(new ViewHostMsg_CreateAudioStream(0, stream_id_, params,
true));
}
void PlatformAudioImpl::OnLowLatencyCreated(
base::SharedMemoryHandle handle, base::SyncSocket::Handle socket_handle,
uint32 length) {
#if defined(OS_WIN)
DCHECK(handle);
DCHECK(socket_handle);
#else
DCHECK_NE(-1, handle.fd);
DCHECK_NE(-1, socket_handle);
#endif
DCHECK(length);
client_->StreamCreated(handle, length, socket_handle);
}
void PlatformAudioImpl::ShutDown() {
// Make sure we don't call shutdown more than once.
if (!stream_id_) {
return;
}
filter_->Send(new ViewHostMsg_CloseAudioStream(0, stream_id_));
filter_->RemoveDelegate(stream_id_);
stream_id_ = 0;
client_ = NULL;
}
} // namespace
PepperPluginDelegateImpl::PepperPluginDelegateImpl(RenderView* render_view)
: render_view_(render_view) {
}
void PepperPluginDelegateImpl::ViewInitiatedPaint() {
// Notify all of our instances that we started painting. This is used for
// internal bookkeeping only, so we know that the set can not change under
// us.
for (std::set<pepper::PluginInstance*>::iterator i =
active_instances_.begin();
i != active_instances_.end(); ++i)
(*i)->ViewInitiatedPaint();
}
void PepperPluginDelegateImpl::ViewFlushedPaint() {
// Notify all instances that we painted. This will call into the plugin, and
// we it may ask to close itself as a result. This will, in turn, modify our
// set, possibly invalidating the iterator. So we iterate on a copy that
// won't change out from under us.
std::set<pepper::PluginInstance*> plugins = active_instances_;
for (std::set<pepper::PluginInstance*>::iterator i = plugins.begin();
i != plugins.end(); ++i) {
// The copy above makes sure our iterator is never invalid if some plugins
// are destroyed. But some plugin may decide to close all of its views in
// response to a paint in one of them, so we need to make sure each one is
// still "current" before using it.
//
// It's possible that a plugin was destroyed, but another one was created
// with the same address. In this case, we'll call ViewFlushedPaint on that
// new plugin. But that's OK for this particular case since we're just
// notifying all of our instances that the view flushed, and the new one is
// one of our instances.
//
// What about the case where a new one is created in a callback at a new
// address and we don't issue the callback? We're still OK since this
// callback is used for flush callbacks and we could not have possibly
// started a new paint (ViewInitiatedPaint) for the new plugin while
// processing a previous paint for an existing one.
if (active_instances_.find(*i) != active_instances_.end())
(*i)->ViewFlushedPaint();
}
}
void PepperPluginDelegateImpl::InstanceCreated(
pepper::PluginInstance* instance) {
active_instances_.insert(instance);
}
void PepperPluginDelegateImpl::InstanceDeleted(
pepper::PluginInstance* instance) {
active_instances_.erase(instance);
}
pepper::PluginDelegate::PlatformImage2D*
PepperPluginDelegateImpl::CreateImage2D(int width, int height) {
uint32 buffer_size = width * height * 4;
// Allocate the transport DIB and the PlatformCanvas pointing to it.
#if defined(OS_MACOSX)
// On the Mac, shared memory has to be created in the browser in order to
// work in the sandbox. Do this by sending a message to the browser
// requesting a TransportDIB (see also
// chrome/renderer/webplugin_delegate_proxy.cc, method
// WebPluginDelegateProxy::CreateBitmap() for similar code). Note that the
// TransportDIB is _not_ cached in the browser; this is because this memory
// gets flushed by the renderer into another TransportDIB that represents the
// page, which is then in turn flushed to the screen by the browser process.
// When |transport_dib_| goes out of scope in the dtor, all of its shared
// memory gets reclaimed.
TransportDIB::Handle dib_handle;
IPC::Message* msg = new ViewHostMsg_AllocTransportDIB(buffer_size,
false,
&dib_handle);
if (!RenderThread::current()->Send(msg))
return NULL;
if (!TransportDIB::is_valid(dib_handle))
return NULL;
TransportDIB* dib = TransportDIB::Map(dib_handle);
#else
static int next_dib_id = 0;
TransportDIB* dib = TransportDIB::Create(buffer_size, next_dib_id++);
if (!dib)
return NULL;
#endif
return new PlatformImage2DImpl(width, height, dib);
}
void PepperPluginDelegateImpl::DidChangeNumberOfFindResults(int identifier,
int total,
bool final_result) {
if (total == 0) {
render_view_->ReportNoFindInPageResults(identifier);
} else {
render_view_->reportFindInPageMatchCount(identifier, total, final_result);
}
}
void PepperPluginDelegateImpl::DidChangeSelectedFindResult(int identifier,
int index) {
render_view_->reportFindInPageSelection(
identifier, index + 1, WebKit::WebRect());
}
pepper::PluginDelegate::PlatformAudio* PepperPluginDelegateImpl::CreateAudio(
uint32_t sample_rate, uint32_t sample_count,
pepper::PluginDelegate::PlatformAudio::Client* client) {
scoped_ptr<PlatformAudioImpl> audio(
new PlatformAudioImpl(render_view_->audio_message_filter()));
if (audio->Initialize(sample_rate, sample_count, client)) {
return audio.release();
} else {
return NULL;
}
}
|