Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(401)

Side by Side Diff: remoting/client/plugin/chromoting_instance.cc

Issue 8985007: Refactoring of the client-side input pipeline and scaling dimension management. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase. Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "remoting/client/plugin/chromoting_instance.h" 5 #include "remoting/client/plugin/chromoting_instance.h"
6 6
7 #include <string> 7 #include <string>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/lazy_instance.h" 11 #include "base/lazy_instance.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/message_loop.h" 13 #include "base/message_loop.h"
14 #include "base/stringprintf.h" 14 #include "base/stringprintf.h"
15 #include "base/synchronization/lock.h" 15 #include "base/synchronization/lock.h"
16 #include "base/synchronization/waitable_event.h" 16 #include "base/synchronization/waitable_event.h"
17 #include "base/threading/thread.h" 17 #include "base/threading/thread.h"
18 #include "media/base/media.h" 18 #include "media/base/media.h"
19 #include "ppapi/cpp/completion_callback.h" 19 #include "ppapi/cpp/completion_callback.h"
20 #include "ppapi/cpp/input_event.h" 20 #include "ppapi/cpp/input_event.h"
21 #include "ppapi/cpp/rect.h" 21 #include "ppapi/cpp/rect.h"
22 // TODO(wez): Remove this when crbug.com/86353 is complete. 22 // TODO(wez): Remove this when crbug.com/86353 is complete.
23 #include "ppapi/cpp/private/var_private.h" 23 #include "ppapi/cpp/private/var_private.h"
24 #include "remoting/base/util.h" 24 #include "remoting/base/util.h"
25 #include "remoting/client/client_config.h" 25 #include "remoting/client/client_config.h"
26 #include "remoting/client/chromoting_client.h" 26 #include "remoting/client/chromoting_client.h"
27 #include "remoting/client/mouse_input_filter.h"
27 #include "remoting/client/plugin/chromoting_scriptable_object.h" 28 #include "remoting/client/plugin/chromoting_scriptable_object.h"
28 #include "remoting/client/plugin/pepper_input_handler.h" 29 #include "remoting/client/plugin/pepper_input_handler.h"
29 #include "remoting/client/plugin/pepper_view.h" 30 #include "remoting/client/plugin/pepper_view.h"
30 #include "remoting/client/plugin/pepper_view_proxy.h"
31 #include "remoting/client/plugin/pepper_xmpp_proxy.h" 31 #include "remoting/client/plugin/pepper_xmpp_proxy.h"
32 #include "remoting/client/rectangle_update_decoder.h" 32 #include "remoting/client/rectangle_update_decoder.h"
33 #include "remoting/protocol/connection_to_host.h" 33 #include "remoting/protocol/connection_to_host.h"
34 #include "remoting/protocol/host_stub.h" 34 #include "remoting/protocol/host_stub.h"
35 #include "remoting/protocol/key_event_tracker.h"
35 36
36 namespace remoting { 37 namespace remoting {
37 38
38 // This flag blocks LOGs to the UI if we're already in the middle of logging 39 // This flag blocks LOGs to the UI if we're already in the middle of logging
39 // to the UI. This prevents a potential infinite loop if we encounter an error 40 // to the UI. This prevents a potential infinite loop if we encounter an error
40 // while sending the log message to the UI. 41 // while sending the log message to the UI.
41 static bool g_logging_to_plugin = false; 42 static bool g_logging_to_plugin = false;
42 static bool g_has_logging_instance = false; 43 static bool g_has_logging_instance = false;
43 static ChromotingInstance* g_logging_instance = NULL; 44 static ChromotingInstance* g_logging_instance = NULL;
44 static logging::LogMessageHandlerFunction g_logging_old_handler = NULL; 45 static logging::LogMessageHandlerFunction g_logging_old_handler = NULL;
(...skipping 30 matching lines...) Expand all
75 // to it. This will stop all logging in all Chromoting instances. 76 // to it. This will stop all logging in all Chromoting instances.
76 UnregisterLoggingInstance(); 77 UnregisterLoggingInstance();
77 78
78 if (client_.get()) { 79 if (client_.get()) {
79 base::WaitableEvent done_event(true, false); 80 base::WaitableEvent done_event(true, false);
80 client_->Stop(base::Bind(&base::WaitableEvent::Signal, 81 client_->Stop(base::Bind(&base::WaitableEvent::Signal,
81 base::Unretained(&done_event))); 82 base::Unretained(&done_event)));
82 done_event.Wait(); 83 done_event.Wait();
83 } 84 }
84 85
85 // Stopping the context shutdown all chromoting threads. This is a requirement 86 // Stopping the context shuts down all chromoting threads.
86 // before we can call Detach() on |view_proxy_|.
87 context_.Stop(); 87 context_.Stop();
88 88
89 if (view_proxy_.get()) {
90 view_proxy_->Detach();
91 }
92
93 // Delete |thread_proxy_| before we detach |plugin_message_loop_|, 89 // Delete |thread_proxy_| before we detach |plugin_message_loop_|,
94 // otherwise ScopedThreadProxy may DCHECK when destroying. 90 // otherwise ScopedThreadProxy may DCHECK when being destroyed.
95 thread_proxy_.reset(); 91 thread_proxy_.reset();
96 92
97 plugin_message_loop_->Detach(); 93 plugin_message_loop_->Detach();
98 } 94 }
99 95
100 bool ChromotingInstance::Init(uint32_t argc, 96 bool ChromotingInstance::Init(uint32_t argc,
101 const char* argn[], 97 const char* argn[],
102 const char* argv[]) { 98 const char* argv[]) {
103 CHECK(!initialized_); 99 CHECK(!initialized_);
104 initialized_ = true; 100 initialized_ = true;
105 101
106 VLOG(1) << "Started ChromotingInstance::Init"; 102 VLOG(1) << "Started ChromotingInstance::Init";
107 103
108 // Check to make sure the media library is initialized. 104 // Check to make sure the media library is initialized.
109 // http://crbug.com/91521. 105 // http://crbug.com/91521.
110 if (!media::IsMediaLibraryInitialized()) { 106 if (!media::IsMediaLibraryInitialized()) {
111 LOG(ERROR) << "Media library not initialized."; 107 LOG(ERROR) << "Media library not initialized.";
112 return false; 108 return false;
113 } 109 }
114 110
115 // Start all the threads. 111 // Start all the threads.
116 context_.Start(); 112 context_.Start();
117 113
118 // Create the chromoting objects that don't depend on the network connection. 114 // Create the chromoting objects that don't depend on the network connection.
119 view_.reset(new PepperView(this, &context_)); 115 view_.reset(new PepperView(this, &context_));
120 view_proxy_ = new PepperViewProxy(this, view_.get(), plugin_message_loop_);
121 rectangle_decoder_ = new RectangleUpdateDecoder( 116 rectangle_decoder_ = new RectangleUpdateDecoder(
122 context_.decode_message_loop(), view_proxy_); 117 context_.decode_message_loop(), view_.get());
123 118
124 // Default to a medium grey. 119 // Default to a medium grey.
125 view_->SetSolidFill(0xFFCDCDCD); 120 view_->SetSolidFill(0xFFCDCDCD);
126 121
127 return true; 122 return true;
128 } 123 }
129 124
130 void ChromotingInstance::Connect(const ClientConfig& config) { 125 void ChromotingInstance::Connect(const ClientConfig& config) {
131 DCHECK(plugin_message_loop_->BelongsToCurrentThread()); 126 DCHECK(plugin_message_loop_->BelongsToCurrentThread());
132 127
133 host_connection_.reset(new protocol::ConnectionToHost( 128 host_connection_.reset(new protocol::ConnectionToHost(
134 context_.network_message_loop(), this, true)); 129 context_.network_message_loop(), this, true));
135
136 input_handler_.reset(new PepperInputHandler(&context_,
137 host_connection_.get(),
138 view_proxy_));
139
140 client_.reset(new ChromotingClient(config, &context_, host_connection_.get(), 130 client_.reset(new ChromotingClient(config, &context_, host_connection_.get(),
141 view_proxy_, rectangle_decoder_.get(), 131 view_.get(), rectangle_decoder_.get(),
142 input_handler_.get(), base::Closure())); 132 base::Closure()));
143 133
144 LOG(INFO) << "Connecting to " << config.host_jid 134 LOG(INFO) << "Connecting to " << config.host_jid
145 << ". Local jid: " << config.local_jid << "."; 135 << ". Local jid: " << config.local_jid << ".";
146 136
147 // Setup the XMPP Proxy. 137 // Setup the XMPP Proxy.
148 ChromotingScriptableObject* scriptable_object = GetScriptableObject(); 138 ChromotingScriptableObject* scriptable_object = GetScriptableObject();
149 scoped_refptr<PepperXmppProxy> xmpp_proxy = 139 scoped_refptr<PepperXmppProxy> xmpp_proxy =
150 new PepperXmppProxy(scriptable_object->AsWeakPtr(), 140 new PepperXmppProxy(scriptable_object->AsWeakPtr(),
151 plugin_message_loop_, 141 plugin_message_loop_,
152 context_.network_message_loop()); 142 context_.network_message_loop());
(...skipping 15 matching lines...) Expand all
168 if (client_.get()) { 158 if (client_.get()) {
169 // TODO(sergeyu): Should we disconnect asynchronously? 159 // TODO(sergeyu): Should we disconnect asynchronously?
170 base::WaitableEvent done_event(true, false); 160 base::WaitableEvent done_event(true, false);
171 client_->Stop(base::Bind(&base::WaitableEvent::Signal, 161 client_->Stop(base::Bind(&base::WaitableEvent::Signal,
172 base::Unretained(&done_event))); 162 base::Unretained(&done_event)));
173 done_event.Wait(); 163 done_event.Wait();
174 client_.reset(); 164 client_.reset();
175 } 165 }
176 166
177 input_handler_.reset(); 167 input_handler_.reset();
168 key_event_tracker_.reset();
169 mouse_input_filter_.reset();
178 host_connection_.reset(); 170 host_connection_.reset();
179 171
180 GetScriptableObject()->SetConnectionStatus( 172 GetScriptableObject()->SetConnectionStatus(
181 ChromotingScriptableObject::STATUS_CLOSED, 173 ChromotingScriptableObject::STATUS_CLOSED,
182 ChromotingScriptableObject::ERROR_NONE); 174 ChromotingScriptableObject::ERROR_NONE);
183 } 175 }
184 176
185 void ChromotingInstance::DidChangeView(const pp::Rect& position, 177 void ChromotingInstance::DidChangeView(const pp::Rect& position,
186 const pp::Rect& clip) { 178 const pp::Rect& clip) {
187 DCHECK(plugin_message_loop_->BelongsToCurrentThread()); 179 DCHECK(plugin_message_loop_->BelongsToCurrentThread());
188 180
189 view_->SetPluginSize(SkISize::Make(position.width(), position.height())); 181 SkISize new_size = SkISize::Make(position.width(), position.height());
190 182 if (view_->SetViewSize(new_size)) {
191 // TODO(wez): Pass the dimensions of the plugin to the RectangleDecoder 183 if (mouse_input_filter_.get()) {
192 // and let it generate the necessary refresh events. 184 mouse_input_filter_->set_input_size(new_size);
193 // If scale-to-fit is enabled then update the scaling ratios. 185 }
194 // We also force a full-frame refresh, in case the ratios changed. 186 rectangle_decoder_->SetOutputSize(new_size);
195 if (scale_to_fit_) {
196 rectangle_decoder_->SetScaleRatios(view_->GetHorizontalScaleRatio(),
197 view_->GetVerticalScaleRatio());
198 rectangle_decoder_->RefreshFullFrame();
199 } 187 }
200 188
201 // Notify the RectangleDecoder of the new clip rect.
202 rectangle_decoder_->UpdateClipRect( 189 rectangle_decoder_->UpdateClipRect(
203 SkIRect::MakeXYWH(clip.x(), clip.y(), clip.width(), clip.height())); 190 SkIRect::MakeXYWH(clip.x(), clip.y(), clip.width(), clip.height()));
204 } 191 }
205 192
206 bool ChromotingInstance::HandleInputEvent(const pp::InputEvent& event) { 193 bool ChromotingInstance::HandleInputEvent(const pp::InputEvent& event) {
207 DCHECK(plugin_message_loop_->BelongsToCurrentThread()); 194 DCHECK(plugin_message_loop_->BelongsToCurrentThread());
208 if (!input_handler_.get()) { 195
196 // Never inject events if the end of the input pipeline doesn't exist.
197 // If it does exist but the pipeline doesn't, construct a pipeline.
198 // TODO(wez): This is really ugly. We should create the pipeline when
199 // the ConnectionToHost's InputStub exists.
200 if (!host_connection_.get()) {
209 return false; 201 return false;
202 } else if (!input_handler_.get()) {
203 protocol::InputStub* input_stub = host_connection_->input_stub();
204 if (!input_stub)
205 return false;
206 mouse_input_filter_.reset(new MouseInputFilter(input_stub));
207 mouse_input_filter_->set_input_size(view_->get_view_size());
208 key_event_tracker_.reset(
209 new protocol::KeyEventTracker(mouse_input_filter_.get()));
210 input_handler_.reset(
211 new PepperInputHandler(key_event_tracker_.get()));
210 } 212 }
211 213
212 PepperInputHandler* pih 214 // TODO(wez): When we have a good hook into Host dimensions changes, move
213 = static_cast<PepperInputHandler*>(input_handler_.get()); 215 // this there.
216 mouse_input_filter_->set_output_size(view_->get_host_size());
214 217
215 switch (event.GetType()) { 218 return input_handler_->HandleInputEvent(event);
216 case PP_INPUTEVENT_TYPE_MOUSEDOWN: {
217 pih->HandleMouseButtonEvent(true, pp::MouseInputEvent(event));
218 return true;
219 }
220
221 case PP_INPUTEVENT_TYPE_MOUSEUP: {
222 pih->HandleMouseButtonEvent(false, pp::MouseInputEvent(event));
223 return true;
224 }
225
226 case PP_INPUTEVENT_TYPE_MOUSEMOVE:
227 case PP_INPUTEVENT_TYPE_MOUSEENTER:
228 case PP_INPUTEVENT_TYPE_MOUSELEAVE: {
229 pih->HandleMouseMoveEvent(pp::MouseInputEvent(event));
230 return true;
231 }
232
233 case PP_INPUTEVENT_TYPE_WHEEL: {
234 pih->HandleMouseWheelEvent(pp::WheelInputEvent(event));
235 return true;
236 }
237
238 case PP_INPUTEVENT_TYPE_CONTEXTMENU: {
239 // We need to return true here or else we'll get a local (plugin) context
240 // menu instead of the mouseup event for the right click.
241 return true;
242 }
243
244 case PP_INPUTEVENT_TYPE_KEYDOWN: {
245 pp::KeyboardInputEvent key = pp::KeyboardInputEvent(event);
246 VLOG(3) << "PP_INPUTEVENT_TYPE_KEYDOWN" << " key=" << key.GetKeyCode();
247 pih->HandleKeyEvent(true, key);
248 return true;
249 }
250
251 case PP_INPUTEVENT_TYPE_KEYUP: {
252 pp::KeyboardInputEvent key = pp::KeyboardInputEvent(event);
253 VLOG(3) << "PP_INPUTEVENT_TYPE_KEYUP" << " key=" << key.GetKeyCode();
254 pih->HandleKeyEvent(false, key);
255 return true;
256 }
257
258 case PP_INPUTEVENT_TYPE_CHAR: {
259 pih->HandleCharacterEvent(pp::KeyboardInputEvent(event));
260 return true;
261 }
262
263 default: {
264 LOG(INFO) << "Unhandled input event: " << event.GetType();
265 break;
266 }
267 }
268
269 return false;
270 } 219 }
271 220
272 ChromotingScriptableObject* ChromotingInstance::GetScriptableObject() { 221 ChromotingScriptableObject* ChromotingInstance::GetScriptableObject() {
273 pp::VarPrivate object = GetInstanceObject(); 222 pp::VarPrivate object = GetInstanceObject();
274 if (!object.is_undefined()) { 223 if (!object.is_undefined()) {
275 pp::deprecated::ScriptableObject* so = object.AsScriptableObject(); 224 pp::deprecated::ScriptableObject* so = object.AsScriptableObject();
276 DCHECK(so != NULL); 225 DCHECK(so != NULL);
277 return static_cast<ChromotingScriptableObject*>(so); 226 return static_cast<ChromotingScriptableObject*>(so);
278 } 227 }
279 LOG(ERROR) << "Unable to get ScriptableObject for Chromoting plugin."; 228 LOG(ERROR) << "Unable to get ScriptableObject for Chromoting plugin.";
280 return NULL; 229 return NULL;
281 } 230 }
282 231
283 void ChromotingInstance::SetScaleToFit(bool scale_to_fit) {
284 DCHECK(plugin_message_loop_->BelongsToCurrentThread());
285
286 if (scale_to_fit == scale_to_fit_)
287 return;
288
289 scale_to_fit_ = scale_to_fit;
290 if (scale_to_fit) {
291 rectangle_decoder_->SetScaleRatios(view_->GetHorizontalScaleRatio(),
292 view_->GetVerticalScaleRatio());
293 } else {
294 rectangle_decoder_->SetScaleRatios(1.0, 1.0);
295 }
296
297 // TODO(wez): The RectangleDecoder should generate refresh events
298 // as necessary in response to any scaling change.
299 rectangle_decoder_->RefreshFullFrame();
300 }
301
302 // static 232 // static
303 void ChromotingInstance::RegisterLogMessageHandler() { 233 void ChromotingInstance::RegisterLogMessageHandler() {
304 base::AutoLock lock(g_logging_lock.Get()); 234 base::AutoLock lock(g_logging_lock.Get());
305 235
306 VLOG(1) << "Registering global log handler"; 236 VLOG(1) << "Registering global log handler";
307 237
308 // Record previous handler so we can call it in a chain. 238 // Record previous handler so we can call it in a chain.
309 g_logging_old_handler = logging::GetLogMessageHandler(); 239 g_logging_old_handler = logging::GetLogMessageHandler();
310 240
311 // Set up log message handler. 241 // Set up log message handler.
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
396 return instance_object_; 326 return instance_object_;
397 } 327 }
398 328
399 ChromotingStats* ChromotingInstance::GetStats() { 329 ChromotingStats* ChromotingInstance::GetStats() {
400 if (!client_.get()) 330 if (!client_.get())
401 return NULL; 331 return NULL;
402 return client_->GetStats(); 332 return client_->GetStats();
403 } 333 }
404 334
405 void ChromotingInstance::ReleaseAllKeys() { 335 void ChromotingInstance::ReleaseAllKeys() {
406 if (!input_handler_.get()) { 336 if (key_event_tracker_.get()) {
407 return; 337 key_event_tracker_->ReleaseAllKeys();
408 } 338 }
409
410 input_handler_->ReleaseAllKeys();
411 } 339 }
412 340
413 } // namespace remoting 341 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698