diff options
29 files changed, 430 insertions, 792 deletions
diff --git a/remoting/base/decoder.h b/remoting/base/decoder.h index d932ff1..dd37757 100644 --- a/remoting/base/decoder.h +++ b/remoting/base/decoder.h @@ -57,11 +57,10 @@ class Decoder { virtual VideoPacketFormat::Encoding Encoding() = 0; - // Set the scale factors of the decoded output. If the decoder doesn't support - // scaling then this all is ignored. - // If both |horizontal_ratio| and |vertical_ratio| equal 1.0 then scaling is - // turned off. - virtual void SetScaleRatios(double horizontal_ratio, double vertical_ratio) {} + // Set the output dimensions for the decoder. If the dimensions are empty + // then the source is rendered without scaling. + // Output dimensions are ignored if the decoder doesn't support scaling. + virtual void SetOutputSize(const SkISize& size) {} // Set the clipping rectangle to the decoder. Decoder should respect this and // only output changes in this rectangle. The new clipping rectangle will be @@ -71,9 +70,8 @@ class Decoder { virtual void SetClipRect(const SkIRect& clip_rect) {} // Force decoder to output a video frame with content in |rects| using the - // last decoded video frame. - // - // Coordinates of rectangles supplied here are before scaling. + // last decoded video frame. |rects| are expressed in video frame rather + // than output coordinates. virtual void RefreshRects(const RectVector& rects) {} }; diff --git a/remoting/base/decoder_vp8.cc b/remoting/base/decoder_vp8.cc index 8c8a205..af1f718 100644 --- a/remoting/base/decoder_vp8.cc +++ b/remoting/base/decoder_vp8.cc @@ -23,8 +23,7 @@ DecoderVp8::DecoderVp8() codec_(NULL), last_image_(NULL), clip_rect_(SkIRect::MakeEmpty()), - horizontal_scale_ratio_(1.0), - vertical_scale_ratio_(1.0) { + output_size_(SkISize::Make(0, 0)) { } DecoderVp8::~DecoderVp8() { @@ -103,10 +102,17 @@ Decoder::DecodeResult DecoderVp8::DecodePacket(const VideoPacket* packet) { remoting_rect.height())); } - if (!DoScaling()) - ConvertRects(rects, &updated_rects_); - else - ScaleAndConvertRects(rects, &updated_rects_); + // TODO(wez): Fix the rest of the decode pipeline not to assume the frame + // size is the host dimensions, since it's not when scaling. If the host + // gets smaller, then the output size will be too big and we'll overrun the + // frame, so currently we render 1:1 in that case; the app will see the + // host size change and resize us if need be. + if ((output_size_.width() > static_cast<int>(frame_->width())) || + (output_size_.height() > static_cast<int>(frame_->height()))) { + output_size_.set(frame_->width(), frame_->height()); + } + + RefreshRects(rects); return DECODE_DONE; } @@ -127,18 +133,8 @@ VideoPacketFormat::Encoding DecoderVp8::Encoding() { return VideoPacketFormat::ENCODING_VP8; } -void DecoderVp8::SetScaleRatios(double horizontal_ratio, - double vertical_ratio) { - // TODO(hclam): Ratio greater than 1.0 is not supported. This is - // because we need to reallocate the backing video frame and this - // is not implemented yet. - if (horizontal_ratio > 1.0 || horizontal_ratio <= 0.0 || - vertical_ratio > 1.0 || vertical_ratio <= 0.0) { - return; - } - - horizontal_scale_ratio_ = horizontal_ratio; - vertical_scale_ratio_ = vertical_ratio; +void DecoderVp8::SetOutputSize(const SkISize& size) { + output_size_ = size; } void DecoderVp8::SetClipRect(const SkIRect& clip_rect) { @@ -153,7 +149,8 @@ void DecoderVp8::RefreshRects(const RectVector& rects) { } bool DecoderVp8::DoScaling() const { - return horizontal_scale_ratio_ != 1.0 || vertical_scale_ratio_ != 1.0; + DCHECK(last_image_); + return !output_size_.equals(last_image_->d_w, last_image_->d_h); } void DecoderVp8::ConvertRects(const RectVector& input_rects, @@ -203,30 +200,25 @@ void DecoderVp8::ScaleAndConvertRects(const RectVector& input_rects, if (!last_image_) return; - int input_width = last_image_->d_w; - int input_height = last_image_->d_h; - - uint8* output_rgb_buf = frame_->data(media::VideoFrame::kRGBPlane); - const int output_stride = frame_->stride(media::VideoFrame::kRGBPlane); - - // TODO(wez): Resize |frame_| to our desired output dimensions when scaling. - int output_width = ceil(input_width * horizontal_scale_ratio_); - int output_height = ceil(input_height * vertical_scale_ratio_); + DCHECK(output_size_.width() <= static_cast<int>(frame_->width())); + DCHECK(output_size_.height() <= static_cast<int>(frame_->height())); output_rects->clear(); // Clip based on both the output dimensions and Pepper clip rect. SkIRect clip_rect = clip_rect_; - if (!clip_rect.intersect(SkIRect::MakeWH(output_width, output_height))) + if (!clip_rect.intersect(SkIRect::MakeSize(output_size_))) return; + SkISize image_size = SkISize::Make(last_image_->d_w, last_image_->d_h); + uint8* output_rgb_buf = frame_->data(media::VideoFrame::kRGBPlane); + const int output_stride = frame_->stride(media::VideoFrame::kRGBPlane); + output_rects->reserve(input_rects.size()); for (size_t i = 0; i < input_rects.size(); ++i) { // Determine the scaled area affected by this rectangle changing. - SkIRect output_rect = ScaleRect(input_rects[i], - horizontal_scale_ratio_, - vertical_scale_ratio_); + SkIRect output_rect = ScaleRect(input_rects[i], image_size, output_size_); if (!output_rect.intersect(clip_rect)) continue; diff --git a/remoting/base/decoder_vp8.h b/remoting/base/decoder_vp8.h index 33ec147..a89991c 100644 --- a/remoting/base/decoder_vp8.h +++ b/remoting/base/decoder_vp8.h @@ -24,8 +24,7 @@ class DecoderVp8 : public Decoder { virtual bool IsReadyForData() OVERRIDE; virtual void Reset() OVERRIDE; virtual VideoPacketFormat::Encoding Encoding() OVERRIDE; - virtual void SetScaleRatios(double horizontal_ratio, - double vertical_ratio) OVERRIDE; + virtual void SetOutputSize(const SkISize& size) OVERRIDE; virtual void SetClipRect(const SkIRect& clip_rect) OVERRIDE; virtual void RefreshRects(const RectVector& rects) OVERRIDE; @@ -67,9 +66,8 @@ class DecoderVp8 : public Decoder { // Clipping rect for the output of the decoder. SkIRect clip_rect_; - // Scale factors of the decoded output. - double horizontal_scale_ratio_; - double vertical_scale_ratio_; + // Output dimensions. + SkISize output_size_; DISALLOW_COPY_AND_ASSIGN(DecoderVp8); }; diff --git a/remoting/base/util.cc b/remoting/base/util.cc index 23af0ea..d069ce8 100644 --- a/remoting/base/util.cc +++ b/remoting/base/util.cc @@ -61,9 +61,9 @@ void ConvertYUVToRGB32WithRect(const uint8* y_plane, int y_stride, int uv_stride, int rgb_stride) { - int rgb_offset = CalculateRGBOffset(rect.fLeft, rect.fTop, rgb_stride); - int y_offset = CalculateYOffset(rect.fLeft, rect.fTop, y_stride); - int uv_offset = CalculateUVOffset(rect.fLeft, rect.fTop, uv_stride); + int rgb_offset = CalculateRGBOffset(rect.left(), rect.top(), rgb_stride); + int y_offset = CalculateYOffset(rect.left(), rect.top(), y_stride); + int uv_offset = CalculateUVOffset(rect.left(), rect.top(), uv_stride); media::ConvertYUVToRGB32(y_plane + y_offset, u_plane + uv_offset, @@ -86,14 +86,14 @@ void ScaleYUVToRGB32WithRect(const uint8* y_plane, int y_stride, int uv_stride, int rgb_stride) { - int rgb_offset = CalculateRGBOffset(dest_rect.fLeft, - dest_rect.fTop, + int rgb_offset = CalculateRGBOffset(dest_rect.left(), + dest_rect.top(), rgb_stride); - int y_offset = CalculateYOffset(source_rect.fLeft, - source_rect.fTop, + int y_offset = CalculateYOffset(source_rect.left(), + source_rect.top(), y_stride); - int uv_offset = CalculateUVOffset(source_rect.fLeft, - source_rect.fTop, + int uv_offset = CalculateUVOffset(source_rect.left(), + source_rect.top(), uv_stride); media::ScaleYUVToRGB32(y_plane + y_offset, @@ -143,20 +143,22 @@ int RoundToTwosMultiple(int x) { } SkIRect AlignRect(const SkIRect& rect) { - int x = RoundToTwosMultiple(rect.fLeft); - int y = RoundToTwosMultiple(rect.fTop); - int right = RoundToTwosMultiple(rect.fRight + 1); - int bottom = RoundToTwosMultiple(rect.fBottom + 1); - return SkIRect::MakeXYWH(x, y, right - x, bottom - y); + int x = RoundToTwosMultiple(rect.left()); + int y = RoundToTwosMultiple(rect.top()); + int right = RoundToTwosMultiple(rect.right() + 1); + int bottom = RoundToTwosMultiple(rect.bottom() + 1); + return SkIRect::MakeLTRB(x, y, right, bottom); } SkIRect ScaleRect(const SkIRect& rect, - double horizontal_ratio, - double vertical_ratio) { - int left = floor(rect.left() * horizontal_ratio); - int top = floor(rect.top() * vertical_ratio); - int right = ceil(rect.right() * horizontal_ratio); - int bottom = ceil(rect.bottom() * vertical_ratio); + const SkISize& in_size, + const SkISize& out_size) { + int left = (rect.left() * out_size.width()) / in_size.width(); + int top = (rect.top() * out_size.height()) / in_size.height(); + int right = (rect.right() * out_size.width() + out_size.width() - 1) / + in_size.width(); + int bottom = (rect.bottom() * out_size.height() + out_size.height() - 1) / + in_size.height(); return SkIRect::MakeLTRB(left, top, right, bottom); } @@ -166,10 +168,10 @@ void CopyRect(const uint8* src_plane, int dest_plane_stride, int bytes_per_pixel, const SkIRect& rect) { - // Get the address of the starting point. - const int src_y_offset = src_plane_stride * rect.fTop; - const int dest_y_offset = dest_plane_stride * rect.fTop; - const int x_offset = bytes_per_pixel * rect.fLeft; + // Get the address of the starting point. + const int src_y_offset = src_plane_stride * rect.top(); + const int dest_y_offset = dest_plane_stride * rect.top(); + const int x_offset = bytes_per_pixel * rect.left(); src_plane += src_y_offset + x_offset; dest_plane += dest_y_offset + x_offset; diff --git a/remoting/base/util.h b/remoting/base/util.h index cf2b2dd..8bed6f4 100644 --- a/remoting/base/util.h +++ b/remoting/base/util.h @@ -54,12 +54,12 @@ int RoundToTwosMultiple(int x); // Align the sides of the rectangle to multiples of 2 (expanding outwards). SkIRect AlignRect(const SkIRect& rect); -// Scale a rectangle by horizontal and vertical factors. If the result has -// non-integer coordinates then the smallest integer-coordinate rectangle that -// wholly encloses it is returned. +// Scales the supplied rectangle from |in_size| coordinates to |out_size|. +// If the result has non-integer coordinates then the smallest integer- +// coordinate rectangle that wholly encloses it is returned. SkIRect ScaleRect(const SkIRect& rect, - double horizontal_ratio, - double vertical_ratio); + const SkISize& in_size, + const SkISize& out_size); // Copy pixels in the rectangle from source to destination. void CopyRect(const uint8* src_plane, diff --git a/remoting/client/chromoting_client.cc b/remoting/client/chromoting_client.cc index 60bb4e6..6f10746 100644 --- a/remoting/client/chromoting_client.cc +++ b/remoting/client/chromoting_client.cc @@ -7,7 +7,6 @@ #include "base/bind.h" #include "remoting/client/chromoting_view.h" #include "remoting/client/client_context.h" -#include "remoting/client/input_handler.h" #include "remoting/client/rectangle_update_decoder.h" #include "remoting/protocol/connection_to_host.h" #include "remoting/protocol/session_config.h" @@ -27,14 +26,12 @@ ChromotingClient::ChromotingClient(const ClientConfig& config, protocol::ConnectionToHost* connection, ChromotingView* view, RectangleUpdateDecoder* rectangle_decoder, - InputHandler* input_handler, const base::Closure& client_done) : config_(config), context_(context), connection_(connection), view_(view), rectangle_decoder_(rectangle_decoder), - input_handler_(input_handler), client_done_(client_done), packet_being_processed_(false), last_sequence_number_(0), @@ -205,9 +202,6 @@ void ChromotingClient::Initialize() { // Initialize the decoder. rectangle_decoder_->Initialize(connection_->config()); - - // Schedule the input handler to process the event queue. - input_handler_->Initialize(); } } // namespace remoting diff --git a/remoting/client/chromoting_client.h b/remoting/client/chromoting_client.h index a0bea89..756c388 100644 --- a/remoting/client/chromoting_client.h +++ b/remoting/client/chromoting_client.h @@ -26,7 +26,6 @@ class MessageLoop; namespace remoting { class ClientContext; -class InputHandler; class RectangleUpdateDecoder; // TODO(sergeyu): Move VideoStub implementation to RectangleUpdateDecoder. @@ -40,7 +39,6 @@ class ChromotingClient : public protocol::ConnectionToHost::HostEventCallback, protocol::ConnectionToHost* connection, ChromotingView* view, RectangleUpdateDecoder* rectangle_decoder, - InputHandler* input_handler, const base::Closure& client_done); virtual ~ChromotingClient(); @@ -94,7 +92,6 @@ class ChromotingClient : public protocol::ConnectionToHost::HostEventCallback, protocol::ConnectionToHost* connection_; ChromotingView* view_; RectangleUpdateDecoder* rectangle_decoder_; - InputHandler* input_handler_; // If non-NULL, this is called when the client is done. base::Closure client_done_; diff --git a/remoting/client/chromoting_view.cc b/remoting/client/chromoting_view.cc deleted file mode 100644 index 23138d0..0000000 --- a/remoting/client/chromoting_view.cc +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2011 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 "remoting/client/chromoting_view.h" - -#include "base/message_loop.h" -#include "base/synchronization/waitable_event.h" - -namespace remoting { - -ChromotingView::ChromotingView() - : frame_width_(0), - frame_height_(0) { -} - -ChromotingView::~ChromotingView() {} - -// TODO(garykac): This assumes a single screen. This will need to be adjusted -// to add support for mulitple monitors. -void ChromotingView::GetScreenSize(int* width, int* height) { - *width = frame_width_; - *height = frame_height_; -} - -} // namespace remoting diff --git a/remoting/client/chromoting_view.h b/remoting/client/chromoting_view.h index 17b24e3..e93ab0d 100644 --- a/remoting/client/chromoting_view.h +++ b/remoting/client/chromoting_view.h @@ -5,10 +5,7 @@ #ifndef REMOTING_CLIENT_CHROMOTING_VIEW_H_ #define REMOTING_CLIENT_CHROMOTING_VIEW_H_ -#include <string> - -#include "base/memory/ref_counted.h" -#include "media/base/video_frame.h" +#include "base/basictypes.h" #include "remoting/protocol/connection_to_host.h" namespace remoting { @@ -22,12 +19,7 @@ static const uint32 kFailedColor = 0xffcc00ff; // screen. class ChromotingView { public: - ChromotingView(); - virtual ~ChromotingView(); - - // Get screen dimensions. - // TODO(garykac): This will need to be extended to support multi-monitors. - void GetScreenSize(int* width, int* height); + virtual ~ChromotingView() {} // Initialize the common structures for the view. virtual bool Initialize() = 0; @@ -49,20 +41,6 @@ class ChromotingView { // Record the update the state of the connection, updating the UI as needed. virtual void SetConnectionState(protocol::ConnectionToHost::State state, protocol::ConnectionToHost::Error error) = 0; - - // Return the horizontal scale factor of this view. - virtual double GetHorizontalScaleRatio() const = 0; - - // Return the vertical scale factor of this view. - virtual double GetVerticalScaleRatio() const = 0; - - protected: - // Framebuffer for the decoder. - scoped_refptr<media::VideoFrame> frame_; - - // Dimensions of |frame_| bitmap. - int frame_width_; - int frame_height_; }; } // namespace remoting diff --git a/remoting/client/input_handler.cc b/remoting/client/input_handler.cc deleted file mode 100644 index 48bedde..0000000 --- a/remoting/client/input_handler.cc +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) 2011 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 "remoting/client/input_handler.h" - -#include "remoting/client/chromoting_view.h" -#include "remoting/proto/event.pb.h" -#include "remoting/protocol/connection_to_host.h" -#include "remoting/protocol/input_stub.h" - -namespace remoting { - -using protocol::KeyEvent; -using protocol::MouseEvent; - -InputHandler::InputHandler(ClientContext* context, - protocol::ConnectionToHost* connection, - ChromotingView* view) - : context_(context), - connection_(connection), - view_(view) { -} - -InputHandler::~InputHandler() { -} - -void InputHandler::SendKeyEvent(bool press, int keycode) { - protocol::InputStub* stub = connection_->input_stub(); - if (stub) { - if (press) { - pressed_keys_.insert(keycode); - } else { - pressed_keys_.erase(keycode); - } - - KeyEvent event; - event.set_keycode(keycode); - event.set_pressed(press); - stub->InjectKeyEvent(event); - } -} - -void InputHandler::SendMouseMoveEvent(int x, int y) { - protocol::InputStub* stub = connection_->input_stub(); - if (stub) { - MouseEvent event; - event.set_x(x); - event.set_y(y); - stub->InjectMouseEvent(event); - } -} - -void InputHandler::SendMouseButtonEvent(bool button_down, - MouseEvent::MouseButton button) { - protocol::InputStub* stub = connection_->input_stub(); - if (stub) { - MouseEvent event; - event.set_button(button); - event.set_button_down(button_down); - stub->InjectMouseEvent(event); - } -} - -void InputHandler::SendMouseWheelEvent(int dx, int dy) { - protocol::InputStub* stub = connection_->input_stub(); - if (stub) { - MouseEvent event; - event.set_wheel_offset_x(dx); - event.set_wheel_offset_y(dy); - stub->InjectMouseEvent(event); - } -} - -void InputHandler::ReleaseAllKeys() { - std::set<int> pressed_keys_copy = pressed_keys_; - std::set<int>::iterator i; - for (i = pressed_keys_copy.begin(); i != pressed_keys_copy.end(); ++i) { - SendKeyEvent(false, *i); - } - pressed_keys_.clear(); -} - -} // namespace remoting diff --git a/remoting/client/input_handler.h b/remoting/client/input_handler.h deleted file mode 100644 index e6082a2..0000000 --- a/remoting/client/input_handler.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2011 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. - -#ifndef REMOTING_CLIENT_INPUT_HANDLER_H_ -#define REMOTING_CLIENT_INPUT_HANDLER_H_ - -#include <set> - -#include "base/basictypes.h" -#include "remoting/proto/event.pb.h" - -namespace remoting { - -class ClientContext; -class ChromotingView; - -namespace protocol { -class ConnectionToHost; -} // namespace protocol - -class InputHandler { - public: - InputHandler(ClientContext* context, - protocol::ConnectionToHost* connection, - ChromotingView* view); - virtual ~InputHandler(); - - virtual void Initialize() = 0; - - void ReleaseAllKeys(); - - protected: - void SendKeyEvent(bool press, int keycode); - void SendMouseMoveEvent(int x, int y); - void SendMouseButtonEvent(bool down, - protocol::MouseEvent::MouseButton button); - void SendMouseWheelEvent(int dx, int dy); - - ClientContext* context_; - protocol::ConnectionToHost* connection_; - ChromotingView* view_; - - private: - std::set<int> pressed_keys_; - - DISALLOW_COPY_AND_ASSIGN(InputHandler); -}; - -} // namespace remoting - -#endif // REMOTING_CLIENT_INPUT_HANDLER_H_ diff --git a/remoting/client/mouse_input_filter.cc b/remoting/client/mouse_input_filter.cc new file mode 100644 index 0000000..49e33a8 --- /dev/null +++ b/remoting/client/mouse_input_filter.cc @@ -0,0 +1,49 @@ +// Copyright (c) 2011 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 "remoting/client/mouse_input_filter.h" + +#include "remoting/proto/event.pb.h" + +namespace remoting { + +MouseInputFilter::MouseInputFilter(protocol::InputStub* input_stub) + : input_stub_(input_stub) { + input_size_.setEmpty(); + output_size_.setEmpty(); +} + +MouseInputFilter::~MouseInputFilter() { +} + +void MouseInputFilter::InjectKeyEvent(const protocol::KeyEvent& event) { + input_stub_->InjectKeyEvent(event); +} + +void MouseInputFilter::InjectMouseEvent(const protocol::MouseEvent& event) { + if (input_size_.isZero() || output_size_.isZero()) + return; + + protocol::MouseEvent out_event(event); + if (out_event.has_x()) { + int x = (out_event.x() * output_size_.width()) / input_size_.width(); + out_event.set_x(std::max(0, std::min(output_size_.width() - 1, x))); + } + if (out_event.has_y()) { + int y = (out_event.y() * output_size_.height()) / input_size_.height(); + out_event.set_y(std::max(0, std::min(output_size_.height() - 1, y))); + } + + input_stub_->InjectMouseEvent(out_event); +} + +void MouseInputFilter::set_input_size(const SkISize& size) { + input_size_ = size; +} + +void MouseInputFilter::set_output_size(const SkISize& size) { + output_size_ = size; +} + +} // namespace remoting diff --git a/remoting/client/mouse_input_filter.h b/remoting/client/mouse_input_filter.h new file mode 100644 index 0000000..0c2a0d9 --- /dev/null +++ b/remoting/client/mouse_input_filter.h @@ -0,0 +1,45 @@ +// Copyright (c) 2011 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. + +#ifndef REMOTING_CLIENT_MOUSE_INPUT_FILTER_H_ +#define REMOTING_CLIENT_MOUSE_INPUT_FILTER_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "remoting/protocol/input_stub.h" +#include "third_party/skia/include/core/SkTypes.h" +#include "third_party/skia/include/core/SkSize.h" + +namespace remoting { + +// Filtering InputStub implementation which scales mouse events based on the +// supplied input and output dimensions, and clamps their coordinates to the +// output dimensions, before passing events on to |input_stub|. +class MouseInputFilter : public protocol::InputStub { + public: + MouseInputFilter(protocol::InputStub* input_stub); + virtual ~MouseInputFilter(); + + // Specify the input dimensions for mouse events. + void set_input_size(const SkISize& size); + + // Specify the output dimensions. + void set_output_size(const SkISize& size); + + // InputStub interface. + virtual void InjectKeyEvent(const protocol::KeyEvent& event) OVERRIDE; + virtual void InjectMouseEvent(const protocol::MouseEvent& event) OVERRIDE; + + private: + protocol::InputStub* input_stub_; + + SkISize input_size_; + SkISize output_size_; + + DISALLOW_COPY_AND_ASSIGN(MouseInputFilter); +}; + +} // namespace remoting + +#endif // REMOTING_CLIENT_MOUSE_INPUT_FILTER_H_ diff --git a/remoting/client/plugin/chromoting_instance.cc b/remoting/client/plugin/chromoting_instance.cc index e6dea0e..d3f7b62 100644 --- a/remoting/client/plugin/chromoting_instance.cc +++ b/remoting/client/plugin/chromoting_instance.cc @@ -24,14 +24,15 @@ #include "remoting/base/util.h" #include "remoting/client/client_config.h" #include "remoting/client/chromoting_client.h" +#include "remoting/client/mouse_input_filter.h" #include "remoting/client/plugin/chromoting_scriptable_object.h" #include "remoting/client/plugin/pepper_input_handler.h" #include "remoting/client/plugin/pepper_view.h" -#include "remoting/client/plugin/pepper_view_proxy.h" #include "remoting/client/plugin/pepper_xmpp_proxy.h" #include "remoting/client/rectangle_update_decoder.h" #include "remoting/protocol/connection_to_host.h" #include "remoting/protocol/host_stub.h" +#include "remoting/protocol/key_event_tracker.h" namespace remoting { @@ -82,16 +83,11 @@ ChromotingInstance::~ChromotingInstance() { done_event.Wait(); } - // Stopping the context shutdown all chromoting threads. This is a requirement - // before we can call Detach() on |view_proxy_|. + // Stopping the context shuts down all chromoting threads. context_.Stop(); - if (view_proxy_.get()) { - view_proxy_->Detach(); - } - // Delete |thread_proxy_| before we detach |plugin_message_loop_|, - // otherwise ScopedThreadProxy may DCHECK when destroying. + // otherwise ScopedThreadProxy may DCHECK when being destroyed. thread_proxy_.reset(); plugin_message_loop_->Detach(); @@ -117,9 +113,8 @@ bool ChromotingInstance::Init(uint32_t argc, // Create the chromoting objects that don't depend on the network connection. view_.reset(new PepperView(this, &context_)); - view_proxy_ = new PepperViewProxy(this, view_.get(), plugin_message_loop_); rectangle_decoder_ = new RectangleUpdateDecoder( - context_.decode_message_loop(), view_proxy_); + context_.decode_message_loop(), view_.get()); // Default to a medium grey. view_->SetSolidFill(0xFFCDCDCD); @@ -132,14 +127,9 @@ void ChromotingInstance::Connect(const ClientConfig& config) { host_connection_.reset(new protocol::ConnectionToHost( context_.network_message_loop(), this, true)); - - input_handler_.reset(new PepperInputHandler(&context_, - host_connection_.get(), - view_proxy_)); - client_.reset(new ChromotingClient(config, &context_, host_connection_.get(), - view_proxy_, rectangle_decoder_.get(), - input_handler_.get(), base::Closure())); + view_.get(), rectangle_decoder_.get(), + base::Closure())); LOG(INFO) << "Connecting to " << config.host_jid << ". Local jid: " << config.local_jid << "."; @@ -175,6 +165,8 @@ void ChromotingInstance::Disconnect() { } input_handler_.reset(); + key_event_tracker_.reset(); + mouse_input_filter_.reset(); host_connection_.reset(); GetScriptableObject()->SetConnectionStatus( @@ -186,87 +178,44 @@ void ChromotingInstance::DidChangeView(const pp::Rect& position, const pp::Rect& clip) { DCHECK(plugin_message_loop_->BelongsToCurrentThread()); - view_->SetPluginSize(SkISize::Make(position.width(), position.height())); - - // TODO(wez): Pass the dimensions of the plugin to the RectangleDecoder - // and let it generate the necessary refresh events. - // If scale-to-fit is enabled then update the scaling ratios. - // We also force a full-frame refresh, in case the ratios changed. - if (scale_to_fit_) { - rectangle_decoder_->SetScaleRatios(view_->GetHorizontalScaleRatio(), - view_->GetVerticalScaleRatio()); - rectangle_decoder_->RefreshFullFrame(); + SkISize new_size = SkISize::Make(position.width(), position.height()); + if (view_->SetViewSize(new_size)) { + if (mouse_input_filter_.get()) { + mouse_input_filter_->set_input_size(new_size); + } + rectangle_decoder_->SetOutputSize(new_size); } - // Notify the RectangleDecoder of the new clip rect. rectangle_decoder_->UpdateClipRect( SkIRect::MakeXYWH(clip.x(), clip.y(), clip.width(), clip.height())); } bool ChromotingInstance::HandleInputEvent(const pp::InputEvent& event) { DCHECK(plugin_message_loop_->BelongsToCurrentThread()); - if (!input_handler_.get()) { + + // Never inject events if the end of the input pipeline doesn't exist. + // If it does exist but the pipeline doesn't, construct a pipeline. + // TODO(wez): This is really ugly. We should create the pipeline when + // the ConnectionToHost's InputStub exists. + if (!host_connection_.get()) { return false; + } else if (!input_handler_.get()) { + protocol::InputStub* input_stub = host_connection_->input_stub(); + if (!input_stub) + return false; + mouse_input_filter_.reset(new MouseInputFilter(input_stub)); + mouse_input_filter_->set_input_size(view_->get_view_size()); + key_event_tracker_.reset( + new protocol::KeyEventTracker(mouse_input_filter_.get())); + input_handler_.reset( + new PepperInputHandler(key_event_tracker_.get())); } - PepperInputHandler* pih - = static_cast<PepperInputHandler*>(input_handler_.get()); - - switch (event.GetType()) { - case PP_INPUTEVENT_TYPE_MOUSEDOWN: { - pih->HandleMouseButtonEvent(true, pp::MouseInputEvent(event)); - return true; - } - - case PP_INPUTEVENT_TYPE_MOUSEUP: { - pih->HandleMouseButtonEvent(false, pp::MouseInputEvent(event)); - return true; - } - - case PP_INPUTEVENT_TYPE_MOUSEMOVE: - case PP_INPUTEVENT_TYPE_MOUSEENTER: - case PP_INPUTEVENT_TYPE_MOUSELEAVE: { - pih->HandleMouseMoveEvent(pp::MouseInputEvent(event)); - return true; - } - - case PP_INPUTEVENT_TYPE_WHEEL: { - pih->HandleMouseWheelEvent(pp::WheelInputEvent(event)); - return true; - } - - case PP_INPUTEVENT_TYPE_CONTEXTMENU: { - // We need to return true here or else we'll get a local (plugin) context - // menu instead of the mouseup event for the right click. - return true; - } - - case PP_INPUTEVENT_TYPE_KEYDOWN: { - pp::KeyboardInputEvent key = pp::KeyboardInputEvent(event); - VLOG(3) << "PP_INPUTEVENT_TYPE_KEYDOWN" << " key=" << key.GetKeyCode(); - pih->HandleKeyEvent(true, key); - return true; - } + // TODO(wez): When we have a good hook into Host dimensions changes, move + // this there. + mouse_input_filter_->set_output_size(view_->get_host_size()); - case PP_INPUTEVENT_TYPE_KEYUP: { - pp::KeyboardInputEvent key = pp::KeyboardInputEvent(event); - VLOG(3) << "PP_INPUTEVENT_TYPE_KEYUP" << " key=" << key.GetKeyCode(); - pih->HandleKeyEvent(false, key); - return true; - } - - case PP_INPUTEVENT_TYPE_CHAR: { - pih->HandleCharacterEvent(pp::KeyboardInputEvent(event)); - return true; - } - - default: { - LOG(INFO) << "Unhandled input event: " << event.GetType(); - break; - } - } - - return false; + return input_handler_->HandleInputEvent(event); } ChromotingScriptableObject* ChromotingInstance::GetScriptableObject() { @@ -280,25 +229,6 @@ ChromotingScriptableObject* ChromotingInstance::GetScriptableObject() { return NULL; } -void ChromotingInstance::SetScaleToFit(bool scale_to_fit) { - DCHECK(plugin_message_loop_->BelongsToCurrentThread()); - - if (scale_to_fit == scale_to_fit_) - return; - - scale_to_fit_ = scale_to_fit; - if (scale_to_fit) { - rectangle_decoder_->SetScaleRatios(view_->GetHorizontalScaleRatio(), - view_->GetVerticalScaleRatio()); - } else { - rectangle_decoder_->SetScaleRatios(1.0, 1.0); - } - - // TODO(wez): The RectangleDecoder should generate refresh events - // as necessary in response to any scaling change. - rectangle_decoder_->RefreshFullFrame(); -} - // static void ChromotingInstance::RegisterLogMessageHandler() { base::AutoLock lock(g_logging_lock.Get()); @@ -403,11 +333,9 @@ ChromotingStats* ChromotingInstance::GetStats() { } void ChromotingInstance::ReleaseAllKeys() { - if (!input_handler_.get()) { - return; + if (key_event_tracker_.get()) { + key_event_tracker_->ReleaseAllKeys(); } - - input_handler_->ReleaseAllKeys(); } } // namespace remoting diff --git a/remoting/client/plugin/chromoting_instance.h b/remoting/client/plugin/chromoting_instance.h index 427d420..2b11b5a 100644 --- a/remoting/client/plugin/chromoting_instance.h +++ b/remoting/client/plugin/chromoting_instance.h @@ -32,14 +32,15 @@ namespace remoting { namespace protocol { class ConnectionToHost; +class KeyEventTracker; } // namespace protocol class ChromotingClient; class ChromotingStats; class ClientContext; -class InputHandler; +class MouseInputFilter; +class PepperInputHandler; class PepperView; -class PepperViewProxy; class RectangleUpdateDecoder; struct ClientConfig; @@ -118,16 +119,10 @@ class ChromotingInstance : public pp::InstancePrivate { // True if scale to fit is enabled. bool scale_to_fit_; - // PepperViewProxy is refcounted and used to interface between chromoting - // objects and PepperView and perform thread switching. It wraps around - // |view_| and receives method calls on chromoting threads. These method - // calls are then delegates on the pepper thread. During destruction of - // ChromotingInstance we need to detach PepperViewProxy from PepperView since - // both ChromotingInstance and PepperView are destroyed and there will be - // outstanding tasks on the pepper message loop. - scoped_refptr<PepperViewProxy> view_proxy_; scoped_refptr<RectangleUpdateDecoder> rectangle_decoder_; - scoped_ptr<InputHandler> input_handler_; + scoped_ptr<MouseInputFilter> mouse_input_filter_; + scoped_ptr<protocol::KeyEventTracker> key_event_tracker_; + scoped_ptr<PepperInputHandler> input_handler_; scoped_ptr<ChromotingClient> client_; // XmppProxy is a refcounted interface used to perform thread-switching and diff --git a/remoting/client/plugin/chromoting_scriptable_object.cc b/remoting/client/plugin/chromoting_scriptable_object.cc index 218c3c9..1185570 100644 --- a/remoting/client/plugin/chromoting_scriptable_object.cc +++ b/remoting/client/plugin/chromoting_scriptable_object.cc @@ -103,9 +103,11 @@ void ChromotingScriptableObject::Init() { AddMethod("connect", &ChromotingScriptableObject::DoConnect); AddMethod("disconnect", &ChromotingScriptableObject::DoDisconnect); - AddMethod("setScaleToFit", &ChromotingScriptableObject::DoSetScaleToFit); AddMethod("onIq", &ChromotingScriptableObject::DoOnIq); AddMethod("releaseAllKeys", &ChromotingScriptableObject::DoReleaseAllKeys); + + // Older versions of the web app expect a setScaleToFit method. + AddMethod("setScaleToFit", &ChromotingScriptableObject::DoNothing); } bool ChromotingScriptableObject::HasProperty(const Var& name, Var* exception) { @@ -410,20 +412,8 @@ Var ChromotingScriptableObject::DoDisconnect(const std::vector<Var>& args, return Var(); } -Var ChromotingScriptableObject::DoSetScaleToFit(const std::vector<Var>& args, - Var* exception) { - if (args.size() != 1) { - *exception = Var("Usage: setScaleToFit(scale_to_fit)"); - return Var(); - } - - if (!args[0].is_bool()) { - *exception = Var("scale_to_fit must be a boolean."); - return Var(); - } - - VLOG(1) << "Setting scale-to-fit."; - instance_->SetScaleToFit(args[0].AsBool()); +Var ChromotingScriptableObject::DoNothing(const std::vector<Var>& args, + Var* exception) { return Var(); } diff --git a/remoting/client/plugin/chromoting_scriptable_object.h b/remoting/client/plugin/chromoting_scriptable_object.h index ece9003..8e50797 100644 --- a/remoting/client/plugin/chromoting_scriptable_object.h +++ b/remoting/client/plugin/chromoting_scriptable_object.h @@ -215,8 +215,8 @@ class ChromotingScriptableObject pp::Var DoConnect(const std::vector<pp::Var>& args, pp::Var* exception); pp::Var DoDisconnect(const std::vector<pp::Var>& args, pp::Var* exception); - // This method is called by JS to set scale-to-fit. - pp::Var DoSetScaleToFit(const std::vector<pp::Var>& args, pp::Var* exception); + // This method is used for legacy script APIs such as setScaleToFit. + pp::Var DoNothing(const std::vector<pp::Var>& args, pp::Var* exception); // This method is called by Javascript to provide responses to sendIq() // requests. diff --git a/remoting/client/plugin/pepper_input_handler.cc b/remoting/client/plugin/pepper_input_handler.cc index 1fe6f6e..c505df1 100644 --- a/remoting/client/plugin/pepper_input_handler.cc +++ b/remoting/client/plugin/pepper_input_handler.cc @@ -4,91 +4,102 @@ #include "remoting/client/plugin/pepper_input_handler.h" +#include "base/logging.h" #include "ppapi/cpp/input_event.h" #include "ppapi/cpp/point.h" -#include "remoting/client/plugin/pepper_view_proxy.h" +#include "remoting/proto/event.pb.h" namespace remoting { -using protocol::MouseEvent; - -PepperInputHandler::PepperInputHandler(ClientContext* context, - protocol::ConnectionToHost* connection, - PepperViewProxy* view) - : InputHandler(context, connection, view), - pepper_view_(view), - wheel_ticks_x_(0), - wheel_ticks_y_(0) { +PepperInputHandler::PepperInputHandler(protocol::InputStub* input_stub) + : input_stub_(input_stub), wheel_ticks_x_(0), wheel_ticks_y_(0) +{ } PepperInputHandler::~PepperInputHandler() { } -void PepperInputHandler::Initialize() { -} - -void PepperInputHandler::HandleKeyEvent(bool keydown, - const pp::KeyboardInputEvent& event) { - SendKeyEvent(keydown, event.GetKeyCode()); -} - -void PepperInputHandler::HandleCharacterEvent( - const pp::KeyboardInputEvent& event) { - // TODO(garykac): Coordinate key and char events. -} - -void PepperInputHandler::HandleMouseMoveEvent( - const pp::MouseInputEvent& event) { - SkIPoint p(SkIPoint::Make(event.GetPosition().x(), event.GetPosition().y())); - // Pepper gives co-ordinates in the plugin instance's co-ordinate system, - // which may be different from the host desktop's co-ordinate system. - double horizontal_ratio = view_->GetHorizontalScaleRatio(); - double vertical_ratio = view_->GetVerticalScaleRatio(); - - if (horizontal_ratio == 0.0) - horizontal_ratio = 1.0; - if (vertical_ratio == 0.0) - vertical_ratio = 1.0; - - SendMouseMoveEvent(p.x() / horizontal_ratio, p.y() / vertical_ratio); -} - -void PepperInputHandler::HandleMouseButtonEvent( - bool button_down, - const pp::MouseInputEvent& event) { - MouseEvent::MouseButton button = MouseEvent::BUTTON_UNDEFINED; - switch (event.GetButton()) { - case PP_INPUTEVENT_MOUSEBUTTON_LEFT: - button = MouseEvent::BUTTON_LEFT; - break; - case PP_INPUTEVENT_MOUSEBUTTON_MIDDLE: - button = MouseEvent::BUTTON_MIDDLE; - break; - case PP_INPUTEVENT_MOUSEBUTTON_RIGHT: - button = MouseEvent::BUTTON_RIGHT; - break; - case PP_INPUTEVENT_MOUSEBUTTON_NONE: - // Leave button undefined. +bool PepperInputHandler::HandleInputEvent(const pp::InputEvent& event) { + switch (event.GetType()) { + case PP_INPUTEVENT_TYPE_CONTEXTMENU: { + // We need to return true here or else we'll get a local (plugin) context + // menu instead of the mouseup event for the right click. + return true; + } + + case PP_INPUTEVENT_TYPE_KEYDOWN: + case PP_INPUTEVENT_TYPE_KEYUP: { + pp::KeyboardInputEvent pp_key_event(event); + protocol::KeyEvent key_event; + key_event.set_keycode(pp_key_event.GetKeyCode()); + key_event.set_pressed(event.GetType() == PP_INPUTEVENT_TYPE_KEYDOWN); + input_stub_->InjectKeyEvent(key_event); + return true; + } + + case PP_INPUTEVENT_TYPE_MOUSEDOWN: + case PP_INPUTEVENT_TYPE_MOUSEUP: { + pp::MouseInputEvent pp_mouse_event(event); + protocol::MouseEvent mouse_event; + switch (pp_mouse_event.GetButton()) { + case PP_INPUTEVENT_MOUSEBUTTON_LEFT: + mouse_event.set_button(protocol::MouseEvent::BUTTON_LEFT); + break; + case PP_INPUTEVENT_MOUSEBUTTON_MIDDLE: + mouse_event.set_button(protocol::MouseEvent::BUTTON_MIDDLE); + break; + case PP_INPUTEVENT_MOUSEBUTTON_RIGHT: + mouse_event.set_button(protocol::MouseEvent::BUTTON_RIGHT); + break; + case PP_INPUTEVENT_MOUSEBUTTON_NONE: + break; + } + if (mouse_event.has_button()) { + bool is_down = (event.GetType() == PP_INPUTEVENT_TYPE_MOUSEDOWN); + mouse_event.set_button_down(is_down); + input_stub_->InjectMouseEvent(mouse_event); + } + return true; + } + + case PP_INPUTEVENT_TYPE_MOUSEMOVE: + case PP_INPUTEVENT_TYPE_MOUSEENTER: + case PP_INPUTEVENT_TYPE_MOUSELEAVE: { + pp::MouseInputEvent pp_mouse_event(event); + protocol::MouseEvent mouse_event; + mouse_event.set_x(pp_mouse_event.GetPosition().x()); + mouse_event.set_y(pp_mouse_event.GetPosition().y()); + input_stub_->InjectMouseEvent(mouse_event); + return true; + } + + case PP_INPUTEVENT_TYPE_WHEEL: { + pp::WheelInputEvent pp_wheel_event(event); + + pp::FloatPoint ticks = pp_wheel_event.GetTicks(); + wheel_ticks_x_ += ticks.x(); + wheel_ticks_y_ += ticks.y(); + + int ticks_x = static_cast<int>(wheel_ticks_x_); + int ticks_y = static_cast<int>(wheel_ticks_y_); + if (ticks_x != 0 || ticks_y != 0) { + wheel_ticks_x_ -= ticks_x; + wheel_ticks_y_ -= ticks_y; + protocol::MouseEvent mouse_event; + mouse_event.set_wheel_offset_x(wheel_ticks_x_); + mouse_event.set_wheel_offset_y(wheel_ticks_y_); + input_stub_->InjectMouseEvent(mouse_event); + } + return true; + } + + default: { + LOG(INFO) << "Unhandled input event: " << event.GetType(); break; + } } - if (button != MouseEvent::BUTTON_UNDEFINED) { - SendMouseButtonEvent(button_down, button); - } -} - -void PepperInputHandler::HandleMouseWheelEvent( - const pp::WheelInputEvent& event) { - pp::FloatPoint ticks = event.GetTicks(); - wheel_ticks_x_ += ticks.x(); - wheel_ticks_y_ += ticks.y(); - int ticks_x = static_cast<int>(wheel_ticks_x_); - int ticks_y = static_cast<int>(wheel_ticks_y_); - if (ticks_x != 0 || ticks_y != 0) { - wheel_ticks_x_ -= ticks_x; - wheel_ticks_y_ -= ticks_y; - SendMouseWheelEvent(ticks_x, ticks_y); - } + return false; } } // namespace remoting diff --git a/remoting/client/plugin/pepper_input_handler.h b/remoting/client/plugin/pepper_input_handler.h index 759e5f2..9c9423e 100644 --- a/remoting/client/plugin/pepper_input_handler.h +++ b/remoting/client/plugin/pepper_input_handler.h @@ -6,37 +6,27 @@ #define REMOTING_CLIENT_PLUGIN_PEPPER_INPUT_HANDLER_H_ #include "base/compiler_specific.h" -#include "remoting/client/input_handler.h" +#include "remoting/protocol/input_stub.h" namespace pp { -class KeyboardInputEvent; -class MouseInputEvent; -class WheelInputEvent; -} +class InputEvent; +} // namespace pp namespace remoting { -class PepperViewProxy; +namespace protocol { +class InputStub; +} // namespace protocol -class PepperInputHandler : public InputHandler { +class PepperInputHandler { public: - PepperInputHandler(ClientContext* context, - protocol::ConnectionToHost* connection, - PepperViewProxy* view); + PepperInputHandler(protocol::InputStub* input_stub); virtual ~PepperInputHandler(); - virtual void Initialize() OVERRIDE; - - void HandleKeyEvent(bool keydown, const pp::KeyboardInputEvent& event); - void HandleCharacterEvent(const pp::KeyboardInputEvent& event); - - void HandleMouseMoveEvent(const pp::MouseInputEvent& event); - void HandleMouseButtonEvent(bool button_down, - const pp::MouseInputEvent& event); - void HandleMouseWheelEvent(const pp::WheelInputEvent& event); + bool HandleInputEvent(const pp::InputEvent& event); private: - PepperViewProxy* pepper_view_; + protocol::InputStub* input_stub_; float wheel_ticks_x_; float wheel_ticks_y_; diff --git a/remoting/client/plugin/pepper_view.cc b/remoting/client/plugin/pepper_view.cc index ec29290..d8a776c 100644 --- a/remoting/client/plugin/pepper_view.cc +++ b/remoting/client/plugin/pepper_view.cc @@ -262,12 +262,12 @@ void PepperView::SetConnectionState(protocol::ConnectionToHost::State state, } } -bool PepperView::SetPluginSize(const SkISize& plugin_size) { - if (plugin_size_ == plugin_size) +bool PepperView::SetViewSize(const SkISize& view_size) { + if (view_size_ == view_size) return false; - plugin_size_ = plugin_size; + view_size_ = view_size; - pp::Size pp_size = pp::Size(plugin_size.width(), plugin_size.height()); + pp::Size pp_size = pp::Size(view_size.width(), view_size.height()); graphics2d_ = pp::Graphics2D(instance_, pp_size, true); if (!instance_->BindGraphics(graphics2d_)) { @@ -275,14 +275,14 @@ bool PepperView::SetPluginSize(const SkISize& plugin_size) { return false; } - if (plugin_size.isEmpty()) + if (view_size.isEmpty()) return false; // Allocate the backing store to save the desktop image. if ((backing_store_.get() == NULL) || (backing_store_->size() != pp_size)) { VLOG(1) << "Allocate backing store: " - << plugin_size.width() << " x " << plugin_size.height(); + << view_size.width() << " x " << view_size.height(); backing_store_.reset( new pp::ImageData(instance_, pp::ImageData::GetNativeImageDataFormat(), pp_size, false)); @@ -292,22 +292,6 @@ bool PepperView::SetPluginSize(const SkISize& plugin_size) { return true; } -double PepperView::GetHorizontalScaleRatio() const { - if (instance_->DoScaling()) { - DCHECK(!host_size_.isEmpty()); - return 1.0 * plugin_size_.width() / host_size_.width(); - } - return 1.0; -} - -double PepperView::GetVerticalScaleRatio() const { - if (instance_->DoScaling()) { - DCHECK(!host_size_.isEmpty()); - return 1.0 * plugin_size_.height() / host_size_.height(); - } - return 1.0; -} - void PepperView::AllocateFrame(media::VideoFrame::Format format, const SkISize& size, scoped_refptr<media::VideoFrame>* frame_out, diff --git a/remoting/client/plugin/pepper_view.h b/remoting/client/plugin/pepper_view.h index a64ae7f..eab7f59 100644 --- a/remoting/client/plugin/pepper_view.h +++ b/remoting/client/plugin/pepper_view.h @@ -2,10 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// This class is an implementation of the ChromotingView using Pepper devices -// as the backing stores. This class is used only on pepper thread. -// Chromoting objects access this object through PepperViewProxy which -// delegates method calls on the pepper thread. +// This class is an implementation of the ChromotingView for Pepper. It is +// callable only on the Pepper thread. #ifndef REMOTING_CLIENT_PLUGIN_PEPPER_VIEW_H_ #define REMOTING_CLIENT_PLUGIN_PEPPER_VIEW_H_ @@ -28,8 +26,8 @@ class ClientContext; class PepperView : public ChromotingView, public FrameConsumer { public: - // Constructs a PepperView that draws to the |rendering_device|. The - // |rendering_device| instance must outlive this class. + // Constructs a PepperView for the |instance|. The |instance| and + // |context| must outlive this class. PepperView(ChromotingInstance* instance, ClientContext* context); virtual ~PepperView(); @@ -42,8 +40,6 @@ class PepperView : public ChromotingView, virtual void SetConnectionState( protocol::ConnectionToHost::State state, protocol::ConnectionToHost::Error error) OVERRIDE; - virtual double GetHorizontalScaleRatio() const OVERRIDE; - virtual double GetVerticalScaleRatio() const OVERRIDE; // FrameConsumer implementation. virtual void AllocateFrame(media::VideoFrame::Format format, @@ -55,9 +51,17 @@ class PepperView : public ChromotingView, RectVector* rects, const base::Closure& done) OVERRIDE; - // This is called when the dimension of the plugin element has changed. - // Return true if plugin size has changed, false otherwise. - bool SetPluginSize(const SkISize& plugin_size); + // Sets the display size of this view. Returns true if plugin size has + // changed, false otherwise. + bool SetViewSize(const SkISize& plugin_size); + + // Return the client view and original host dimensions. + const SkISize& get_view_size() const { + return view_size_; + } + const SkISize& get_host_size() const { + return host_size_; + } private: void OnPaintDone(base::Time paint_start); @@ -95,7 +99,7 @@ class PepperView : public ChromotingView, bool flush_blocked_; // The size of the plugin element. - SkISize plugin_size_; + SkISize view_size_; // The size of the host screen. SkISize host_size_; diff --git a/remoting/client/plugin/pepper_view_proxy.cc b/remoting/client/plugin/pepper_view_proxy.cc deleted file mode 100644 index 189602f..0000000 --- a/remoting/client/plugin/pepper_view_proxy.cc +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright (c) 2011 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 "remoting/client/plugin/pepper_view_proxy.h" - -#include "base/message_loop.h" -#include "remoting/client/client_context.h" -#include "remoting/client/plugin/chromoting_instance.h" - -namespace remoting { - -PepperViewProxy::PepperViewProxy(ChromotingInstance* instance, PepperView* view, - base::MessageLoopProxy* plugin_message_loop) - : instance_(instance), - view_(view), - plugin_message_loop_(plugin_message_loop) { -} - -PepperViewProxy::~PepperViewProxy() { -} - -bool PepperViewProxy::Initialize() { - // This method needs a return value so we can't post a task and process on - // another thread so just return true since PepperView doesn't do anything - // either. - return true; -} - -void PepperViewProxy::TearDown() { - if (instance_ && !plugin_message_loop_->BelongsToCurrentThread()) { - plugin_message_loop_->PostTask( - FROM_HERE, base::Bind(&PepperViewProxy::TearDown, this)); - return; - } - - if (view_) - view_->TearDown(); -} - -void PepperViewProxy::Paint() { - if (instance_ && !plugin_message_loop_->BelongsToCurrentThread()) { - plugin_message_loop_->PostTask( - FROM_HERE, base::Bind(&PepperViewProxy::Paint, this)); - return; - } - - if (view_) - view_->Paint(); -} - -void PepperViewProxy::SetSolidFill(uint32 color) { - if (instance_ && !plugin_message_loop_->BelongsToCurrentThread()) { - plugin_message_loop_->PostTask(FROM_HERE, base::Bind( - &PepperViewProxy::SetSolidFill, this, color)); - return; - } - - if (view_) - view_->SetSolidFill(color); -} - -void PepperViewProxy::UnsetSolidFill() { - if (instance_ && !plugin_message_loop_->BelongsToCurrentThread()) { - plugin_message_loop_->PostTask( - FROM_HERE, base::Bind(&PepperViewProxy::UnsetSolidFill, this)); - return; - } - - if (view_) - view_->UnsetSolidFill(); -} - -void PepperViewProxy::SetConnectionState( - protocol::ConnectionToHost::State state, - protocol::ConnectionToHost::Error error) { - if (instance_ && !plugin_message_loop_->BelongsToCurrentThread()) { - plugin_message_loop_->PostTask(FROM_HERE, base::Bind( - &PepperViewProxy::SetConnectionState, this, state, error)); - return; - } - - if (view_) - view_->SetConnectionState(state, error); -} - -double PepperViewProxy::GetHorizontalScaleRatio() const { - // This method returns a value, so must run synchronously, so must be - // called only on the pepper thread. - DCHECK(plugin_message_loop_->BelongsToCurrentThread()); - - if (view_) - return view_->GetHorizontalScaleRatio(); - return 1.0; -} - -double PepperViewProxy::GetVerticalScaleRatio() const { - // This method returns a value, so must run synchronously, so must be - // called only on the pepper thread. - DCHECK(plugin_message_loop_->BelongsToCurrentThread()); - - if (view_) - return view_->GetVerticalScaleRatio(); - return 1.0; -} - -void PepperViewProxy::AllocateFrame( - media::VideoFrame::Format format, - const SkISize& size, - scoped_refptr<media::VideoFrame>* frame_out, - const base::Closure& done) { - if (instance_ && !plugin_message_loop_->BelongsToCurrentThread()) { - plugin_message_loop_->PostTask(FROM_HERE, base::Bind( - &PepperViewProxy::AllocateFrame, this, format, size, frame_out, done)); - return; - } - - if (view_) { - view_->AllocateFrame(format, size, frame_out, done); - } -} - -void PepperViewProxy::ReleaseFrame(media::VideoFrame* frame) { - if (instance_ && !plugin_message_loop_->BelongsToCurrentThread()) { - plugin_message_loop_->PostTask(FROM_HERE, base::Bind( - &PepperViewProxy::ReleaseFrame, this, make_scoped_refptr(frame))); - return; - } - - if (view_) - view_->ReleaseFrame(frame); -} - -void PepperViewProxy::OnPartialFrameOutput(media::VideoFrame* frame, - RectVector* rects, - const base::Closure& done) { - if (instance_ && !plugin_message_loop_->BelongsToCurrentThread()) { - plugin_message_loop_->PostTask(FROM_HERE, base::Bind( - &PepperViewProxy::OnPartialFrameOutput, this, - make_scoped_refptr(frame), rects, done)); - return; - } - - if (view_) - view_->OnPartialFrameOutput(frame, rects, done); -} - -void PepperViewProxy::Detach() { - DCHECK(plugin_message_loop_->BelongsToCurrentThread()); - instance_ = NULL; - view_ = NULL; -} - -} // namespace remoting diff --git a/remoting/client/plugin/pepper_view_proxy.h b/remoting/client/plugin/pepper_view_proxy.h deleted file mode 100644 index b76da59..0000000 --- a/remoting/client/plugin/pepper_view_proxy.h +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) 2011 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. - -// PepperViewProxy is used to invoke PepperView object on pepper thread. It -// has the same interface as PepperView. When a method calls is received on -// any chromoting threads it delegates the method call to pepper thread. -// It also provide a detach mechanism so that when PepperView object is -// destroyed PepperViewProxy will not call it anymore. This is important in -// providing a safe shutdown of ChromotingInstance and PepperView. - -// This object is accessed on chromoting threads and pepper thread. The internal -// PepperView object is only accessed on pepper thread so as the Detach() method -// call. - -#ifndef REMOTING_CLIENT_PLUGIN_PEPPER_VIEW_PROXY_H_ -#define REMOTING_CLIENT_PLUGIN_PEPPER_VIEW_PROXY_H_ - -#include "base/memory/ref_counted.h" -#include "remoting/client/plugin/pepper_view.h" - -namespace base { -class MessageLoopProxy; -} // namespace base - -namespace remoting { - -class ChromotingInstance; - -class PepperViewProxy : public base::RefCountedThreadSafe<PepperViewProxy>, - public ChromotingView, - public FrameConsumer { - public: - PepperViewProxy(ChromotingInstance* instance, PepperView* view, - base::MessageLoopProxy* plugin_message_loop); - virtual ~PepperViewProxy(); - - // ChromotingView implementation. - virtual bool Initialize() OVERRIDE; - virtual void TearDown() OVERRIDE; - virtual void Paint() OVERRIDE; - virtual void SetSolidFill(uint32 color) OVERRIDE; - virtual void UnsetSolidFill() OVERRIDE; - virtual void SetConnectionState( - protocol::ConnectionToHost::State state, - protocol::ConnectionToHost::Error error) OVERRIDE; - - // This method returns a value, so must run synchronously, so must be - // called only on the pepper thread. - virtual double GetHorizontalScaleRatio() const OVERRIDE; - virtual double GetVerticalScaleRatio() const OVERRIDE; - - // FrameConsumer implementation. - virtual void AllocateFrame(media::VideoFrame::Format format, - const SkISize& size, - scoped_refptr<media::VideoFrame>* frame_out, - const base::Closure& done) OVERRIDE; - virtual void ReleaseFrame(media::VideoFrame* frame) OVERRIDE; - virtual void OnPartialFrameOutput(media::VideoFrame* frame, - RectVector* rects, - const base::Closure& done) OVERRIDE; - - // Remove the reference to |instance_| and |view_| by setting the value to - // NULL. - // This method should only be called on pepper thread. - void Detach(); - - private: - // This variable is accessed on chromoting threads and pepper thread. - // This is initialized when this object is constructed. Its value is reset - // to NULL on pepper thread when Detach() is called and there will be no - // other threads accessing this variable at the same time. Given the above - // conditions locking this variable is not necessary. - ChromotingInstance* instance_; - - // This variable is only accessed on the pepper thread. Locking is not - // necessary. - PepperView* view_; - - scoped_refptr<base::MessageLoopProxy> plugin_message_loop_; - - DISALLOW_COPY_AND_ASSIGN(PepperViewProxy); -}; - -} // namespace remoting - -#endif // REMOTING_CLIENT_PLUGIN_PEPPER_VIEW_PROXY_H_ diff --git a/remoting/client/rectangle_update_decoder.cc b/remoting/client/rectangle_update_decoder.cc index 09dfb4c..8b7ca9e 100644 --- a/remoting/client/rectangle_update_decoder.cc +++ b/remoting/client/rectangle_update_decoder.cc @@ -131,12 +131,11 @@ void RectangleUpdateDecoder::ProcessPacketData( SubmitToConsumer(); } -void RectangleUpdateDecoder::SetScaleRatios(double horizontal_ratio, - double vertical_ratio) { +void RectangleUpdateDecoder::SetOutputSize(const SkISize& size) { if (message_loop_ != MessageLoop::current()) { message_loop_->PostTask( - FROM_HERE, base::Bind(&RectangleUpdateDecoder::SetScaleRatios, - this, horizontal_ratio, vertical_ratio)); + FROM_HERE, base::Bind(&RectangleUpdateDecoder::SetOutputSize, + this, size)); return; } @@ -149,11 +148,10 @@ void RectangleUpdateDecoder::SetScaleRatios(double horizontal_ratio, // TODO(hclam): If the scale ratio has changed we should reallocate a // VideoFrame of different size. However if the scale ratio is always // smaller than 1.0 we can use the same video frame. - decoder_->SetScaleRatios(horizontal_ratio, vertical_ratio); - - // TODO(wez): Defer refresh, so that resize, which will affect both scale - // factor and clip rect, doesn't lead to unnecessary refreshes. - DoRefresh(); + if (decoder_.get()) { + decoder_->SetOutputSize(size); + RefreshFullFrame(); + } } void RectangleUpdateDecoder::UpdateClipRect(const SkIRect& new_clip_rect) { diff --git a/remoting/client/rectangle_update_decoder.h b/remoting/client/rectangle_update_decoder.h index 33bee55..9af727a 100644 --- a/remoting/client/rectangle_update_decoder.h +++ b/remoting/client/rectangle_update_decoder.h @@ -39,15 +39,12 @@ class RectangleUpdateDecoder : // executed. void DecodePacket(const VideoPacket* packet, const base::Closure& done); - // Set the scale ratio for the decoded video frame. Scale ratio greater - // than 1.0 is not supported. - void SetScaleRatios(double horizontal_ratio, double vertical_ratio); + // Set the output dimensions to scale video output to. + void SetOutputSize(const SkISize& size); // Set a new clipping rectangle for the decoder. Decoder should respect // this clipping rectangle and only decode content in this rectangle and // report dirty rectangles accordingly to enhance performance. - // - // If scale ratio is not 1.0 then clipping rectangle is ignored. void UpdateClipRect(const SkIRect& clip_rect); // Force the decoder to output the last decoded video frame without any diff --git a/remoting/host/client_session.cc b/remoting/host/client_session.cc index c358508..532b825 100644 --- a/remoting/host/client_session.cc +++ b/remoting/host/client_session.cc @@ -239,6 +239,7 @@ void ClientSession::RestoreEventState() { for (int i = 1; i < MouseEvent::BUTTON_MAX; i++) { if (remote_mouse_button_state_ & (1 << (i - 1))) { MouseEvent mouse; + // TODO(wez): Shouldn't [need to] set position here. mouse.set_x(remote_mouse_pos_.x()); mouse.set_y(remote_mouse_pos_.y()); mouse.set_button((MouseEvent::MouseButton)i); diff --git a/remoting/protocol/key_event_tracker.cc b/remoting/protocol/key_event_tracker.cc new file mode 100644 index 0000000..a2aa836 --- /dev/null +++ b/remoting/protocol/key_event_tracker.cc @@ -0,0 +1,48 @@ +// Copyright (c) 2011 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 "remoting/protocol/key_event_tracker.h" + +#include "base/logging.h" +#include "remoting/proto/event.pb.h" + +namespace remoting { +namespace protocol { + +KeyEventTracker::KeyEventTracker(InputStub* input_stub) + : input_stub_(input_stub) { +} + +KeyEventTracker::~KeyEventTracker() { + DCHECK(pressed_keys_.empty()); +} + +void KeyEventTracker::InjectKeyEvent(const KeyEvent& event) { + DCHECK(event.has_pressed()); + DCHECK(event.has_keycode()); + if (event.pressed()) { + pressed_keys_.insert(event.keycode()); + } else { + pressed_keys_.erase(event.keycode()); + } + input_stub_->InjectKeyEvent(event); +} + +void KeyEventTracker::InjectMouseEvent(const MouseEvent& event) { + input_stub_->InjectMouseEvent(event); +} + +void KeyEventTracker::ReleaseAllKeys() { + std::set<int>::iterator i; + for (i = pressed_keys_.begin(); i != pressed_keys_.end(); ++i) { + KeyEvent event; + event.set_keycode(*i); + event.set_pressed(false); + input_stub_->InjectKeyEvent(event); + } + pressed_keys_.clear(); +} + +} // namespace protocol +} // namespace remoting diff --git a/remoting/protocol/key_event_tracker.h b/remoting/protocol/key_event_tracker.h new file mode 100644 index 0000000..80ab6e2 --- /dev/null +++ b/remoting/protocol/key_event_tracker.h @@ -0,0 +1,43 @@ +// Copyright (c) 2011 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. + +#ifndef REMOTING_PROTOCOL_KEY_EVENT_TRACKER_H_ +#define REMOTING_PROTOCOL_KEY_EVENT_TRACKER_H_ + +#include <set> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "remoting/protocol/input_stub.h" + +namespace remoting { +namespace protocol { + +// Filtering InputStub which tracks key press and release events before passing +// them on to |input_stub|, and can dispatch release events to |input_stub| for +// all currently-pressed keys when necessary. +class KeyEventTracker : public InputStub { + public: + KeyEventTracker(protocol::InputStub* input_stub); + virtual ~KeyEventTracker(); + + // Dispatch release events for all currently-pressed keys to the InputStub. + void ReleaseAllKeys(); + + // InputStub interface. + virtual void InjectKeyEvent(const KeyEvent& event) OVERRIDE; + virtual void InjectMouseEvent(const MouseEvent& event) OVERRIDE; + + private: + protocol::InputStub* input_stub_; + + std::set<int> pressed_keys_; + + DISALLOW_COPY_AND_ASSIGN(KeyEventTracker); +}; + +} // namespace protocol +} // namespace remoting + +#endif // REMOTING_PROTOCOL_KEY_EVENT_TRACKER_H_ diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp index 9f65fc2..5b2bc26 100644 --- a/remoting/remoting.gyp +++ b/remoting/remoting.gyp @@ -265,8 +265,6 @@ 'client/plugin/pepper_plugin_thread_delegate.h', 'client/plugin/pepper_view.cc', 'client/plugin/pepper_view.h', - 'client/plugin/pepper_view_proxy.cc', - 'client/plugin/pepper_view_proxy.h', 'client/plugin/pepper_util.cc', 'client/plugin/pepper_util.h', 'client/plugin/pepper_xmpp_proxy.cc', @@ -632,15 +630,14 @@ 'client/chromoting_client.h', 'client/chromoting_stats.cc', 'client/chromoting_stats.h', - 'client/chromoting_view.cc', 'client/chromoting_view.h', 'client/client_config.cc', 'client/client_config.h', 'client/client_context.cc', 'client/client_context.h', 'client/frame_consumer.h', - 'client/input_handler.cc', - 'client/input_handler.h', + 'client/mouse_input_filter.cc', + 'client/mouse_input_filter.h', 'client/rectangle_update_decoder.cc', 'client/rectangle_update_decoder.h', ], @@ -780,6 +777,8 @@ 'protocol/jingle_session_manager.h', 'protocol/jingle_stream_connector.cc', 'protocol/jingle_stream_connector.h', + 'protocol/key_event_tracker.cc', + 'protocol/key_event_tracker.h', 'protocol/message_decoder.cc', 'protocol/message_decoder.h', 'protocol/message_reader.cc', |