#include <android/bitmap.h>
+#include "base/android/build_info.h"
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/sys_info.h"
#include "base/threading/worker_pool.h"
#include "cc/base/latency_info_swap_promise.h"
#include "cc/layers/delegated_frame_provider.h"
#include "cc/layers/delegated_renderer_layer.h"
#include "cc/layers/layer.h"
-#include "cc/layers/texture_layer.h"
#include "cc/output/compositor_frame.h"
#include "cc/output/compositor_frame_ack.h"
#include "cc/output/copy_output_request.h"
#include "cc/resources/single_release_callback.h"
#include "cc/trees/layer_tree_host.h"
#include "content/browser/accessibility/browser_accessibility_manager_android.h"
+#include "content/browser/android/composited_touch_handle_drawable.h"
#include "content/browser/android/content_view_core_impl.h"
+#include "content/browser/android/edge_effect.h"
+#include "content/browser/android/edge_effect_l.h"
#include "content/browser/android/in_process/synchronous_compositor_impl.h"
#include "content/browser/android/overscroll_glow.h"
#include "content/browser/devtools/render_view_devtools_agent_host.h"
+#include "content/browser/gpu/compositor_util.h"
#include "content/browser/gpu/gpu_data_manager_impl.h"
#include "content/browser/gpu/gpu_process_host_ui_shim.h"
#include "content/browser/gpu/gpu_surface_tracker.h"
+#include "content/browser/media/media_web_contents_observer.h"
#include "content/browser/renderer_host/compositor_impl_android.h"
#include "content/browser/renderer_host/dip_util.h"
#include "content/browser/renderer_host/image_transport_factory_android.h"
#include "content/browser/renderer_host/input/synthetic_gesture_target_android.h"
+#include "content/browser/renderer_host/input/touch_selection_controller.h"
+#include "content/browser/renderer_host/input/web_input_event_builders_android.h"
+#include "content/browser/renderer_host/input/web_input_event_util.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
+#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/common/gpu/client/gl_helper.h"
#include "content/common/gpu/gpu_messages.h"
+#include "content/common/input/did_overscroll_params.h"
#include "content/common/input_messages.h"
#include "content/common/view_messages.h"
+#include "content/public/browser/browser_thread.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/common/content_switches.h"
#include "third_party/khronos/GLES2/gl2ext.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "ui/base/android/window_android.h"
+#include "ui/base/android/window_android_compositor.h"
+#include "ui/events/gesture_detection/gesture_config_helper.h"
+#include "ui/events/gesture_detection/motion_event.h"
#include "ui/gfx/android/device_display_info.h"
#include "ui/gfx/android/java_bitmap.h"
#include "ui/gfx/display.h"
namespace {
const int kUndefinedOutputSurfaceId = -1;
-static const char kAsyncReadBackString[] = "Compositing.CopyFromSurfaceTime";
-void InsertSyncPointAndAckForCompositor(
- int renderer_host_id,
- uint32 output_surface_id,
- int route_id,
- const gpu::Mailbox& return_mailbox,
- const gfx::Size return_size) {
- cc::CompositorFrameAck ack;
- ack.gl_frame_data.reset(new cc::GLFrameData());
- if (!return_mailbox.IsZero()) {
- ack.gl_frame_data->mailbox = return_mailbox;
- ack.gl_frame_data->size = return_size;
- ack.gl_frame_data->sync_point =
- ImageTransportFactoryAndroid::GetInstance()->InsertSyncPoint();
- }
- RenderWidgetHostImpl::SendSwapCompositorFrameAck(
- route_id, output_surface_id, renderer_host_id, ack);
-}
+// Used to accomodate finite precision when comparing scaled viewport and
+// content widths. While this value may seem large, width=device-width on an N7
+// V1 saw errors of ~0.065 between computed window and content widths.
+const float kMobileViewportWidthEpsilon = 0.15f;
+
+// Used for conditional creation of EdgeEffect types for overscroll.
+const int kKitKatMR2SDKVersion = 19;
+
+static const char kAsyncReadBackString[] = "Compositing.CopyFromSurfaceTime";
// Sends an acknowledgement to the renderer of a processed IME event.
void SendImeEventAck(RenderWidgetHostImpl* host) {
const base::TimeTicks& start_time,
scoped_ptr<SkAutoLockPixels> bitmap_pixels_lock,
bool result) {
+ TRACE_EVENT0(
+ "cc", "RenderWidgetHostViewAndroid::CopyFromCompositingSurfaceFinished");
bitmap_pixels_lock.reset();
- release_callback->Run(0, false);
+ uint32 sync_point = 0;
+ if (result) {
+ GLHelper* gl_helper =
+ ImageTransportFactoryAndroid::GetInstance()->GetGLHelper();
+ sync_point = gl_helper->InsertSyncPoint();
+ }
+ bool lost_resource = sync_point == 0;
+ release_callback->Run(sync_point, lost_resource);
UMA_HISTOGRAM_TIMES(kAsyncReadBackString,
base::TimeTicks::Now() - start_time);
callback.Run(result, *bitmap);
}
-bool UsingDelegatedRenderer() {
- bool using_delegated_renderer = false;
-
- using_delegated_renderer |= CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableDelegatedRenderer);
-
- using_delegated_renderer &= !CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableDelegatedRenderer);
-
- return using_delegated_renderer;
-}
-
-ui::LatencyInfo CreateLatencyInfo(const blink::WebInputEvent event) {
+ui::LatencyInfo CreateLatencyInfo(const blink::WebInputEvent& event) {
ui::LatencyInfo latency_info;
// The latency number should only be added if the timestamp is valid.
if (event.timeStampSeconds) {
return latency_info;
}
+OverscrollGlow::DisplayParameters CreateOverscrollDisplayParameters(
+ const cc::CompositorFrameMetadata& frame_metadata) {
+ const float scale_factor =
+ frame_metadata.page_scale_factor * frame_metadata.device_scale_factor;
+
+ // Compute the size and offsets for each edge, where each effect is sized to
+ // the viewport and offset by the distance of each viewport edge to the
+ // respective content edge.
+ OverscrollGlow::DisplayParameters params;
+ params.size = gfx::ScaleSize(
+ frame_metadata.scrollable_viewport_size, scale_factor);
+ params.edge_offsets[OverscrollGlow::EDGE_TOP] =
+ -frame_metadata.root_scroll_offset.y() * scale_factor;
+ params.edge_offsets[OverscrollGlow::EDGE_LEFT] =
+ -frame_metadata.root_scroll_offset.x() * scale_factor;
+ params.edge_offsets[OverscrollGlow::EDGE_BOTTOM] =
+ (frame_metadata.root_layer_size.height() -
+ frame_metadata.root_scroll_offset.y() -
+ frame_metadata.scrollable_viewport_size.height()) *
+ scale_factor;
+ params.edge_offsets[OverscrollGlow::EDGE_RIGHT] =
+ (frame_metadata.root_layer_size.width() -
+ frame_metadata.root_scroll_offset.x() -
+ frame_metadata.scrollable_viewport_size.width()) *
+ scale_factor;
+
+ return params;
+}
+
+bool UseEdgeEffectL() {
+ static bool use_edge_effect_l =
+ base::android::BuildInfo::GetInstance()->sdk_int() > kKitKatMR2SDKVersion;
+ return use_edge_effect_l;
+}
+
+scoped_ptr<EdgeEffectBase> CreateEdgeEffect(
+ ui::SystemUIResourceManager* resource_manager,
+ float device_scale_factor) {
+ DCHECK(resource_manager);
+ if (UseEdgeEffectL())
+ return scoped_ptr<EdgeEffectBase>(new EdgeEffectL(resource_manager));
+
+ return scoped_ptr<EdgeEffectBase>(
+ new EdgeEffect(resource_manager, device_scale_factor));
+}
+
+scoped_ptr<OverscrollGlow> CreateOverscrollEffect(
+ ContentViewCore* content_view_core) {
+ DCHECK(content_view_core);
+ ui::WindowAndroidCompositor* compositor =
+ content_view_core->GetWindowAndroid()->GetCompositor();
+ DCHECK(compositor);
+ ui::SystemUIResourceManager* system_resource_manager =
+ &compositor->GetSystemUIResourceManager();
+
+ if (UseEdgeEffectL())
+ EdgeEffectL::PreloadResources(system_resource_manager);
+ else
+ EdgeEffect::PreloadResources(system_resource_manager);
+
+ return make_scoped_ptr(
+ new OverscrollGlow(base::Bind(&CreateEdgeEffect,
+ system_resource_manager,
+ content_view_core->GetDpiScale())));
+}
+
+ui::GestureProvider::Config CreateGestureProviderConfig() {
+ ui::GestureProvider::Config config = ui::DefaultGestureProviderConfig();
+ config.disable_click_delay =
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableClickDelay);
+ return config;
+}
+
+bool HasFixedPageScale(const cc::CompositorFrameMetadata& frame_metadata) {
+ return frame_metadata.min_page_scale_factor ==
+ frame_metadata.max_page_scale_factor;
+}
+
+bool HasMobileViewport(const cc::CompositorFrameMetadata& frame_metadata) {
+ float window_width_dip =
+ frame_metadata.page_scale_factor *
+ frame_metadata.scrollable_viewport_size.width();
+ float content_width_css = frame_metadata.root_layer_size.width();
+ return content_width_css <= window_width_dip + kMobileViewportWidthEpsilon;
+}
+
} // anonymous namespace
+RenderWidgetHostViewAndroid::LastFrameInfo::LastFrameInfo(
+ uint32 output_id,
+ scoped_ptr<cc::CompositorFrame> output_frame)
+ : output_surface_id(output_id), frame(output_frame.Pass()) {}
+
+RenderWidgetHostViewAndroid::LastFrameInfo::~LastFrameInfo() {}
+
RenderWidgetHostViewAndroid::RenderWidgetHostViewAndroid(
RenderWidgetHostImpl* widget_host,
ContentViewCoreImpl* content_view_core)
: host_(widget_host),
- needs_begin_frame_(false),
- are_layers_attached_(!widget_host->is_hidden()),
+ outstanding_vsync_requests_(0),
+ is_showing_(!widget_host->is_hidden()),
content_view_core_(NULL),
ime_adapter_android_(this),
cached_background_color_(SK_ColorWHITE),
- texture_id_in_layer_(0),
last_output_surface_id_(kUndefinedOutputSurfaceId),
weak_ptr_factory_(this),
overscroll_effect_enabled_(
- !CommandLine::ForCurrentProcess()->
- HasSwitch(switches::kDisableOverscrollEdgeEffect)),
- overscroll_effect_(OverscrollGlow::Create(overscroll_effect_enabled_)),
- flush_input_requested_(false),
+ !base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableOverscrollEdgeEffect)),
+ gesture_provider_(CreateGestureProviderConfig(), this),
+ gesture_text_selector_(this),
+ touch_scrolling_(false),
+ potentially_active_fling_count_(0),
accelerated_surface_route_id_(0),
using_synchronous_compositor_(SynchronousCompositorImpl::FromID(
widget_host->GetProcess()->GetID(),
widget_host->GetRoutingID()) != NULL),
- frame_evictor_(new DelegatedFrameEvictor(this)) {
- if (!UsingDelegatedRenderer()) {
- texture_layer_ = cc::TextureLayer::Create(NULL);
- layer_ = texture_layer_;
- }
-
+ frame_evictor_(new DelegatedFrameEvictor(this)),
+ locks_on_frame_count_(0),
+ observing_root_window_(false) {
host_->SetView(this);
SetContentViewCore(content_view_core);
ImageTransportFactoryAndroid::AddObserver(this);
ImageTransportFactoryAndroid::RemoveObserver(this);
SetContentViewCore(NULL);
DCHECK(ack_callbacks_.empty());
- if (texture_id_in_layer_) {
- ImageTransportFactoryAndroid::GetInstance()->DeleteTexture(
- texture_id_in_layer_);
- }
-
- if (texture_layer_.get())
- texture_layer_->ClearClient();
-
if (resource_collection_.get())
resource_collection_->SetClient(NULL);
}
OnDidChangeBodyBackgroundColor)
IPC_MESSAGE_HANDLER(ViewHostMsg_SetNeedsBeginFrame,
OnSetNeedsBeginFrame)
- IPC_MESSAGE_HANDLER(ViewHostMsg_TextInputStateChanged,
- OnTextInputStateChanged)
IPC_MESSAGE_HANDLER(ViewHostMsg_SmartClipDataExtracted,
OnSmartClipDataExtracted)
IPC_MESSAGE_UNHANDLED(handled = false)
if (!host_ || !host_->is_hidden())
return;
- host_->WasShown();
+ host_->WasShown(ui::LatencyInfo());
- if (content_view_core_ && !using_synchronous_compositor_)
- content_view_core_->GetWindowAndroid()->AddObserver(this);
+ if (content_view_core_) {
+ StartObservingRootWindow();
+ RequestVSyncUpdate(BEGIN_FRAME);
+ }
}
void RenderWidgetHostViewAndroid::WasHidden() {
// utilization.
host_->WasHidden();
- if (content_view_core_ && !using_synchronous_compositor_)
- content_view_core_->GetWindowAndroid()->RemoveObserver(this);
+ StopObservingRootWindow();
}
void RenderWidgetHostViewAndroid::WasResized() {
// Ignore the given size as only the Java code has the power to
// resize the view on Android.
default_size_ = size;
- WasResized();
}
void RenderWidgetHostViewAndroid::SetBounds(const gfx::Rect& rect) {
SetSize(rect.size());
}
-blink::WebGLId RenderWidgetHostViewAndroid::GetScaledContentTexture(
+void RenderWidgetHostViewAndroid::GetScaledContentBitmap(
float scale,
- gfx::Size* out_size) {
- gfx::Size size(gfx::ToCeiledSize(
- gfx::ScaleSize(texture_size_in_layer_, scale)));
-
- if (!CompositorImpl::IsInitialized() ||
- texture_id_in_layer_ == 0 ||
- texture_size_in_layer_.IsEmpty() ||
- size.IsEmpty()) {
- if (out_size)
- out_size->SetSize(0, 0);
-
- return 0;
+ SkColorType color_type,
+ gfx::Rect src_subrect,
+ const base::Callback<void(bool, const SkBitmap&)>& result_callback) {
+ if (!host_ || host_->is_hidden()) {
+ result_callback.Run(false, SkBitmap());
+ return;
+ }
+ if (!IsSurfaceAvailableForCopy()) {
+ // TODO(Sikugu): allow a read-back request to wait for a first frame if it
+ // was invoked while no frame was received yet
+ result_callback.Run(false, SkBitmap());
+ return;
}
- if (out_size)
- *out_size = size;
-
- GLHelper* helper = ImageTransportFactoryAndroid::GetInstance()->GetGLHelper();
- return helper->CopyAndScaleTexture(texture_id_in_layer_,
- texture_size_in_layer_,
- size,
- true,
- GLHelper::SCALER_QUALITY_FAST);
-}
-
-bool RenderWidgetHostViewAndroid::PopulateBitmapWithContents(jobject jbitmap) {
- if (!CompositorImpl::IsInitialized() ||
- texture_id_in_layer_ == 0 ||
- texture_size_in_layer_.IsEmpty())
- return false;
-
- gfx::JavaBitmap bitmap(jbitmap);
-
- // TODO(dtrainor): Eventually add support for multiple formats here.
- DCHECK(bitmap.format() == ANDROID_BITMAP_FORMAT_RGBA_8888);
-
- GLHelper* helper = ImageTransportFactoryAndroid::GetInstance()->GetGLHelper();
-
- GLuint texture = helper->CopyAndScaleTexture(
- texture_id_in_layer_,
- texture_size_in_layer_,
- bitmap.size(),
- true,
- GLHelper::SCALER_QUALITY_FAST);
- if (texture == 0u)
- return false;
-
- helper->ReadbackTextureSync(texture,
- gfx::Rect(bitmap.size()),
- static_cast<unsigned char*> (bitmap.pixels()),
- SkBitmap::kARGB_8888_Config);
-
- gpu::gles2::GLES2Interface* gl =
- ImageTransportFactoryAndroid::GetInstance()->GetContextGL();
- gl->DeleteTextures(1, &texture);
-
- return true;
+ gfx::Size bounds = layer_->bounds();
+ if (src_subrect.IsEmpty())
+ src_subrect = gfx::Rect(bounds);
+ DCHECK_LE(src_subrect.width() + src_subrect.x(), bounds.width());
+ DCHECK_LE(src_subrect.height() + src_subrect.y(), bounds.height());
+ const gfx::Display& display =
+ gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
+ float device_scale_factor = display.device_scale_factor();
+ DCHECK_GT(device_scale_factor, 0);
+ gfx::Size dst_size(
+ gfx::ToCeiledSize(gfx::ScaleSize(bounds, scale / device_scale_factor)));
+ CopyFromCompositingSurface(
+ src_subrect, dst_size, result_callback, color_type);
}
bool RenderWidgetHostViewAndroid::HasValidFrame() const {
if (!content_view_core_)
return false;
+ if (!layer_)
+ return false;
+
if (texture_size_in_layer_.IsEmpty())
return false;
- if (UsingDelegatedRenderer()) {
- if (!delegated_renderer_layer_.get())
- return false;
- } else {
- if (texture_id_in_layer_ == 0)
- return false;
- }
+ if (!frame_evictor_->HasFrame())
+ return false;
return true;
}
}
void RenderWidgetHostViewAndroid::MovePluginWindows(
- const gfx::Vector2d& scroll_offset,
const std::vector<WebPluginGeometry>& moves) {
// We don't have plugin windows on Android. Do nothing. Note: this is called
// from RenderWidgetHost::OnUpdateRect which is itself invoked while
void RenderWidgetHostViewAndroid::Focus() {
host_->Focus();
host_->SetInputMethodActive(true);
- ResetClipping();
- if (overscroll_effect_enabled_)
+ if (overscroll_effect_)
overscroll_effect_->Enable();
}
host_->ExecuteEditCommand("Unselect", "");
host_->SetInputMethodActive(false);
host_->Blur();
- overscroll_effect_->Disable();
+ if (overscroll_effect_)
+ overscroll_effect_->Disable();
}
bool RenderWidgetHostViewAndroid::HasFocus() const {
}
void RenderWidgetHostViewAndroid::Show() {
- if (are_layers_attached_)
+ if (is_showing_)
return;
- are_layers_attached_ = true;
- AttachLayers();
+ is_showing_ = true;
+ if (layer_)
+ layer_->SetHideLayerAndSubtree(false);
frame_evictor_->SetVisible(true);
WasShown();
}
void RenderWidgetHostViewAndroid::Hide() {
- if (!are_layers_attached_)
+ if (!is_showing_)
return;
- are_layers_attached_ = false;
- RemoveLayers();
+ is_showing_ = false;
+ if (layer_ && locks_on_frame_count_ == 0)
+ layer_->SetHideLayerAndSubtree(true);
frame_evictor_->SetVisible(false);
WasHidden();
// 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 this RWHVA as hidden.
- return are_layers_attached_ && content_view_core_;
+ return is_showing_ && content_view_core_;
}
-void RenderWidgetHostViewAndroid::LockResources() {
+void RenderWidgetHostViewAndroid::LockCompositingSurface() {
DCHECK(HasValidFrame());
DCHECK(host_);
- DCHECK(!host_->is_hidden());
+ DCHECK(frame_evictor_->HasFrame());
frame_evictor_->LockFrame();
+ locks_on_frame_count_++;
}
-void RenderWidgetHostViewAndroid::UnlockResources() {
+void RenderWidgetHostViewAndroid::UnlockCompositingSurface() {
+ if (!frame_evictor_->HasFrame() || locks_on_frame_count_ == 0)
+ return;
+
DCHECK(HasValidFrame());
frame_evictor_->UnlockFrame();
+ locks_on_frame_count_--;
+
+ if (locks_on_frame_count_ == 0) {
+ if (last_frame_info_) {
+ InternalSwapCompositorFrame(last_frame_info_->output_surface_id,
+ last_frame_info_->frame.Pass());
+ last_frame_info_.reset();
+ }
+
+ if (!is_showing_ && layer_)
+ layer_->SetHideLayerAndSubtree(true);
+ }
+}
+
+void RenderWidgetHostViewAndroid::SetTextSurroundingSelectionCallback(
+ const TextSurroundingSelectionCallback& callback) {
+ // Only one outstanding request is allowed at any given time.
+ DCHECK(!callback.is_null());
+ text_surrounding_selection_callback_ = callback;
+}
+
+void RenderWidgetHostViewAndroid::OnTextSurroundingSelectionResponse(
+ const base::string16& content,
+ size_t start_offset,
+ size_t end_offset) {
+ if (text_surrounding_selection_callback_.is_null())
+ return;
+ text_surrounding_selection_callback_.Run(content, start_offset, end_offset);
+ text_surrounding_selection_callback_.Reset();
+}
+
+void RenderWidgetHostViewAndroid::ReleaseLocksOnSurface() {
+ if (!frame_evictor_->HasFrame()) {
+ DCHECK_EQ(locks_on_frame_count_, 0u);
+ return;
+ }
+ while (locks_on_frame_count_ > 0) {
+ UnlockCompositingSurface();
+ }
+ RunAckCallbacks();
}
gfx::Rect RenderWidgetHostViewAndroid::GetViewBounds() const {
if (!content_view_core_)
return gfx::Rect(default_size_);
- gfx::Size size = content_view_core_->GetViewportSizeDip();
- gfx::Size offset = content_view_core_->GetViewportSizeOffsetDip();
- size.Enlarge(-offset.width(), -offset.height());
-
- return gfx::Rect(size);
+ return gfx::Rect(content_view_core_->GetViewSize());
}
gfx::Size RenderWidgetHostViewAndroid::GetPhysicalBackingSize() const {
// is TabContentsDelegate.
}
-void RenderWidgetHostViewAndroid::TextInputTypeChanged(
- ui::TextInputType type,
- ui::TextInputMode input_mode,
- bool can_compose_inline) {
- // Unused on Android, which uses OnTextInputChanged instead.
-}
-
-int RenderWidgetHostViewAndroid::GetNativeImeAdapter() {
- return reinterpret_cast<int>(&ime_adapter_android_);
+long RenderWidgetHostViewAndroid::GetNativeImeAdapter() {
+ return reinterpret_cast<intptr_t>(&ime_adapter_android_);
}
-void RenderWidgetHostViewAndroid::OnTextInputStateChanged(
+void RenderWidgetHostViewAndroid::TextInputStateChanged(
const ViewHostMsg_TextInputState_Params& params) {
- // If an acknowledgement is required for this event, regardless of how we exit
- // from this method, we must acknowledge that we processed the input state
- // change.
+ if (selection_controller_) {
+ // This call is semi-redundant with that in |OnFocusedNodeChanged|. The
+ // latter is guaranteed to be called before |OnSelectionBoundsChanged|,
+ // while this call is present to ensure consistency with IME after
+ // navigation and tab focus changes
+ const bool is_editable_node = params.type != ui::TEXT_INPUT_TYPE_NONE;
+ selection_controller_->OnSelectionEditable(is_editable_node);
+ }
+
+ // If the change is not originated from IME (e.g. Javascript, autofill),
+ // send back the renderer an acknowledgement, regardless of how we exit from
+ // this method.
base::ScopedClosureRunner ack_caller;
- if (params.require_ack)
+ if (params.is_non_ime_change)
ack_caller.Reset(base::Bind(&SendImeEventAck, host_));
if (!IsShowing())
content_view_core_->UpdateImeAdapter(
GetNativeImeAdapter(),
- static_cast<int>(params.type),
+ static_cast<int>(params.type), params.flags,
params.value, params.selection_start, params.selection_end,
params.composition_start, params.composition_end,
- params.show_ime_if_needed, params.require_ack);
+ params.show_ime_if_needed, params.is_non_ime_change);
}
void RenderWidgetHostViewAndroid::OnDidChangeBodyBackgroundColor(
content_view_core_->OnBackgroundColorChanged(color);
}
-void RenderWidgetHostViewAndroid::SendBeginFrame(
- const cc::BeginFrameArgs& args) {
- TRACE_EVENT0("cc", "RenderWidgetHostViewAndroid::SendBeginFrame");
- if (!host_)
- return;
-
- if (flush_input_requested_) {
- flush_input_requested_ = false;
- host_->FlushInput();
- content_view_core_->RemoveBeginFrameSubscriber();
- }
-
- host_->Send(new ViewMsg_BeginFrame(host_->GetRoutingID(), args));
-}
-
-void RenderWidgetHostViewAndroid::OnSetNeedsBeginFrame(
- bool enabled) {
+void RenderWidgetHostViewAndroid::OnSetNeedsBeginFrame(bool enabled) {
+ DCHECK(!using_synchronous_compositor_);
TRACE_EVENT1("cc", "RenderWidgetHostViewAndroid::OnSetNeedsBeginFrame",
"enabled", enabled);
- // ContentViewCoreImpl handles multiple subscribers to the BeginFrame, so
- // we have to make sure calls to ContentViewCoreImpl's
- // {Add,Remove}BeginFrameSubscriber are balanced, even if
- // RenderWidgetHostViewAndroid's may not be.
- if (content_view_core_ && needs_begin_frame_ != enabled) {
- if (enabled)
- content_view_core_->AddBeginFrameSubscriber();
- else
- content_view_core_->RemoveBeginFrameSubscriber();
- needs_begin_frame_ = enabled;
- }
+ if (enabled)
+ RequestVSyncUpdate(PERSISTENT_BEGIN_FRAME);
+ else
+ outstanding_vsync_requests_ &= ~PERSISTENT_BEGIN_FRAME;
}
void RenderWidgetHostViewAndroid::OnStartContentIntent(
}
void RenderWidgetHostViewAndroid::OnSmartClipDataExtracted(
- const base::string16& result) {
- // Custom serialization over IPC isn't allowed normally for security reasons.
- // Since this feature is only used in (single-process) WebView, there are no
- // security issues. Enforce that it's only called in single process mode.
- CHECK(RenderProcessHost::run_renderer_in_process());
+ const base::string16& text,
+ const base::string16& html,
+ const gfx::Rect rect) {
if (content_view_core_)
- content_view_core_->OnSmartClipDataExtracted(result);
+ content_view_core_->OnSmartClipDataExtracted(text, html, rect);
+}
+
+bool RenderWidgetHostViewAndroid::OnTouchEvent(
+ const ui::MotionEvent& event) {
+ if (!host_)
+ return false;
+
+ if (selection_controller_ &&
+ selection_controller_->WillHandleTouchEvent(event))
+ return true;
+
+ if (!gesture_provider_.OnTouchEvent(event))
+ return false;
+
+ if (gesture_text_selector_.OnTouchEvent(event)) {
+ gesture_provider_.OnTouchEventAck(false);
+ return true;
+ }
+
+ // Short-circuit touch forwarding if no touch handlers exist.
+ if (!host_->ShouldForwardTouchEvent()) {
+ const bool event_consumed = false;
+ gesture_provider_.OnTouchEventAck(event_consumed);
+ return true;
+ }
+
+ SendTouchEvent(CreateWebTouchEventFromMotionEvent(event));
+ return true;
+}
+
+bool RenderWidgetHostViewAndroid::OnTouchHandleEvent(
+ const ui::MotionEvent& event) {
+ return selection_controller_ &&
+ selection_controller_->WillHandleTouchEvent(event);
+}
+
+void RenderWidgetHostViewAndroid::ResetGestureDetection() {
+ const ui::MotionEvent* current_down_event =
+ gesture_provider_.GetCurrentDownEvent();
+ if (!current_down_event)
+ return;
+
+ scoped_ptr<ui::MotionEvent> cancel_event = current_down_event->Cancel();
+ DCHECK(cancel_event);
+ OnTouchEvent(*cancel_event);
+
+ touch_scrolling_ = false;
+ potentially_active_fling_count_ = 0;
+ OnContentScrollingChange();
+}
+
+void RenderWidgetHostViewAndroid::SetDoubleTapSupportEnabled(bool enabled) {
+ gesture_provider_.SetDoubleTapSupportForPlatformEnabled(enabled);
+}
+
+void RenderWidgetHostViewAndroid::SetMultiTouchZoomSupportEnabled(
+ bool enabled) {
+ gesture_provider_.SetMultiTouchZoomSupportEnabled(enabled);
}
void RenderWidgetHostViewAndroid::ImeCancelComposition() {
void RenderWidgetHostViewAndroid::FocusedNodeChanged(bool is_editable_node) {
ime_adapter_android_.FocusedNodeChanged(is_editable_node);
-}
-
-void RenderWidgetHostViewAndroid::DidUpdateBackingStore(
- const gfx::Rect& scroll_rect,
- const gfx::Vector2d& scroll_delta,
- const std::vector<gfx::Rect>& copy_rects,
- const std::vector<ui::LatencyInfo>& latency_info) {
- NOTIMPLEMENTED();
+ if (selection_controller_)
+ selection_controller_->OnSelectionEditable(is_editable_node);
}
void RenderWidgetHostViewAndroid::RenderProcessGone(
const gfx::Range& range) {
RenderWidgetHostViewBase::SelectionChanged(text, offset, range);
+ if (selection_controller_)
+ selection_controller_->OnSelectionEmpty(text.empty());
+
if (text.empty() || range.is_empty() || !content_view_core_)
return;
size_t pos = range.GetMin() - offset;
void RenderWidgetHostViewAndroid::SelectionBoundsChanged(
const ViewHostMsg_SelectionBounds_Params& params) {
- if (content_view_core_) {
- content_view_core_->OnSelectionBoundsChanged(params);
+ if (!selection_controller_)
+ return;
+
+ gfx::RectF anchor_rect(params.anchor_rect);
+ gfx::RectF focus_rect(params.focus_rect);
+ if (params.is_anchor_first)
+ std::swap(anchor_rect, focus_rect);
+
+ TouchHandleOrientation anchor_orientation(TOUCH_HANDLE_ORIENTATION_UNDEFINED);
+ TouchHandleOrientation focus_orientation(TOUCH_HANDLE_ORIENTATION_UNDEFINED);
+ if (params.anchor_rect == params.focus_rect) {
+ if (params.anchor_rect.x() && params.anchor_rect.y())
+ anchor_orientation = focus_orientation = TOUCH_HANDLE_CENTER;
+ } else {
+ anchor_orientation = params.anchor_dir == blink::WebTextDirectionRightToLeft
+ ? TOUCH_HANDLE_LEFT
+ : TOUCH_HANDLE_RIGHT;
+ focus_orientation = params.focus_dir == blink::WebTextDirectionRightToLeft
+ ? TOUCH_HANDLE_RIGHT
+ : TOUCH_HANDLE_LEFT;
}
-}
-void RenderWidgetHostViewAndroid::ScrollOffsetChanged() {
+ selection_controller_->OnSelectionBoundsChanged(anchor_rect,
+ anchor_orientation,
+ true,
+ focus_rect,
+ focus_orientation,
+ true);
}
-BackingStore* RenderWidgetHostViewAndroid::AllocBackingStore(
- const gfx::Size& size) {
- NOTIMPLEMENTED();
- return NULL;
+void RenderWidgetHostViewAndroid::ScrollOffsetChanged() {
}
-void RenderWidgetHostViewAndroid::SetBackground(const SkBitmap& background) {
- RenderWidgetHostViewBase::SetBackground(background);
- host_->Send(new ViewMsg_SetBackground(host_->GetRoutingID(), background));
+void RenderWidgetHostViewAndroid::SetBackgroundOpaque(bool opaque) {
+ RenderWidgetHostViewBase::SetBackgroundOpaque(opaque);
+ host_->SetBackgroundOpaque(opaque);
}
void RenderWidgetHostViewAndroid::CopyFromCompositingSurface(
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
const base::Callback<void(bool, const SkBitmap&)>& callback,
- const SkBitmap::Config bitmap_config) {
- // Only ARGB888 and RGB565 supported as of now.
- bool format_support = ((bitmap_config == SkBitmap::kRGB_565_Config) ||
- (bitmap_config == SkBitmap::kARGB_8888_Config));
- if (!format_support) {
- DCHECK(format_support);
+ const SkColorType color_type) {
+ TRACE_EVENT0("cc", "RenderWidgetHostViewAndroid::CopyFromCompositingSurface");
+ if ((!host_ || host_->is_hidden()) ||
+ !IsReadbackConfigSupported(color_type)) {
callback.Run(false, SkBitmap());
return;
}
callback.Run(false, SkBitmap());
return;
}
- ImageTransportFactoryAndroid* factory =
- ImageTransportFactoryAndroid::GetInstance();
- GLHelper* gl_helper = factory->GetGLHelper();
- if (!gl_helper)
- return;
- bool check_rgb565_support = gl_helper->CanUseRgb565Readback();
- if ((bitmap_config == SkBitmap::kRGB_565_Config) &&
- !check_rgb565_support) {
- LOG(ERROR) << "Readbackformat rgb565 not supported";
- callback.Run(false, SkBitmap());
- return;
- }
const gfx::Display& display =
gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
float device_scale_factor = display.device_scale_factor();
-
- DCHECK_EQ(device_scale_factor,
- ui::GetImageScale(GetScaleFactorForView(this)));
-
- const gfx::Size& dst_size_in_pixel = ConvertViewSizeToPixel(this, dst_size);
+ gfx::Size dst_size_in_pixel =
+ ConvertRectToPixel(device_scale_factor, gfx::Rect(dst_size)).size();
gfx::Rect src_subrect_in_pixel =
ConvertRectToPixel(device_scale_factor, src_subrect);
if (using_synchronous_compositor_) {
- SynchronousCopyContents(src_subrect_in_pixel, dst_size_in_pixel, callback);
+ SynchronousCopyContents(src_subrect_in_pixel, dst_size_in_pixel, callback,
+ color_type);
UMA_HISTOGRAM_TIMES("Compositing.CopyFromSurfaceTimeSynchronous",
base::TimeTicks::Now() - start_time);
return;
}
+
scoped_ptr<cc::CopyOutputRequest> request;
- if (src_subrect_in_pixel.size() == dst_size_in_pixel) {
- request = cc::CopyOutputRequest::CreateBitmapRequest(base::Bind(
- &RenderWidgetHostViewAndroid::PrepareBitmapCopyOutputResult,
- dst_size_in_pixel,
- start_time,
- callback));
- } else {
- request = cc::CopyOutputRequest::CreateRequest(base::Bind(
- &RenderWidgetHostViewAndroid::PrepareTextureCopyOutputResult,
- dst_size_in_pixel,
- bitmap_config,
- start_time,
- callback));
- }
+ scoped_refptr<cc::Layer> readback_layer;
+ DCHECK(content_view_core_);
+ DCHECK(content_view_core_->GetWindowAndroid());
+ ui::WindowAndroidCompositor* compositor =
+ content_view_core_->GetWindowAndroid()->GetCompositor();
+ DCHECK(compositor);
+ DCHECK(frame_provider_);
+ scoped_refptr<cc::DelegatedRendererLayer> delegated_layer =
+ cc::DelegatedRendererLayer::Create(frame_provider_);
+ delegated_layer->SetBounds(content_size_in_layer_);
+ delegated_layer->SetHideLayerAndSubtree(true);
+ delegated_layer->SetIsDrawable(true);
+ delegated_layer->SetContentsOpaque(true);
+ compositor->AttachLayerForReadback(delegated_layer);
+
+ readback_layer = delegated_layer;
+ request = cc::CopyOutputRequest::CreateRequest(
+ base::Bind(&RenderWidgetHostViewAndroid::
+ PrepareTextureCopyOutputResultForDelegatedReadback,
+ dst_size_in_pixel,
+ color_type,
+ start_time,
+ readback_layer,
+ callback));
request->set_area(src_subrect_in_pixel);
- layer_->RequestCopyOfOutput(request.Pass());
+ readback_layer->RequestCopyOfOutput(request.Pass());
}
void RenderWidgetHostViewAndroid::CopyFromCompositingSurfaceToVideoFrame(
host_, content_view_core_->CreateTouchEventSynthesizer()));
}
-void RenderWidgetHostViewAndroid::OnAcceleratedCompositingStateChange() {
-}
-
void RenderWidgetHostViewAndroid::SendDelegatedFrameAck(
uint32 output_surface_id) {
+ DCHECK(host_);
cc::CompositorFrameAck ack;
if (resource_collection_.get())
resource_collection_->TakeUnusedResourcesForChildCompositor(&ack.resources);
ack);
}
+void RenderWidgetHostViewAndroid::SendReturnedDelegatedResources(
+ uint32 output_surface_id) {
+ DCHECK(resource_collection_);
+
+ cc::CompositorFrameAck ack;
+ resource_collection_->TakeUnusedResourcesForChildCompositor(&ack.resources);
+ DCHECK(!ack.resources.empty());
+
+ RenderWidgetHostImpl::SendReclaimCompositorResources(
+ host_->GetRoutingID(),
+ output_surface_id,
+ host_->GetProcess()->GetID(),
+ ack);
+}
+
void RenderWidgetHostViewAndroid::UnusedResourcesAreAvailable() {
- // TODO(danakj): If no ack is pending, collect and send resources now.
+ if (ack_callbacks_.size())
+ return;
+ SendReturnedDelegatedResources(last_output_surface_id_);
}
void RenderWidgetHostViewAndroid::DestroyDelegatedContent() {
- if (are_layers_attached_)
- RemoveLayers();
+ RemoveLayers();
frame_provider_ = NULL;
- delegated_renderer_layer_ = NULL;
layer_ = NULL;
}
bool has_content = !texture_size_in_layer_.IsEmpty();
if (output_surface_id != last_output_surface_id_) {
- // TODO(danakj): Lose all resources and send them back here, such as:
- // resource_collection_->LoseAllResources();
- // SendReturnedDelegatedResources(last_output_surface_id_);
-
// Drop the cc::DelegatedFrameResourceCollection so that we will not return
// any resources from the old output surface with the new output surface id.
if (resource_collection_.get()) {
resource_collection_->SetClient(NULL);
+ if (resource_collection_->LoseAllResources())
+ SendReturnedDelegatedResources(last_output_surface_id_);
resource_collection_ = NULL;
}
DestroyDelegatedContent();
last_output_surface_id_ = output_surface_id;
}
+ // DelegatedRendererLayerImpl applies the inverse device_scale_factor of the
+ // renderer frame, assuming that the browser compositor will scale
+ // it back up to device scale. But on Android we put our browser layers in
+ // physical pixels and set our browser CC device_scale_factor to 1, so this
+ // suppresses the transform. This line may need to be removed when fixing
+ // http://crbug.com/384134 or http://crbug.com/310763
+ frame_data->device_scale_factor = 1.0f;
+
if (!has_content) {
DestroyDelegatedContent();
} else {
}
if (!frame_provider_ ||
texture_size_in_layer_ != frame_provider_->frame_size()) {
- if (are_layers_attached_)
- RemoveLayers();
+ RemoveLayers();
frame_provider_ = new cc::DelegatedFrameProvider(
resource_collection_.get(), frame_data.Pass());
- delegated_renderer_layer_ =
- cc::DelegatedRendererLayer::Create(frame_provider_);
- layer_ = delegated_renderer_layer_;
- if (are_layers_attached_)
- AttachLayers();
+ layer_ = cc::DelegatedRendererLayer::Create(frame_provider_);
+ AttachLayers();
} else {
frame_provider_->SetFrameData(frame_data.Pass());
}
}
- if (delegated_renderer_layer_.get()) {
- delegated_renderer_layer_->SetDisplaySize(texture_size_in_layer_);
- delegated_renderer_layer_->SetIsDrawable(true);
- delegated_renderer_layer_->SetContentsOpaque(true);
- delegated_renderer_layer_->SetBounds(content_size_in_layer_);
- delegated_renderer_layer_->SetNeedsDisplay();
+ if (layer_.get()) {
+ layer_->SetIsDrawable(true);
+ layer_->SetContentsOpaque(true);
+ layer_->SetBounds(content_size_in_layer_);
+ layer_->SetNeedsDisplay();
}
base::Closure ack_callback =
weak_ptr_factory_.GetWeakPtr(),
output_surface_id);
+ ack_callbacks_.push(ack_callback);
if (host_->is_hidden())
- ack_callback.Run();
- else
- ack_callbacks_.push(ack_callback);
+ RunAckCallbacks();
}
void RenderWidgetHostViewAndroid::ComputeContentsSize(
content_size_in_layer_ =
gfx::Size(texture_size_in_layer_.width() - offset.x(),
texture_size_in_layer_.height() - offset.y());
- // Content size changes should be reflected in associated animation effects.
- UpdateAnimationSize(frame_metadata);
+
+ if (overscroll_effect_) {
+ overscroll_effect_->UpdateDisplayParameters(
+ CreateOverscrollDisplayParameters(frame_metadata));
+ }
}
-void RenderWidgetHostViewAndroid::OnSwapCompositorFrame(
+void RenderWidgetHostViewAndroid::InternalSwapCompositorFrame(
uint32 output_surface_id,
scoped_ptr<cc::CompositorFrame> frame) {
- // Always let ContentViewCore know about the new frame first, so it can decide
- // to schedule a Draw immediately when it sees the texture layer invalidation.
- UpdateContentViewCoreFrameMetadata(frame->metadata);
-
- if (frame->delegated_frame_data) {
- DCHECK(UsingDelegatedRenderer());
-
- DCHECK(frame->delegated_frame_data);
- DCHECK(!frame->delegated_frame_data->render_pass_list.empty());
-
- cc::RenderPass* root_pass =
- frame->delegated_frame_data->render_pass_list.back();
- texture_size_in_layer_ = root_pass->output_rect.size();
- ComputeContentsSize(frame->metadata);
-
- SwapDelegatedFrame(output_surface_id, frame->delegated_frame_data.Pass());
+ if (!frame->delegated_frame_data) {
+ LOG(ERROR) << "Non-delegated renderer path no longer supported";
return;
}
- DCHECK(!UsingDelegatedRenderer());
-
- if (!frame->gl_frame_data || frame->gl_frame_data->mailbox.IsZero())
+ if (locks_on_frame_count_ > 0) {
+ DCHECK(HasValidFrame());
+ RetainFrame(output_surface_id, frame.Pass());
return;
-
- if (output_surface_id != last_output_surface_id_) {
- current_mailbox_ = gpu::Mailbox();
- last_output_surface_id_ = kUndefinedOutputSurfaceId;
}
- base::Closure callback = base::Bind(&InsertSyncPointAndAckForCompositor,
- host_->GetProcess()->GetID(),
- output_surface_id,
- host_->GetRoutingID(),
- current_mailbox_,
- texture_size_in_layer_);
- ImageTransportFactoryAndroid::GetInstance()->WaitSyncPoint(
- frame->gl_frame_data->sync_point);
-
- texture_size_in_layer_ = frame->gl_frame_data->size;
- ComputeContentsSize(frame->metadata);
-
- if (layer_->layer_tree_host()) {
+ if (layer_ && layer_->layer_tree_host()) {
for (size_t i = 0; i < frame->metadata.latency_info.size(); i++) {
scoped_ptr<cc::SwapPromise> swap_promise(
new cc::LatencyInfoSwapPromise(frame->metadata.latency_info[i]));
}
}
- BuffersSwapped(frame->gl_frame_data->mailbox, output_surface_id, callback);
+ DCHECK(!frame->delegated_frame_data->render_pass_list.empty());
+
+ cc::RenderPass* root_pass =
+ frame->delegated_frame_data->render_pass_list.back();
+ texture_size_in_layer_ = root_pass->output_rect.size();
+ ComputeContentsSize(frame->metadata);
+
+ SwapDelegatedFrame(output_surface_id, frame->delegated_frame_data.Pass());
frame_evictor_->SwappedFrame(!host_->is_hidden());
+
+ // As the metadata update may trigger view invalidation, always call it after
+ // any potential compositor scheduling.
+ OnFrameMetadataUpdated(frame->metadata);
+}
+
+void RenderWidgetHostViewAndroid::OnSwapCompositorFrame(
+ uint32 output_surface_id,
+ scoped_ptr<cc::CompositorFrame> frame) {
+ InternalSwapCompositorFrame(output_surface_id, frame.Pass());
+}
+
+void RenderWidgetHostViewAndroid::RetainFrame(
+ uint32 output_surface_id,
+ scoped_ptr<cc::CompositorFrame> frame) {
+ DCHECK(locks_on_frame_count_);
+
+ // Store the incoming frame so that it can be swapped when all the locks have
+ // been released. If there is already a stored frame, then replace and skip
+ // the previous one but make sure we still eventually send the ACK. Holding
+ // the ACK also blocks the renderer when its max_frames_pending is reached.
+ if (last_frame_info_) {
+ base::Closure ack_callback =
+ base::Bind(&RenderWidgetHostViewAndroid::SendDelegatedFrameAck,
+ weak_ptr_factory_.GetWeakPtr(),
+ last_frame_info_->output_surface_id);
+
+ ack_callbacks_.push(ack_callback);
+ }
+
+ last_frame_info_.reset(new LastFrameInfo(output_surface_id, frame.Pass()));
}
void RenderWidgetHostViewAndroid::SynchronousFrameMetadata(
const cc::CompositorFrameMetadata& frame_metadata) {
// This is a subset of OnSwapCompositorFrame() used in the synchronous
// compositor flow.
- UpdateContentViewCoreFrameMetadata(frame_metadata);
+ OnFrameMetadataUpdated(frame_metadata);
ComputeContentsSize(frame_metadata);
// DevTools ScreenCast support for Android WebView.
- if (DevToolsAgentHost::HasFor(RenderViewHost::From(GetRenderWidgetHost()))) {
+ WebContents* web_contents = content_view_core_->GetWebContents();
+ if (DevToolsAgentHost::HasFor(web_contents)) {
scoped_refptr<DevToolsAgentHost> dtah =
- DevToolsAgentHost::GetOrCreateFor(
- RenderViewHost::From(GetRenderWidgetHost()));
+ DevToolsAgentHost::GetOrCreateFor(web_contents);
// Unblock the compositor.
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
}
void RenderWidgetHostViewAndroid::SetOverlayVideoMode(bool enabled) {
- layer_->SetContentsOpaque(!enabled);
+ if (layer_)
+ layer_->SetContentsOpaque(!enabled);
+}
+
+bool RenderWidgetHostViewAndroid::SupportsAnimation() const {
+ // The synchronous (WebView) compositor does not have a proper browser
+ // compositor with which to drive animations.
+ return !using_synchronous_compositor_;
+}
+
+void RenderWidgetHostViewAndroid::SetNeedsAnimate() {
+ DCHECK(content_view_core_);
+ DCHECK(!using_synchronous_compositor_);
+ content_view_core_->GetWindowAndroid()->SetNeedsAnimate();
+}
+
+void RenderWidgetHostViewAndroid::MoveCaret(const gfx::PointF& position) {
+ MoveCaret(gfx::Point(position.x(), position.y()));
+}
+
+void RenderWidgetHostViewAndroid::SelectBetweenCoordinates(
+ const gfx::PointF& start,
+ const gfx::PointF& end) {
+ DCHECK(content_view_core_);
+ content_view_core_->SelectBetweenCoordinates(start, end);
+}
+
+void RenderWidgetHostViewAndroid::OnSelectionEvent(
+ SelectionEventType event,
+ const gfx::PointF& position) {
+ DCHECK(content_view_core_);
+ content_view_core_->OnSelectionEvent(event, position);
+}
+
+scoped_ptr<TouchHandleDrawable> RenderWidgetHostViewAndroid::CreateDrawable() {
+ DCHECK(content_view_core_);
+ if (using_synchronous_compositor_)
+ return content_view_core_->CreatePopupTouchHandleDrawable();
+
+ return scoped_ptr<TouchHandleDrawable>(new CompositedTouchHandleDrawable(
+ content_view_core_->GetLayer(),
+ content_view_core_->GetDpiScale(),
+ base::android::GetApplicationContext()));
}
void RenderWidgetHostViewAndroid::SynchronousCopyContents(
const gfx::Rect& src_subrect_in_pixel,
const gfx::Size& dst_size_in_pixel,
- const base::Callback<void(bool, const SkBitmap&)>& callback) {
+ const base::Callback<void(bool, const SkBitmap&)>& callback,
+ const SkColorType color_type) {
SynchronousCompositor* compositor =
SynchronousCompositorImpl::FromID(host_->GetProcess()->GetID(),
host_->GetRoutingID());
}
SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config,
- dst_size_in_pixel.width(),
- dst_size_in_pixel.height());
- bitmap.allocPixels();
+ bitmap.allocPixels(SkImageInfo::Make(dst_size_in_pixel.width(),
+ dst_size_in_pixel.height(),
+ color_type,
+ kPremul_SkAlphaType));
SkCanvas canvas(bitmap);
canvas.scale(
(float)dst_size_in_pixel.width() / (float)src_subrect_in_pixel.width(),
callback.Run(true, bitmap);
}
-void RenderWidgetHostViewAndroid::UpdateContentViewCoreFrameMetadata(
+void RenderWidgetHostViewAndroid::OnFrameMetadataUpdated(
const cc::CompositorFrameMetadata& frame_metadata) {
- if (content_view_core_) {
- // All offsets and sizes are in CSS pixels.
- content_view_core_->UpdateFrameInfo(
- frame_metadata.root_scroll_offset,
- frame_metadata.page_scale_factor,
- gfx::Vector2dF(frame_metadata.min_page_scale_factor,
- frame_metadata.max_page_scale_factor),
- frame_metadata.root_layer_size,
- frame_metadata.viewport_size,
- frame_metadata.location_bar_offset,
- frame_metadata.location_bar_content_translation,
- frame_metadata.overdraw_bottom_height);
+
+ // Disable double tap zoom for pages that have a width=device-width or
+ // narrower viewport (indicating that this is a mobile-optimized or responsive
+ // web design, so text will be legible without zooming). Also disable
+ // double tap and pinch for pages that prevent zooming in or out.
+ bool has_mobile_viewport = HasMobileViewport(frame_metadata);
+ bool has_fixed_page_scale = HasFixedPageScale(frame_metadata);
+ gesture_provider_.SetDoubleTapSupportForPageEnabled(
+ !has_fixed_page_scale && !has_mobile_viewport);
+
+ if (!content_view_core_)
+ return;
+
+ // All offsets and sizes are in CSS pixels.
+ content_view_core_->UpdateFrameInfo(
+ frame_metadata.root_scroll_offset,
+ frame_metadata.page_scale_factor,
+ gfx::Vector2dF(frame_metadata.min_page_scale_factor,
+ frame_metadata.max_page_scale_factor),
+ frame_metadata.root_layer_size,
+ frame_metadata.scrollable_viewport_size,
+ frame_metadata.location_bar_offset,
+ frame_metadata.location_bar_content_translation,
+ frame_metadata.overdraw_bottom_height);
+#if defined(VIDEO_HOLE)
+ if (host_ && host_->IsRenderView()) {
+ RenderViewHostImpl* rvhi = static_cast<RenderViewHostImpl*>(
+ RenderViewHost::From(host_));
+ rvhi->media_web_contents_observer()->OnFrameInfoUpdated();
}
+#endif // defined(VIDEO_HOLE)
}
void RenderWidgetHostViewAndroid::AcceleratedSurfaceInitialized(int host_id,
NOTREACHED() << "Need --composite-to-mailbox or --enable-delegated-renderer";
}
-void RenderWidgetHostViewAndroid::BuffersSwapped(
- const gpu::Mailbox& mailbox,
- uint32_t output_surface_id,
- const base::Closure& ack_callback) {
- ImageTransportFactoryAndroid* factory =
- ImageTransportFactoryAndroid::GetInstance();
-
- if (!texture_id_in_layer_) {
- texture_id_in_layer_ = factory->CreateTexture();
- texture_layer_->SetTextureId(texture_id_in_layer_);
- texture_layer_->SetIsDrawable(true);
- texture_layer_->SetContentsOpaque(true);
- }
-
- ImageTransportFactoryAndroid::GetInstance()->AcquireTexture(
- texture_id_in_layer_, mailbox.name);
-
- ResetClipping();
-
- current_mailbox_ = mailbox;
- last_output_surface_id_ = output_surface_id;
-
- if (host_->is_hidden())
- ack_callback.Run();
- else
- ack_callbacks_.push(ack_callback);
-}
-
void RenderWidgetHostViewAndroid::AttachLayers() {
if (!content_view_core_)
return;
return;
content_view_core_->AttachLayer(layer_);
- if (overscroll_effect_enabled_)
+ if (overscroll_effect_)
overscroll_effect_->Enable();
+ layer_->SetHideLayerAndSubtree(!is_showing_);
}
void RenderWidgetHostViewAndroid::RemoveLayers() {
if (!content_view_core_)
return;
+
if (!layer_.get())
return;
content_view_core_->RemoveLayer(layer_);
- overscroll_effect_->Disable();
+ if (overscroll_effect_)
+ overscroll_effect_->Disable();
+}
+
+void RenderWidgetHostViewAndroid::RequestVSyncUpdate(uint32 requests) {
+ // The synchronous compositor does not requre BeginFrame messages.
+ if (using_synchronous_compositor_)
+ requests &= FLUSH_INPUT;
+
+ bool should_request_vsync = !outstanding_vsync_requests_ && requests;
+ outstanding_vsync_requests_ |= requests;
+ // Note that if we're not currently observing the root window, outstanding
+ // vsync requests will be pushed if/when we resume observing in
+ // |StartObservingRootWindow()|.
+ if (observing_root_window_ && should_request_vsync)
+ content_view_core_->GetWindowAndroid()->RequestVSyncUpdate();
+}
+
+void RenderWidgetHostViewAndroid::StartObservingRootWindow() {
+ DCHECK(content_view_core_);
+ if (observing_root_window_)
+ return;
+
+ observing_root_window_ = true;
+ content_view_core_->GetWindowAndroid()->AddObserver(this);
+
+ // Clear existing vsync requests to allow a request to the new window.
+ uint32 outstanding_vsync_requests = outstanding_vsync_requests_;
+ outstanding_vsync_requests_ = 0;
+ RequestVSyncUpdate(outstanding_vsync_requests);
+}
+
+void RenderWidgetHostViewAndroid::StopObservingRootWindow() {
+ if (!content_view_core_) {
+ DCHECK(!observing_root_window_);
+ return;
+ }
+
+ if (!observing_root_window_)
+ return;
+
+ observing_root_window_ = false;
+ content_view_core_->GetWindowAndroid()->RemoveObserver(this);
+}
+
+void RenderWidgetHostViewAndroid::SendBeginFrame(base::TimeTicks frame_time,
+ base::TimeDelta vsync_period) {
+ TRACE_EVENT0("cc", "RenderWidgetHostViewAndroid::SendBeginFrame");
+ base::TimeTicks display_time = frame_time + vsync_period;
+
+ // TODO(brianderson): Use adaptive draw-time estimation.
+ base::TimeDelta estimated_browser_composite_time =
+ base::TimeDelta::FromMicroseconds(
+ (1.0f * base::Time::kMicrosecondsPerSecond) / (3.0f * 60));
+
+ base::TimeTicks deadline = display_time - estimated_browser_composite_time;
+
+ host_->Send(new ViewMsg_BeginFrame(
+ host_->GetRoutingID(),
+ cc::BeginFrameArgs::Create(frame_time, deadline, vsync_period)));
}
bool RenderWidgetHostViewAndroid::Animate(base::TimeTicks frame_time) {
- return overscroll_effect_->Animate(frame_time);
+ bool needs_animate =
+ overscroll_effect_ ? overscroll_effect_->Animate(frame_time) : false;
+ if (selection_controller_)
+ needs_animate |= selection_controller_->Animate(frame_time);
+ return needs_animate;
}
-void RenderWidgetHostViewAndroid::UpdateAnimationSize(
- const cc::CompositorFrameMetadata& frame_metadata) {
- // Disable edge effects for axes on which scrolling is impossible.
- gfx::SizeF ceiled_viewport_size =
- gfx::ToCeiledSize(frame_metadata.viewport_size);
- overscroll_effect_->set_horizontal_overscroll_enabled(
- ceiled_viewport_size.width() < frame_metadata.root_layer_size.width());
- overscroll_effect_->set_vertical_overscroll_enabled(
- ceiled_viewport_size.height() < frame_metadata.root_layer_size.height());
- overscroll_effect_->set_size(content_size_in_layer_);
+void RenderWidgetHostViewAndroid::OnContentScrollingChange() {
+ if (selection_controller_)
+ selection_controller_->SetTemporarilyHidden(IsContentScrolling());
+}
+
+bool RenderWidgetHostViewAndroid::IsContentScrolling() const {
+ return touch_scrolling_ || potentially_active_fling_count_ > 0;
}
void RenderWidgetHostViewAndroid::AcceleratedSurfacePostSubBuffer(
}
void RenderWidgetHostViewAndroid::EvictDelegatedFrame() {
- if (texture_id_in_layer_) {
- texture_layer_->SetTextureId(0);
- texture_layer_->SetIsDrawable(false);
- ImageTransportFactoryAndroid::GetInstance()->DeleteTexture(
- texture_id_in_layer_);
- texture_id_in_layer_ = 0;
- current_mailbox_ = gpu::Mailbox();
- last_output_surface_id_ = kUndefinedOutputSurfaceId;
- }
- if (delegated_renderer_layer_.get())
+ if (layer_.get())
DestroyDelegatedContent();
frame_evictor_->DiscardedFrame();
}
void RenderWidgetHostViewAndroid::ProcessAckedTouchEvent(
const TouchEventWithLatencyInfo& touch, InputEventAckState ack_result) {
- if (content_view_core_)
- content_view_core_->ConfirmTouchEvent(ack_result);
-}
-
-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
-}
-
-void RenderWidgetHostViewAndroid::UnhandledWheelEvent(
- const blink::WebMouseWheelEvent& event) {
- // intentionally empty, like RenderWidgetHostViewViews
+ const bool event_consumed = ack_result == INPUT_EVENT_ACK_STATE_CONSUMED;
+ gesture_provider_.OnTouchEventAck(event_consumed);
}
void RenderWidgetHostViewAndroid::GestureEventAck(
- int gesture_event_type,
+ const blink::WebGestureEvent& event,
InputEventAckState ack_result) {
- // Scroll events.
- if (gesture_event_type == blink::WebInputEvent::GestureScrollBegin) {
- content_view_core_->OnScrollBeginEventAck();
- }
- if (gesture_event_type == blink::WebInputEvent::GestureScrollUpdate &&
- ack_result == INPUT_EVENT_ACK_STATE_CONSUMED) {
- content_view_core_->OnScrollUpdateGestureConsumed();
- }
- if (gesture_event_type == blink::WebInputEvent::GestureScrollEnd) {
- content_view_core_->OnScrollEndEventAck();
+ // The overscroll effect requires an explicit release signal that may not be
+ // sent from the renderer compositor.
+ if (event.type == blink::WebInputEvent::GestureScrollEnd ||
+ event.type == blink::WebInputEvent::GestureFlingStart) {
+ DidOverscroll(DidOverscrollParams());
}
- // Fling events.
- if (gesture_event_type == blink::WebInputEvent::GestureFlingStart) {
- content_view_core_->OnFlingStartEventAck(ack_result);
+ switch (event.type) {
+ case blink::WebInputEvent::GestureScrollBegin:
+ touch_scrolling_ = true;
+ potentially_active_fling_count_ = 0;
+ OnContentScrollingChange();
+ break;
+ case blink::WebInputEvent::GestureScrollEnd:
+ touch_scrolling_ = false;
+ OnContentScrollingChange();
+ break;
+ case blink::WebInputEvent::GestureFlingStart:
+ touch_scrolling_ = false;
+ if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED)
+ ++potentially_active_fling_count_;
+ OnContentScrollingChange();
+ break;
+ default:
+ break;
}
+
+ if (content_view_core_)
+ content_view_core_->OnGestureEventAck(event, ack_result);
}
InputEventAckState RenderWidgetHostViewAndroid::FilterInputEvent(
const blink::WebInputEvent& input_event) {
+ if (selection_controller_) {
+ switch (input_event.type) {
+ case blink::WebInputEvent::GestureLongPress:
+ selection_controller_->OnLongPressEvent();
+ break;
+ case blink::WebInputEvent::GestureTap:
+ selection_controller_->OnTapEvent();
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (content_view_core_ &&
+ content_view_core_->FilterInputEvent(input_event))
+ return INPUT_EVENT_ACK_STATE_CONSUMED;
+
if (!host_)
return INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
}
void RenderWidgetHostViewAndroid::OnSetNeedsFlushInput() {
- if (flush_input_requested_ || !content_view_core_)
- return;
- flush_input_requested_ = true;
- content_view_core_->AddBeginFrameSubscriber();
-}
-
-void RenderWidgetHostViewAndroid::CreateBrowserAccessibilityManagerIfNeeded() {
- if (!host_ || host_->accessibility_mode() != AccessibilityModeComplete)
- return;
-
- if (!GetBrowserAccessibilityManager()) {
- base::android::ScopedJavaLocalRef<jobject> obj;
- if (content_view_core_)
- obj = content_view_core_->GetJavaObject();
- SetBrowserAccessibilityManager(
- new BrowserAccessibilityManagerAndroid(
- obj, BrowserAccessibilityManagerAndroid::GetEmptyDocument(), this));
- }
-}
-
-void RenderWidgetHostViewAndroid::SetAccessibilityFocus(int acc_obj_id) {
- if (!host_)
- return;
-
- host_->AccessibilitySetFocus(acc_obj_id);
-}
-
-void RenderWidgetHostViewAndroid::AccessibilityDoDefaultAction(int acc_obj_id) {
- if (!host_)
- return;
-
- host_->AccessibilityDoDefaultAction(acc_obj_id);
-}
-
-void RenderWidgetHostViewAndroid::AccessibilityScrollToMakeVisible(
- int acc_obj_id, gfx::Rect subfocus) {
- if (!host_)
- return;
-
- host_->AccessibilityScrollToMakeVisible(acc_obj_id, subfocus);
-}
-
-void RenderWidgetHostViewAndroid::AccessibilityScrollToPoint(
- int acc_obj_id, gfx::Point point) {
- if (!host_)
- return;
-
- host_->AccessibilityScrollToPoint(acc_obj_id, point);
+ TRACE_EVENT0("input", "RenderWidgetHostViewAndroid::OnSetNeedsFlushInput");
+ RequestVSyncUpdate(FLUSH_INPUT);
}
-void RenderWidgetHostViewAndroid::AccessibilitySetTextSelection(
- int acc_obj_id, int start_offset, int end_offset) {
- if (!host_)
- return;
-
- host_->AccessibilitySetTextSelection(
- acc_obj_id, start_offset, end_offset);
-}
-
-gfx::Point RenderWidgetHostViewAndroid::GetLastTouchEventLocation() const {
- NOTIMPLEMENTED();
- // Only used on Win8
- return gfx::Point();
-}
-
-void RenderWidgetHostViewAndroid::FatalAccessibilityTreeError() {
- if (!host_)
- return;
-
- host_->FatalAccessibilityTreeError();
- SetBrowserAccessibilityManager(NULL);
+BrowserAccessibilityManager*
+ RenderWidgetHostViewAndroid::CreateBrowserAccessibilityManager(
+ BrowserAccessibilityDelegate* delegate) {
+ base::android::ScopedJavaLocalRef<jobject> obj;
+ if (content_view_core_)
+ obj = content_view_core_->GetJavaObject();
+ return new BrowserAccessibilityManagerAndroid(
+ obj,
+ BrowserAccessibilityManagerAndroid::GetEmptyDocument(),
+ delegate);
}
bool RenderWidgetHostViewAndroid::LockMouse() {
const blink::WebTouchEvent& event) {
if (host_)
host_->ForwardTouchEventWithLatencyInfo(event, CreateLatencyInfo(event));
-}
+ // Send a proactive BeginFrame on the next vsync to reduce latency.
+ // This is good enough as long as the first touch event has Begin semantics
+ // and the actual scroll happens on the next vsync.
+ // TODO: Is this actually still needed?
+ if (observing_root_window_)
+ RequestVSyncUpdate(BEGIN_FRAME);
+}
void RenderWidgetHostViewAndroid::SendMouseEvent(
const blink::WebMouseEvent& event) {
void RenderWidgetHostViewAndroid::SendGestureEvent(
const blink::WebGestureEvent& event) {
// Sending a gesture that may trigger overscroll should resume the effect.
- if (overscroll_effect_enabled_)
- overscroll_effect_->Enable();
+ if (overscroll_effect_)
+ overscroll_effect_->Enable();
if (host_)
host_->ForwardGestureEventWithLatencyInfo(event, CreateLatencyInfo(event));
}
-void RenderWidgetHostViewAndroid::SelectRange(const gfx::Point& start,
- const gfx::Point& end) {
- if (host_)
- host_->SelectRange(start, end);
-}
-
void RenderWidgetHostViewAndroid::MoveCaret(const gfx::Point& point) {
if (host_)
host_->MoveCaret(point);
}
-void RenderWidgetHostViewAndroid::RequestContentClipping(
- const gfx::Rect& clipping,
- const gfx::Size& content_size) {
- // A focused view provides its own clipping.
- if (HasFocus())
- return;
-
- ClipContents(clipping, content_size);
+void RenderWidgetHostViewAndroid::HideTextHandles() {
+ if (selection_controller_)
+ selection_controller_->HideAndDisallowShowingAutomatically();
}
-void RenderWidgetHostViewAndroid::ResetClipping() {
- ClipContents(gfx::Rect(gfx::Point(), content_size_in_layer_),
- content_size_in_layer_);
-}
-
-void RenderWidgetHostViewAndroid::ClipContents(const gfx::Rect& clipping,
- const gfx::Size& content_size) {
- if (!texture_id_in_layer_ || content_size_in_layer_.IsEmpty())
- return;
-
- gfx::Size clipped_content(content_size_in_layer_);
- clipped_content.SetToMin(clipping.size());
- texture_layer_->SetBounds(clipped_content);
- texture_layer_->SetNeedsDisplay();
-
- if (texture_size_in_layer_.IsEmpty()) {
- texture_layer_->SetUV(gfx::PointF(), gfx::PointF());
+void RenderWidgetHostViewAndroid::OnShowingPastePopup(
+ const gfx::PointF& point) {
+ if (!selection_controller_)
return;
- }
- gfx::PointF offset(
- clipping.x() + content_size_in_layer_.width() - content_size.width(),
- clipping.y() + content_size_in_layer_.height() - content_size.height());
- offset.SetToMax(gfx::PointF());
-
- gfx::Vector2dF uv_scale(1.f / texture_size_in_layer_.width(),
- 1.f / texture_size_in_layer_.height());
- texture_layer_->SetUV(
- gfx::PointF(offset.x() * uv_scale.x(),
- offset.y() * uv_scale.y()),
- gfx::PointF((offset.x() + clipped_content.width()) * uv_scale.x(),
- (offset.y() + clipped_content.height()) * uv_scale.y()));
+ // As the paste popup may be triggered *before* the bounds and editability
+ // of the region have been updated, explicitly set the properties now.
+ // TODO(jdduke): Remove this workaround when auxiliary paste popup
+ // notifications are no longer required, crbug.com/398170.
+ gfx::RectF rect(point, gfx::SizeF());
+ TouchHandleOrientation orientation = TOUCH_HANDLE_CENTER;
+ const bool visible = true;
+ HideTextHandles();
+ ShowSelectionHandlesAutomatically();
+ selection_controller_->OnSelectionEditable(true);
+ selection_controller_->OnSelectionEmpty(true);
+ selection_controller_->OnSelectionBoundsChanged(
+ rect, orientation, visible, rect, orientation, visible);
}
SkColor RenderWidgetHostViewAndroid::GetCachedBackgroundColor() const {
return cached_background_color_;
}
-void RenderWidgetHostViewAndroid::OnOverscrolled(
- gfx::Vector2dF accumulated_overscroll,
- gfx::Vector2dF current_fling_velocity) {
- if (!content_view_core_ || !are_layers_attached_)
+void RenderWidgetHostViewAndroid::DidOverscroll(
+ const DidOverscrollParams& params) {
+ if (!content_view_core_ || !layer_ || !is_showing_)
return;
- if (overscroll_effect_->OnOverscrolled(content_view_core_->GetLayer(),
- base::TimeTicks::Now(),
- accumulated_overscroll,
- current_fling_velocity)) {
- content_view_core_->SetNeedsAnimate();
+ const float device_scale_factor = content_view_core_->GetDpiScale();
+
+ if (overscroll_effect_ &&
+ overscroll_effect_->OnOverscrolled(
+ content_view_core_->GetLayer(),
+ base::TimeTicks::Now(),
+ gfx::ScaleVector2d(params.accumulated_overscroll,
+ device_scale_factor),
+ gfx::ScaleVector2d(params.latest_overscroll_delta,
+ device_scale_factor),
+ gfx::ScaleVector2d(params.current_fling_velocity,
+ device_scale_factor),
+ gfx::ScaleVector2d(
+ params.causal_event_viewport_point.OffsetFromOrigin(),
+ device_scale_factor))) {
+ SetNeedsAnimate();
}
}
void RenderWidgetHostViewAndroid::DidStopFlinging() {
+ if (potentially_active_fling_count_) {
+ --potentially_active_fling_count_;
+ OnContentScrollingChange();
+ }
+
if (content_view_core_)
content_view_core_->DidStopFlinging();
}
void RenderWidgetHostViewAndroid::SetContentViewCore(
ContentViewCoreImpl* content_view_core) {
- RunAckCallbacks();
-
- if (are_layers_attached_)
- RemoveLayers();
-
- if (content_view_core_ && !using_synchronous_compositor_)
- content_view_core_->GetWindowAndroid()->RemoveObserver(this);
+ RemoveLayers();
+ StopObservingRootWindow();
+
+ bool resize = false;
+ if (content_view_core != content_view_core_) {
+ overscroll_effect_.reset();
+ selection_controller_.reset();
+ ReleaseLocksOnSurface();
+ resize = true;
+ }
content_view_core_ = content_view_core;
- if (GetBrowserAccessibilityManager()) {
+ BrowserAccessibilityManager* manager = NULL;
+ if (host_)
+ manager = host_->GetRootBrowserAccessibilityManager();
+ if (manager) {
base::android::ScopedJavaLocalRef<jobject> obj;
if (content_view_core_)
obj = content_view_core_->GetJavaObject();
- GetBrowserAccessibilityManager()->ToBrowserAccessibilityManagerAndroid()->
- SetContentViewCore(obj);
+ manager->ToBrowserAccessibilityManagerAndroid()->SetContentViewCore(obj);
}
- if (are_layers_attached_) {
- AttachLayers();
- if (content_view_core_ && !using_synchronous_compositor_)
- content_view_core_->GetWindowAndroid()->AddObserver(this);
- }
+ AttachLayers();
- // Ensure ContentsViewCore is aware of the current touch handling state, eg.
- // in case we've already been running JS for the page as part of preload.
- if (content_view_core_ && host_)
- content_view_core_->HasTouchEventHandlers(host_->has_touch_handler());
+ if (!content_view_core_)
+ return;
+
+ StartObservingRootWindow();
+
+ if (resize)
+ WasResized();
+
+ if (!selection_controller_)
+ selection_controller_.reset(new TouchSelectionController(this));
+
+ if (overscroll_effect_enabled_ && !overscroll_effect_ &&
+ content_view_core_->GetWindowAndroid()->GetCompositor())
+ overscroll_effect_ = CreateOverscrollEffect(content_view_core_);
}
void RenderWidgetHostViewAndroid::RunAckCallbacks() {
}
}
-void RenderWidgetHostViewAndroid::HasTouchEventHandlers(
- bool need_touch_events) {
- if (content_view_core_)
- content_view_core_->HasTouchEventHandlers(need_touch_events);
+void RenderWidgetHostViewAndroid::OnGestureEvent(
+ const ui::GestureEventData& gesture) {
+ if (gesture_text_selector_.OnGestureEvent(gesture))
+ return;
+
+ SendGestureEvent(CreateWebGestureEventFromGestureEventData(gesture));
}
void RenderWidgetHostViewAndroid::OnCompositingDidCommit() {
RunAckCallbacks();
}
+
+void RenderWidgetHostViewAndroid::OnAttachCompositor() {
+ DCHECK(content_view_core_);
+ if (overscroll_effect_enabled_ && !overscroll_effect_)
+ overscroll_effect_ = CreateOverscrollEffect(content_view_core_);
+}
+
void RenderWidgetHostViewAndroid::OnDetachCompositor() {
DCHECK(content_view_core_);
DCHECK(!using_synchronous_compositor_);
RunAckCallbacks();
+ overscroll_effect_.reset();
+}
+
+void RenderWidgetHostViewAndroid::OnVSync(base::TimeTicks frame_time,
+ base::TimeDelta vsync_period) {
+ TRACE_EVENT0("cc", "RenderWidgetHostViewAndroid::OnVSync");
+ if (!host_)
+ return;
+
+ const uint32 current_vsync_requests = outstanding_vsync_requests_;
+ outstanding_vsync_requests_ = 0;
+
+ if (current_vsync_requests & FLUSH_INPUT)
+ host_->FlushInput();
+
+ if (current_vsync_requests & BEGIN_FRAME ||
+ current_vsync_requests & PERSISTENT_BEGIN_FRAME) {
+ SendBeginFrame(frame_time, vsync_period);
+ }
+
+ if (current_vsync_requests & PERSISTENT_BEGIN_FRAME)
+ RequestVSyncUpdate(PERSISTENT_BEGIN_FRAME);
+}
+
+void RenderWidgetHostViewAndroid::OnAnimate(base::TimeTicks begin_frame_time) {
+ if (Animate(begin_frame_time))
+ SetNeedsAnimate();
}
void RenderWidgetHostViewAndroid::OnLostResources() {
- if (texture_layer_.get())
- texture_layer_->SetIsDrawable(false);
- if (delegated_renderer_layer_.get())
+ ReleaseLocksOnSurface();
+ if (layer_.get())
DestroyDelegatedContent();
- texture_id_in_layer_ = 0;
- RunAckCallbacks();
+ DCHECK(ack_callbacks_.empty());
+}
+
+// static
+void
+RenderWidgetHostViewAndroid::PrepareTextureCopyOutputResultForDelegatedReadback(
+ const gfx::Size& dst_size_in_pixel,
+ const SkColorType color_type,
+ const base::TimeTicks& start_time,
+ scoped_refptr<cc::Layer> readback_layer,
+ const base::Callback<void(bool, const SkBitmap&)>& callback,
+ scoped_ptr<cc::CopyOutputResult> result) {
+ readback_layer->RemoveFromParent();
+ PrepareTextureCopyOutputResult(
+ dst_size_in_pixel, color_type, start_time, callback, result.Pass());
}
// static
void RenderWidgetHostViewAndroid::PrepareTextureCopyOutputResult(
const gfx::Size& dst_size_in_pixel,
- const SkBitmap::Config bitmap_config,
+ const SkColorType color_type,
const base::TimeTicks& start_time,
const base::Callback<void(bool, const SkBitmap&)>& callback,
scoped_ptr<cc::CopyOutputResult> result) {
- DCHECK(result->HasTexture());
base::ScopedClosureRunner scoped_callback_runner(
base::Bind(callback, false, SkBitmap()));
+ TRACE_EVENT0("cc",
+ "RenderWidgetHostViewAndroid::PrepareTextureCopyOutputResult");
if (!result->HasTexture() || result->IsEmpty() || result->size().IsEmpty())
return;
scoped_ptr<SkBitmap> bitmap(new SkBitmap);
- bitmap->setConfig(bitmap_config,
- dst_size_in_pixel.width(),
- dst_size_in_pixel.height(),
- 0, kOpaque_SkAlphaType);
- if (!bitmap->allocPixels())
+ if (!bitmap->allocPixels(SkImageInfo::Make(dst_size_in_pixel.width(),
+ dst_size_in_pixel.height(),
+ color_type,
+ kOpaque_SkAlphaType)))
return;
ImageTransportFactoryAndroid* factory =
ImageTransportFactoryAndroid::GetInstance();
GLHelper* gl_helper = factory->GetGLHelper();
+
if (!gl_helper)
return;
ignore_result(scoped_callback_runner.Release());
gl_helper->CropScaleReadbackAndCleanMailbox(
- texture_mailbox.name(),
+ texture_mailbox.mailbox(),
texture_mailbox.sync_point(),
result->size(),
gfx::Rect(result->size()),
dst_size_in_pixel,
pixels,
- bitmap_config,
+ color_type,
base::Bind(&CopyFromCompositingSurfaceFinished,
callback,
base::Passed(&release_callback),
base::Passed(&bitmap),
start_time,
- base::Passed(&bitmap_pixels_lock)));
+ base::Passed(&bitmap_pixels_lock)),
+ GLHelper::SCALER_QUALITY_GOOD);
}
-// static
-void RenderWidgetHostViewAndroid::PrepareBitmapCopyOutputResult(
- const gfx::Size& dst_size_in_pixel,
- const base::TimeTicks& start_time,
- const base::Callback<void(bool, const SkBitmap&)>& callback,
- scoped_ptr<cc::CopyOutputResult> result) {
- DCHECK(result->HasBitmap());
- base::ScopedClosureRunner scoped_callback_runner(
- base::Bind(callback, false, SkBitmap()));
+bool RenderWidgetHostViewAndroid::IsReadbackConfigSupported(
+ SkColorType color_type) {
+ ImageTransportFactoryAndroid* factory =
+ ImageTransportFactoryAndroid::GetInstance();
+ GLHelper* gl_helper = factory->GetGLHelper();
+ if (!gl_helper)
+ return false;
+ return gl_helper->IsReadbackConfigSupported(color_type);
+}
- if (!result->HasBitmap() || result->IsEmpty() || result->size().IsEmpty())
- return;
+SkColorType RenderWidgetHostViewAndroid::PreferredReadbackFormat() {
+ // Define the criteria here. If say the 16 texture readback is
+ // supported we should go with that (this degrades quality)
+ // or stick back to the default format.
+ if (base::SysInfo::IsLowEndDevice()) {
+ if (IsReadbackConfigSupported(kRGB_565_SkColorType))
+ return kRGB_565_SkColorType;
+ }
+ return kN32_SkColorType;
+}
- scoped_ptr<SkBitmap> source = result->TakeBitmap();
- DCHECK(source);
- if (!source)
- return;
+void RenderWidgetHostViewAndroid::ShowSelectionHandlesAutomatically() {
+ // Fake a long press to allow automatic selection handle showing.
+ if (selection_controller_)
+ selection_controller_->OnLongPressEvent();
+}
- DCHECK_EQ(source->width(), dst_size_in_pixel.width());
- DCHECK_EQ(source->height(), dst_size_in_pixel.height());
+void RenderWidgetHostViewAndroid::SelectRange(
+ float x1, float y1, float x2, float y2) {
+ if (content_view_core_)
+ static_cast<WebContentsImpl*>(content_view_core_->GetWebContents())->
+ SelectRange(gfx::Point(x1, y1), gfx::Point(x2, y2));
+}
- ignore_result(scoped_callback_runner.Release());
- UMA_HISTOGRAM_TIMES(kAsyncReadBackString,
- base::TimeTicks::Now() - start_time);
+void RenderWidgetHostViewAndroid::Unselect() {
+ if (content_view_core_)
+ content_view_core_->GetWebContents()->Unselect();
+}
- callback.Run(true, *source);
+void RenderWidgetHostViewAndroid::LongPress(
+ base::TimeTicks time, float x, float y) {
+ blink::WebGestureEvent long_press = WebGestureEventBuilder::Build(
+ blink::WebInputEvent::GestureLongPress,
+ (time - base::TimeTicks()).InSecondsF(), x, y);
+ SendGestureEvent(long_press);
}
// static
-void RenderWidgetHostViewPort::GetDefaultScreenInfo(
+void RenderWidgetHostViewBase::GetDefaultScreenInfo(
blink::WebScreenInfo* results) {
const gfx::Display& display =
gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
// TODO(husky): Remove any system controls from availableRect.
results->availableRect = display.work_area();
results->deviceScaleFactor = display.device_scale_factor();
+ results->orientationAngle = display.RotationAsDegree();
+ results->orientationType =
+ RenderWidgetHostViewBase::GetOrientationTypeForMobile(display);
gfx::DeviceDisplayInfo info;
results->depth = info.GetBitsPerPixel();
results->depthPerComponent = info.GetBitsPerComponent();
results->isMonochrome = (results->depthPerComponent == 0);
}
-////////////////////////////////////////////////////////////////////////////////
-// RenderWidgetHostView, public:
-
-// static
-RenderWidgetHostView*
-RenderWidgetHostView::CreateViewForWidget(RenderWidgetHost* widget) {
- RenderWidgetHostImpl* rwhi = RenderWidgetHostImpl::From(widget);
- return new RenderWidgetHostViewAndroid(rwhi, NULL);
-}
-
} // namespace content