#include "cc/output/compositor_frame_ack.h"
#include "cc/output/copy_output_request.h"
#include "cc/output/copy_output_result.h"
+#include "cc/output/viewport_selection_bound.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 "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/android/view_configuration.h"
#include "ui/gfx/display.h"
#include "ui/gfx/screen.h"
#include "ui/gfx/size_conversions.h"
content_view_core->GetDpiScale())));
}
+scoped_ptr<TouchSelectionController> CreateSelectionController(
+ TouchSelectionControllerClient* client,
+ ContentViewCore* content_view_core) {
+ DCHECK(client);
+ DCHECK(content_view_core);
+ int tap_timeout_ms = gfx::ViewConfiguration::GetTapTimeoutInMs();
+ int touch_slop_pixels = gfx::ViewConfiguration::GetTouchSlopInPixels();
+ return make_scoped_ptr(new TouchSelectionController(
+ client,
+ base::TimeDelta::FromMilliseconds(tap_timeout_ms),
+ touch_slop_pixels / content_view_core->GetDpiScale()));
+}
+
ui::GestureProvider::Config CreateGestureProviderConfig() {
ui::GestureProvider::Config config = ui::DefaultGestureProviderConfig();
config.disable_click_delay =
} // anonymous namespace
+ReadbackRequest::ReadbackRequest(
+ float scale,
+ SkColorType color_type,
+ gfx::Rect src_subrect,
+ const base::Callback<void(bool, const SkBitmap&)>& result_callback)
+ : scale_(scale),
+ color_type_(color_type),
+ src_subrect_(src_subrect),
+ result_callback_(result_callback) {
+}
+
+ReadbackRequest::ReadbackRequest() {
+}
+
+ReadbackRequest::~ReadbackRequest() {
+}
+
RenderWidgetHostViewAndroid::LastFrameInfo::LastFrameInfo(
uint32 output_id,
scoped_ptr<cc::CompositorFrame> output_frame)
ime_adapter_android_(this),
cached_background_color_(SK_ColorWHITE),
last_output_surface_id_(kUndefinedOutputSurfaceId),
- weak_ptr_factory_(this),
overscroll_effect_enabled_(
!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)),
locks_on_frame_count_(0),
- observing_root_window_(false) {
+ observing_root_window_(false),
+ weak_ptr_factory_(this) {
host_->SetView(this);
SetContentViewCore(content_view_core);
ImageTransportFactoryAndroid::AddObserver(this);
ImageTransportFactoryAndroid::RemoveObserver(this);
SetContentViewCore(NULL);
DCHECK(ack_callbacks_.empty());
+ DCHECK(readbacks_waiting_for_frame_.empty());
if (resource_collection_.get())
resource_collection_->SetClient(NULL);
}
SetSize(rect.size());
}
+void RenderWidgetHostViewAndroid::AbortPendingReadbackRequests() {
+ while (!readbacks_waiting_for_frame_.empty()) {
+ ReadbackRequest& readback_request = readbacks_waiting_for_frame_.front();
+ readback_request.GetResultCallback().Run(false, SkBitmap());
+ readbacks_waiting_for_frame_.pop();
+ }
+}
+
void RenderWidgetHostViewAndroid::GetScaledContentBitmap(
float scale,
SkColorType color_type,
gfx::Rect src_subrect,
- const base::Callback<void(bool, const SkBitmap&)>& result_callback) {
+ CopyFromCompositingSurfaceCallback& 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());
+ // The view is visible, probably the frame has not yet arrived.
+ // Just add the ReadbackRequest to queue and wait for frame arrival
+ // to get this request processed.
+ readbacks_waiting_for_frame_.push(
+ ReadbackRequest(scale, color_type, src_subrect, result_callback));
return;
}
src_subrect, dst_size, result_callback, color_type);
}
+scoped_refptr<cc::DelegatedRendererLayer>
+RenderWidgetHostViewAndroid::CreateDelegatedLayerForFrameProvider() const {
+ DCHECK(frame_provider_);
+
+ scoped_refptr<cc::DelegatedRendererLayer> delegated_layer =
+ cc::DelegatedRendererLayer::Create(frame_provider_);
+ delegated_layer->SetBounds(content_size_in_layer_);
+ delegated_layer->SetIsDrawable(true);
+ delegated_layer->SetContentsOpaque(true);
+
+ return delegated_layer;
+}
+
bool RenderWidgetHostViewAndroid::HasValidFrame() const {
if (!content_view_core_)
return false;
if (texture_size_in_layer_.IsEmpty())
return false;
-
+ // This tell us whether a valid frame has arrived or not.
if (!frame_evictor_->HasFrame())
return false;
return true;
}
+gfx::Vector2dF RenderWidgetHostViewAndroid::GetLastScrollOffset() const {
+ return last_scroll_offset_;
+}
+
gfx::NativeView RenderWidgetHostViewAndroid::GetNativeView() const {
return content_view_core_->GetViewAndroid();
}
host_->SetInputMethodActive(true);
if (overscroll_effect_)
overscroll_effect_->Enable();
+ if (selection_controller_)
+ selection_controller_->SetTemporarilyHidden(false);
}
void RenderWidgetHostViewAndroid::Blur() {
- host_->ExecuteEditCommand("Unselect", "");
host_->SetInputMethodActive(false);
host_->Blur();
if (overscroll_effect_)
overscroll_effect_->Disable();
+ if (selection_controller_)
+ selection_controller_->SetTemporarilyHidden(true);
}
bool RenderWidgetHostViewAndroid::HasFocus() const {
layer_->SetHideLayerAndSubtree(true);
frame_evictor_->SetVisible(false);
+ // We don't know if we will ever get a frame if we are hiding the renderer, so
+ // we need to cancel all requests
+ AbortPendingReadbackRequests();
WasHidden();
}
return content_view_core_->GetPhysicalBackingSize();
}
-float RenderWidgetHostViewAndroid::GetOverdrawBottomHeight() const {
+float RenderWidgetHostViewAndroid::GetTopControlsLayoutHeight() const {
if (!content_view_core_)
return 0.f;
- return content_view_core_->GetOverdrawBottomHeightDip();
+ // The amount that the viewport size given to Blink is shrunk by the URL-bar.
+ return content_view_core_->GetTopControlsLayoutHeightDip();
}
void RenderWidgetHostViewAndroid::UpdateCursor(const WebCursor& cursor) {
return true;
}
- // Short-circuit touch forwarding if no touch handlers exist.
- if (!host_->ShouldForwardTouchEvent()) {
+ if (host_->ShouldForwardTouchEvent()) {
+ blink::WebTouchEvent web_event = CreateWebTouchEventFromMotionEvent(event);
+ host_->ForwardTouchEventWithLatencyInfo(web_event,
+ CreateLatencyInfo(web_event));
+ } else {
const bool event_consumed = false;
gesture_provider_.OnTouchEventAck(event_consumed);
- return true;
}
- SendTouchEvent(CreateWebTouchEventFromMotionEvent(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.
+ if (observing_root_window_)
+ RequestVSyncUpdate(BEGIN_FRAME);
+
return true;
}
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) {
if (selection_controller_)
selection_controller_->OnSelectionEmpty(text.empty());
- if (text.empty() || range.is_empty() || !content_view_core_)
+ if (!content_view_core_)
return;
+ if (range.is_empty()) {
+ content_view_core_->OnSelectionChanged("");
+ return;
+ }
+
+ DCHECK(!text.empty());
size_t pos = range.GetMin() - offset;
size_t n = range.length();
void RenderWidgetHostViewAndroid::SelectionBoundsChanged(
const ViewHostMsg_SelectionBounds_Params& 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;
- }
-
- selection_controller_->OnSelectionBoundsChanged(anchor_rect,
- anchor_orientation,
- true,
- focus_rect,
- focus_orientation,
- true);
-}
-
-void RenderWidgetHostViewAndroid::ScrollOffsetChanged() {
+ NOTREACHED() << "Selection bounds should be routed through the compositor.";
}
void RenderWidgetHostViewAndroid::SetBackgroundOpaque(bool opaque) {
void RenderWidgetHostViewAndroid::CopyFromCompositingSurface(
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
- const base::Callback<void(bool, const SkBitmap&)>& callback,
+ CopyFromCompositingSurfaceCallback& callback,
const SkColorType color_type) {
TRACE_EVENT0("cc", "RenderWidgetHostViewAndroid::CopyFromCompositingSurface");
if ((!host_ || host_->is_hidden()) ||
DCHECK(compositor);
DCHECK(frame_provider_);
scoped_refptr<cc::DelegatedRendererLayer> delegated_layer =
- cc::DelegatedRendererLayer::Create(frame_provider_);
- delegated_layer->SetBounds(content_size_in_layer_);
+ CreateDelegatedLayerForFrameProvider();
delegated_layer->SetHideLayerAndSubtree(true);
- delegated_layer->SetIsDrawable(true);
- delegated_layer->SetContentsOpaque(true);
compositor->AttachLayerForReadback(delegated_layer);
readback_layer = delegated_layer;
}
void RenderWidgetHostViewAndroid::ShowDisambiguationPopup(
- const gfx::Rect& target_rect, const SkBitmap& zoomed_bitmap) {
+ const gfx::Rect& rect_pixels, const SkBitmap& zoomed_bitmap) {
if (!content_view_core_)
return;
- content_view_core_->ShowDisambiguationPopup(target_rect, zoomed_bitmap);
+ content_view_core_->ShowDisambiguationPopup(rect_pixels, zoomed_bitmap);
}
scoped_ptr<SyntheticGestureTarget>
RemoveLayers();
frame_provider_ = NULL;
layer_ = NULL;
+ // This gets called when ever any eviction, loosing resources, swapping
+ // problems are encountered and so we abort any pending readbacks here.
+ AbortPendingReadbackRequests();
}
void RenderWidgetHostViewAndroid::SwapDelegatedFrame(
const cc::CompositorFrameMetadata& frame_metadata) {
// Calculate the content size. This should be 0 if the texture_size is 0.
gfx::Vector2dF offset;
- if (texture_size_in_layer_.GetArea() > 0)
- offset = frame_metadata.location_bar_content_translation;
- offset.set_y(offset.y() + frame_metadata.overdraw_bottom_height);
- offset.Scale(frame_metadata.device_scale_factor);
- content_size_in_layer_ =
- gfx::Size(texture_size_in_layer_.width() - offset.x(),
- texture_size_in_layer_.height() - offset.y());
+ if (texture_size_in_layer_.IsEmpty())
+ content_size_in_layer_ = gfx::Size();
+ content_size_in_layer_ = gfx::ToCeiledSize(gfx::ScaleSize(
+ frame_metadata.scrollable_viewport_size,
+ frame_metadata.device_scale_factor * frame_metadata.page_scale_factor));
if (overscroll_effect_) {
overscroll_effect_->UpdateDisplayParameters(
void RenderWidgetHostViewAndroid::InternalSwapCompositorFrame(
uint32 output_surface_id,
scoped_ptr<cc::CompositorFrame> frame) {
+ last_scroll_offset_ = frame->metadata.root_scroll_offset;
if (!frame->delegated_frame_data) {
LOG(ERROR) << "Non-delegated renderer path no longer supported";
return;
// As the metadata update may trigger view invalidation, always call it after
// any potential compositor scheduling.
OnFrameMetadataUpdated(frame->metadata);
+ // Check if we have any pending readbacks, see if we have a frame available
+ // and process them here.
+ if (!readbacks_waiting_for_frame_.empty()) {
+ while (!readbacks_waiting_for_frame_.empty()) {
+ ReadbackRequest& readback_request = readbacks_waiting_for_frame_.front();
+ GetScaledContentBitmap(readback_request.GetScale(),
+ readback_request.GetColorFormat(),
+ readback_request.GetCaptureRect(),
+ readback_request.GetResultCallback());
+ readbacks_waiting_for_frame_.pop();
+ }
+ }
}
void RenderWidgetHostViewAndroid::OnSwapCompositorFrame(
if (!content_view_core_)
return;
+ DCHECK(selection_controller_);
+ selection_controller_->OnSelectionBoundsChanged(
+ frame_metadata.selection_start, frame_metadata.selection_end);
+
// All offsets and sizes are in CSS pixels.
content_view_core_->UpdateFrameInfo(
frame_metadata.root_scroll_offset,
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);
+ frame_metadata.location_bar_content_translation);
#if defined(VIDEO_HOLE)
if (host_ && host_->IsRenderView()) {
RenderViewHostImpl* rvhi = static_cast<RenderViewHostImpl*>(
void RenderWidgetHostViewAndroid::SendBeginFrame(base::TimeTicks frame_time,
base::TimeDelta vsync_period) {
- TRACE_EVENT0("cc", "RenderWidgetHostViewAndroid::SendBeginFrame");
+ TRACE_EVENT1("cc", "RenderWidgetHostViewAndroid::SendBeginFrame",
+ "frame_time_us", frame_time.ToInternalValue());
base::TimeTicks display_time = frame_time + vsync_period;
// TODO(brianderson): Use adaptive draw-time estimation.
return needs_animate;
}
-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(
const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params,
int gpu_host_id) {
if (layer_.get())
DestroyDelegatedContent();
frame_evictor_->DiscardedFrame();
+ // We are evicting the delegated frame,
+ // so there should be no pending readback requests
+ DCHECK(readbacks_waiting_for_frame_.empty());
}
bool RenderWidgetHostViewAndroid::HasAcceleratedSurface(
DidOverscroll(DidOverscrollParams());
}
- 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);
}
host_->ForwardKeyboardEvent(event);
}
-void RenderWidgetHostViewAndroid::SendTouchEvent(
- 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) {
if (host_)
// 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;
+ cc::ViewportSelectionBound insertion_bound;
+ insertion_bound.type = cc::SELECTION_BOUND_CENTER;
+ insertion_bound.visible = true;
+ insertion_bound.edge_top = point;
+ insertion_bound.edge_bottom = point;
HideTextHandles();
ShowSelectionHandlesAutomatically();
selection_controller_->OnSelectionEditable(true);
selection_controller_->OnSelectionEmpty(true);
- selection_controller_->OnSelectionBoundsChanged(
- rect, orientation, visible, rect, orientation, visible);
+ selection_controller_->OnSelectionBoundsChanged(insertion_bound,
+ insertion_bound);
}
SkColor RenderWidgetHostViewAndroid::GetCachedBackgroundColor() const {
}
void RenderWidgetHostViewAndroid::DidStopFlinging() {
- if (potentially_active_fling_count_) {
- --potentially_active_fling_count_;
- OnContentScrollingChange();
- }
-
if (content_view_core_)
content_view_core_->DidStopFlinging();
}
WasResized();
if (!selection_controller_)
- selection_controller_.reset(new TouchSelectionController(this));
+ selection_controller_ = CreateSelectionController(this, content_view_core_);
if (overscroll_effect_enabled_ && !overscroll_effect_ &&
content_view_core_->GetWindowAndroid()->GetCompositor())
if (layer_.get())
DestroyDelegatedContent();
DCHECK(ack_callbacks_.empty());
+ // We should not loose a frame if we have readback requests pending.
+ DCHECK(readbacks_waiting_for_frame_.empty());
}
// static
return;
scoped_ptr<SkBitmap> bitmap(new SkBitmap);
- if (!bitmap->allocPixels(SkImageInfo::Make(dst_size_in_pixel.width(),
- dst_size_in_pixel.height(),
- color_type,
- kOpaque_SkAlphaType)))
+ if (!bitmap->tryAllocPixels(SkImageInfo::Make(dst_size_in_pixel.width(),
+ dst_size_in_pixel.height(),
+ color_type,
+ kOpaque_SkAlphaType)))
return;
ImageTransportFactoryAndroid* factory =