#include "base/metrics/histogram.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/sys_info.h"
#include "build/build_config.h"
#include "cc/base/switches.h"
#include "cc/debug/benchmark_instrumentation.h"
#include "content/renderer/gpu/compositor_output_surface.h"
#include "content/renderer/gpu/compositor_software_output_device.h"
#include "content/renderer/gpu/delegated_compositor_output_surface.h"
+#include "content/renderer/gpu/frame_swap_message_queue.h"
#include "content/renderer/gpu/mailbox_output_surface.h"
+#include "content/renderer/gpu/queue_message_swap_promise.h"
#include "content/renderer/gpu/render_widget_compositor.h"
#include "content/renderer/ime_event_guard.h"
#include "content/renderer/input/input_handler_manager.h"
#if defined(OS_ANDROID)
#include <android/keycodes.h>
-#include "base/android/sys_utils.h"
#include "content/renderer/android/synchronous_compositor_factory.h"
#endif
return it->second;
}
+bool IsThreadedCompositingEnabled() {
+ content::RenderThreadImpl* impl = content::RenderThreadImpl::current();
+ return impl && !!impl->compositor_message_loop_proxy().get();
+}
+
// TODO(brianderson): Replace the hard-coded threshold with a fraction of
// the BeginMainFrame interval.
// 4166us will allow 1/4 of a 60Hz interval or 1/2 of a 120Hz interval to
void OnUpdateScreenRectsMessage(const gfx::Rect& view_screen_rect,
const gfx::Rect& window_screen_rect);
void OnShowContextMenu(ContextMenuParams* params);
+ gfx::Rect AdjustValidationMessageAnchor(const gfx::Rect& anchor);
private:
void Reapply();
params->y += offset_.y();
}
+gfx::Rect RenderWidget::ScreenMetricsEmulator::AdjustValidationMessageAnchor(
+ const gfx::Rect& anchor) {
+ gfx::Rect scaled = gfx::ToEnclosedRect(gfx::ScaleRect(anchor, scale_));
+ scaled.set_x(scaled.x() + offset_.x());
+ scaled.set_y(scaled.y() + offset_.y());
+ return scaled;
+}
+
// RenderWidget ---------------------------------------------------------------
RenderWidget::RenderWidget(blink::WebPopupType popup_type,
suppress_next_char_events_(false),
screen_info_(screen_info),
device_scale_factor_(screen_info_.deviceScaleFactor),
- is_threaded_compositing_enabled_(false),
current_event_latency_info_(NULL),
next_output_surface_id_(0),
#if defined(OS_ANDROID)
body_background_color_(SK_ColorWHITE),
#endif
popup_origin_scale_for_emulation_(0.f),
+ frame_swap_message_queue_(new FrameSwapMessageQueue()),
resizing_mode_selector_(new ResizingModeSelector()),
context_menu_source_type_(ui::MENU_SOURCE_MOUSE),
has_host_context_menu_location_(false) {
if (!swapped_out)
RenderProcess::current()->AddRefProcess();
DCHECK(RenderThread::Get());
- is_threaded_compositing_enabled_ =
- CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableThreadedCompositing);
+ device_color_profile_.push_back('0');
}
RenderWidget::~RenderWidget() {
device_scale_factor_ = screen_info_.deviceScaleFactor;
}
+gfx::Rect RenderWidget::AdjustValidationMessageAnchor(const gfx::Rect& anchor) {
+ if (screen_metrics_emulator_)
+ return screen_metrics_emulator_->AdjustValidationMessageAnchor(anchor);
+ return anchor;
+}
+
void RenderWidget::SetScreenMetricsEmulationParameters(
float device_scale_factor,
const gfx::Point& root_layer_offset,
IPC_MESSAGE_HANDLER(InputMsg_HandleInputEvent, OnHandleInputEvent)
IPC_MESSAGE_HANDLER(InputMsg_CursorVisibilityChange,
OnCursorVisibilityChange)
+ IPC_MESSAGE_HANDLER(InputMsg_ImeSetComposition, OnImeSetComposition)
+ IPC_MESSAGE_HANDLER(InputMsg_ImeConfirmComposition, OnImeConfirmComposition)
IPC_MESSAGE_HANDLER(InputMsg_MouseCaptureLost, OnMouseCaptureLost)
IPC_MESSAGE_HANDLER(InputMsg_SetFocus, OnSetFocus)
IPC_MESSAGE_HANDLER(InputMsg_SyntheticGestureCompleted,
IPC_MESSAGE_HANDLER(ViewMsg_CandidateWindowUpdated,
OnCandidateWindowUpdated)
IPC_MESSAGE_HANDLER(ViewMsg_CandidateWindowHidden, OnCandidateWindowHidden)
- IPC_MESSAGE_HANDLER(ViewMsg_ImeSetComposition, OnImeSetComposition)
- IPC_MESSAGE_HANDLER(ViewMsg_ImeConfirmComposition, OnImeConfirmComposition)
IPC_MESSAGE_HANDLER(ViewMsg_Repaint, OnRepaint)
IPC_MESSAGE_HANDLER(ViewMsg_SetTextDirection, OnSetTextDirection)
IPC_MESSAGE_HANDLER(ViewMsg_Move_ACK, OnRequestMoveAck)
WasHidden());
}
-void RenderWidget::OnWasShown(bool needs_repainting) {
+void RenderWidget::OnWasShown(bool needs_repainting,
+ const ui::LatencyInfo& latency_info) {
TRACE_EVENT0("renderer", "RenderWidget::OnWasShown");
// During shutdown we can just ignore this message.
if (!webwidget_)
return;
// Generate a full repaint.
- if (compositor_)
+ if (compositor_) {
+ ui::LatencyInfo swap_latency_info(latency_info);
+ scoped_ptr<cc::SwapPromiseMonitor> latency_info_swap_promise_monitor(
+ compositor_->CreateLatencyInfoSwapPromiseMonitor(&swap_latency_info));
compositor_->SetNeedsForcedRedraw();
+ }
scheduleComposite();
}
#if defined(OS_ANDROID)
if (SynchronousCompositorFactory* factory =
SynchronousCompositorFactory::GetInstance()) {
- return factory->CreateOutputSurface(routing_id());
+ return factory->CreateOutputSurface(routing_id(),
+ frame_swap_message_queue_);
}
#endif
uint32 output_surface_id = next_output_surface_id_++;
if (command_line.HasSwitch(switches::kEnableDelegatedRenderer)) {
- DCHECK(is_threaded_compositing_enabled_);
+ DCHECK(IsThreadedCompositingEnabled());
return scoped_ptr<cc::OutputSurface>(
- new DelegatedCompositorOutputSurface(
- routing_id(),
- output_surface_id,
- context_provider));
+ new DelegatedCompositorOutputSurface(routing_id(),
+ output_surface_id,
+ context_provider,
+ frame_swap_message_queue_));
}
if (!context_provider.get()) {
scoped_ptr<cc::SoftwareOutputDevice> software_device(
new CompositorSoftwareOutputDevice());
- return scoped_ptr<cc::OutputSurface>(new CompositorOutputSurface(
- routing_id(),
- output_surface_id,
- NULL,
- software_device.Pass(),
- true));
+ return scoped_ptr<cc::OutputSurface>(
+ new CompositorOutputSurface(routing_id(),
+ output_surface_id,
+ NULL,
+ software_device.Pass(),
+ frame_swap_message_queue_,
+ true));
}
if (command_line.HasSwitch(cc::switches::kCompositeToMailbox)) {
// Composite-to-mailbox is currently used for layout tests in order to cause
// them to draw inside in the renderer to do the readback there. This should
// no longer be the case when crbug.com/311404 is fixed.
- DCHECK(is_threaded_compositing_enabled_ ||
+ DCHECK(IsThreadedCompositingEnabled() ||
RenderThreadImpl::current()->layout_test_mode());
cc::ResourceFormat format = cc::RGBA_8888;
-#if defined(OS_ANDROID)
- if (base::android::SysUtils::IsLowEndDevice())
+ if (base::SysInfo::IsLowEndDevice())
format = cc::RGB_565;
-#endif
return scoped_ptr<cc::OutputSurface>(
- new MailboxOutputSurface(
- routing_id(),
- output_surface_id,
- context_provider,
- scoped_ptr<cc::SoftwareOutputDevice>(),
- format));
+ new MailboxOutputSurface(routing_id(),
+ output_surface_id,
+ context_provider,
+ scoped_ptr<cc::SoftwareOutputDevice>(),
+ frame_swap_message_queue_,
+ format));
}
bool use_swap_compositor_frame_message = false;
return scoped_ptr<cc::OutputSurface>(
- new CompositorOutputSurface(
- routing_id(),
- output_surface_id,
- context_provider,
- scoped_ptr<cc::SoftwareOutputDevice>(),
- use_swap_compositor_frame_message));
+ new CompositorOutputSurface(routing_id(),
+ output_surface_id,
+ context_provider,
+ scoped_ptr<cc::SoftwareOutputDevice>(),
+ frame_swap_message_queue_,
+ use_swap_compositor_frame_message));
}
void RenderWidget::OnSwapBuffersAborted() {
return;
base::AutoReset<WebInputEvent::Type> handling_event_type_resetter(
&handling_event_type_, input_event->type);
+#if defined(OS_ANDROID)
+ // On Android, when the delete key or forward delete key is pressed using IME,
+ // |AdapterInputConnection| generates input key events to make sure all JS
+ // listeners that monitor KeyUp and KeyDown events receive the proper key
+ // code. Since this input key event comes from IME, we need to set the
+ // IME event guard here to make sure it does not interfere with other IME
+ // events.
+ scoped_ptr<ImeEventGuard> ime_event_guard_maybe;
+ if (WebInputEvent::isKeyboardEventType(input_event->type)) {
+ const WebKeyboardEvent& key_event =
+ *static_cast<const WebKeyboardEvent*>(input_event);
+ if (key_event.nativeKeyCode == AKEYCODE_FORWARD_DEL ||
+ key_event.nativeKeyCode == AKEYCODE_DEL) {
+ ime_event_guard_maybe.reset(new ImeEventGuard(this));
+ }
+ }
+#endif
base::AutoReset<const ui::LatencyInfo*> resetter(¤t_event_latency_info_,
&latency_info);
}
void RenderWidget::initializeLayerTreeView() {
- compositor_ = RenderWidgetCompositor::Create(
- this, is_threaded_compositing_enabled_);
+ compositor_ =
+ RenderWidgetCompositor::Create(this, IsThreadedCompositingEnabled());
compositor_->setViewportSize(size_, physical_backing_size_);
if (init_complete_)
StartCompositor();
#endif // defined(VIDEO_HOLE)
}
+// static
+scoped_ptr<cc::SwapPromise> RenderWidget::QueueMessageImpl(
+ IPC::Message* msg,
+ MessageDeliveryPolicy policy,
+ FrameSwapMessageQueue* frame_swap_message_queue,
+ scoped_refptr<IPC::SyncMessageFilter> sync_message_filter,
+ bool commit_requested,
+ int source_frame_number) {
+ if (policy == MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE &&
+ // No need for lock: this gets changed only on this thread.
+ !commit_requested &&
+ // No need for lock: Messages are only enqueued from this thread, if we
+ // don't have any now, no other thread will add any.
+ frame_swap_message_queue->Empty()) {
+ sync_message_filter->Send(msg);
+ return scoped_ptr<cc::SwapPromise>();
+ }
+
+ bool first_message_for_frame = false;
+ frame_swap_message_queue->QueueMessageForFrame(policy,
+ source_frame_number,
+ make_scoped_ptr(msg),
+ &first_message_for_frame);
+ if (first_message_for_frame) {
+ scoped_ptr<cc::SwapPromise> promise(new QueueMessageSwapPromise(
+ sync_message_filter, frame_swap_message_queue, source_frame_number));
+ return promise.PassAs<cc::SwapPromise>();
+ }
+ return scoped_ptr<cc::SwapPromise>();
+}
+
+void RenderWidget::QueueMessage(IPC::Message* msg,
+ MessageDeliveryPolicy policy) {
+ // RenderThreadImpl::current() is NULL in some tests.
+ if (!compositor_ || !RenderThreadImpl::current()) {
+ Send(msg);
+ return;
+ }
+
+ scoped_ptr<cc::SwapPromise> swap_promise =
+ QueueMessageImpl(msg,
+ policy,
+ frame_swap_message_queue_,
+ RenderThreadImpl::current()->sync_message_filter(),
+ compositor_->commitRequested(),
+ compositor_->GetSourceFrameNumber());
+
+ if (swap_promise) {
+ compositor_->QueueSwapPromise(swap_promise.Pass());
+ compositor_->SetNeedsCommit();
+ }
+}
+
void RenderWidget::didCommitAndDrawCompositorFrame() {
// NOTE: Tests may break if this event is renamed or moved. See
// tab_capture_performancetest.cc.
// If we failed to set the composition text, then we need to let the browser
// process to cancel the input method's ongoing composition session, to make
// sure we are in a consistent state.
- Send(new ViewHostMsg_ImeCancelComposition(routing_id()));
+ Send(new InputHostMsg_ImeCancelComposition(routing_id()));
}
#if defined(OS_MACOSX) || defined(USE_AURA)
UpdateCompositionInfo(true);
Send(new ViewHostMsg_UpdateScreenRects_ACK(routing_id()));
}
-#if defined(OS_ANDROID)
+void RenderWidget::showImeIfNeeded() {
+ OnShowImeIfNeeded();
+}
+
void RenderWidget::OnShowImeIfNeeded() {
+#if defined(OS_ANDROID) || defined(USE_AURA)
UpdateTextInputState(SHOW_IME_IF_NEEDED, FROM_NON_IME);
+#endif
}
+#if defined(OS_ANDROID)
void RenderWidget::IncrementOutstandingImeEventAcks() {
++outstanding_ime_acks_;
}
) {
ViewHostMsg_TextInputState_Params p;
p.type = new_type;
+ p.flags = new_info.flags;
p.mode = new_mode;
p.value = new_info.value.utf8();
p.selection_start = new_info.selectionStart;
return;
composition_character_bounds_ = character_bounds;
composition_range_ = range;
- Send(new ViewHostMsg_ImeCompositionRangeChanged(
+ Send(new InputHostMsg_ImeCompositionRangeChanged(
routing_id(), composition_range_, composition_character_bounds_));
}
// If a composition text exists, then we need to let the browser process
// to cancel the input method's ongoing composition session.
if (webwidget_->confirmComposition())
- Send(new ViewHostMsg_ImeCancelComposition(routing_id()));
+ Send(new InputHostMsg_ImeCancelComposition(routing_id()));
}
#if defined(OS_MACOSX) || defined(USE_AURA)
// uploads, after which we are just wasting memory. Since we don't
// know our upload throughput yet, this just caps our memory usage.
size_t divider = 1;
- if (base::android::SysUtils::IsLowEndDevice())
+ if (base::SysInfo::IsLowEndDevice())
divider = 6;
// For reference Nexus10 can upload 1MB in about 2.5ms.
const double max_mb_uploaded_per_ms = 2.0 / (5 * divider);