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

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

Issue 23484015: Added support of relative mouse motion in Chromoting. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: feedback Created 7 years, 3 months 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) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 <algorithm>
7 #include <string> 8 #include <string>
8 #include <vector> 9 #include <vector>
9 10
10 #include "base/bind.h" 11 #include "base/bind.h"
11 #include "base/callback.h" 12 #include "base/callback.h"
12 #include "base/json/json_reader.h" 13 #include "base/json/json_reader.h"
13 #include "base/json/json_writer.h" 14 #include "base/json/json_writer.h"
14 #include "base/lazy_instance.h" 15 #include "base/lazy_instance.h"
15 #include "base/logging.h" 16 #include "base/logging.h"
16 #include "base/strings/string_split.h" 17 #include "base/strings/string_split.h"
17 #include "base/strings/stringprintf.h" 18 #include "base/strings/stringprintf.h"
18 #include "base/synchronization/lock.h" 19 #include "base/synchronization/lock.h"
19 #include "base/threading/thread.h" 20 #include "base/threading/thread.h"
20 #include "base/values.h" 21 #include "base/values.h"
21 #include "jingle/glue/thread_wrapper.h" 22 #include "jingle/glue/thread_wrapper.h"
22 #include "media/base/media.h" 23 #include "media/base/media.h"
23 #include "net/socket/ssl_server_socket.h" 24 #include "net/socket/ssl_server_socket.h"
24 #include "ppapi/cpp/completion_callback.h" 25 #include "ppapi/cpp/completion_callback.h"
25 #include "ppapi/cpp/dev/url_util_dev.h" 26 #include "ppapi/cpp/dev/url_util_dev.h"
27 #include "ppapi/cpp/image_data.h"
26 #include "ppapi/cpp/input_event.h" 28 #include "ppapi/cpp/input_event.h"
27 #include "ppapi/cpp/mouse_cursor.h"
28 #include "ppapi/cpp/rect.h" 29 #include "ppapi/cpp/rect.h"
29 #include "remoting/base/constants.h" 30 #include "remoting/base/constants.h"
30 #include "remoting/base/util.h" 31 #include "remoting/base/util.h"
31 #include "remoting/client/chromoting_client.h" 32 #include "remoting/client/chromoting_client.h"
32 #include "remoting/client/client_config.h" 33 #include "remoting/client/client_config.h"
33 #include "remoting/client/frame_consumer_proxy.h" 34 #include "remoting/client/frame_consumer_proxy.h"
34 #include "remoting/client/plugin/delegating_signal_strategy.h" 35 #include "remoting/client/plugin/delegating_signal_strategy.h"
35 #include "remoting/client/plugin/pepper_audio_player.h" 36 #include "remoting/client/plugin/pepper_audio_player.h"
36 #include "remoting/client/plugin/pepper_input_handler.h" 37 #include "remoting/client/plugin/pepper_input_handler.h"
37 #include "remoting/client/plugin/pepper_port_allocator.h" 38 #include "remoting/client/plugin/pepper_port_allocator.h"
(...skipping 10 matching lines...) Expand all
48 #undef PostMessage 49 #undef PostMessage
49 #endif 50 #endif
50 51
51 namespace remoting { 52 namespace remoting {
52 53
53 namespace { 54 namespace {
54 55
55 // 32-bit BGRA is 4 bytes per pixel. 56 // 32-bit BGRA is 4 bytes per pixel.
56 const int kBytesPerPixel = 4; 57 const int kBytesPerPixel = 4;
57 58
59 #if defined(ARCH_CPU_LITTLE_ENDIAN)
60 const uint32_t kPixelAlphaMask = 0xff000000;
61 #else // !defined(ARCH_CPU_LITTLE_ENDIAN)
62 const uint32_t kPixelAlphaMask = 0x000000ff;
63 #endif // !defined(ARCH_CPU_LITTLE_ENDIAN)
64
58 // Default DPI to assume for old clients that use notifyClientResolution. 65 // Default DPI to assume for old clients that use notifyClientResolution.
59 const int kDefaultDPI = 96; 66 const int kDefaultDPI = 96;
60 67
61 // Interval at which to sample performance statistics. 68 // Interval at which to sample performance statistics.
62 const int kPerfStatsIntervalMs = 1000; 69 const int kPerfStatsIntervalMs = 1000;
63 70
64 // URL scheme used by Chrome apps and extensions. 71 // URL scheme used by Chrome apps and extensions.
65 const char kChromeExtensionUrlScheme[] = "chrome-extension"; 72 const char kChromeExtensionUrlScheme[] = "chrome-extension";
66 73
67 // Maximum width and height of a mouse cursor supported by PPAPI. 74 // Maximum width and height of a mouse cursor supported by PPAPI.
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
118 case protocol::CHANNEL_CONNECTION_ERROR: 125 case protocol::CHANNEL_CONNECTION_ERROR:
119 case protocol::SIGNALING_ERROR: 126 case protocol::SIGNALING_ERROR:
120 case protocol::SIGNALING_TIMEOUT: 127 case protocol::SIGNALING_TIMEOUT:
121 case protocol::UNKNOWN_ERROR: 128 case protocol::UNKNOWN_ERROR:
122 return "NETWORK_FAILURE"; 129 return "NETWORK_FAILURE";
123 } 130 }
124 DLOG(FATAL) << "Unknown error code" << error; 131 DLOG(FATAL) << "Unknown error code" << error;
125 return std::string(); 132 return std::string();
126 } 133 }
127 134
135 // Returns true if |pixel| is not completely transparent.
136 bool IsVisiblePixel(uint32_t pixel) {
137 return (pixel & kPixelAlphaMask) != 0;
138 }
139
140 // Returns true if there is at least one visible pixel in the given range.
141 bool IsVisibleRow(const uint32_t* begin, const uint32_t* end) {
142 return std::find_if(begin, end, &IsVisiblePixel) != end;
143 }
144
128 // This flag blocks LOGs to the UI if we're already in the middle of logging 145 // This flag blocks LOGs to the UI if we're already in the middle of logging
129 // to the UI. This prevents a potential infinite loop if we encounter an error 146 // to the UI. This prevents a potential infinite loop if we encounter an error
130 // while sending the log message to the UI. 147 // while sending the log message to the UI.
131 bool g_logging_to_plugin = false; 148 bool g_logging_to_plugin = false;
132 bool g_has_logging_instance = false; 149 bool g_has_logging_instance = false;
133 base::LazyInstance<scoped_refptr<base::SingleThreadTaskRunner> >::Leaky 150 base::LazyInstance<scoped_refptr<base::SingleThreadTaskRunner> >::Leaky
134 g_logging_task_runner = LAZY_INSTANCE_INITIALIZER; 151 g_logging_task_runner = LAZY_INSTANCE_INITIALIZER;
135 base::LazyInstance<base::WeakPtr<ChromotingInstance> >::Leaky 152 base::LazyInstance<base::WeakPtr<ChromotingInstance> >::Leaky
136 g_logging_instance = LAZY_INSTANCE_INITIALIZER; 153 g_logging_instance = LAZY_INSTANCE_INITIALIZER;
137 base::LazyInstance<base::Lock>::Leaky 154 base::LazyInstance<base::Lock>::Leaky
138 g_logging_lock = LAZY_INSTANCE_INITIALIZER; 155 g_logging_lock = LAZY_INSTANCE_INITIALIZER;
139 logging::LogMessageHandlerFunction g_logging_old_handler = NULL; 156 logging::LogMessageHandlerFunction g_logging_old_handler = NULL;
140 157
141 } // namespace 158 } // namespace
142 159
143 // String sent in the "hello" message to the webapp to describe features. 160 // String sent in the "hello" message to the webapp to describe features.
144 const char ChromotingInstance::kApiFeatures[] = 161 const char ChromotingInstance::kApiFeatures[] =
145 "highQualityScaling injectKeyEvent sendClipboardItem remapKey trapKey " 162 "highQualityScaling injectKeyEvent sendClipboardItem remapKey trapKey "
146 "notifyClientResolution pauseVideo pauseAudio asyncPin thirdPartyAuth " 163 "notifyClientResolution pauseVideo pauseAudio asyncPin thirdPartyAuth "
147 "pinlessAuth extensionMessage"; 164 "pinlessAuth extensionMessage allowMouseLock";
148 165
149 const char ChromotingInstance::kRequestedCapabilities[] = ""; 166 const char ChromotingInstance::kRequestedCapabilities[] = "";
150 const char ChromotingInstance::kSupportedCapabilities[] = "desktopShape"; 167 const char ChromotingInstance::kSupportedCapabilities[] = "desktopShape";
151 168
152 bool ChromotingInstance::ParseAuthMethods(const std::string& auth_methods_str, 169 bool ChromotingInstance::ParseAuthMethods(const std::string& auth_methods_str,
153 ClientConfig* config) { 170 ClientConfig* config) {
154 std::vector<std::string> auth_methods; 171 std::vector<std::string> auth_methods;
155 base::SplitString(auth_methods_str, ',', &auth_methods); 172 base::SplitString(auth_methods_str, ',', &auth_methods);
156 for (std::vector<std::string>::iterator it = auth_methods.begin(); 173 for (std::vector<std::string>::iterator it = auth_methods.begin();
157 it != auth_methods.end(); ++it) { 174 it != auth_methods.end(); ++it) {
(...skipping 11 matching lines...) Expand all
169 } 186 }
170 187
171 ChromotingInstance::ChromotingInstance(PP_Instance pp_instance) 188 ChromotingInstance::ChromotingInstance(PP_Instance pp_instance)
172 : pp::Instance(pp_instance), 189 : pp::Instance(pp_instance),
173 initialized_(false), 190 initialized_(false),
174 plugin_task_runner_(new PluginThreadTaskRunner(&plugin_thread_delegate_)), 191 plugin_task_runner_(new PluginThreadTaskRunner(&plugin_thread_delegate_)),
175 context_(plugin_task_runner_.get()), 192 context_(plugin_task_runner_.get()),
176 input_tracker_(&mouse_input_filter_), 193 input_tracker_(&mouse_input_filter_),
177 key_mapper_(&input_tracker_), 194 key_mapper_(&input_tracker_),
178 normalizing_input_filter_(CreateNormalizingInputFilter(&key_mapper_)), 195 normalizing_input_filter_(CreateNormalizingInputFilter(&key_mapper_)),
179 input_handler_(normalizing_input_filter_.get()), 196 input_handler_(this, normalizing_input_filter_.get()),
180 use_async_pin_dialog_(false), 197 use_async_pin_dialog_(false),
181 weak_factory_(this) { 198 weak_factory_(this) {
182 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_WHEEL); 199 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_WHEEL);
183 RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD); 200 RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD);
184 201
185 // Resister this instance to handle debug log messsages. 202 // Resister this instance to handle debug log messsages.
186 RegisterLoggingInstance(); 203 RegisterLoggingInstance();
187 204
188 // Send hello message. 205 // Send hello message.
189 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); 206 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue());
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
297 } else if (method == "useAsyncPinDialog") { 314 } else if (method == "useAsyncPinDialog") {
298 use_async_pin_dialog_ = true; 315 use_async_pin_dialog_ = true;
299 } else if (method == "onPinFetched") { 316 } else if (method == "onPinFetched") {
300 HandleOnPinFetched(*data); 317 HandleOnPinFetched(*data);
301 } else if (method == "onThirdPartyTokenFetched") { 318 } else if (method == "onThirdPartyTokenFetched") {
302 HandleOnThirdPartyTokenFetched(*data); 319 HandleOnThirdPartyTokenFetched(*data);
303 } else if (method == "requestPairing") { 320 } else if (method == "requestPairing") {
304 HandleRequestPairing(*data); 321 HandleRequestPairing(*data);
305 } else if (method == "extensionMessage") { 322 } else if (method == "extensionMessage") {
306 HandleExtensionMessage(*data); 323 HandleExtensionMessage(*data);
324 } else if (method == "allowMouseLock") {
325 HandleAllowMouseLockMessage();
307 } 326 }
308 } 327 }
309 328
329 void ChromotingInstance::DidChangeFocus(bool has_focus) {
330 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
331
332 input_handler_.DidChangeFocus(has_focus);
333 }
334
310 void ChromotingInstance::DidChangeView(const pp::View& view) { 335 void ChromotingInstance::DidChangeView(const pp::View& view) {
311 DCHECK(plugin_task_runner_->BelongsToCurrentThread()); 336 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
312 337
313 plugin_view_ = view; 338 plugin_view_ = view;
314 if (view_) { 339 if (view_) {
315 view_->SetView(view); 340 view_->SetView(view);
316 mouse_input_filter_.set_input_size(view_->get_view_size_dips()); 341 mouse_input_filter_.set_input_size(view_->get_view_size_dips());
317 } 342 }
318 } 343 }
319 344
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
457 void ChromotingInstance::InjectClipboardEvent( 482 void ChromotingInstance::InjectClipboardEvent(
458 const protocol::ClipboardEvent& event) { 483 const protocol::ClipboardEvent& event) {
459 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); 484 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue());
460 data->SetString("mimeType", event.mime_type()); 485 data->SetString("mimeType", event.mime_type());
461 data->SetString("item", event.data()); 486 data->SetString("item", event.data());
462 PostChromotingMessage("injectClipboardItem", data.Pass()); 487 PostChromotingMessage("injectClipboardItem", data.Pass());
463 } 488 }
464 489
465 void ChromotingInstance::SetCursorShape( 490 void ChromotingInstance::SetCursorShape(
466 const protocol::CursorShapeInfo& cursor_shape) { 491 const protocol::CursorShapeInfo& cursor_shape) {
492 COMPILE_ASSERT(sizeof(uint32_t) == kBytesPerPixel, rgba_pixels_are_32bit);
493
467 if (!cursor_shape.has_data() || 494 if (!cursor_shape.has_data() ||
468 !cursor_shape.has_width() || 495 !cursor_shape.has_width() ||
469 !cursor_shape.has_height() || 496 !cursor_shape.has_height() ||
470 !cursor_shape.has_hotspot_x() || 497 !cursor_shape.has_hotspot_x() ||
471 !cursor_shape.has_hotspot_y()) { 498 !cursor_shape.has_hotspot_y()) {
472 return; 499 return;
473 } 500 }
474 501
475 int width = cursor_shape.width(); 502 int width = cursor_shape.width();
476 int height = cursor_shape.height(); 503 int height = cursor_shape.height();
(...skipping 16 matching lines...) Expand all
493 } 520 }
494 521
495 if (pp::ImageData::GetNativeImageDataFormat() != 522 if (pp::ImageData::GetNativeImageDataFormat() !=
496 PP_IMAGEDATAFORMAT_BGRA_PREMUL) { 523 PP_IMAGEDATAFORMAT_BGRA_PREMUL) {
497 VLOG(2) << "Unable to set cursor shape - non-native image format"; 524 VLOG(2) << "Unable to set cursor shape - non-native image format";
498 return; 525 return;
499 } 526 }
500 527
501 int hotspot_x = cursor_shape.hotspot_x(); 528 int hotspot_x = cursor_shape.hotspot_x();
502 int hotspot_y = cursor_shape.hotspot_y(); 529 int hotspot_y = cursor_shape.hotspot_y();
530 int bytes_per_row = width * kBytesPerPixel;
531 int src_stride = width;
532 const uint32_t* src_row_data = reinterpret_cast<const uint32_t*>(
533 cursor_shape.data().data());
534 const uint32_t* src_row_data_end = src_row_data + src_stride * height;
503 535
504 int bytes_per_row = width * kBytesPerPixel; 536 scoped_ptr<pp::ImageData> cursor_image;
505 const uint8* src_row_data = reinterpret_cast<const uint8*>( 537 pp::Point cursor_hotspot;
506 cursor_shape.data().data());
507 int stride = bytes_per_row;
508 538
509 // If the cursor exceeds the size permitted by PPAPI then crop it, keeping 539 // Check if the cursor is visible.
510 // the hotspot as close to the center of the new cursor shape as possible. 540 if (IsVisibleRow(src_row_data, src_row_data_end)) {
511 if (height > kMaxCursorHeight) { 541 // If the cursor exceeds the size permitted by PPAPI then crop it, keeping
512 int y = hotspot_y - (kMaxCursorHeight / 2); 542 // the hotspot as close to the center of the new cursor shape as possible.
513 y = std::max(y, 0); 543 if (height > kMaxCursorHeight) {
514 y = std::min(y, height - kMaxCursorHeight); 544 int y = hotspot_y - (kMaxCursorHeight / 2);
545 y = std::max(y, 0);
546 y = std::min(y, height - kMaxCursorHeight);
515 547
516 src_row_data += stride * y; 548 src_row_data += src_stride * y;
517 height = kMaxCursorHeight; 549 height = kMaxCursorHeight;
518 hotspot_y -= y; 550 hotspot_y -= y;
519 } 551 }
520 if (width > kMaxCursorWidth) { 552 if (width > kMaxCursorWidth) {
521 int x = hotspot_x - (kMaxCursorWidth / 2); 553 int x = hotspot_x - (kMaxCursorWidth / 2);
522 x = std::max(x, 0); 554 x = std::max(x, 0);
523 x = std::min(x, height - kMaxCursorWidth); 555 x = std::min(x, height - kMaxCursorWidth);
524 556
525 src_row_data += x * kBytesPerPixel; 557 src_row_data += x;
526 width = kMaxCursorWidth; 558 width = kMaxCursorWidth;
527 bytes_per_row = width * kBytesPerPixel; 559 bytes_per_row = width * kBytesPerPixel;
528 hotspot_x -= x; 560 hotspot_x -= x;
561 }
562
563 cursor_image.reset(new pp::ImageData(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
564 pp::Size(width, height), false));
565 cursor_hotspot = pp::Point(hotspot_x, hotspot_y);
566
567 uint8* dst_row_data = reinterpret_cast<uint8*>(cursor_image->data());
568 for (int row = 0; row < height; row++) {
569 memcpy(dst_row_data, src_row_data, bytes_per_row);
570 src_row_data += src_stride;
571 dst_row_data += cursor_image->stride();
572 }
529 } 573 }
530 574
531 pp::ImageData cursor_image(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL, 575 input_handler_.SetMouseCursor(cursor_image.Pass(), cursor_hotspot);
532 pp::Size(width, height), false);
533
534 uint8* dst_row_data = reinterpret_cast<uint8*>(cursor_image.data());
535 for (int row = 0; row < height; row++) {
536 memcpy(dst_row_data, src_row_data, bytes_per_row);
537 src_row_data += stride;
538 dst_row_data += cursor_image.stride();
539 }
540
541 pp::MouseCursor::SetCursor(this, PP_MOUSECURSOR_TYPE_CUSTOM,
542 cursor_image,
543 pp::Point(hotspot_x, hotspot_y));
544 } 576 }
545 577
546 void ChromotingInstance::OnFirstFrameReceived() { 578 void ChromotingInstance::OnFirstFrameReceived() {
547 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); 579 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue());
548 PostChromotingMessage("onFirstFrameReceived", data.Pass()); 580 PostChromotingMessage("onFirstFrameReceived", data.Pass());
549 } 581 }
550 582
551 void ChromotingInstance::HandleConnect(const base::DictionaryValue& data) { 583 void ChromotingInstance::HandleConnect(const base::DictionaryValue& data) {
552 ClientConfig config; 584 ClientConfig config;
553 std::string local_jid; 585 std::string local_jid;
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after
853 } 885 }
854 if (!IsConnected()) { 886 if (!IsConnected()) {
855 return; 887 return;
856 } 888 }
857 protocol::ExtensionMessage message; 889 protocol::ExtensionMessage message;
858 message.set_type(type); 890 message.set_type(type);
859 message.set_data(message_data); 891 message.set_data(message_data);
860 host_connection_->host_stub()->DeliverClientMessage(message); 892 host_connection_->host_stub()->DeliverClientMessage(message);
861 } 893 }
862 894
895 void ChromotingInstance::HandleAllowMouseLockMessage() {
896 input_handler_.AllowMouseLock();
897 }
898
863 ChromotingStats* ChromotingInstance::GetStats() { 899 ChromotingStats* ChromotingInstance::GetStats() {
864 if (!client_.get()) 900 if (!client_.get())
865 return NULL; 901 return NULL;
866 return client_->GetStats(); 902 return client_->GetStats();
867 } 903 }
868 904
869 void ChromotingInstance::PostChromotingMessage( 905 void ChromotingInstance::PostChromotingMessage(
870 const std::string& method, 906 const std::string& method,
871 scoped_ptr<base::DictionaryValue> data) { 907 scoped_ptr<base::DictionaryValue> data) {
872 scoped_ptr<base::DictionaryValue> message(new base::DictionaryValue()); 908 scoped_ptr<base::DictionaryValue> message(new base::DictionaryValue());
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
1030 url_components.scheme.len); 1066 url_components.scheme.len);
1031 return url_scheme == kChromeExtensionUrlScheme; 1067 return url_scheme == kChromeExtensionUrlScheme;
1032 } 1068 }
1033 1069
1034 bool ChromotingInstance::IsConnected() { 1070 bool ChromotingInstance::IsConnected() {
1035 return host_connection_.get() && 1071 return host_connection_.get() &&
1036 (host_connection_->state() == protocol::ConnectionToHost::CONNECTED); 1072 (host_connection_->state() == protocol::ConnectionToHost::CONNECTED);
1037 } 1073 }
1038 1074
1039 } // namespace remoting 1075 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698