Index: remoting/client/plugin/chromoting_instance.cc |
diff --git a/remoting/client/plugin/chromoting_instance.cc b/remoting/client/plugin/chromoting_instance.cc |
index 37bceee87bf26631c5e5b5735bff033fb6cd9594..3532b9a205d7732261725a495cab44be7770e829 100644 |
--- a/remoting/client/plugin/chromoting_instance.cc |
+++ b/remoting/client/plugin/chromoting_instance.cc |
@@ -4,6 +4,7 @@ |
#include "remoting/client/plugin/chromoting_instance.h" |
+#include <algorithm> |
#include <string> |
#include <vector> |
@@ -23,8 +24,8 @@ |
#include "net/socket/ssl_server_socket.h" |
#include "ppapi/cpp/completion_callback.h" |
#include "ppapi/cpp/dev/url_util_dev.h" |
+#include "ppapi/cpp/image_data.h" |
#include "ppapi/cpp/input_event.h" |
-#include "ppapi/cpp/mouse_cursor.h" |
#include "ppapi/cpp/rect.h" |
#include "remoting/base/constants.h" |
#include "remoting/base/util.h" |
@@ -55,6 +56,12 @@ namespace { |
// 32-bit BGRA is 4 bytes per pixel. |
const int kBytesPerPixel = 4; |
+#if defined(ARCH_CPU_LITTLE_ENDIAN) |
+const uint32_t kPixelAlphaMask = 0xff000000; |
+#else // !defined(ARCH_CPU_LITTLE_ENDIAN) |
+const uint32_t kPixelAlphaMask = 0x000000ff; |
+#endif // !defined(ARCH_CPU_LITTLE_ENDIAN) |
+ |
// Default DPI to assume for old clients that use notifyClientResolution. |
const int kDefaultDPI = 96; |
@@ -125,6 +132,16 @@ std::string ConnectionErrorToString(protocol::ErrorCode error) { |
return std::string(); |
} |
+// Returns true if |pixel| is not completely transparent. |
+bool IsVisiblePixel(uint32_t pixel) { |
+ return (pixel & kPixelAlphaMask) != 0; |
+} |
+ |
+// Returns true if there is at least one visible pixel in the given range. |
+bool IsVisibleRow(const uint32_t* begin, const uint32_t* end) { |
+ return std::find_if(begin, end, &IsVisiblePixel) != end; |
+} |
+ |
// This flag blocks LOGs to the UI if we're already in the middle of logging |
// to the UI. This prevents a potential infinite loop if we encounter an error |
// while sending the log message to the UI. |
@@ -144,7 +161,7 @@ logging::LogMessageHandlerFunction g_logging_old_handler = NULL; |
const char ChromotingInstance::kApiFeatures[] = |
"highQualityScaling injectKeyEvent sendClipboardItem remapKey trapKey " |
"notifyClientResolution pauseVideo pauseAudio asyncPin thirdPartyAuth " |
- "pinlessAuth extensionMessage"; |
+ "pinlessAuth extensionMessage allowMouseLock"; |
const char ChromotingInstance::kRequestedCapabilities[] = ""; |
const char ChromotingInstance::kSupportedCapabilities[] = "desktopShape"; |
@@ -176,7 +193,7 @@ ChromotingInstance::ChromotingInstance(PP_Instance pp_instance) |
input_tracker_(&mouse_input_filter_), |
key_mapper_(&input_tracker_), |
normalizing_input_filter_(CreateNormalizingInputFilter(&key_mapper_)), |
- input_handler_(normalizing_input_filter_.get()), |
+ input_handler_(this, normalizing_input_filter_.get()), |
use_async_pin_dialog_(false), |
weak_factory_(this) { |
RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_WHEEL); |
@@ -304,9 +321,17 @@ void ChromotingInstance::HandleMessage(const pp::Var& message) { |
HandleRequestPairing(*data); |
} else if (method == "extensionMessage") { |
HandleExtensionMessage(*data); |
+ } else if (method == "allowMouseLock") { |
+ HandleAllowMouseLockMessage(); |
} |
} |
+void ChromotingInstance::DidChangeFocus(bool has_focus) { |
+ DCHECK(plugin_task_runner_->BelongsToCurrentThread()); |
+ |
+ input_handler_.DidChangeFocus(has_focus); |
+} |
+ |
void ChromotingInstance::DidChangeView(const pp::View& view) { |
DCHECK(plugin_task_runner_->BelongsToCurrentThread()); |
@@ -464,6 +489,8 @@ void ChromotingInstance::InjectClipboardEvent( |
void ChromotingInstance::SetCursorShape( |
const protocol::CursorShapeInfo& cursor_shape) { |
+ COMPILE_ASSERT(sizeof(uint32_t) == kBytesPerPixel, rgba_pixels_are_32bit); |
+ |
if (!cursor_shape.has_data() || |
!cursor_shape.has_width() || |
!cursor_shape.has_height() || |
@@ -500,47 +527,52 @@ void ChromotingInstance::SetCursorShape( |
int hotspot_x = cursor_shape.hotspot_x(); |
int hotspot_y = cursor_shape.hotspot_y(); |
- |
int bytes_per_row = width * kBytesPerPixel; |
- const uint8* src_row_data = reinterpret_cast<const uint8*>( |
+ int src_stride = width; |
+ const uint32_t* src_row_data = reinterpret_cast<const uint32_t*>( |
cursor_shape.data().data()); |
- int stride = bytes_per_row; |
- |
- // If the cursor exceeds the size permitted by PPAPI then crop it, keeping |
- // the hotspot as close to the center of the new cursor shape as possible. |
- if (height > kMaxCursorHeight) { |
- int y = hotspot_y - (kMaxCursorHeight / 2); |
- y = std::max(y, 0); |
- y = std::min(y, height - kMaxCursorHeight); |
- |
- src_row_data += stride * y; |
- height = kMaxCursorHeight; |
- hotspot_y -= y; |
- } |
- if (width > kMaxCursorWidth) { |
- int x = hotspot_x - (kMaxCursorWidth / 2); |
- x = std::max(x, 0); |
- x = std::min(x, height - kMaxCursorWidth); |
- |
- src_row_data += x * kBytesPerPixel; |
- width = kMaxCursorWidth; |
- bytes_per_row = width * kBytesPerPixel; |
- hotspot_x -= x; |
- } |
+ const uint32_t* src_row_data_end = src_row_data + src_stride * height; |
+ |
+ scoped_ptr<pp::ImageData> cursor_image; |
+ pp::Point cursor_hotspot; |
+ |
+ // Check if the cursor is visible. |
+ if (IsVisibleRow(src_row_data, src_row_data_end)) { |
+ // If the cursor exceeds the size permitted by PPAPI then crop it, keeping |
+ // the hotspot as close to the center of the new cursor shape as possible. |
+ if (height > kMaxCursorHeight) { |
+ int y = hotspot_y - (kMaxCursorHeight / 2); |
+ y = std::max(y, 0); |
+ y = std::min(y, height - kMaxCursorHeight); |
+ |
+ src_row_data += src_stride * y; |
+ height = kMaxCursorHeight; |
+ hotspot_y -= y; |
+ } |
+ if (width > kMaxCursorWidth) { |
+ int x = hotspot_x - (kMaxCursorWidth / 2); |
+ x = std::max(x, 0); |
+ x = std::min(x, height - kMaxCursorWidth); |
+ |
+ src_row_data += x; |
+ width = kMaxCursorWidth; |
+ bytes_per_row = width * kBytesPerPixel; |
+ hotspot_x -= x; |
+ } |
- pp::ImageData cursor_image(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL, |
- pp::Size(width, height), false); |
+ cursor_image.reset(new pp::ImageData(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL, |
+ pp::Size(width, height), false)); |
+ cursor_hotspot = pp::Point(hotspot_x, hotspot_y); |
- uint8* dst_row_data = reinterpret_cast<uint8*>(cursor_image.data()); |
- for (int row = 0; row < height; row++) { |
- memcpy(dst_row_data, src_row_data, bytes_per_row); |
- src_row_data += stride; |
- dst_row_data += cursor_image.stride(); |
+ uint8* dst_row_data = reinterpret_cast<uint8*>(cursor_image->data()); |
+ for (int row = 0; row < height; row++) { |
+ memcpy(dst_row_data, src_row_data, bytes_per_row); |
+ src_row_data += src_stride; |
+ dst_row_data += cursor_image->stride(); |
+ } |
} |
- pp::MouseCursor::SetCursor(this, PP_MOUSECURSOR_TYPE_CUSTOM, |
- cursor_image, |
- pp::Point(hotspot_x, hotspot_y)); |
+ input_handler_.SetMouseCursor(cursor_image.Pass(), cursor_hotspot); |
} |
void ChromotingInstance::OnFirstFrameReceived() { |
@@ -860,6 +892,10 @@ void ChromotingInstance::HandleExtensionMessage( |
host_connection_->host_stub()->DeliverClientMessage(message); |
} |
+void ChromotingInstance::HandleAllowMouseLockMessage() { |
+ input_handler_.AllowMouseLock(); |
+} |
+ |
ChromotingStats* ChromotingInstance::GetStats() { |
if (!client_.get()) |
return NULL; |