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())); |