Chromium Code Reviews| 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())); |