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

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: 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"
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
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 |pixel| is not completely transparent.
Wez 2013/09/05 20:24:45 nit: "... true if ..."
alexeypa (please no reviews) 2013/09/06 20:00:17 Done.
136 bool IsVisiblePixel(uint32_t pixel) {
137 return (pixel & kPixelAlphaMask) != 0;
138 }
139
128 // This flag blocks LOGs to the UI if we're already in the middle of logging 140 // 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 141 // to the UI. This prevents a potential infinite loop if we encounter an error
130 // while sending the log message to the UI. 142 // while sending the log message to the UI.
131 bool g_logging_to_plugin = false; 143 bool g_logging_to_plugin = false;
132 bool g_has_logging_instance = false; 144 bool g_has_logging_instance = false;
133 base::LazyInstance<scoped_refptr<base::SingleThreadTaskRunner> >::Leaky 145 base::LazyInstance<scoped_refptr<base::SingleThreadTaskRunner> >::Leaky
134 g_logging_task_runner = LAZY_INSTANCE_INITIALIZER; 146 g_logging_task_runner = LAZY_INSTANCE_INITIALIZER;
135 base::LazyInstance<base::WeakPtr<ChromotingInstance> >::Leaky 147 base::LazyInstance<base::WeakPtr<ChromotingInstance> >::Leaky
136 g_logging_instance = LAZY_INSTANCE_INITIALIZER; 148 g_logging_instance = LAZY_INSTANCE_INITIALIZER;
137 base::LazyInstance<base::Lock>::Leaky 149 base::LazyInstance<base::Lock>::Leaky
138 g_logging_lock = LAZY_INSTANCE_INITIALIZER; 150 g_logging_lock = LAZY_INSTANCE_INITIALIZER;
139 logging::LogMessageHandlerFunction g_logging_old_handler = NULL; 151 logging::LogMessageHandlerFunction g_logging_old_handler = NULL;
140 152
141 } // namespace 153 } // namespace
142 154
143 // String sent in the "hello" message to the webapp to describe features. 155 // String sent in the "hello" message to the webapp to describe features.
144 const char ChromotingInstance::kApiFeatures[] = 156 const char ChromotingInstance::kApiFeatures[] =
145 "highQualityScaling injectKeyEvent sendClipboardItem remapKey trapKey " 157 "highQualityScaling injectKeyEvent sendClipboardItem remapKey trapKey "
146 "notifyClientResolution pauseVideo pauseAudio asyncPin thirdPartyAuth " 158 "notifyClientResolution pauseVideo pauseAudio asyncPin thirdPartyAuth "
147 "pinlessAuth extensionMessage"; 159 "pinlessAuth extensionMessage allowMouseLock";
148 160
149 const char ChromotingInstance::kRequestedCapabilities[] = ""; 161 const char ChromotingInstance::kRequestedCapabilities[] = "";
150 const char ChromotingInstance::kSupportedCapabilities[] = "desktopShape"; 162 const char ChromotingInstance::kSupportedCapabilities[] = "desktopShape";
151 163
152 bool ChromotingInstance::ParseAuthMethods(const std::string& auth_methods_str, 164 bool ChromotingInstance::ParseAuthMethods(const std::string& auth_methods_str,
153 ClientConfig* config) { 165 ClientConfig* config) {
154 std::vector<std::string> auth_methods; 166 std::vector<std::string> auth_methods;
155 base::SplitString(auth_methods_str, ',', &auth_methods); 167 base::SplitString(auth_methods_str, ',', &auth_methods);
156 for (std::vector<std::string>::iterator it = auth_methods.begin(); 168 for (std::vector<std::string>::iterator it = auth_methods.begin();
157 it != auth_methods.end(); ++it) { 169 it != auth_methods.end(); ++it) {
158 protocol::AuthenticationMethod authentication_method = 170 protocol::AuthenticationMethod authentication_method =
159 protocol::AuthenticationMethod::FromString(*it); 171 protocol::AuthenticationMethod::FromString(*it);
160 if (authentication_method.is_valid()) 172 if (authentication_method.is_valid())
161 config->authentication_methods.push_back(authentication_method); 173 config->authentication_methods.push_back(authentication_method);
162 } 174 }
163 if (config->authentication_methods.empty()) { 175 if (config->authentication_methods.empty()) {
164 LOG(ERROR) << "No valid authentication methods specified."; 176 LOG(ERROR) << "No valid authentication methods specified.";
165 return false; 177 return false;
166 } 178 }
167 179
168 return true; 180 return true;
169 } 181 }
170 182
171 ChromotingInstance::ChromotingInstance(PP_Instance pp_instance) 183 ChromotingInstance::ChromotingInstance(PP_Instance pp_instance)
172 : pp::Instance(pp_instance), 184 : pp::Instance(pp_instance),
185 pp::MouseLock(this),
173 initialized_(false), 186 initialized_(false),
174 plugin_task_runner_(new PluginThreadTaskRunner(&plugin_thread_delegate_)), 187 plugin_task_runner_(new PluginThreadTaskRunner(&plugin_thread_delegate_)),
175 context_(plugin_task_runner_.get()), 188 context_(plugin_task_runner_.get()),
189 focused_(false),
190 mouse_lock_state_(MouseLockDisabled),
176 input_tracker_(&mouse_input_filter_), 191 input_tracker_(&mouse_input_filter_),
177 key_mapper_(&input_tracker_), 192 key_mapper_(&input_tracker_),
178 normalizing_input_filter_(CreateNormalizingInputFilter(&key_mapper_)), 193 normalizing_input_filter_(CreateNormalizingInputFilter(&key_mapper_)),
179 input_handler_(normalizing_input_filter_.get()), 194 input_handler_(normalizing_input_filter_.get()),
180 use_async_pin_dialog_(false), 195 use_async_pin_dialog_(false),
196 callback_factory_(this),
181 weak_factory_(this) { 197 weak_factory_(this) {
182 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_WHEEL); 198 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_WHEEL);
183 RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD); 199 RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD);
184 200
185 // Resister this instance to handle debug log messsages. 201 // Resister this instance to handle debug log messsages.
186 RegisterLoggingInstance(); 202 RegisterLoggingInstance();
187 203
188 // Send hello message. 204 // Send hello message.
189 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); 205 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue());
190 data->SetInteger("apiVersion", kApiVersion); 206 data->SetInteger("apiVersion", kApiVersion);
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
297 } else if (method == "useAsyncPinDialog") { 313 } else if (method == "useAsyncPinDialog") {
298 use_async_pin_dialog_ = true; 314 use_async_pin_dialog_ = true;
299 } else if (method == "onPinFetched") { 315 } else if (method == "onPinFetched") {
300 HandleOnPinFetched(*data); 316 HandleOnPinFetched(*data);
301 } else if (method == "onThirdPartyTokenFetched") { 317 } else if (method == "onThirdPartyTokenFetched") {
302 HandleOnThirdPartyTokenFetched(*data); 318 HandleOnThirdPartyTokenFetched(*data);
303 } else if (method == "requestPairing") { 319 } else if (method == "requestPairing") {
304 HandleRequestPairing(*data); 320 HandleRequestPairing(*data);
305 } else if (method == "extensionMessage") { 321 } else if (method == "extensionMessage") {
306 HandleExtensionMessage(*data); 322 HandleExtensionMessage(*data);
323 } else if (method == "allowMouseLock") {
324 HandleAllowMouseLockMessage();
307 } 325 }
308 } 326 }
309 327
328 void ChromotingInstance::DidChangeFocus(bool has_focus) {
329 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
330
331 focused_ = has_focus;
332 RequestMouseLock();
Wez 2013/09/05 20:24:45 nit: It looks strange to call RequestMouseLock() i
alexeypa (please no reviews) 2013/09/06 20:00:17 RequestMouseLock() checks whether the plugin is fo
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
320 bool ChromotingInstance::HandleInputEvent(const pp::InputEvent& event) { 345 bool ChromotingInstance::HandleInputEvent(const pp::InputEvent& event) {
321 DCHECK(plugin_task_runner_->BelongsToCurrentThread()); 346 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
322 347
323 if (!IsConnected()) 348 if (!IsConnected())
324 return false; 349 return false;
325 350
326 return input_handler_.HandleInputEvent(event); 351 return input_handler_.HandleInputEvent(event,
352 mouse_lock_state_ == MouseLockOn);
353 }
354
355 void ChromotingInstance::MouseLockLost() {
356 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
357 DCHECK(mouse_lock_state_ == MouseLockOn ||
358 mouse_lock_state_ == MouseLockCancelling);
359
360 mouse_lock_state_ = MouseLockOff;
361 EnableMousePointer();
327 } 362 }
328 363
329 void ChromotingInstance::SetDesktopSize(const SkISize& size, 364 void ChromotingInstance::SetDesktopSize(const SkISize& size,
330 const SkIPoint& dpi) { 365 const SkIPoint& dpi) {
331 mouse_input_filter_.set_output_size(size); 366 mouse_input_filter_.set_output_size(size);
332 367
333 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); 368 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue());
334 data->SetInteger("width", size.width()); 369 data->SetInteger("width", size.width());
335 data->SetInteger("height", size.height()); 370 data->SetInteger("height", size.height());
336 if (dpi.x()) 371 if (dpi.x())
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
457 void ChromotingInstance::InjectClipboardEvent( 492 void ChromotingInstance::InjectClipboardEvent(
458 const protocol::ClipboardEvent& event) { 493 const protocol::ClipboardEvent& event) {
459 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); 494 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue());
460 data->SetString("mimeType", event.mime_type()); 495 data->SetString("mimeType", event.mime_type());
461 data->SetString("item", event.data()); 496 data->SetString("item", event.data());
462 PostChromotingMessage("injectClipboardItem", data.Pass()); 497 PostChromotingMessage("injectClipboardItem", data.Pass());
463 } 498 }
464 499
465 void ChromotingInstance::SetCursorShape( 500 void ChromotingInstance::SetCursorShape(
466 const protocol::CursorShapeInfo& cursor_shape) { 501 const protocol::CursorShapeInfo& cursor_shape) {
502 COMPILE_ASSERT(sizeof(uint32_t) == kBytesPerPixel, rgba_pixels_are_32bit);
503
467 if (!cursor_shape.has_data() || 504 if (!cursor_shape.has_data() ||
468 !cursor_shape.has_width() || 505 !cursor_shape.has_width() ||
469 !cursor_shape.has_height() || 506 !cursor_shape.has_height() ||
470 !cursor_shape.has_hotspot_x() || 507 !cursor_shape.has_hotspot_x() ||
471 !cursor_shape.has_hotspot_y()) { 508 !cursor_shape.has_hotspot_y()) {
472 return; 509 return;
473 } 510 }
474 511
475 int width = cursor_shape.width(); 512 int width = cursor_shape.width();
476 int height = cursor_shape.height(); 513 int height = cursor_shape.height();
(...skipping 16 matching lines...) Expand all
493 } 530 }
494 531
495 if (pp::ImageData::GetNativeImageDataFormat() != 532 if (pp::ImageData::GetNativeImageDataFormat() !=
496 PP_IMAGEDATAFORMAT_BGRA_PREMUL) { 533 PP_IMAGEDATAFORMAT_BGRA_PREMUL) {
497 VLOG(2) << "Unable to set cursor shape - non-native image format"; 534 VLOG(2) << "Unable to set cursor shape - non-native image format";
498 return; 535 return;
499 } 536 }
500 537
501 int hotspot_x = cursor_shape.hotspot_x(); 538 int hotspot_x = cursor_shape.hotspot_x();
502 int hotspot_y = cursor_shape.hotspot_y(); 539 int hotspot_y = cursor_shape.hotspot_y();
540 int bytes_per_row = width * kBytesPerPixel;
541 int src_stride = width;
542 const uint32_t* src_row_data = reinterpret_cast<const uint32_t*>(
543 cursor_shape.data().data());
544 const uint32_t* src_row_data_end = src_row_data + src_stride * height;
503 545
504 int bytes_per_row = width * kBytesPerPixel; 546 // See if the cursor image completely consists of transparent pixels.
Wez 2013/09/05 20:24:45 nit: consists completely
alexeypa (please no reviews) 2013/09/06 20:00:17 Done.
505 const uint8* src_row_data = reinterpret_cast<const uint8*>( 547 bool mouse_lock_requested = (mouse_lock_state_ != MouseLockDisabled) &&
506 cursor_shape.data().data()); 548 (std::find_if(src_row_data,
507 int stride = bytes_per_row; 549 src_row_data_end,
550 &IsVisiblePixel) == src_row_data_end);
Wez 2013/09/05 20:24:45 nit: Move this find_if() into an IsVisibleRow() he
alexeypa (please no reviews) 2013/09/06 20:00:17 Done.
551 if (mouse_lock_requested) {
552 // Request mouse lock.
553 cursor_image_.reset();
554 RequestMouseLock();
555 } else {
556 // If the cursor exceeds the size permitted by PPAPI then crop it, keeping
557 // the hotspot as close to the center of the new cursor shape as possible.
Wez 2013/09/05 20:24:45 Nit, can we move this crop logic into a CropCursor
alexeypa (please no reviews) 2013/09/06 20:00:17 Not sure. This code updates a bunch of local varia
558 if (height > kMaxCursorHeight) {
559 int y = hotspot_y - (kMaxCursorHeight / 2);
560 y = std::max(y, 0);
561 y = std::min(y, height - kMaxCursorHeight);
508 562
509 // If the cursor exceeds the size permitted by PPAPI then crop it, keeping 563 src_row_data += src_stride * y;
510 // the hotspot as close to the center of the new cursor shape as possible. 564 height = kMaxCursorHeight;
511 if (height > kMaxCursorHeight) { 565 hotspot_y -= y;
512 int y = hotspot_y - (kMaxCursorHeight / 2); 566 }
513 y = std::max(y, 0); 567 if (width > kMaxCursorWidth) {
514 y = std::min(y, height - kMaxCursorHeight); 568 int x = hotspot_x - (kMaxCursorWidth / 2);
569 x = std::max(x, 0);
570 x = std::min(x, height - kMaxCursorWidth);
515 571
516 src_row_data += stride * y; 572 src_row_data += x;
517 height = kMaxCursorHeight; 573 width = kMaxCursorWidth;
518 hotspot_y -= y; 574 bytes_per_row = width * kBytesPerPixel;
575 hotspot_x -= x;
576 }
577
578 cursor_image_.reset(new pp::ImageData(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
579 pp::Size(width, height), false));
580 cursor_hotspot_ = pp::Point(hotspot_x, hotspot_y);
581
582 uint8* dst_row_data = reinterpret_cast<uint8*>(cursor_image_->data());
583 for (int row = 0; row < height; row++) {
584 memcpy(dst_row_data, src_row_data, bytes_per_row);
585 src_row_data += src_stride;
586 dst_row_data += cursor_image_->stride();
587 }
588
589 // Cancel mouse lock if any and apply the new cursor image.
Wez 2013/09/05 20:24:45 nit: if any and -> if active, and
alexeypa (please no reviews) 2013/09/06 20:00:17 Done.
590 CancelMouseLock();
519 } 591 }
520 if (width > kMaxCursorWidth) {
521 int x = hotspot_x - (kMaxCursorWidth / 2);
522 x = std::max(x, 0);
523 x = std::min(x, height - kMaxCursorWidth);
524
525 src_row_data += x * kBytesPerPixel;
526 width = kMaxCursorWidth;
527 bytes_per_row = width * kBytesPerPixel;
528 hotspot_x -= x;
529 }
530
531 pp::ImageData cursor_image(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
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 } 592 }
545 593
546 void ChromotingInstance::OnFirstFrameReceived() { 594 void ChromotingInstance::OnFirstFrameReceived() {
547 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); 595 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue());
548 PostChromotingMessage("onFirstFrameReceived", data.Pass()); 596 PostChromotingMessage("onFirstFrameReceived", data.Pass());
549 } 597 }
550 598
551 void ChromotingInstance::HandleConnect(const base::DictionaryValue& data) { 599 void ChromotingInstance::HandleConnect(const base::DictionaryValue& data) {
552 ClientConfig config; 600 ClientConfig config;
553 std::string local_jid; 601 std::string local_jid;
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after
853 } 901 }
854 if (!IsConnected()) { 902 if (!IsConnected()) {
855 return; 903 return;
856 } 904 }
857 protocol::ExtensionMessage message; 905 protocol::ExtensionMessage message;
858 message.set_type(type); 906 message.set_type(type);
859 message.set_data(message_data); 907 message.set_data(message_data);
860 host_connection_->host_stub()->DeliverClientMessage(message); 908 host_connection_->host_stub()->DeliverClientMessage(message);
861 } 909 }
862 910
911 void ChromotingInstance::HandleAllowMouseLockMessage() {
912 DCHECK_EQ(mouse_lock_state_, MouseLockDisabled);
913 mouse_lock_state_ = MouseLockOff;
914 }
915
863 ChromotingStats* ChromotingInstance::GetStats() { 916 ChromotingStats* ChromotingInstance::GetStats() {
864 if (!client_.get()) 917 if (!client_.get())
865 return NULL; 918 return NULL;
866 return client_->GetStats(); 919 return client_->GetStats();
867 } 920 }
868 921
869 void ChromotingInstance::PostChromotingMessage( 922 void ChromotingInstance::PostChromotingMessage(
870 const std::string& method, 923 const std::string& method,
871 scoped_ptr<base::DictionaryValue> data) { 924 scoped_ptr<base::DictionaryValue> data) {
872 scoped_ptr<base::DictionaryValue> message(new base::DictionaryValue()); 925 scoped_ptr<base::DictionaryValue> message(new base::DictionaryValue());
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after
1029 std::string url_scheme = url.substr(url_components.scheme.begin, 1082 std::string url_scheme = url.substr(url_components.scheme.begin,
1030 url_components.scheme.len); 1083 url_components.scheme.len);
1031 return url_scheme == kChromeExtensionUrlScheme; 1084 return url_scheme == kChromeExtensionUrlScheme;
1032 } 1085 }
1033 1086
1034 bool ChromotingInstance::IsConnected() { 1087 bool ChromotingInstance::IsConnected() {
1035 return host_connection_.get() && 1088 return host_connection_.get() &&
1036 (host_connection_->state() == protocol::ConnectionToHost::CONNECTED); 1089 (host_connection_->state() == protocol::ConnectionToHost::CONNECTED);
1037 } 1090 }
1038 1091
1092 void ChromotingInstance::EnableMousePointer() {
Wez 2013/09/05 20:24:45 This name doesn't feel right; you're setting the c
alexeypa (please no reviews) 2013/09/06 20:00:17 Done.
1093 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
1094 DCHECK(mouse_lock_state_ == MouseLockDisabled ||
1095 mouse_lock_state_ == MouseLockOff);
1096
1097 if (cursor_image_) {
1098 pp::MouseCursor::SetCursor(this, PP_MOUSECURSOR_TYPE_CUSTOM,
1099 *cursor_image_,
1100 cursor_hotspot_);
1101 } else {
1102 // THe browser cancelled mouse lock but we don't have a cursor to show. Use
1103 // the standard arrow pointer instead.
Wez 2013/09/05 20:24:45 Will we also be in this state if the host never se
alexeypa (please no reviews) 2013/09/06 20:00:17 Done.
1104 pp::MouseCursor::SetCursor(this, PP_MOUSECURSOR_TYPE_POINTER);
1105 }
1106 }
1107
1108 void ChromotingInstance::RequestMouseLock() {
1109 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
1110
1111 // Request mouse lock if the plugin is focused, mouse lock requested by
Wez 2013/09/05 20:24:45 nit: lock if -> lock only if
alexeypa (please no reviews) 2013/09/06 20:00:17 Done.
1112 // the host and no callback is pending.
Wez 2013/09/05 20:24:45 nit: mouse lock requested by the host -> the host-
alexeypa (please no reviews) 2013/09/06 20:00:17 Done.
1113 if (focused_ && !cursor_image_ && mouse_lock_state_ == MouseLockOff) {
Wez 2013/09/05 20:24:45 nit: I think this function would be more readable
alexeypa (please no reviews) 2013/09/06 20:00:17 Six lines instead of one? I don't think so.
1114 pp::CompletionCallback callback =
1115 callback_factory_.NewCallback(&ChromotingInstance::OnMouseLocked);
1116 int result = pp::MouseLock::LockMouse(callback);
1117 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING);
1118
1119 // Hide the cursor to workaround http://crbug.com/285809.
Wez 2013/09/05 20:24:45 nit: Suggest: "Hide cursor to avoid it becoming a
alexeypa (please no reviews) 2013/09/06 20:00:17 Done.
1120 pp::MouseCursor::SetCursor(this, PP_MOUSECURSOR_TYPE_NONE);
1121 mouse_lock_state_ = MouseLockPending;
Wez 2013/09/05 20:24:45 nit: Since the comment "Hide the cursor" doesn't a
alexeypa (please no reviews) 2013/09/06 20:00:17 Done.
1122 }
1123 }
1124
1125 void ChromotingInstance::CancelMouseLock() {
1126 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
1127
1128 switch (mouse_lock_state_) {
1129 case MouseLockDisabled:
1130 case MouseLockOff:
1131 EnableMousePointer();
1132 break;
1133
1134 case MouseLockCancelling:
1135 break;
1136
1137 case MouseLockPending:
1138 // Let the callback know that the operation should be cancelled.
Wez 2013/09/05 20:24:45 nit: Clarify here that we can't call UnlockMouse()
alexeypa (please no reviews) 2013/09/06 20:00:17 Done.
1139 mouse_lock_state_ = MouseLockCancelling;
1140 break;
1141
1142 case MouseLockOn:
1143 pp::MouseLock::UnlockMouse();
1144
1145 // Wait until MouseLockLost() is called.
Wez 2013/09/05 20:24:45 nit: Suggest "Note that mouse-lock has been cancel
alexeypa (please no reviews) 2013/09/06 20:00:17 Done.
1146 mouse_lock_state_ = MouseLockCancelling;
1147 break;
1148
1149 default:
1150 NOTREACHED();
1151 }
1152 }
1153
1154 void ChromotingInstance::OnMouseLocked(int error) {
1155 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
1156 DCHECK(mouse_lock_state_ == MouseLockPending ||
1157 mouse_lock_state_ == MouseLockCancelling);
1158
1159 bool cancel = (mouse_lock_state_ == MouseLockCancelling);
Wez 2013/09/05 20:24:45 nit: cancel -> should_cancel?
alexeypa (please no reviews) 2013/09/06 20:00:17 Done.
1160
1161 // See if the operation succeeded.
1162 if (error == PP_OK) {
1163 mouse_lock_state_ = MouseLockOn;
1164 } else {
1165 mouse_lock_state_ = MouseLockOff;
1166 EnableMousePointer();
1167 }
1168
1169 // Cancel as needed.
1170 if (cancel)
1171 CancelMouseLock();
Wez 2013/09/05 20:24:45 So we can't dispatch the mouse-lock cancel until a
alexeypa (please no reviews) 2013/09/06 20:00:17 I don't know. I implemented it this way because th
1172 }
1173
1039 } // namespace remoting 1174 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698