blob: 28a86d8c335d4714a43235cac1dd7511d0fed1cb [file] [log] [blame]
// Copyright (c) 2012 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 "content/browser/renderer_host/render_widget_host_view_android.h"
#include "base/bind.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/utf_string_conversions.h"
#include "content/browser/android/content_view_core_impl.h"
#include "content/browser/android/draw_delegate_impl.h"
#include "content/browser/gpu/gpu_surface_tracker.h"
#include "content/browser/renderer_host/compositor_impl_android.h"
#include "content/browser/renderer_host/image_transport_factory_android.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/common/android/device_info.h"
#include "content/common/gpu/gpu_messages.h"
#include "content/common/view_messages.h"
#include "third_party/WebKit/Source/Platform/chromium/public/WebSize.h"
namespace content {
RenderWidgetHostViewAndroid::RenderWidgetHostViewAndroid(
RenderWidgetHostImpl* widget_host,
ContentViewCoreImpl* content_view_core)
: host_(widget_host),
// ContentViewCoreImpl represents the native side of the Java
// ContentViewCore. It being NULL means that it is not attached to the
// View system yet, so we treat it as hidden.
is_hidden_(!content_view_core),
content_view_core_(content_view_core),
ime_adapter_android_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
texture_layer_(WebKit::WebExternalTextureLayer::create()) {
host_->SetView(this);
// RenderWidgetHost is initialized as visible. If is_hidden_ is true, tell
// RenderWidgetHost to hide.
if (is_hidden_)
host_->WasHidden();
texture_layer_->layer()->setDrawsContent(!is_hidden_);
host_->AttachLayer(texture_layer_->layer());
}
RenderWidgetHostViewAndroid::~RenderWidgetHostViewAndroid() {
if (!shared_surface_.is_null()) {
ImageTransportFactoryAndroid::GetInstance()->DestroySharedSurfaceHandle(
shared_surface_);
}
}
void RenderWidgetHostViewAndroid::InitAsChild(gfx::NativeView parent_view) {
NOTIMPLEMENTED();
}
void RenderWidgetHostViewAndroid::InitAsPopup(
RenderWidgetHostView* parent_host_view, const gfx::Rect& pos) {
NOTIMPLEMENTED();
}
void RenderWidgetHostViewAndroid::InitAsFullscreen(
RenderWidgetHostView* reference_host_view) {
NOTIMPLEMENTED();
}
RenderWidgetHost*
RenderWidgetHostViewAndroid::GetRenderWidgetHost() const {
return host_;
}
void RenderWidgetHostViewAndroid::WasShown() {
if (!is_hidden_)
return;
is_hidden_ = false;
host_->WasShown();
}
void RenderWidgetHostViewAndroid::WasHidden() {
if (is_hidden_)
return;
// If we receive any more paint messages while we are hidden, we want to
// ignore them so we don't re-allocate the backing store. We will paint
// everything again when we become visible again.
//
is_hidden_ = true;
// Inform the renderer that we are being hidden so it can reduce its resource
// utilization.
host_->WasHidden();
}
void RenderWidgetHostViewAndroid::SetSize(const gfx::Size& size) {
// Update the size of the RWH.
if (requested_size_.width() != size.width() ||
requested_size_.height() != size.height()) {
requested_size_ = gfx::Size(size.width(), size.height());
host_->WasResized();
}
texture_layer_->layer()->setBounds(size);
}
void RenderWidgetHostViewAndroid::SetBounds(const gfx::Rect& rect) {
if (rect.origin().x() || rect.origin().y()) {
VLOG(0) << "SetBounds not implemented for (x,y)!=(0,0)";
}
SetSize(rect.size());
}
gfx::NativeView RenderWidgetHostViewAndroid::GetNativeView() const {
return content_view_core_;
}
gfx::NativeViewId RenderWidgetHostViewAndroid::GetNativeViewId() const {
return reinterpret_cast<gfx::NativeViewId>(
const_cast<RenderWidgetHostViewAndroid*>(this));
}
gfx::NativeViewAccessible
RenderWidgetHostViewAndroid::GetNativeViewAccessible() {
NOTIMPLEMENTED();
return NULL;
}
void RenderWidgetHostViewAndroid::MovePluginWindows(
const gfx::Point& scroll_offset,
const std::vector<webkit::npapi::WebPluginGeometry>& moves) {
// We don't have plugin windows on Android. Do nothing. Note: this is called
// from RenderWidgetHost::OnMsgUpdateRect which is itself invoked while
// processing the corresponding message from Renderer.
}
void RenderWidgetHostViewAndroid::Focus() {
host_->Focus();
host_->SetInputMethodActive(true);
}
void RenderWidgetHostViewAndroid::Blur() {
host_->Send(new ViewMsg_ExecuteEditCommand(
host_->GetRoutingID(), "Unselect", ""));
host_->SetInputMethodActive(false);
host_->Blur();
}
bool RenderWidgetHostViewAndroid::HasFocus() const {
if (!content_view_core_)
return false; // ContentViewCore not created yet.
return content_view_core_->HasFocus();
}
bool RenderWidgetHostViewAndroid::IsSurfaceAvailableForCopy() const {
NOTIMPLEMENTED();
return false;
}
void RenderWidgetHostViewAndroid::Show() {
texture_layer_->layer()->setDrawsContent(true);
}
void RenderWidgetHostViewAndroid::Hide() {
texture_layer_->layer()->setDrawsContent(false);
}
bool RenderWidgetHostViewAndroid::IsShowing() {
return !is_hidden_;
}
gfx::Rect RenderWidgetHostViewAndroid::GetViewBounds() const {
gfx::Size bounds = DrawDelegateImpl::GetInstance()->GetBounds();
if (!bounds.IsEmpty())
return gfx::Rect(bounds);
if (content_view_core_) {
return content_view_core_->GetBounds();
} else {
// The ContentViewCore has not been created yet. This only happens when
// renderer asks for creating new window, for example,
// javascript window.open().
return gfx::Rect(0, 0, 0, 0);
}
}
void RenderWidgetHostViewAndroid::UpdateCursor(const WebCursor& cursor) {
// There are no cursors on Android.
}
void RenderWidgetHostViewAndroid::SetIsLoading(bool is_loading) {
// Do nothing. The UI notification is handled through ContentViewClient which
// is TabContentsDelegate.
}
void RenderWidgetHostViewAndroid::TextInputStateChanged(
const ViewHostMsg_TextInputState_Params& params) {
if (is_hidden_)
return;
content_view_core_->ImeUpdateAdapter(
GetNativeImeAdapter(),
static_cast<int>(params.type),
params.value, params.selection_start, params.selection_end,
params.composition_start, params.composition_end,
params.show_ime_if_needed);
}
int RenderWidgetHostViewAndroid::GetNativeImeAdapter() {
return reinterpret_cast<int>(&ime_adapter_android_);
}
void RenderWidgetHostViewAndroid::ImeCancelComposition() {
ime_adapter_android_.CancelComposition();
}
void RenderWidgetHostViewAndroid::DidUpdateBackingStore(
const gfx::Rect& scroll_rect, int scroll_dx, int scroll_dy,
const std::vector<gfx::Rect>& copy_rects) {
NOTIMPLEMENTED();
}
void RenderWidgetHostViewAndroid::RenderViewGone(
base::TerminationStatus status, int error_code) {
Destroy();
}
void RenderWidgetHostViewAndroid::Destroy() {
host_->RemoveLayer(texture_layer_->layer());
content_view_core_ = NULL;
// The RenderWidgetHost's destruction led here, so don't call it.
host_ = NULL;
delete this;
}
void RenderWidgetHostViewAndroid::SetTooltipText(
const string16& tooltip_text) {
// Tooltips don't makes sense on Android.
}
void RenderWidgetHostViewAndroid::SelectionChanged(const string16& text,
size_t offset,
const ui::Range& range) {
RenderWidgetHostViewBase::SelectionChanged(text, offset, range);
if (text.empty() || range.is_empty() || !content_view_core_)
return;
size_t pos = range.GetMin() - offset;
size_t n = range.length();
DCHECK(pos + n <= text.length()) << "The text can not fully cover range.";
if (pos >= text.length()) {
NOTREACHED() << "The text can not cover range.";
return;
}
std::string utf8_selection = UTF16ToUTF8(text.substr(pos, n));
content_view_core_->OnSelectionChanged(utf8_selection);
}
BackingStore* RenderWidgetHostViewAndroid::AllocBackingStore(
const gfx::Size& size) {
NOTIMPLEMENTED();
return NULL;
}
void RenderWidgetHostViewAndroid::SetBackground(const SkBitmap& background) {
RenderWidgetHostViewBase::SetBackground(background);
host_->Send(new ViewMsg_SetBackground(host_->GetRoutingID(), background));
}
void RenderWidgetHostViewAndroid::CopyFromCompositingSurface(
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
const base::Callback<void(bool)>& callback,
skia::PlatformCanvas* output) {
NOTIMPLEMENTED();
callback.Run(false);
}
void RenderWidgetHostViewAndroid::OnAcceleratedCompositingStateChange() {
}
void RenderWidgetHostViewAndroid::AcceleratedSurfaceBuffersSwapped(
const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params,
int gpu_host_id) {
texture_layer_->setTextureId(params.surface_handle);
texture_layer_->layer()->invalidate();
// TODO(sievers): The view and layer should get sized proactively.
if (((gfx::Size)texture_layer_->layer()->bounds()).IsEmpty())
texture_layer_->layer()->setBounds(
DrawDelegateImpl::GetInstance()->GetBounds());
DrawDelegateImpl::GetInstance()->OnSurfaceUpdated(
params.surface_handle,
this,
base::Bind(&RenderWidgetHostImpl::AcknowledgeBufferPresent,
params.route_id, gpu_host_id));
}
void RenderWidgetHostViewAndroid::AcceleratedSurfacePostSubBuffer(
const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params,
int gpu_host_id) {
NOTREACHED();
}
void RenderWidgetHostViewAndroid::AcceleratedSurfaceSuspend() {
NOTREACHED();
}
bool RenderWidgetHostViewAndroid::HasAcceleratedSurface(
const gfx::Size& desired_size) {
NOTREACHED();
return false;
}
void RenderWidgetHostViewAndroid::StartContentIntent(
const GURL& content_url) {
if (content_view_core_)
content_view_core_->StartContentIntent(content_url);
}
gfx::GLSurfaceHandle RenderWidgetHostViewAndroid::GetCompositingSurface() {
if (CompositorImpl::IsInitialized()) {
// The app uses the browser-side compositor.
if (shared_surface_.is_null())
shared_surface_ =
ImageTransportFactoryAndroid::GetInstance()->
CreateSharedSurfaceHandle();
return shared_surface_;
}
// On Android, we cannot generate a window handle that can be passed to the
// GPU process through the native side. Instead, we send the surface handle
// through Binder after the compositing context has been created.
return gfx::GLSurfaceHandle(gfx::kNullPluginWindow, true);
}
void RenderWidgetHostViewAndroid::GetScreenInfo(WebKit::WebScreenInfo* result) {
// ScreenInfo isn't tied to the widget on Android. Always return the default.
RenderWidgetHostViewBase::GetDefaultScreenInfo(result);
}
// TODO(jrg): Find out the implications and answer correctly here,
// as we are returning the WebView and not root window bounds.
gfx::Rect RenderWidgetHostViewAndroid::GetBoundsInRootWindow() {
return GetViewBounds();
}
void RenderWidgetHostViewAndroid::UnhandledWheelEvent(
const WebKit::WebMouseWheelEvent& event) {
// intentionally empty, like RenderWidgetHostViewViews
}
void RenderWidgetHostViewAndroid::ProcessTouchAck(
WebKit::WebInputEvent::Type type, bool processed) {
// intentionally empty, like RenderWidgetHostViewViews
}
void RenderWidgetHostViewAndroid::SetHasHorizontalScrollbar(
bool has_horizontal_scrollbar) {
// intentionally empty, like RenderWidgetHostViewViews
}
void RenderWidgetHostViewAndroid::SetScrollOffsetPinning(
bool is_pinned_to_left, bool is_pinned_to_right) {
// intentionally empty, like RenderWidgetHostViewViews
}
bool RenderWidgetHostViewAndroid::LockMouse() {
NOTIMPLEMENTED();
return false;
}
void RenderWidgetHostViewAndroid::UnlockMouse() {
NOTIMPLEMENTED();
}
// Methods called from the host to the render
void RenderWidgetHostViewAndroid::SendKeyEvent(
const NativeWebKeyboardEvent& event) {
if (host_)
host_->ForwardKeyboardEvent(event);
}
void RenderWidgetHostViewAndroid::TouchEvent(
const WebKit::WebTouchEvent& event) {
if (host_)
host_->ForwardTouchEvent(event);
}
void RenderWidgetHostViewAndroid::GestureEvent(
const WebKit::WebGestureEvent& event) {
if (host_)
host_->ForwardGestureEvent(event);
}
void RenderWidgetHostViewAndroid::SelectRange(const gfx::Point& start,
const gfx::Point& end) {
if (host_)
host_->SelectRange(start, end);
}
void RenderWidgetHostViewAndroid::SetContentViewCore(
ContentViewCoreImpl* content_view_core) {
content_view_core_ = content_view_core;
if (host_) {
GpuSurfaceTracker::Get()->SetSurfaceHandle(
host_->surface_id(), content_view_core_ ?
GetCompositingSurface() : gfx::GLSurfaceHandle());
}
}
void RenderWidgetHostViewAndroid::DidSetNeedTouchEvents(
bool need_touch_events) {
if (content_view_core_)
content_view_core_->DidSetNeedTouchEvents(need_touch_events);
}
// static
void RenderWidgetHostViewPort::GetDefaultScreenInfo(
::WebKit::WebScreenInfo* results) {
DeviceInfo info;
const int width = info.GetWidth();
const int height = info.GetHeight();
results->horizontalDPI = 160 * info.GetDPIScale();
results->verticalDPI = 160 * info.GetDPIScale();
results->depth = info.GetBitsPerPixel();
results->depthPerComponent = info.GetBitsPerComponent();
results->isMonochrome = (results->depthPerComponent == 0);
results->rect = ::WebKit::WebRect(0, 0, width, height);
// TODO(husky): Remove any system controls from availableRect.
results->availableRect = ::WebKit::WebRect(0, 0, width, height);
}
////////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostView, public:
// static
RenderWidgetHostView*
RenderWidgetHostView::CreateViewForWidget(RenderWidgetHost* widget) {
RenderWidgetHostImpl* rwhi = RenderWidgetHostImpl::From(widget);
return new RenderWidgetHostViewAndroid(rwhi, NULL);
}
} // namespace content