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

Unified Diff: content/renderer/render_widget.cc

Issue 23364004: Implementation of device metrics emulation in render view. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Moved helper class to cc Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« content/renderer/render_view_impl.cc ('K') | « content/renderer/render_widget.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: content/renderer/render_widget.cc
===================================================================
--- content/renderer/render_widget.cc (revision 221161)
+++ content/renderer/render_widget.cc (working copy)
@@ -53,7 +53,7 @@
#include "third_party/WebKit/public/web/WebScreenInfo.h"
#include "third_party/skia/include/core/SkShader.h"
#include "ui/base/ui_base_switches.h"
-#include "ui/gfx/point.h"
+#include "ui/gfx/point_conversions.h"
#include "ui/gfx/rect_conversions.h"
#include "ui/gfx/size_conversions.h"
#include "ui/gfx/skia_util.h"
@@ -79,6 +79,7 @@
using WebKit::WebInputEvent;
using WebKit::WebKeyboardEvent;
using WebKit::WebMouseEvent;
+using WebKit::WebMouseWheelEvent;
using WebKit::WebNavigationPolicy;
using WebKit::WebPagePopup;
using WebKit::WebPoint;
@@ -186,6 +187,280 @@
namespace content {
+// RenderWidget::DeviceEmulator ------------------------------------------------
+
+class RenderWidget::DeviceEmulator {
aelias_OOO_until_Jul13 2013/09/20 07:10:14 I suggest renaming this to ScreenMetricsEmulator.
dgozman 2013/09/27 19:02:03 Done. I've left "device" in Blink API though, as "
+ public:
+ DeviceEmulator(const gfx::Size& device_size,
+ const gfx::Rect& widget_rect,
pfeldman 2013/09/19 17:27:16 Poor indent.
dgozman 2013/09/27 19:02:03 Done.
+ float device_scale_factor,
+ bool fit_to_view);
+ virtual ~DeviceEmulator();
+
+ base::WeakPtr<DeviceEmulator> AsWeakPtr();
+
+ void BeginEmulation(RenderWidget* widget);
aelias_OOO_until_Jul13 2013/09/20 07:10:14 If it's always the same RenderWidget, can we just
dgozman 2013/09/27 19:02:03 Done.
+ void ChangeEmulationParams(RenderWidget* widget,
+ DeviceEmulator* params);
+ void EndEmulation(RenderWidget* widget);
+
+ // The following methods alter handlers' behavior for messages related to
+ // widget size and position.
+ void OnResizeMessage(RenderWidget* widget,
+ const ViewMsg_Resize_Params& params);
+ void OnUpdateScreenRectsMessage(RenderWidget* widget,
+ const gfx::Rect view_screen_rect,
+ const gfx::Rect window_screen_rect);
+ void OnShowContextMenu(RenderWidget* widget, ContextMenuParams* params);
+
+ WebKit::WebInputEvent* ConvertInputEventToEmulated(
+ RenderWidget* widget, const WebKit::WebInputEvent* event);
+
+ // Created popups need to be repositioned.
+ WebKit::WebRect ConvertPopupScreenRectFromEmulated(
+ RenderWidget* popup, const WebKit::WebRect& rect);
+
+ private:
+ void Apply(RenderWidget* widget, float overdraw_bottom_height,
+ gfx::Rect resizer_rect, bool is_fullscreen);
+ void ConvertMouseEventToEmulated(WebKit::WebMouseEvent* event);
+ void ConvertTouchPointToEmulated(WebKit::WebTouchPoint* point);
+
+ // Parameters as passed by WebViewClient::EmulateDevice.
+ gfx::Size device_size_;
+ gfx::Rect widget_rect_;
+ float device_scale_factor_;
+ bool fit_to_view_;
+
+ // The computed scaled used to fit widget into browser window.
+ float scale_;
+
+ // Original values to restore back after emulation ends.
+ gfx::Size original_size_;
+ gfx::Size original_physical_backing_size_;
+ WebKit::WebScreenInfo original_screen_info_;
+ gfx::Rect original_view_screen_rect_;
+ gfx::Rect original_window_screen_rect_;
+
+ base::WeakPtrFactory<DeviceEmulator> weak_ptr_factory_;
+};
+
+RenderWidget::DeviceEmulator::DeviceEmulator(
+ const gfx::Size& device_size,
+ const gfx::Rect& widget_rect,
+ float device_scale_factor,
+ bool fit_to_view)
pfeldman 2013/09/19 17:27:16 scale_ is not initialized.
dgozman 2013/09/27 19:02:03 Done.
+ : device_size_(device_size),
+ widget_rect_(widget_rect),
+ device_scale_factor_(device_scale_factor),
+ fit_to_view_(fit_to_view),
+ weak_ptr_factory_(this) {
+}
+
+RenderWidget::DeviceEmulator::~DeviceEmulator() {
+}
+
+void RenderWidget::DeviceEmulator::BeginEmulation(RenderWidget* widget) {
+ original_size_ = widget->size_;
+ original_physical_backing_size_ = widget->physical_backing_size_;
+ original_screen_info_ = widget->screen_info_;
+ original_view_screen_rect_ = widget->view_screen_rect_;
+ original_window_screen_rect_ = widget->window_screen_rect_;
+ Apply(widget, widget->overdraw_bottom_height_,
+ widget->resizer_rect_, widget->is_fullscreen_);
+}
+
+void RenderWidget::DeviceEmulator::ChangeEmulationParams(
+ RenderWidget* widget, DeviceEmulator* params) {
+ device_size_ = params->device_size_;
+ widget_rect_ = params->widget_rect_;
+ device_scale_factor_ = params->device_scale_factor_;
+ fit_to_view_ = params->fit_to_view_;
+ Apply(widget, widget->overdraw_bottom_height_,
+ widget->resizer_rect_, widget->is_fullscreen_);
+}
+
+void RenderWidget::DeviceEmulator::EndEmulation(RenderWidget* widget) {
+ widget->screen_info_ = original_screen_info_;
+
+ widget->Send(new ViewHostMsg_SetExpectedSize(widget->routing_id(),
+ gfx::Size()));
+
+ widget->SetDeviceScaleFactor(original_screen_info_.deviceScaleFactor);
+ widget->SetDeviceEmulationParameters(false /* enabled */, 1.f, 1.f);
+ widget->view_screen_rect_ = original_view_screen_rect_;
+ widget->window_screen_rect_ = original_window_screen_rect_;
+ widget->Resize(original_size_, original_physical_backing_size_,
+ widget->overdraw_bottom_height_, widget->resizer_rect_,
+ widget->is_fullscreen_, NO_RESIZE_ACK);
+}
+
+void RenderWidget::DeviceEmulator::Apply(RenderWidget* widget,
+ float overdraw_bottom_height, gfx::Rect resizer_rect, bool is_fullscreen) {
+ if (fit_to_view_) {
+ float width_ratio = !original_size_.width() ? 1.f :
+ static_cast<float>(widget_rect_.width()) / original_size_.width();
+ float height_ratio = !original_size_.height() ? 1.f :
+ static_cast<float>(widget_rect_.height()) / original_size_.height();
+ float ratio = std::max(1.0f, std::max(width_ratio, height_ratio));
+ scale_ = 1.f / ratio;
+ } else {
+ scale_ = 1.f;
+ }
+
+ widget->screen_info_.rect = gfx::Rect(device_size_);
+ widget->screen_info_.availableRect = gfx::Rect(device_size_);
+ widget->screen_info_.deviceScaleFactor = device_scale_factor_;
+
+ // Pass two emulation parameters to the blink side:
+ // - we keep the real device scale factor in compositor to produce sharp image
+ // even when emulating different scale factor;
+ // - in order to fit into view, WebView applies scaling transform to the
+ // root layer.
+ widget->SetDeviceEmulationParameters(true /* enabled */,
+ original_screen_info_.deviceScaleFactor, scale_);
+
+ widget->SetDeviceScaleFactor(device_scale_factor_);
+ widget->view_screen_rect_ = widget_rect_;
+ widget->window_screen_rect_ = widget->screen_info_.availableRect;
+
+ // Make host accept an image of different size.
+ widget->Send(new ViewHostMsg_SetExpectedSize(widget->routing_id(),
+ gfx::ToCeiledSize(gfx::ScaleSize(widget_rect_.size(), scale_))));
+
+ gfx::Size physical_backing_size = gfx::ToCeiledSize(gfx::ScaleSize(
+ widget_rect_.size(), original_screen_info_.deviceScaleFactor * scale_));
+ widget->Resize(widget_rect_.size(), physical_backing_size,
+ overdraw_bottom_height, resizer_rect, is_fullscreen, NO_RESIZE_ACK);
+}
+
+void RenderWidget::DeviceEmulator::OnResizeMessage(
+ RenderWidget* widget, const ViewMsg_Resize_Params& params) {
+ bool need_ack = params.new_size != original_size_;
+ original_size_ = params.new_size;
+ original_physical_backing_size_ = params.physical_backing_size;
+ original_screen_info_ = params.screen_info;
+ Apply(widget, params.overdraw_bottom_height, params.resizer_rect,
+ params.is_fullscreen);
+
+ if (need_ack) {
+ widget->set_next_paint_is_resize_ack();
+ if (widget->is_accelerated_compositing_active_ && widget->compositor_)
+ widget->compositor_->SetNeedsRedrawRect(gfx::Rect(widget->size_));
+ else
+ widget->didInvalidateRect(gfx::Rect(widget->size_));
aelias_OOO_until_Jul13 2013/09/20 07:10:14 I thought accelerated compositing was mandatory fo
dgozman 2013/09/27 19:02:03 You are right. Removed.
+ }
+}
+
+void RenderWidget::DeviceEmulator::OnUpdateScreenRectsMessage(
+ RenderWidget* widget,
+ const gfx::Rect view_screen_rect,
+ const gfx::Rect window_screen_rect) {
+ original_view_screen_rect_ = view_screen_rect;
+ original_window_screen_rect_ = window_screen_rect;
+ widget->Send(new ViewHostMsg_UpdateScreenRects_ACK(widget->routing_id()));
+}
+
+void RenderWidget::DeviceEmulator::OnShowContextMenu(
+ RenderWidget* widget, ContextMenuParams* params) {
+ params->x *= scale_;
+ params->y *= scale_;
+}
+
+WebInputEvent* RenderWidget::DeviceEmulator::ConvertInputEventToEmulated(
aelias_OOO_until_Jul13 2013/09/20 07:10:14 It's the job of Source/web/WebInputEventConversion
dgozman 2013/09/27 19:02:03 Done. Please see https://codereview.chromium.org/2
+ RenderWidget* widget, const WebInputEvent* event) {
+ if (!event)
+ return NULL;
+
+ if (WebInputEvent::isKeyboardEventType(event->type)) {
+ const WebKeyboardEvent& keyboard_event =
+ *static_cast<const WebKeyboardEvent*>(event);
+ WebKeyboardEvent* result = new WebKeyboardEvent(keyboard_event);
pfeldman 2013/09/19 17:27:16 return new ...
dgozman 2013/09/27 19:02:03 Done.
+ return result;
+ }
+
+ if (WebInputEvent::isMouseEventType(event->type)) {
+ const WebMouseEvent& mouse_event =
+ *static_cast<const WebMouseEvent*>(event);
+ WebMouseEvent* result = new WebMouseEvent(mouse_event);
+ ConvertMouseEventToEmulated(result);
+ return result;
+ }
+
+ if (WebInputEvent::MouseWheel == event->type) {
+ const WebMouseWheelEvent& mouse_wheel_event =
+ *static_cast<const WebMouseWheelEvent*>(event);
+ WebMouseWheelEvent* result = new WebMouseWheelEvent(mouse_wheel_event);
+ ConvertMouseEventToEmulated(result);
+ return result;
+ }
+
+ if (WebInputEvent::isGestureEventType(event->type)) {
+ const WebGestureEvent& gesture_event =
+ *static_cast<const WebGestureEvent*>(event);
+ WebGestureEvent* result = new WebGestureEvent(gesture_event);
+ result->x = 1.f / scale_ * result->x;
+ result->y = 1.f / scale_ * result->y;
+ result->globalX = widget_rect_.x() + result->x;
+ result->globalY = widget_rect_.y() + result->y;
+ return result;
+ }
+
+ if (WebInputEvent::isTouchEventType(event->type)) {
+ const WebTouchEvent& touch_event =
+ *static_cast<const WebTouchEvent*>(event);
+ WebTouchEvent* result = new WebTouchEvent(touch_event);
+ for (size_t index = 0; index < result->touchesLength; ++index) {
pfeldman 2013/09/19 17:27:16 One line blocks don't need {}
dgozman 2013/09/27 19:02:03 Done.
+ ConvertTouchPointToEmulated(&result->touches[index]);
+ }
+ for (size_t index = 0; index < result->changedTouchesLength; ++index) {
+ ConvertTouchPointToEmulated(&result->changedTouches[index]);
+ }
+ for (size_t index = 0; index < result->targetTouchesLength; ++index) {
+ ConvertTouchPointToEmulated(&result->targetTouches[index]);
+ }
+ return result;
+ }
+
+ return NULL;
+}
+
+void RenderWidget::DeviceEmulator::ConvertMouseEventToEmulated(
+ WebKit::WebMouseEvent* event) {
+ event->x = 1.f / scale_ * event->x;
+ event->y = 1.f / scale_ * event->y;
+ event->movementX = 1.f / scale_ * event->movementX;
+ event->movementY = 1.f / scale_ * event->movementY;
+ event->windowX = widget_rect_.x() + event->x;
+ event->windowY = widget_rect_.y() + event->y;
+ event->globalX = event->windowX;
+ event->globalY = event->windowY;
+}
+
+void RenderWidget::DeviceEmulator::ConvertTouchPointToEmulated(
+ WebKit::WebTouchPoint* point) {
+ point->position.x = 1.f / scale_ * point->position.x;
+ point->position.y = 1.f / scale_ * point->position.y;
+ point->screenPosition.x = widget_rect_.x() + point->position.x;
+ point->screenPosition.y = widget_rect_.y() + point->position.y;
+}
+
+base::WeakPtr<RenderWidget::DeviceEmulator> RenderWidget::DeviceEmulator::AsWeakPtr() {
pfeldman 2013/09/19 17:27:16 80 chars limit please. base::WeakPtr<RenderWidget
dgozman 2013/09/27 19:02:03 Done.
+ return weak_ptr_factory_.GetWeakPtr();
+}
+
+WebKit::WebRect RenderWidget::DeviceEmulator::ConvertPopupScreenRectFromEmulated(
pfeldman 2013/09/19 17:27:16 ditto
dgozman 2013/09/27 19:02:03 Done.
+ RenderWidget* popup, const WebKit::WebRect& rect) {
+ WebKit::WebRect result = rect;
+ result.x = original_view_screen_rect_.x() +
+ (result.x - widget_rect_.x()) * scale_;
+ result.y = original_view_screen_rect_.y() +
+ (result.y - widget_rect_.y()) * scale_;
+ return result;
+}
+
+// RenderWidget ----------------------------------------------------------------
+
RenderWidget::RenderWidget(WebKit::WebPopupType popup_type,
const WebKit::WebScreenInfo& screen_info,
bool swapped_out,
@@ -368,6 +643,45 @@
#endif
}
+void RenderWidget::EmulateDevice(
+ bool enabled,
+ const gfx::Size& device_size,
+ const gfx::Rect& widget_rect,
+ float device_scale_factor,
+ bool fit_to_view) {
+ if (enabled) {
+ DeviceEmulator* helper = new DeviceEmulator(device_size, widget_rect,
+ device_scale_factor, fit_to_view);
+
+ if (!device_emulator_) {
+ device_emulator_.reset(helper);
+ device_emulator_->BeginEmulation(this);
pfeldman 2013/09/19 17:27:16 I prefer StartEmulation / UpdateEmulation / StopEm
dgozman 2013/09/27 19:02:03 BeginEmulation/EndEmulation are removed. I'd keep
+ } else {
+ device_emulator_->ChangeEmulationParams(this, helper);
aelias_OOO_until_Jul13 2013/09/20 07:10:14 You're leaking the "helper" object" in this codepa
dgozman 2013/09/27 19:02:03 Done.
+ }
+ } else {
+ if (device_emulator_)
+ device_emulator_->EndEmulation(this);
aelias_OOO_until_Jul13 2013/09/20 07:10:14 Doesn't look like keeping BeginEmulation/EndEmulat
dgozman 2013/09/27 19:02:03 Done.
+ device_emulator_.reset();
+ }
+}
+
+void RenderWidget::SetDeviceEmulationParameters(
+ bool enabled, float device_scale_factor, float root_layer_scale) {
+ // This is only supported in RenderView.
+ NOTREACHED();
+}
+
+void RenderWidget::OnShowHostContextMenu(ContextMenuParams* params) {
+ if (device_emulator_)
+ device_emulator_->OnShowContextMenu(this, params);
+}
+
+void RenderWidget::set_popup_device_emulator(
+ RenderWidget::DeviceEmulator *emulator) {
+ popup_device_emulator_ = emulator->AsWeakPtr();
+}
+
bool RenderWidget::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(RenderWidget, message)
@@ -531,6 +845,11 @@
}
void RenderWidget::OnResize(const ViewMsg_Resize_Params& params) {
+ if (device_emulator_) {
+ device_emulator_->OnResizeMessage(this, params);
+ return;
+ }
+
screen_info_ = params.screen_info;
SetDeviceScaleFactor(screen_info_.deviceScaleFactor);
Resize(params.new_size, params.physical_backing_size,
@@ -813,6 +1132,15 @@
const ui::LatencyInfo& latency_info,
bool is_keyboard_shortcut) {
handling_input_event_ = true;
+
+ scoped_ptr<const WebKit::WebInputEvent> owner;
+ if (device_emulator_) {
+ input_event = device_emulator_->ConvertInputEventToEmulated(
+ this, input_event);
+ if (input_event)
+ owner.reset(input_event);
pfeldman 2013/09/19 17:27:16 You can reset unconditionally.
dgozman 2013/09/27 19:02:03 Removed.
+ }
+
if (!input_event) {
handling_input_event_ = false;
return;
@@ -1776,7 +2104,13 @@
Send(new ViewHostMsg_SetTooltipText(routing_id_, text, hint));
}
-void RenderWidget::setWindowRect(const WebRect& pos) {
+void RenderWidget::setWindowRect(const WebRect& rect) {
+ WebRect pos = rect;
+ if (popup_device_emulator_) {
+ pos = popup_device_emulator_->ConvertPopupScreenRectFromEmulated(
+ this, rect);
+ }
+
if (did_show_) {
if (!RenderThreadImpl::current()->layout_test_mode()) {
Send(new ViewHostMsg_RequestMove(routing_id_, pos));
@@ -2017,6 +2351,11 @@
void RenderWidget::OnUpdateScreenRects(const gfx::Rect& view_screen_rect,
const gfx::Rect& window_screen_rect) {
+ if (device_emulator_) {
+ device_emulator_->OnUpdateScreenRectsMessage(
+ this, view_screen_rect, window_screen_rect);
+ return;
+ }
view_screen_rect_ = view_screen_rect;
window_screen_rect_ = window_screen_rect;
Send(new ViewHostMsg_UpdateScreenRects_ACK(routing_id()));
« content/renderer/render_view_impl.cc ('K') | « content/renderer/render_widget.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698