[Android WebView] Disable fallback ticks when paused or window invisible
[chromium-blink-merge.git] / android_webview / browser / in_process_view_renderer.cc
blobd9f8232a0538997e8ed3f81eb7a0edc82699303a
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "android_webview/browser/in_process_view_renderer.h"
7 #include <android/bitmap.h>
9 #include "android_webview/browser/aw_gl_surface.h"
10 #include "android_webview/browser/scoped_app_gl_state_restore.h"
11 #include "android_webview/common/aw_switches.h"
12 #include "android_webview/public/browser/draw_gl.h"
13 #include "android_webview/public/browser/draw_sw.h"
14 #include "base/android/jni_android.h"
15 #include "base/auto_reset.h"
16 #include "base/command_line.h"
17 #include "base/debug/trace_event.h"
18 #include "base/lazy_instance.h"
19 #include "base/logging.h"
20 #include "base/strings/stringprintf.h"
21 #include "content/public/browser/android/synchronous_compositor.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/web_contents.h"
24 #include "gpu/command_buffer/service/in_process_command_buffer.h"
25 #include "third_party/skia/include/core/SkBitmap.h"
26 #include "third_party/skia/include/core/SkCanvas.h"
27 #include "third_party/skia/include/core/SkDevice.h"
28 #include "third_party/skia/include/core/SkGraphics.h"
29 #include "third_party/skia/include/core/SkPicture.h"
30 #include "ui/gfx/skia_util.h"
31 #include "ui/gfx/transform.h"
32 #include "ui/gfx/vector2d_conversions.h"
33 #include "ui/gfx/vector2d_f.h"
35 using base::android::AttachCurrentThread;
36 using base::android::JavaRef;
37 using base::android::ScopedJavaLocalRef;
38 using content::BrowserThread;
40 namespace android_webview {
42 namespace {
45 const void* kUserDataKey = &kUserDataKey;
47 class UserData : public content::WebContents::Data {
48 public:
49 UserData(InProcessViewRenderer* ptr) : instance_(ptr) {}
50 virtual ~UserData() {
51 instance_->WebContentsGone();
54 static InProcessViewRenderer* GetInstance(content::WebContents* contents) {
55 if (!contents)
56 return NULL;
57 UserData* data = reinterpret_cast<UserData*>(
58 contents->GetUserData(kUserDataKey));
59 return data ? data->instance_ : NULL;
62 private:
63 InProcessViewRenderer* instance_;
66 bool RasterizeIntoBitmap(JNIEnv* env,
67 const JavaRef<jobject>& jbitmap,
68 int scroll_x,
69 int scroll_y,
70 const InProcessViewRenderer::RenderMethod& renderer) {
71 DCHECK(jbitmap.obj());
73 AndroidBitmapInfo bitmap_info;
74 if (AndroidBitmap_getInfo(env, jbitmap.obj(), &bitmap_info) < 0) {
75 LOG(ERROR) << "Error getting java bitmap info.";
76 return false;
79 void* pixels = NULL;
80 if (AndroidBitmap_lockPixels(env, jbitmap.obj(), &pixels) < 0) {
81 LOG(ERROR) << "Error locking java bitmap pixels.";
82 return false;
85 bool succeeded;
87 SkBitmap bitmap;
88 bitmap.setConfig(SkBitmap::kARGB_8888_Config,
89 bitmap_info.width,
90 bitmap_info.height,
91 bitmap_info.stride);
92 bitmap.setPixels(pixels);
94 SkDevice device(bitmap);
95 SkCanvas canvas(&device);
96 canvas.translate(-scroll_x, -scroll_y);
97 succeeded = renderer.Run(&canvas);
100 if (AndroidBitmap_unlockPixels(env, jbitmap.obj()) < 0) {
101 LOG(ERROR) << "Error unlocking java bitmap pixels.";
102 return false;
105 return succeeded;
108 bool RenderPictureToCanvas(SkPicture* picture, SkCanvas* canvas) {
109 canvas->drawPicture(*picture);
110 return true;
113 class ScopedPixelAccess {
114 public:
115 ScopedPixelAccess(JNIEnv* env, jobject java_canvas) {
116 AwDrawSWFunctionTable* sw_functions =
117 BrowserViewRenderer::GetAwDrawSWFunctionTable();
118 pixels_ = sw_functions ?
119 sw_functions->access_pixels(env, java_canvas) : NULL;
121 ~ScopedPixelAccess() {
122 if (pixels_)
123 BrowserViewRenderer::GetAwDrawSWFunctionTable()->release_pixels(pixels_);
125 AwPixelInfo* pixels() { return pixels_; }
127 private:
128 AwPixelInfo* pixels_;
130 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedPixelAccess);
133 bool HardwareEnabled() {
134 static bool g_hw_enabled = !CommandLine::ForCurrentProcess()->HasSwitch(
135 switches::kDisableWebViewGLMode);
136 return g_hw_enabled;
139 // Provides software rendering functions from the Android glue layer.
140 // Allows preventing extra copies of data when rendering.
141 AwDrawSWFunctionTable* g_sw_draw_functions = NULL;
143 const int64 kFallbackTickTimeoutInMilliseconds = 20;
145 class ScopedAllowGL {
146 public:
147 ScopedAllowGL();
148 ~ScopedAllowGL();
150 static bool IsAllowed() {
151 return BrowserThread::CurrentlyOn(BrowserThread::UI) && allow_gl;
154 private:
155 static bool allow_gl;
157 DISALLOW_COPY_AND_ASSIGN(ScopedAllowGL);
160 ScopedAllowGL::ScopedAllowGL() {
161 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
162 DCHECK(!allow_gl);
163 allow_gl = true;
166 ScopedAllowGL::~ScopedAllowGL() {
167 allow_gl = false;
170 bool ScopedAllowGL::allow_gl = false;
172 base::LazyInstance<GLViewRendererManager>::Leaky g_view_renderer_manager;
174 } // namespace
176 // Called from different threads!
177 static void ScheduleGpuWork() {
178 if (ScopedAllowGL::IsAllowed()) {
179 gpu::InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread();
180 } else {
181 InProcessViewRenderer* renderer = static_cast<InProcessViewRenderer*>(
182 g_view_renderer_manager.Get().GetMostRecentlyDrawn());
183 if (!renderer || !renderer->RequestProcessGL()) {
184 LOG(ERROR) << "Failed to request DrawGL. Probably going to deadlock.";
189 // static
190 void BrowserViewRenderer::SetAwDrawSWFunctionTable(
191 AwDrawSWFunctionTable* table) {
192 g_sw_draw_functions = table;
193 gpu::InProcessCommandBuffer::SetScheduleCallback(
194 base::Bind(&ScheduleGpuWork));
197 // static
198 AwDrawSWFunctionTable* BrowserViewRenderer::GetAwDrawSWFunctionTable() {
199 return g_sw_draw_functions;
202 InProcessViewRenderer::InProcessViewRenderer(
203 BrowserViewRenderer::Client* client,
204 JavaHelper* java_helper,
205 content::WebContents* web_contents)
206 : client_(client),
207 java_helper_(java_helper),
208 web_contents_(web_contents),
209 compositor_(NULL),
210 is_paused_(false),
211 view_visible_(false),
212 window_visible_(false),
213 attached_to_window_(false),
214 dip_scale_(0.0),
215 page_scale_factor_(1.0),
216 on_new_picture_enable_(false),
217 compositor_needs_continuous_invalidate_(false),
218 block_invalidates_(false),
219 width_(0),
220 height_(0),
221 hardware_initialized_(false),
222 hardware_failed_(false),
223 last_egl_context_(NULL),
224 manager_key_(g_view_renderer_manager.Get().NullKey()) {
225 CHECK(web_contents_);
226 web_contents_->SetUserData(kUserDataKey, new UserData(this));
227 content::SynchronousCompositor::SetClientForWebContents(web_contents_, this);
229 // Currently the logic in this class relies on |compositor_| remaining NULL
230 // until the DidInitializeCompositor() call, hence it is not set here.
233 InProcessViewRenderer::~InProcessViewRenderer() {
234 CHECK(web_contents_);
235 content::SynchronousCompositor::SetClientForWebContents(web_contents_, NULL);
236 web_contents_->SetUserData(kUserDataKey, NULL);
237 NoLongerExpectsDrawGL();
238 DCHECK(web_contents_ == NULL); // WebContentsGone should have been called.
242 // TODO(boliu): Should also call this when we know for sure we are no longer,
243 // for example, when visible rect becomes 0.
244 void InProcessViewRenderer::NoLongerExpectsDrawGL() {
245 GLViewRendererManager& mru = g_view_renderer_manager.Get();
246 if (manager_key_ != mru.NullKey()) {
247 mru.NoLongerExpectsDrawGL(manager_key_);
248 manager_key_ = mru.NullKey();
250 // TODO(boliu): If this is the first one and there are GL pending,
251 // requestDrawGL on next one.
252 // TODO(boliu): If this is the last one, lose all global contexts.
256 // static
257 InProcessViewRenderer* InProcessViewRenderer::FromWebContents(
258 content::WebContents* contents) {
259 return UserData::GetInstance(contents);
262 void InProcessViewRenderer::WebContentsGone() {
263 web_contents_ = NULL;
264 compositor_ = NULL;
267 bool InProcessViewRenderer::RequestProcessGL() {
268 return client_->RequestDrawGL(NULL);
271 void InProcessViewRenderer::UpdateCachedGlobalVisibleRect() {
272 client_->UpdateGlobalVisibleRect();
275 bool InProcessViewRenderer::OnDraw(jobject java_canvas,
276 bool is_hardware_canvas,
277 const gfx::Vector2d& scroll,
278 const gfx::Rect& clip) {
279 scroll_at_start_of_frame_ = scroll;
280 if (is_hardware_canvas && attached_to_window_ && HardwareEnabled()) {
281 // We should be performing a hardware draw here. If we don't have the
282 // comositor yet or if RequestDrawGL fails, it means we failed this draw and
283 // thus return false here to clear to background color for this draw.
284 return compositor_ && client_->RequestDrawGL(java_canvas);
286 // Perform a software draw
287 block_invalidates_ = true;
288 bool result = DrawSWInternal(java_canvas, clip);
289 block_invalidates_ = false;
290 EnsureContinuousInvalidation(NULL, false);
291 return result;
294 bool InProcessViewRenderer::InitializeHwDraw() {
295 TRACE_EVENT0("android_webview", "InitializeHwDraw");
296 DCHECK(!gl_surface_);
297 gl_surface_ = new AwGLSurface;
298 hardware_failed_ = !compositor_->InitializeHwDraw(gl_surface_);
299 hardware_initialized_ = true;
301 if (hardware_failed_)
302 gl_surface_ = NULL;
304 return !hardware_failed_;
307 void InProcessViewRenderer::DrawGL(AwDrawGLInfo* draw_info) {
308 TRACE_EVENT0("android_webview", "InProcessViewRenderer::DrawGL");
310 manager_key_ = g_view_renderer_manager.Get().DidDrawGL(manager_key_, this);
312 // We need to watch if the current Android context has changed and enforce
313 // a clean-up in the compositor.
314 EGLContext current_context = eglGetCurrentContext();
315 if (!current_context) {
316 TRACE_EVENT_INSTANT0(
317 "android_webview", "EarlyOut_NullEGLContext", TRACE_EVENT_SCOPE_THREAD);
318 return;
321 ScopedAppGLStateRestore state_restore(ScopedAppGLStateRestore::MODE_DRAW);
322 gpu::InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread();
323 ScopedAllowGL allow_gl;
325 if (attached_to_window_ && compositor_ && !hardware_initialized_) {
326 if (InitializeHwDraw()) {
327 last_egl_context_ = current_context;
328 } else {
329 return;
333 if (draw_info->mode == AwDrawGLInfo::kModeProcess) {
334 TRACE_EVENT_INSTANT0(
335 "android_webview", "EarlyOut_ModeProcess", TRACE_EVENT_SCOPE_THREAD);
336 return;
339 UpdateCachedGlobalVisibleRect();
340 if (cached_global_visible_rect_.IsEmpty()) {
341 TRACE_EVENT_INSTANT0("android_webview",
342 "EarlyOut_EmptyVisibleRect",
343 TRACE_EVENT_SCOPE_THREAD);
344 return;
347 // DrawGL may be called without OnDraw, so cancel |fallback_tick_| here as
348 // well just to be safe.
349 fallback_tick_.Cancel();
351 if (last_egl_context_ != current_context) {
352 // TODO(boliu): Handle context lost
353 TRACE_EVENT_INSTANT0(
354 "android_webview", "EGLContextChanged", TRACE_EVENT_SCOPE_THREAD);
357 if (!compositor_) {
358 TRACE_EVENT_INSTANT0(
359 "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD);
360 return;
363 DCHECK(gl_surface_);
364 gl_surface_->SetBackingFrameBufferObject(
365 state_restore.framebuffer_binding_ext());
367 gfx::Transform transform;
368 transform.matrix().setColMajorf(draw_info->transform);
369 transform.Translate(scroll_at_start_of_frame_.x(),
370 scroll_at_start_of_frame_.y());
371 gfx::Rect clip_rect(draw_info->clip_left,
372 draw_info->clip_top,
373 draw_info->clip_right - draw_info->clip_left,
374 draw_info->clip_bottom - draw_info->clip_top);
376 // Assume we always draw the full visible rect if we are drawing into a layer.
377 bool drew_full_visible_rect = true;
379 if (!draw_info->is_layer) {
380 clip_rect.Intersect(cached_global_visible_rect_);
381 drew_full_visible_rect = clip_rect.Contains(cached_global_visible_rect_);
384 block_invalidates_ = true;
385 // TODO(joth): Check return value.
386 compositor_->DemandDrawHw(gfx::Size(draw_info->width, draw_info->height),
387 transform,
388 clip_rect,
389 state_restore.stencil_enabled());
390 block_invalidates_ = false;
391 gl_surface_->ResetBackingFrameBufferObject();
393 EnsureContinuousInvalidation(draw_info, !drew_full_visible_rect);
396 void InProcessViewRenderer::SetGlobalVisibleRect(
397 const gfx::Rect& visible_rect) {
398 cached_global_visible_rect_ = visible_rect;
401 bool InProcessViewRenderer::DrawSWInternal(jobject java_canvas,
402 const gfx::Rect& clip) {
403 fallback_tick_.Cancel();
405 if (clip.IsEmpty()) {
406 TRACE_EVENT_INSTANT0(
407 "android_webview", "EarlyOut_EmptyClip", TRACE_EVENT_SCOPE_THREAD);
408 return true;
411 if (!compositor_) {
412 TRACE_EVENT_INSTANT0(
413 "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD);
414 return false;
417 return RenderViaAuxilaryBitmapIfNeeded(
418 java_canvas,
419 java_helper_,
420 scroll_at_start_of_frame_,
421 clip,
422 base::Bind(&InProcessViewRenderer::CompositeSW,
423 base::Unretained(this)),
424 web_contents_);
427 // static
428 bool InProcessViewRenderer::RenderViaAuxilaryBitmapIfNeeded(
429 jobject java_canvas,
430 BrowserViewRenderer::JavaHelper* java_helper,
431 const gfx::Vector2d& scroll_correction,
432 const gfx::Rect& clip,
433 InProcessViewRenderer::RenderMethod render_source,
434 void* owner_key) {
435 TRACE_EVENT0("android_webview",
436 "InProcessViewRenderer::RenderViaAuxilaryBitmapIfNeeded");
438 JNIEnv* env = AttachCurrentThread();
439 ScopedPixelAccess auto_release_pixels(env, java_canvas);
440 AwPixelInfo* pixels = auto_release_pixels.pixels();
441 SkMatrix matrix;
442 SkBitmap::Config config(SkBitmap::kNo_Config);
443 if (pixels) {
444 switch (pixels->config) {
445 case AwConfig_ARGB_8888:
446 config = SkBitmap::kARGB_8888_Config;
447 break;
448 case AwConfig_RGB_565:
449 config = SkBitmap::kRGB_565_Config;
450 break;
453 for (int i = 0; i < 9; i++) {
454 matrix.set(i, pixels->matrix[i]);
456 // Workaround for http://crbug.com/271096: SW draw only supports
457 // translate & scale transforms.
458 if (matrix.getType() & ~(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask))
459 config = SkBitmap::kNo_Config;
462 if (config == SkBitmap::kNo_Config) {
463 // Render into an auxiliary bitmap if pixel info is not available.
464 ScopedJavaLocalRef<jobject> jcanvas(env, java_canvas);
465 TRACE_EVENT0("android_webview", "RenderToAuxBitmap");
466 ScopedJavaLocalRef<jobject> jbitmap(java_helper->CreateBitmap(
467 env, clip.width(), clip.height(), jcanvas, owner_key));
468 if (!jbitmap.obj()) {
469 TRACE_EVENT_INSTANT0("android_webview",
470 "EarlyOut_BitmapAllocFail",
471 TRACE_EVENT_SCOPE_THREAD);
472 return false;
475 if (!RasterizeIntoBitmap(env, jbitmap,
476 clip.x() - scroll_correction.x(),
477 clip.y() - scroll_correction.y(),
478 render_source)) {
479 TRACE_EVENT_INSTANT0("android_webview",
480 "EarlyOut_RasterizeFail",
481 TRACE_EVENT_SCOPE_THREAD);
482 return false;
485 java_helper->DrawBitmapIntoCanvas(env, jbitmap, jcanvas,
486 clip.x(), clip.y());
487 return true;
490 // Draw in a SkCanvas built over the pixel information.
491 SkBitmap bitmap;
492 bitmap.setConfig(config,
493 pixels->width,
494 pixels->height,
495 pixels->row_bytes);
496 bitmap.setPixels(pixels->pixels);
497 SkDevice device(bitmap);
498 SkCanvas canvas(&device);
499 canvas.setMatrix(matrix);
501 if (pixels->clip_rect_count) {
502 SkRegion clip;
503 for (int i = 0; i < pixels->clip_rect_count; ++i) {
504 clip.op(SkIRect::MakeXYWH(pixels->clip_rects[i + 0],
505 pixels->clip_rects[i + 1],
506 pixels->clip_rects[i + 2],
507 pixels->clip_rects[i + 3]),
508 SkRegion::kUnion_Op);
510 canvas.setClipRegion(clip);
513 canvas.translate(scroll_correction.x(),
514 scroll_correction.y());
516 return render_source.Run(&canvas);
519 skia::RefPtr<SkPicture> InProcessViewRenderer::CapturePicture(int width,
520 int height) {
521 TRACE_EVENT0("android_webview", "InProcessViewRenderer::CapturePicture");
523 // Return empty Picture objects for empty SkPictures.
524 skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture);
525 if (width <= 0 || height <= 0) {
526 return picture;
529 // Reset scroll back to the origin, will go back to the old
530 // value when scroll_reset is out of scope.
531 base::AutoReset<gfx::Vector2dF> scroll_reset(&scroll_offset_css_,
532 gfx::Vector2d());
534 SkCanvas* rec_canvas = picture->beginRecording(width, height, 0);
535 if (compositor_)
536 CompositeSW(rec_canvas);
537 picture->endRecording();
538 return picture;
541 void InProcessViewRenderer::EnableOnNewPicture(bool enabled) {
542 on_new_picture_enable_ = enabled;
545 void InProcessViewRenderer::SetIsPaused(bool paused) {
546 TRACE_EVENT_INSTANT1("android_webview",
547 "InProcessViewRenderer::SetIsPaused",
548 TRACE_EVENT_SCOPE_THREAD,
549 "paused",
550 paused);
551 is_paused_ = paused;
552 EnsureContinuousInvalidation(NULL, false);
555 void InProcessViewRenderer::SetViewVisibility(bool view_visible) {
556 TRACE_EVENT_INSTANT1("android_webview",
557 "InProcessViewRenderer::SetViewVisibility",
558 TRACE_EVENT_SCOPE_THREAD,
559 "view_visible",
560 view_visible);
561 view_visible_ = view_visible;
564 void InProcessViewRenderer::SetWindowVisibility(bool window_visible) {
565 TRACE_EVENT_INSTANT1("android_webview",
566 "InProcessViewRenderer::SetWindowVisibility",
567 TRACE_EVENT_SCOPE_THREAD,
568 "window_visible",
569 window_visible);
570 window_visible_ = window_visible;
571 EnsureContinuousInvalidation(NULL, false);
574 void InProcessViewRenderer::OnSizeChanged(int width, int height) {
575 TRACE_EVENT_INSTANT2("android_webview",
576 "InProcessViewRenderer::OnSizeChanged",
577 TRACE_EVENT_SCOPE_THREAD,
578 "width",
579 width,
580 "height",
581 height);
582 width_ = width;
583 height_ = height;
586 void InProcessViewRenderer::OnAttachedToWindow(int width, int height) {
587 TRACE_EVENT2("android_webview",
588 "InProcessViewRenderer::OnAttachedToWindow",
589 "width",
590 width,
591 "height",
592 height);
593 attached_to_window_ = true;
594 width_ = width;
595 height_ = height;
598 void InProcessViewRenderer::OnDetachedFromWindow() {
599 TRACE_EVENT0("android_webview",
600 "InProcessViewRenderer::OnDetachedFromWindow");
602 NoLongerExpectsDrawGL();
603 if (hardware_initialized_) {
604 DCHECK(compositor_);
606 ScopedAppGLStateRestore state_restore(
607 ScopedAppGLStateRestore::MODE_DETACH_FROM_WINDOW);
608 gpu::InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread();
609 ScopedAllowGL allow_gl;
610 compositor_->ReleaseHwDraw();
611 hardware_initialized_ = false;
614 gl_surface_ = NULL;
615 attached_to_window_ = false;
618 bool InProcessViewRenderer::IsAttachedToWindow() {
619 return attached_to_window_;
622 bool InProcessViewRenderer::IsVisible() {
623 // Ignore |window_visible_| if |attached_to_window_| is false.
624 return view_visible_ && (!attached_to_window_ || window_visible_);
627 gfx::Rect InProcessViewRenderer::GetScreenRect() {
628 return gfx::Rect(client_->GetLocationOnScreen(), gfx::Size(width_, height_));
631 void InProcessViewRenderer::DidInitializeCompositor(
632 content::SynchronousCompositor* compositor) {
633 TRACE_EVENT0("android_webview",
634 "InProcessViewRenderer::DidInitializeCompositor");
635 DCHECK(compositor && compositor_ == NULL);
636 compositor_ = compositor;
637 hardware_initialized_ = false;
638 hardware_failed_ = false;
641 void InProcessViewRenderer::DidDestroyCompositor(
642 content::SynchronousCompositor* compositor) {
643 TRACE_EVENT0("android_webview",
644 "InProcessViewRenderer::DidDestroyCompositor");
645 DCHECK(compositor_ == compositor);
647 // This can fail if Apps call destroy while the webview is still attached
648 // to the view tree. This is an illegal operation that will lead to leaks.
649 // Log for now. Consider a proper fix if this becomes a problem.
650 LOG_IF(ERROR, hardware_initialized_)
651 << "Destroy called before OnDetachedFromWindow. May Leak GL resources";
652 compositor_ = NULL;
655 void InProcessViewRenderer::SetContinuousInvalidate(bool invalidate) {
656 if (compositor_needs_continuous_invalidate_ == invalidate)
657 return;
659 TRACE_EVENT_INSTANT1("android_webview",
660 "InProcessViewRenderer::SetContinuousInvalidate",
661 TRACE_EVENT_SCOPE_THREAD,
662 "invalidate",
663 invalidate);
664 compositor_needs_continuous_invalidate_ = invalidate;
665 EnsureContinuousInvalidation(NULL, false);
668 void InProcessViewRenderer::SetDipScale(float dip_scale) {
669 dip_scale_ = dip_scale;
670 CHECK(dip_scale_ > 0);
673 void InProcessViewRenderer::SetPageScaleFactor(float page_scale_factor) {
674 page_scale_factor_ = page_scale_factor;
675 CHECK(page_scale_factor_ > 0);
678 void InProcessViewRenderer::ScrollTo(gfx::Vector2d new_value) {
679 DCHECK(dip_scale_ > 0);
680 // In general we don't guarantee that the scroll offset transforms are
681 // symmetrical. That is if scrolling from JS to offset1 results in a native
682 // offset2 then scrolling from UI to offset2 results in JS being scrolled to
683 // offset1 again.
684 // The reason we explicitly do rounding here is that it seems to yeld the
685 // most stabile transformation.
686 gfx::Vector2dF new_value_css = gfx::ToRoundedVector2d(
687 gfx::ScaleVector2d(new_value, 1.0f / (dip_scale_ * page_scale_factor_)));
689 // It's possible that more than one set of unique physical coordinates maps
690 // to the same set of CSS coordinates which means we can't reliably early-out
691 // earlier in the call stack.
692 if (scroll_offset_css_ == new_value_css)
693 return;
695 scroll_offset_css_ = new_value_css;
697 if (compositor_)
698 compositor_->DidChangeRootLayerScrollOffset();
701 void InProcessViewRenderer::DidUpdateContent() {
702 if (on_new_picture_enable_)
703 client_->OnNewPicture();
706 void InProcessViewRenderer::SetTotalRootLayerScrollOffset(
707 gfx::Vector2dF new_value_css) {
708 // TOOD(mkosiba): Add a DCHECK to say that this does _not_ get called during
709 // DrawGl when http://crbug.com/249972 is fixed.
710 if (scroll_offset_css_ == new_value_css)
711 return;
713 scroll_offset_css_ = new_value_css;
715 DCHECK(dip_scale_ > 0);
716 DCHECK(page_scale_factor_ > 0);
718 gfx::Vector2d scroll_offset = gfx::ToRoundedVector2d(
719 gfx::ScaleVector2d(new_value_css, dip_scale_ * page_scale_factor_));
721 client_->ScrollContainerViewTo(scroll_offset);
724 gfx::Vector2dF InProcessViewRenderer::GetTotalRootLayerScrollOffset() {
725 return scroll_offset_css_;
728 void InProcessViewRenderer::DidOverscroll(
729 gfx::Vector2dF latest_overscroll_delta,
730 gfx::Vector2dF current_fling_velocity) {
731 // TODO(mkosiba): Enable this once flinging is handled entirely Java-side.
732 // DCHECK(current_fling_velocity.IsZero());
733 const float physical_pixel_scale = dip_scale_ * page_scale_factor_;
734 gfx::Vector2dF scaled_overscroll_delta = gfx::ScaleVector2d(
735 latest_overscroll_delta + overscroll_rounding_error_,
736 physical_pixel_scale);
737 gfx::Vector2d rounded_overscroll_delta =
738 gfx::ToRoundedVector2d(scaled_overscroll_delta);
739 overscroll_rounding_error_ =
740 scaled_overscroll_delta - rounded_overscroll_delta;
741 client_->DidOverscroll(rounded_overscroll_delta);
744 void InProcessViewRenderer::EnsureContinuousInvalidation(
745 AwDrawGLInfo* draw_info,
746 bool invalidate_ignore_compositor) {
747 // This method should be called again when any of these conditions change.
748 bool need_invalidate =
749 compositor_needs_continuous_invalidate_ || invalidate_ignore_compositor;
750 bool throttle = is_paused_ || (attached_to_window_ && !window_visible_);
751 if (!need_invalidate || block_invalidates_ || throttle)
752 return;
754 if (draw_info) {
755 draw_info->dirty_left = cached_global_visible_rect_.x();
756 draw_info->dirty_top = cached_global_visible_rect_.y();
757 draw_info->dirty_right = cached_global_visible_rect_.right();
758 draw_info->dirty_bottom = cached_global_visible_rect_.bottom();
759 draw_info->status_mask |= AwDrawGLInfo::kStatusMaskDraw;
760 } else {
761 client_->PostInvalidate();
764 block_invalidates_ = true;
766 // Unretained here is safe because the callback is cancelled when
767 // |fallback_tick_| is destroyed.
768 fallback_tick_.Reset(base::Bind(&InProcessViewRenderer::FallbackTickFired,
769 base::Unretained(this)));
771 // No need to reschedule fallback tick if compositor does not need to be
772 // ticked. This can happen if this is reached because
773 // invalidate_ignore_compositor is true.
774 if (compositor_needs_continuous_invalidate_) {
775 base::MessageLoop::current()->PostDelayedTask(
776 FROM_HERE,
777 fallback_tick_.callback(),
778 base::TimeDelta::FromMilliseconds(
779 kFallbackTickTimeoutInMilliseconds));
783 void InProcessViewRenderer::FallbackTickFired() {
784 TRACE_EVENT1("android_webview",
785 "InProcessViewRenderer::FallbackTickFired",
786 "compositor_needs_continuous_invalidate_",
787 compositor_needs_continuous_invalidate_);
789 // This should only be called if OnDraw or DrawGL did not come in time, which
790 // means block_invalidates_ must still be true.
791 DCHECK(block_invalidates_);
792 if (compositor_needs_continuous_invalidate_ && compositor_) {
793 SkDevice device(SkBitmap::kARGB_8888_Config, 1, 1);
794 SkCanvas canvas(&device);
795 block_invalidates_ = true;
796 CompositeSW(&canvas);
798 block_invalidates_ = false;
799 EnsureContinuousInvalidation(NULL, false);
802 bool InProcessViewRenderer::CompositeSW(SkCanvas* canvas) {
803 DCHECK(compositor_);
804 return compositor_->DemandDrawSw(canvas);
807 std::string InProcessViewRenderer::ToString(AwDrawGLInfo* draw_info) const {
808 std::string str;
809 base::StringAppendF(&str, "is_paused: %d ", is_paused_);
810 base::StringAppendF(&str, "view_visible: %d ", view_visible_);
811 base::StringAppendF(&str, "window_visible: %d ", window_visible_);
812 base::StringAppendF(&str, "dip_scale: %f ", dip_scale_);
813 base::StringAppendF(&str, "page_scale_factor: %f ", page_scale_factor_);
814 base::StringAppendF(&str,
815 "compositor_needs_continuous_invalidate: %d ",
816 compositor_needs_continuous_invalidate_);
817 base::StringAppendF(&str, "block_invalidates: %d ", block_invalidates_);
818 base::StringAppendF(&str, "view width height: [%d %d] ", width_, height_);
819 base::StringAppendF(&str, "attached_to_window: %d ", attached_to_window_);
820 base::StringAppendF(&str, "hardware_initialized: %d ", hardware_initialized_);
821 base::StringAppendF(&str, "hardware_failed: %d ", hardware_failed_);
822 base::StringAppendF(&str,
823 "global visible rect: %s ",
824 cached_global_visible_rect_.ToString().c_str());
825 base::StringAppendF(&str,
826 "scroll_at_start_of_frame: %s ",
827 scroll_at_start_of_frame_.ToString().c_str());
828 base::StringAppendF(
829 &str, "scroll_offset_css: %s ", scroll_offset_css_.ToString().c_str());
830 base::StringAppendF(&str,
831 "overscroll_rounding_error_: %s ",
832 overscroll_rounding_error_.ToString().c_str());
833 if (draw_info) {
834 base::StringAppendF(&str,
835 "clip left top right bottom: [%d %d %d %d] ",
836 draw_info->clip_left,
837 draw_info->clip_top,
838 draw_info->clip_right,
839 draw_info->clip_bottom);
840 base::StringAppendF(&str,
841 "surface width height: [%d %d] ",
842 draw_info->width,
843 draw_info->height);
844 base::StringAppendF(&str, "is_layer: %d ", draw_info->is_layer);
846 return str;
849 } // namespace android_webview