summaryrefslogtreecommitdiffstats
path: root/remoting
diff options
context:
space:
mode:
authorsimonmorris@chromium.org <simonmorris@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-20 10:25:53 +0000
committersimonmorris@chromium.org <simonmorris@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-20 10:25:53 +0000
commit73a822fc4edecfd7995319f791f0fdd2fe60da60 (patch)
treeba9da5ad28528835015e5ec810110fdd6fc48ad2 /remoting
parent55cb9d5693f8b8e9ebac337d55c2dcab4cd27dd0 (diff)
downloadchromium_src-73a822fc4edecfd7995319f791f0fdd2fe60da60.zip
chromium_src-73a822fc4edecfd7995319f791f0fdd2fe60da60.tar.gz
chromium_src-73a822fc4edecfd7995319f791f0fdd2fe60da60.tar.bz2
If the user selects scale-to-fit, then PepperView starts
maintaining and displaying a scaled copy of its pixel backing store. BUG=none TEST=none Review URL: http://codereview.chromium.org/6811043 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@82279 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting')
-rw-r--r--remoting/client/appengine/chromoting_session.html2
-rw-r--r--remoting/client/appengine/static_files/chromoting_session.js8
-rw-r--r--remoting/client/appengine/static_files/main.css5
-rw-r--r--remoting/client/chromoting_view.h5
-rw-r--r--remoting/client/plugin/chromoting_instance.cc15
-rw-r--r--remoting/client/plugin/chromoting_instance.h7
-rw-r--r--remoting/client/plugin/chromoting_scriptable_object.cc20
-rw-r--r--remoting/client/plugin/chromoting_scriptable_object.h6
-rw-r--r--remoting/client/plugin/pepper_input_handler.cc11
-rw-r--r--remoting/client/plugin/pepper_view.cc253
-rw-r--r--remoting/client/plugin/pepper_view.h77
-rw-r--r--remoting/client/plugin/pepper_view_proxy.cc21
-rw-r--r--remoting/client/plugin/pepper_view_proxy.h22
-rw-r--r--remoting/client/x11_view.cc6
-rw-r--r--remoting/client/x11_view.h18
15 files changed, 423 insertions, 53 deletions
diff --git a/remoting/client/appengine/chromoting_session.html b/remoting/client/appengine/chromoting_session.html
index eba943d..8af2190 100644
--- a/remoting/client/appengine/chromoting_session.html
+++ b/remoting/client/appengine/chromoting_session.html
@@ -29,6 +29,8 @@ found in the LICENSE file.
<body class="chromoting_body" onload="init();">
<div id="status_msg_div">
<span id="status_msg" class="status_msg">Initializing...</span>
+ <input type="button" value="Scale to fit" class="scale_to_fit_toggle"
+ id="scale_to_fit_toggle" onclick="toggleScaleToFit();"/>
<input type="button" value="Show Debug Log" class="debug_log_toggle"
id="debug_log_toggle" onclick="toggleDebugLog();"/>
</div>
diff --git a/remoting/client/appengine/static_files/chromoting_session.js b/remoting/client/appengine/static_files/chromoting_session.js
index cb7813b..50c9079 100644
--- a/remoting/client/appengine/static_files/chromoting_session.js
+++ b/remoting/client/appengine/static_files/chromoting_session.js
@@ -10,6 +10,7 @@ var MAX_DEBUG_LOG_SIZE = 1000;
// old messages. This starts at 1 and is incremented for each new message.
chromoting.messageId = 1;
+chromoting.scaleToFit = false;
// Default to trying to sandboxed connections.
chromoting.connectMethod = 'sandboxed';
@@ -145,6 +146,13 @@ function toggleDebugLog() {
}
}
+function toggleScaleToFit() {
+ chromoting.scaleToFit = !chromoting.scaleToFit;
+ document.getElementById("scale_to_fit_toggle").value =
+ chromoting.scaleToFit ? "No scaling" : "Scale to fit";
+ chromoting.plugin.setScaleToFit(chromoting.scaleToFit);
+}
+
function submitLogin() {
var username = document.getElementById("username").value;
var password = document.getElementById("password").value;
diff --git a/remoting/client/appengine/static_files/main.css b/remoting/client/appengine/static_files/main.css
index 7fb6ed1..38a9e9a 100644
--- a/remoting/client/appengine/static_files/main.css
+++ b/remoting/client/appengine/static_files/main.css
@@ -148,6 +148,11 @@ a.hostentry {
float: right;
}
+.scale_to_fit_toggle {
+ line-height: 0.8em;
+ float: right;
+ }
+
.gaia_login_panel {
-webkit-user-select: none;
font-family: arial,sans-serif;
diff --git a/remoting/client/chromoting_view.h b/remoting/client/chromoting_view.h
index 5dfd408..0a8c721 100644
--- a/remoting/client/chromoting_view.h
+++ b/remoting/client/chromoting_view.h
@@ -9,6 +9,7 @@
#include "base/memory/ref_counted.h"
#include "media/base/video_frame.h"
+#include "ui/gfx/point.h"
class MessageLoop;
@@ -72,6 +73,10 @@ class ChromotingView {
// extends past the end of the backing store, it is filled with black.
virtual void SetViewport(int x, int y, int width, int height) = 0;
+ // Converts screen co-ordinates to host co-ordinates, and clips to the host
+ // screen.
+ virtual gfx::Point ConvertScreenToHost(const gfx::Point& p) const = 0;
+
protected:
// Framebuffer for the decoder.
scoped_refptr<media::VideoFrame> frame_;
diff --git a/remoting/client/plugin/chromoting_instance.cc b/remoting/client/plugin/chromoting_instance.cc
index a23598c..874e336 100644
--- a/remoting/client/plugin/chromoting_instance.cc
+++ b/remoting/client/plugin/chromoting_instance.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// 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.
@@ -185,6 +185,15 @@ void ChromotingInstance::ViewChanged(const pp::Rect& position,
view_->Paint();
}
+void ChromotingInstance::DidChangeView(const pp::Rect& position,
+ const pp::Rect& clip) {
+ // This lets |view_| implement scale-to-fit. But it only specifies a
+ // sub-rectangle of the plugin window as the rectangle on which the host
+ // screen can be displayed, so |view_| has to make sure the plugin window
+ // is large.
+ view_->SetScreenSize(clip.width(), clip.height());
+}
+
bool ChromotingInstance::HandleInputEvent(const PP_InputEvent& event) {
DCHECK(CurrentlyOnPluginThread());
@@ -261,6 +270,10 @@ void ChromotingInstance::SubmitLoginInfo(const std::string& username,
new DeleteTask<protocol::LocalLoginCredentials>(credentials));
}
+void ChromotingInstance::SetScaleToFit(bool scale_to_fit) {
+ view_proxy_->SetScaleToFit(scale_to_fit);
+}
+
void ChromotingInstance::LogDebugInfo(const std::string& info) {
GetScriptableObject()->LogDebugInfo(info);
}
diff --git a/remoting/client/plugin/chromoting_instance.h b/remoting/client/plugin/chromoting_instance.h
index 8c5aee8..3458c78 100644
--- a/remoting/client/plugin/chromoting_instance.h
+++ b/remoting/client/plugin/chromoting_instance.h
@@ -70,6 +70,10 @@ class ChromotingInstance : public pp::Instance {
virtual pp::Var GetInstanceObject();
virtual void ViewChanged(const pp::Rect& position, const pp::Rect& clip);
+ // pp::Instance interface.
+ virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip)
+ OVERRIDE;
+
// Convenience wrapper to get the ChromotingScriptableObject.
ChromotingScriptableObject* GetScriptableObject();
@@ -77,6 +81,9 @@ class ChromotingInstance : public pp::Instance {
void SubmitLoginInfo(const std::string& username,
const std::string& password);
+ // Called by ChromotingScriptableObject to set scale-to-fit.
+ void SetScaleToFit(bool scale_to_fit);
+
void LogDebugInfo(const std::string& info);
// Return statistics record by ChromotingClient.
diff --git a/remoting/client/plugin/chromoting_scriptable_object.cc b/remoting/client/plugin/chromoting_scriptable_object.cc
index 714be1f..e2b5fe9 100644
--- a/remoting/client/plugin/chromoting_scriptable_object.cc
+++ b/remoting/client/plugin/chromoting_scriptable_object.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// 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.
@@ -87,6 +87,7 @@ void ChromotingScriptableObject::Init() {
&ChromotingScriptableObject::DoConnectSandboxed);
AddMethod("disconnect", &ChromotingScriptableObject::DoDisconnect);
AddMethod("submitLoginInfo", &ChromotingScriptableObject::DoSubmitLogin);
+ AddMethod("setScaleToFit", &ChromotingScriptableObject::DoSetScaleToFit);
AddMethod("onIq", &ChromotingScriptableObject::DoOnIq);
}
@@ -416,6 +417,23 @@ Var ChromotingScriptableObject::DoSubmitLogin(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();
+ }
+
+ LogDebugInfo("Setting scale-to-fit.");
+ instance_->SetScaleToFit(args[0].AsBool());
+ return Var();
+}
+
Var ChromotingScriptableObject::DoOnIq(const std::vector<Var>& args,
Var* exception) {
if (args.size() != 1) {
diff --git a/remoting/client/plugin/chromoting_scriptable_object.h b/remoting/client/plugin/chromoting_scriptable_object.h
index bf997b3..62f9c68 100644
--- a/remoting/client/plugin/chromoting_scriptable_object.h
+++ b/remoting/client/plugin/chromoting_scriptable_object.h
@@ -80,6 +80,9 @@
//
// // Method for submitting login information.
// void submitLoginInfo(string username, string password);
+//
+// // Method for setting scale-to-fit.
+// void setScaleToFit(bool scale_to_fit);
// }
#ifndef REMOTING_CLIENT_PLUGIN_CHROMOTING_SCRIPTABLE_OBJECT_H_
@@ -193,6 +196,9 @@ class ChromotingScriptableObject
// This method is called by JS to provide login information.
pp::Var DoSubmitLogin(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 caleld by Javascript to provide responses to sendIq()
// requests when establishing a sandboxed Chromoting connection.
pp::Var DoOnIq(const std::vector<pp::Var>& args, pp::Var* exception);
diff --git a/remoting/client/plugin/pepper_input_handler.cc b/remoting/client/plugin/pepper_input_handler.cc
index 16a5738..452668e 100644
--- a/remoting/client/plugin/pepper_input_handler.cc
+++ b/remoting/client/plugin/pepper_input_handler.cc
@@ -1,10 +1,12 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// 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_input_handler.h"
#include "ppapi/c/pp_input_event.h"
+#include "remoting/client/chromoting_view.h"
+#include "ui/gfx/point.h"
namespace remoting {
@@ -35,8 +37,11 @@ void PepperInputHandler::HandleCharacterEvent(
void PepperInputHandler::HandleMouseMoveEvent(
const PP_InputEvent_Mouse& event) {
- SendMouseMoveEvent(static_cast<int>(event.x),
- static_cast<int>(event.y));
+ gfx::Point p(static_cast<int>(event.x), static_cast<int>(event.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.
+ p = view_->ConvertScreenToHost(p);
+ SendMouseMoveEvent(p.x(), p.y());
}
void PepperInputHandler::HandleMouseButtonEvent(
diff --git a/remoting/client/plugin/pepper_view.cc b/remoting/client/plugin/pepper_view.cc
index 6dc9a51..54b8344 100644
--- a/remoting/client/plugin/pepper_view.cc
+++ b/remoting/client/plugin/pepper_view.cc
@@ -22,8 +22,12 @@ namespace remoting {
PepperView::PepperView(ChromotingInstance* instance, ClientContext* context)
: instance_(instance),
context_(context),
- viewport_width_(0),
- viewport_height_(0),
+ screen_scale_(1.0),
+ scale_to_fit_(false),
+ host_width_(0),
+ host_height_(0),
+ client_width_(0),
+ client_height_(0),
is_static_fill_(false),
static_fill_color_(0),
ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)) {
@@ -51,11 +55,11 @@ void PepperView::Paint() {
if (is_static_fill_) {
LOG(ERROR) << "Static filling " << static_fill_color_;
pp::ImageData image(instance_, pp::ImageData::GetNativeImageDataFormat(),
- pp::Size(viewport_width_, viewport_height_),
+ pp::Size(host_width_, host_height_),
false);
if (image.is_null()) {
LOG(ERROR) << "Unable to allocate image of size: "
- << viewport_width_ << "x" << viewport_height_;
+ << host_width_ << "x" << host_height_;
return;
}
@@ -72,8 +76,8 @@ void PepperView::Paint() {
task_factory_.NewRunnableMethod(&PepperView::OnPaintDone,
base::Time::Now())));
} else {
- // TODO(ajwong): We need to keep a backing store image of the viewport that
- // has the data here which can be redrawn.
+ // TODO(ajwong): We need to keep a backing store image of the host screen
+ // that has the data here which can be redrawn.
return;
}
TraceContext::tracer()->PrintString("End Paint.");
@@ -94,6 +98,11 @@ void PepperView::PaintFrame(media::VideoFrame* frame, UpdatedRects* rects) {
LOG(ERROR) << "Backing store is not available.";
return;
}
+ if (DoScaling()) {
+ if (!scaled_backing_store_.get() || scaled_backing_store_->is_null()) {
+ LOG(ERROR) << "Scaled backing store is not available.";
+ }
+ }
// Copy updated regions to the backing store and then paint the regions.
for (size_t i = 0; i < rects->size(); ++i) {
@@ -116,10 +125,17 @@ void PepperView::PaintFrame(media::VideoFrame* frame, UpdatedRects* rects) {
out += backing_store_->stride();
}
- // Pepper Graphics 2D has a strange and badly documented API that the
- // point here is the offset from the source rect. Why?
- graphics2d_.PaintImageData(*backing_store_.get(), pp::Point(0, 0),
- pp::Rect(r.x(), r.y(), r.width(), r.height()));
+ if (DoScaling()) {
+ gfx::Rect r_scaled = UpdateScaledBackingStore(r);
+ graphics2d_.PaintImageData(*scaled_backing_store_.get(), pp::Point(0, 0),
+ pp::Rect(r_scaled.x(), r_scaled.y(),
+ r_scaled.width(), r_scaled.height()));
+ } else {
+ // Pepper Graphics 2D has a strange and badly documented API that the
+ // point here is the offset from the source rect. Why?
+ graphics2d_.PaintImageData(*backing_store_.get(), pp::Point(0, 0),
+ pp::Rect(r.x(), r.y(), r.width(), r.height()));
+ }
}
graphics2d_.Flush(TaskToCompletionCallback(
@@ -129,6 +145,76 @@ void PepperView::PaintFrame(media::VideoFrame* frame, UpdatedRects* rects) {
TraceContext::tracer()->PrintString("End Paint Frame.");
}
+gfx::Rect PepperView::UpdateScaledBackingStore(const gfx::Rect& r) {
+ const int kBytesPerPixel = GetBytesPerPixel(media::VideoFrame::RGB32);
+ // Find the updated rectangle in the scaled backing store.
+ gfx::Point top_left = ConvertHostToScreen(r.origin());
+ gfx::Point bottom_right = ConvertHostToScreen(gfx::Point(r.right(),
+ r.bottom()));
+ int r_scaled_left = top_left.x();
+ int r_scaled_right = bottom_right.x();
+ int r_scaled_top = top_left.y();
+ int r_scaled_bottom = bottom_right.y();
+ if (r_scaled_right <= r_scaled_left || r_scaled_bottom <= r_scaled_top)
+ return gfx::Rect(r_scaled_left, r_scaled_top, 0, 0);
+
+ // Allow for the fact that ConvertHostToScreen and ConvertScreenToHost aren't
+ // exact inverses.
+ r_scaled_right++;
+ r_scaled_bottom++;
+
+ // Clip the scaled rectangle.
+ r_scaled_left = std::max(r_scaled_left, 0);
+ r_scaled_left = std::min(r_scaled_left, client_width_);
+ r_scaled_right = std::max(r_scaled_right, 0);
+ r_scaled_right = std::min(r_scaled_right, client_width_);
+ r_scaled_top = std::max(r_scaled_top, 0);
+ r_scaled_top = std::min(r_scaled_top, client_height_);
+ r_scaled_bottom = std::max(r_scaled_bottom, 0);
+ r_scaled_bottom = std::min(r_scaled_bottom, client_height_);
+
+ // Blit from the backing store to the scaled backing store.
+ for (int y_scaled = r_scaled_top; y_scaled < r_scaled_bottom; y_scaled++) {
+ int y = ConvertScreenToHost(gfx::Point(0, y_scaled)).y();
+ // Special case where each pixel is a word.
+ if ((kBytesPerPixel == 4) && (backing_store_->stride() % 4 == 0) &&
+ (scaled_backing_store_->stride() % 4 == 0)) {
+ uint32* from = reinterpret_cast<uint32*>(backing_store_->data()) +
+ (y * backing_store_->stride() / 4);
+ uint32* to = reinterpret_cast<uint32*>(scaled_backing_store_->data()) +
+ (y_scaled * scaled_backing_store_->stride() / 4) + r_scaled_left;
+ uint32* to_max = to + (r_scaled_right - r_scaled_left);
+ const int* offset = &screen_x_to_host_x_[r_scaled_left];
+ while (to < to_max)
+ *to++ = from[*offset++];
+ } else {
+ // Currently that special case is the only case that's ever encountered.
+ NOTREACHED();
+ uint8* from = reinterpret_cast<uint8*>(backing_store_->data()) +
+ (y * backing_store_->stride());
+ uint8* to = reinterpret_cast<uint8*>(scaled_backing_store_->data()) +
+ (y_scaled * scaled_backing_store_->stride()) +
+ (r_scaled_left * kBytesPerPixel);
+ for (int x_sc = r_scaled_left; x_sc < r_scaled_right; x_sc++) {
+ int x = screen_x_to_host_x_[x_sc];
+ memcpy(to, from + (x * kBytesPerPixel), kBytesPerPixel);
+ to += kBytesPerPixel;
+ }
+ }
+ }
+ return gfx::Rect(r_scaled_left, r_scaled_top, r_scaled_right - r_scaled_left,
+ r_scaled_bottom - r_scaled_top);
+}
+
+void PepperView::BlankRect(pp::ImageData& image_data, const gfx::Rect& rect) {
+ const int kBytesPerPixel = GetBytesPerPixel(media::VideoFrame::RGB32);
+ for (int y = rect.y(); y < rect.bottom(); y++) {
+ uint8* to = reinterpret_cast<uint8*>(image_data.data()) +
+ (y * image_data.stride()) + (rect.x() * kBytesPerPixel);
+ memset(to, 0xff, rect.width() * kBytesPerPixel);
+ }
+}
+
void PepperView::SetSolidFill(uint32 color) {
DCHECK(CurrentlyOnPluginThread());
@@ -184,28 +270,151 @@ void PepperView::UpdateLoginStatus(bool success, const std::string& info) {
void PepperView::SetViewport(int x, int y, int width, int height) {
DCHECK(CurrentlyOnPluginThread());
- if ((width == viewport_width_) && (height == viewport_height_))
+ if ((width == host_width_) && (height == host_height_))
return;
- viewport_width_ = width;
- viewport_height_ = height;
+ host_width_ = width;
+ host_height_ = height;
+
+ ResizeInternals();
+ instance_->GetScriptableObject()->SetDesktopSize(host_width_, host_height_);
+}
+
+gfx::Point PepperView::ConvertScreenToHost(const gfx::Point& p) const {
+ DCHECK(CurrentlyOnPluginThread());
+
+ int x = static_cast<int>(p.x() / screen_scale_);
+ x = std::min(x, host_width_ - 1);
+ x = std::max(x, 0);
+ int y = static_cast<int>(p.y() / screen_scale_);
+ y = std::min(y, host_height_ - 1);
+ y = std::max(y, 0);
+ return gfx::Point(x, y);
+}
+
+gfx::Point PepperView::ConvertHostToScreen(const gfx::Point& p) const {
+ return gfx::Point(static_cast<int>(p.x() * screen_scale_),
+ static_cast<int>(p.y() * screen_scale_));
+}
+
+void PepperView::SetScreenScale(double screen_scale) {
+ if (screen_scale == screen_scale_)
+ return;
+ screen_scale_ = screen_scale;
+ ResizeInternals();
+ RefreshPaint();
+}
+
+void PepperView::RefreshPaint() {
+ if (DoScaling()) {
+ // Render from the whole backing store, to the scaled backing store, at the
+ // current scale.
+ gfx::Rect updated_rect = UpdateScaledBackingStore(gfx::Rect(
+ host_width_, host_height_));
+ // If the scale has just decreased, then there is stale raster data
+ // to the right of, and below, the scaled copy of the host screen that's
+ // just been rendered into the scaled backing store.
+ // So blank out everything to the east of that copy...
+ BlankRect(*scaled_backing_store_, gfx::Rect(
+ updated_rect.right(), 0,
+ scaled_backing_store_->size().width() - updated_rect.right(),
+ updated_rect.bottom()));
+ // ...and everything to the south and south-east.
+ BlankRect(*scaled_backing_store_, gfx::Rect(
+ 0, updated_rect.bottom(), scaled_backing_store_->size().width(),
+ scaled_backing_store_->size().height() - updated_rect.bottom()));
+ graphics2d_.PaintImageData(*scaled_backing_store_.get(), pp::Point(0, 0),
+ pp::Rect(scaled_backing_store_->size()));
+ graphics2d_.Flush(TaskToCompletionCallback(
+ task_factory_.NewRunnableMethod(&PepperView::OnRefreshPaintDone)));
+ } else {
+ graphics2d_.PaintImageData(*backing_store_.get(), pp::Point(0, 0),
+ pp::Rect(backing_store_->size()));
+ graphics2d_.Flush(TaskToCompletionCallback(
+ task_factory_.NewRunnableMethod(&PepperView::OnRefreshPaintDone)));
+ }
+}
+
+void PepperView::ResizeInternals() {
graphics2d_ = pp::Graphics2D(instance_,
- pp::Size(viewport_width_, viewport_height_),
+ pp::Size(host_width_, host_height_),
false);
if (!instance_->BindGraphics(graphics2d_)) {
LOG(ERROR) << "Couldn't bind the device context.";
return;
}
+ if (host_width_ == 0 && host_height_ == 0)
+ return;
+
// Allocate the backing store to save the desktop image.
- backing_store_.reset(
- new pp::ImageData(instance_, pp::ImageData::GetNativeImageDataFormat(),
- pp::Size(viewport_width_, viewport_height_), false));
- DCHECK(backing_store_.get() && !backing_store_->is_null())
- << "Not enough memory for backing store.";
+ pp::Size host_size(host_width_, host_height_);
+ if ((backing_store_.get() == NULL) || (backing_store_->size() != host_size)) {
+ backing_store_.reset(
+ new pp::ImageData(instance_, pp::ImageData::GetNativeImageDataFormat(),
+ host_size, false));
+ DCHECK(backing_store_.get() && !backing_store_->is_null())
+ << "Not enough memory for backing store.";
+ }
- instance_->GetScriptableObject()->SetDesktopSize(width, height);
+ // Allocate the scaled backing store.
+ // This is the same size as |graphics2d_|, so that it can be used to blank out
+ // stale regions of |graphics2d_|, as well as to update |graphics2d_| with
+ // fresh data.
+ if (DoScaling()) {
+ if ((scaled_backing_store_.get() == NULL) ||
+ (scaled_backing_store_->size() != host_size)) {
+ scaled_backing_store_.reset(
+ new pp::ImageData(instance_,
+ pp::ImageData::GetNativeImageDataFormat(),
+ host_size, false));
+ DCHECK(scaled_backing_store_.get() && !scaled_backing_store_->is_null())
+ << "Not enough memory for scaled backing store.";
+ }
+ } else {
+ scaled_backing_store_.reset();
+ }
+
+ // Cache the horizontal component of the map from client screen co-ordinates
+ // to host screen co-ordinates.
+ screen_x_to_host_x_.reset(new int[client_width_]);
+ for (int x = 0; x < client_width_; x++)
+ screen_x_to_host_x_[x] = ConvertScreenToHost(gfx::Point(x, 0)).x();
+}
+
+bool PepperView::DoScaling() const {
+ return (screen_scale_ != 1.0);
+}
+
+void PepperView::SetScreenSize(int width, int height) {
+ DCHECK(CurrentlyOnPluginThread());
+
+ client_width_ = width;
+ client_height_ = height;
+ if (!scale_to_fit_)
+ return;
+ if (host_width_ == 0 || host_height_ == 0) {
+ SetScreenScale(1.0);
+ return;
+ }
+ double scale_x = double(client_width_) / double(host_width_);
+ double scale_y = double(client_height_) / double(host_height_);
+ double scale = std::min(scale_x, scale_y);
+ SetScreenScale(scale);
+}
+
+void PepperView::SetScaleToFit(bool scale_to_fit) {
+ DCHECK(CurrentlyOnPluginThread());
+
+ if (scale_to_fit == scale_to_fit_)
+ return;
+ scale_to_fit_ = scale_to_fit;
+ if (scale_to_fit_) {
+ SetScreenSize(client_width_, client_height_);
+ } else {
+ SetScreenScale(1.0);
+ }
}
void PepperView::AllocateFrame(media::VideoFrame::Format format,
@@ -258,4 +467,8 @@ void PepperView::OnPaintDone(base::Time paint_start) {
return;
}
+void PepperView::OnRefreshPaintDone() {
+ DCHECK(CurrentlyOnPluginThread());
+}
+
} // namespace remoting
diff --git a/remoting/client/plugin/pepper_view.h b/remoting/client/plugin/pepper_view.h
index 30f2527..e869d91 100644
--- a/remoting/client/plugin/pepper_view.h
+++ b/remoting/client/plugin/pepper_view.h
@@ -31,14 +31,16 @@ class PepperView : public ChromotingView,
virtual ~PepperView();
// ChromotingView implementation.
- virtual bool Initialize();
- virtual void TearDown();
- virtual void Paint();
- virtual void SetSolidFill(uint32 color);
- virtual void UnsetSolidFill();
- virtual void SetConnectionState(ConnectionState state);
- virtual void UpdateLoginStatus(bool success, const std::string& info);
- virtual void SetViewport(int x, int y, int width, int height);
+ 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(ConnectionState state) OVERRIDE;
+ virtual void UpdateLoginStatus(bool success, const std::string& info)
+ OVERRIDE;
+ virtual void SetViewport(int x, int y, int width, int height) OVERRIDE;
+ virtual gfx::Point ConvertScreenToHost(const gfx::Point& p) const OVERRIDE;
// FrameConsumer implementation.
virtual void AllocateFrame(media::VideoFrame::Format format,
@@ -53,12 +55,45 @@ class PepperView : public ChromotingView,
UpdatedRects* rects,
Task* done);
+ // Sets the size of the visible screen area that this object can render into.
+ void SetScreenSize(int width, int height);
+
+ // Sets whether the host screen is scaled to fit the visible screen area.
+ void SetScaleToFit(bool enabled);
+
private:
void OnPaintDone(base::Time paint_start);
+ void OnRefreshPaintDone();
void PaintFrame(media::VideoFrame* frame, UpdatedRects* rects);
+ // Blits the pixels in |r| in the backing store into the corresponding
+ // rectangle in the scaled backing store. Returns that rectangle.
+ gfx::Rect UpdateScaledBackingStore(const gfx::Rect& r);
+
+ // Blanks out a rectangle in an image.
+ void BlankRect(pp::ImageData& image_data, const gfx::Rect& rect);
+
+ // Converts host co-ordinates to screen co-ordinates.
+ gfx::Point ConvertHostToScreen(const gfx::Point& p) const;
+
+ // Sets the screen scale. A value of 1.0 indicates no scaling.
+ void SetScreenScale(double screen_scale);
+
+ // Paints the entire host screen.
+ // This is called, for example, when the screen scale is changed.
+ void RefreshPaint();
+
+ // Resizes internals of this object after the host screen size has changed,
+ // or the scale applied to that screen has changed.
+ // More specifically, pepper's graphics object, the backing stores, and the
+ // scaling cache are resized and/or recalculated.
+ void ResizeInternals();
+
+ // Whether to scale the screen.
+ bool DoScaling() const;
+
// Reference to the creating plugin instance. Needed for interacting with
- // pepper. Marking explciitly as const since it must be initialized at
+ // pepper. Marking explicitly as const since it must be initialized at
// object creation, and never change.
ChromotingInstance* const instance_;
@@ -70,8 +105,28 @@ class PepperView : public ChromotingView,
// A backing store that saves the current desktop image.
scoped_ptr<pp::ImageData> backing_store_;
- int viewport_width_;
- int viewport_height_;
+ // A scaled copy of the backing store.
+ scoped_ptr<pp::ImageData> scaled_backing_store_;
+
+ // The factor by which to scale the host screen. A value of 1.0 indicates
+ // no scaling.
+ double screen_scale_;
+
+ // An array containing the x co-ordinate of the point on the host screen
+ // corresponding to the point (i, 0) on the client screen.
+ scoped_array<int> screen_x_to_host_x_;
+
+ // Whether to scale to fit.
+ bool scale_to_fit_;
+
+ // The size of the host screen.
+ int host_width_;
+ int host_height_;
+
+ // The size of the visible area on the client screen that can be used to
+ // display the host screen.
+ int client_width_;
+ int client_height_;
bool is_static_fill_;
uint32 static_fill_color_;
diff --git a/remoting/client/plugin/pepper_view_proxy.cc b/remoting/client/plugin/pepper_view_proxy.cc
index e01ee9f..5f523a1 100644
--- a/remoting/client/plugin/pepper_view_proxy.cc
+++ b/remoting/client/plugin/pepper_view_proxy.cc
@@ -103,6 +103,16 @@ void PepperViewProxy::SetViewport(int x, int y, int width, int height) {
view_->SetViewport(x, y, width, height);
}
+gfx::Point PepperViewProxy::ConvertScreenToHost(const gfx::Point& p) const {
+ // This method returns a value, so must run synchronously, so must be
+ // called only on the pepper thread.
+ DCHECK(CurrentlyOnPluginThread());
+
+ if (view_)
+ return view_->ConvertScreenToHost(p);
+ return gfx::Point();
+}
+
void PepperViewProxy::AllocateFrame(
media::VideoFrame::Format format,
size_t width,
@@ -150,6 +160,17 @@ void PepperViewProxy::OnPartialFrameOutput(media::VideoFrame* frame,
view_->OnPartialFrameOutput(frame, rects, done);
}
+void PepperViewProxy::SetScaleToFit(bool scale_to_fit) {
+ if (instance_ && !CurrentlyOnPluginThread()) {
+ RunTaskOnPluginThread(
+ NewTracedMethod(this, &PepperViewProxy::SetScaleToFit, scale_to_fit));
+ return;
+ }
+
+ if (view_)
+ view_->SetScaleToFit(scale_to_fit);
+}
+
void PepperViewProxy::Detach() {
DCHECK(CurrentlyOnPluginThread());
instance_ = NULL;
diff --git a/remoting/client/plugin/pepper_view_proxy.h b/remoting/client/plugin/pepper_view_proxy.h
index f6212d3..d9075442 100644
--- a/remoting/client/plugin/pepper_view_proxy.h
+++ b/remoting/client/plugin/pepper_view_proxy.h
@@ -32,14 +32,18 @@ class PepperViewProxy : public base::RefCountedThreadSafe<PepperViewProxy>,
virtual ~PepperViewProxy();
// ChromotingView implementation.
- virtual bool Initialize();
- virtual void TearDown();
- virtual void Paint();
- virtual void SetSolidFill(uint32 color);
- virtual void UnsetSolidFill();
- virtual void SetConnectionState(ConnectionState state);
- virtual void UpdateLoginStatus(bool success, const std::string& info);
- virtual void SetViewport(int x, int y, int width, int height);
+ 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(ConnectionState state) OVERRIDE;
+ virtual void UpdateLoginStatus(bool success, const std::string& info)
+ OVERRIDE;
+ virtual void SetViewport(int x, int y, int width, int height) OVERRIDE;
+ // This method returns a value, so must run synchronously, so must be
+ // called only on the pepper thread.
+ virtual gfx::Point ConvertScreenToHost(const gfx::Point& p) const OVERRIDE;
// FrameConsumer implementation.
virtual void AllocateFrame(media::VideoFrame::Format format,
@@ -54,6 +58,8 @@ class PepperViewProxy : public base::RefCountedThreadSafe<PepperViewProxy>,
UpdatedRects* rects,
Task* done);
+ void SetScaleToFit(bool scale_to_fit);
+
// Remove the reference to |instance_| and |view_| by setting the value to
// NULL.
// This method should only be called on pepper thread.
diff --git a/remoting/client/x11_view.cc b/remoting/client/x11_view.cc
index 2bbddd3..a7501d8 100644
--- a/remoting/client/x11_view.cc
+++ b/remoting/client/x11_view.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// 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.
@@ -145,6 +145,10 @@ void X11View::SetViewport(int x, int y, int width, int height) {
// TODO(garykac): Implement.
}
+gfx::Point X11View::ConvertScreenToHost(const gfx::Point& p) const {
+ return p;
+}
+
void X11View::InitPaintTarget() {
// Testing XRender support.
int dummy;
diff --git a/remoting/client/x11_view.h b/remoting/client/x11_view.h
index 21b6438..963e9b8 100644
--- a/remoting/client/x11_view.h
+++ b/remoting/client/x11_view.h
@@ -24,14 +24,16 @@ class X11View : public ChromotingView, public FrameConsumer {
virtual ~X11View();
// ChromotingView implementations.
- virtual bool Initialize();
- virtual void TearDown();
- virtual void Paint();
- virtual void SetSolidFill(uint32 color);
- virtual void UnsetSolidFill();
- virtual void SetConnectionState(ConnectionState s);
- virtual void UpdateLoginStatus(bool success, const std::string& info);
- virtual void SetViewport(int x, int y, int width, int height);
+ 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(ConnectionState s) OVERRIDE;
+ virtual void UpdateLoginStatus(bool success, const std::string& info)
+ OVERRIDE;
+ virtual void SetViewport(int x, int y, int width, int height) OVERRIDE;
+ virtual gfx::Point ConvertScreenToHost(const gfx::Point& p) const OVERRIDE;
// FrameConsumer implementation.
virtual void AllocateFrame(media::VideoFrame::Format format,