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/string_number_conversions.h"
21 #include "base/strings/stringprintf.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/web_contents.h"
24 #include "content/public/common/content_switches.h"
25 #include "gpu/command_buffer/service/in_process_command_buffer.h"
26 #include "third_party/skia/include/core/SkBitmap.h"
27 #include "third_party/skia/include/core/SkBitmapDevice.h"
28 #include "third_party/skia/include/core/SkCanvas.h"
29 #include "third_party/skia/include/core/SkGraphics.h"
30 #include "third_party/skia/include/core/SkPicture.h"
31 #include "third_party/skia/include/utils/SkCanvasStateUtils.h"
32 #include "ui/gfx/skia_util.h"
33 #include "ui/gfx/transform.h"
34 #include "ui/gfx/vector2d_conversions.h"
35 #include "ui/gfx/vector2d_f.h"
37 using base::android::AttachCurrentThread;
38 using base::android::JavaRef;
39 using base::android::ScopedJavaLocalRef;
40 using content::BrowserThread;
42 namespace android_webview {
47 const void* kUserDataKey = &kUserDataKey;
49 class UserData : public content::WebContents::Data {
51 UserData(InProcessViewRenderer* ptr) : instance_(ptr) {}
53 instance_->WebContentsGone();
56 static InProcessViewRenderer* GetInstance(content::WebContents* contents) {
59 UserData* data = reinterpret_cast<UserData*>(
60 contents->GetUserData(kUserDataKey));
61 return data ? data->instance_ : NULL;
65 InProcessViewRenderer* instance_;
68 bool RasterizeIntoBitmap(JNIEnv* env,
69 const JavaRef<jobject>& jbitmap,
72 const InProcessViewRenderer::RenderMethod& renderer) {
73 DCHECK(jbitmap.obj());
75 AndroidBitmapInfo bitmap_info;
76 if (AndroidBitmap_getInfo(env, jbitmap.obj(), &bitmap_info) < 0) {
77 LOG(ERROR) << "Error getting java bitmap info.";
82 if (AndroidBitmap_lockPixels(env, jbitmap.obj(), &pixels) < 0) {
83 LOG(ERROR) << "Error locking java bitmap pixels.";
90 bitmap.setConfig(SkBitmap::kARGB_8888_Config,
94 bitmap.setPixels(pixels);
96 SkBitmapDevice device(bitmap);
97 SkCanvas canvas(&device);
98 canvas.translate(-scroll_x, -scroll_y);
99 succeeded = renderer.Run(&canvas);
102 if (AndroidBitmap_unlockPixels(env, jbitmap.obj()) < 0) {
103 LOG(ERROR) << "Error unlocking java bitmap pixels.";
110 bool RenderPictureToCanvas(SkPicture* picture, SkCanvas* canvas) {
111 canvas->drawPicture(*picture);
115 class ScopedPixelAccess {
117 ScopedPixelAccess(JNIEnv* env, jobject java_canvas) {
118 AwDrawSWFunctionTable* sw_functions =
119 BrowserViewRenderer::GetAwDrawSWFunctionTable();
120 pixels_ = sw_functions ?
121 sw_functions->access_pixels(env, java_canvas) : NULL;
123 ~ScopedPixelAccess() {
125 BrowserViewRenderer::GetAwDrawSWFunctionTable()->release_pixels(pixels_);
127 AwPixelInfo* pixels() { return pixels_; }
130 AwPixelInfo* pixels_;
132 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedPixelAccess);
135 bool HardwareEnabled() {
136 static bool g_hw_enabled = !CommandLine::ForCurrentProcess()->HasSwitch(
137 switches::kDisableWebViewGLMode);
141 // Provides software rendering functions from the Android glue layer.
142 // Allows preventing extra copies of data when rendering.
143 AwDrawSWFunctionTable* g_sw_draw_functions = NULL;
145 const int64 kFallbackTickTimeoutInMilliseconds = 20;
148 // Used to calculate memory and resource allocation. Determined experimentally.
149 size_t g_memory_multiplier = 10;
150 size_t g_num_gralloc_limit = 150;
151 const size_t kBytesPerPixel = 4;
152 const size_t kMemoryAllocationStep = 5 * 1024 * 1024;
154 class ScopedAllowGL {
159 static bool IsAllowed() {
160 return BrowserThread::CurrentlyOn(BrowserThread::UI) && allow_gl;
164 static bool allow_gl;
166 DISALLOW_COPY_AND_ASSIGN(ScopedAllowGL);
169 ScopedAllowGL::ScopedAllowGL() {
170 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
175 ScopedAllowGL::~ScopedAllowGL() {
179 bool ScopedAllowGL::allow_gl = false;
181 base::LazyInstance<GLViewRendererManager>::Leaky g_view_renderer_manager;
183 void RequestProcessGLOnUIThread() {
184 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
185 BrowserThread::PostTask(
186 BrowserThread::UI, FROM_HERE, base::Bind(&RequestProcessGLOnUIThread));
190 InProcessViewRenderer* renderer = static_cast<InProcessViewRenderer*>(
191 g_view_renderer_manager.Get().GetMostRecentlyDrawn());
192 if (!renderer || !renderer->RequestProcessGL()) {
193 LOG(ERROR) << "Failed to request GL process. Deadlock likely: "
200 // Called from different threads!
201 static void ScheduleGpuWork() {
202 if (ScopedAllowGL::IsAllowed()) {
203 gpu::InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread();
205 RequestProcessGLOnUIThread();
210 void BrowserViewRenderer::SetAwDrawSWFunctionTable(
211 AwDrawSWFunctionTable* table) {
212 g_sw_draw_functions = table;
213 gpu::InProcessCommandBuffer::SetScheduleCallback(
214 base::Bind(&ScheduleGpuWork));
218 AwDrawSWFunctionTable* BrowserViewRenderer::GetAwDrawSWFunctionTable() {
219 return g_sw_draw_functions;
222 InProcessViewRenderer::InProcessViewRenderer(
223 BrowserViewRenderer::Client* client,
224 JavaHelper* java_helper,
225 content::WebContents* web_contents)
227 java_helper_(java_helper),
228 web_contents_(web_contents),
231 view_visible_(false),
232 window_visible_(false),
233 attached_to_window_(false),
235 page_scale_factor_(1.0),
236 on_new_picture_enable_(false),
237 compositor_needs_continuous_invalidate_(false),
238 block_invalidates_(false),
241 hardware_initialized_(false),
242 hardware_failed_(false),
243 last_egl_context_(NULL),
244 manager_key_(g_view_renderer_manager.Get().NullKey()) {
245 CHECK(web_contents_);
246 web_contents_->SetUserData(kUserDataKey, new UserData(this));
247 content::SynchronousCompositor::SetClientForWebContents(web_contents_, this);
249 // Currently the logic in this class relies on |compositor_| remaining NULL
250 // until the DidInitializeCompositor() call, hence it is not set here.
253 InProcessViewRenderer::~InProcessViewRenderer() {
254 CHECK(web_contents_);
255 content::SynchronousCompositor::SetClientForWebContents(web_contents_, NULL);
256 web_contents_->SetUserData(kUserDataKey, NULL);
257 NoLongerExpectsDrawGL();
258 DCHECK(web_contents_ == NULL); // WebContentsGone should have been called.
261 void InProcessViewRenderer::NoLongerExpectsDrawGL() {
262 GLViewRendererManager& mru = g_view_renderer_manager.Get();
263 if (manager_key_ != mru.NullKey()) {
264 mru.NoLongerExpectsDrawGL(manager_key_);
265 manager_key_ = mru.NullKey();
270 InProcessViewRenderer* InProcessViewRenderer::FromWebContents(
271 content::WebContents* contents) {
272 return UserData::GetInstance(contents);
275 void InProcessViewRenderer::WebContentsGone() {
276 web_contents_ = NULL;
281 void InProcessViewRenderer::CalculateTileMemoryPolicy() {
282 CommandLine* cl = CommandLine::ForCurrentProcess();
283 if (cl->HasSwitch(switches::kTileMemoryMultiplier)) {
284 std::string string_value =
285 cl->GetSwitchValueASCII(switches::kTileMemoryMultiplier);
287 if (base::StringToInt(string_value, &int_value) &&
288 int_value >= 2 && int_value <= 50) {
289 g_memory_multiplier = int_value;
293 if (cl->HasSwitch(switches::kNumGrallocBuffersPerWebview)) {
294 std::string string_value =
295 cl->GetSwitchValueASCII(switches::kNumGrallocBuffersPerWebview);
297 if (base::StringToInt(string_value, &int_value) &&
298 int_value >= 50 && int_value <= 500) {
299 g_num_gralloc_limit = int_value;
303 const char kDefaultTileSize[] = "384";
304 if (!cl->HasSwitch(switches::kDefaultTileWidth))
305 cl->AppendSwitchASCII(switches::kDefaultTileWidth, kDefaultTileSize);
307 if (!cl->HasSwitch(switches::kDefaultTileHeight))
308 cl->AppendSwitchASCII(switches::kDefaultTileHeight, kDefaultTileSize);
311 bool InProcessViewRenderer::RequestProcessGL() {
312 return client_->RequestDrawGL(NULL);
315 void InProcessViewRenderer::TrimMemory(int level) {
316 // Constants from Android ComponentCallbacks2.
318 TRIM_MEMORY_RUNNING_LOW = 10,
319 TRIM_MEMORY_UI_HIDDEN = 20,
320 TRIM_MEMORY_BACKGROUND = 40,
323 // Not urgent enough. TRIM_MEMORY_UI_HIDDEN is treated specially because
324 // it does not indicate memory pressure, but merely that the app is
326 if (level < TRIM_MEMORY_RUNNING_LOW || level == TRIM_MEMORY_UI_HIDDEN)
330 if (!attached_to_window_ || !hardware_initialized_ || !compositor_)
333 // Do not release resources on view we expect to get DrawGL soon.
334 if (level < TRIM_MEMORY_BACKGROUND) {
335 client_->UpdateGlobalVisibleRect();
336 if (view_visible_ && window_visible_ &&
337 !cached_global_visible_rect_.IsEmpty()) {
342 if (!eglGetCurrentContext()) {
347 // Just set the memory limit to 0 and drop all tiles. This will be reset to
348 // normal levels in the next DrawGL call.
349 content::SynchronousCompositorMemoryPolicy policy;
350 policy.bytes_limit = 0;
351 policy.num_resources_limit = 0;
352 if (memory_policy_ == policy)
355 TRACE_EVENT0("android_webview", "InProcessViewRenderer::TrimMemory");
356 ScopedAppGLStateRestore state_restore(
357 ScopedAppGLStateRestore::MODE_RESOURCE_MANAGEMENT);
358 gpu::InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread();
359 ScopedAllowGL allow_gl;
361 SetMemoryPolicy(policy);
362 ForceFakeCompositeSW();
365 void InProcessViewRenderer::SetMemoryPolicy(
366 content::SynchronousCompositorMemoryPolicy& new_policy) {
367 if (memory_policy_ == new_policy)
370 memory_policy_ = new_policy;
371 compositor_->SetMemoryPolicy(memory_policy_);
374 void InProcessViewRenderer::UpdateCachedGlobalVisibleRect() {
375 client_->UpdateGlobalVisibleRect();
378 bool InProcessViewRenderer::OnDraw(jobject java_canvas,
379 bool is_hardware_canvas,
380 const gfx::Vector2d& scroll,
381 const gfx::Rect& clip) {
382 scroll_at_start_of_frame_ = scroll;
383 if (is_hardware_canvas && attached_to_window_ && HardwareEnabled()) {
384 // We should be performing a hardware draw here. If we don't have the
385 // comositor yet or if RequestDrawGL fails, it means we failed this draw and
386 // thus return false here to clear to background color for this draw.
387 return compositor_ && client_->RequestDrawGL(java_canvas);
389 // Perform a software draw
390 return DrawSWInternal(java_canvas, clip);
393 bool InProcessViewRenderer::InitializeHwDraw() {
394 TRACE_EVENT0("android_webview", "InitializeHwDraw");
395 DCHECK(!gl_surface_);
396 gl_surface_ = new AwGLSurface;
397 hardware_failed_ = !compositor_->InitializeHwDraw(gl_surface_);
398 hardware_initialized_ = true;
400 if (hardware_failed_)
403 return !hardware_failed_;
406 void InProcessViewRenderer::DrawGL(AwDrawGLInfo* draw_info) {
407 TRACE_EVENT0("android_webview", "InProcessViewRenderer::DrawGL");
409 manager_key_ = g_view_renderer_manager.Get().DidDrawGL(manager_key_, this);
411 // We need to watch if the current Android context has changed and enforce
412 // a clean-up in the compositor.
413 EGLContext current_context = eglGetCurrentContext();
414 if (!current_context) {
415 TRACE_EVENT_INSTANT0(
416 "android_webview", "EarlyOut_NullEGLContext", TRACE_EVENT_SCOPE_THREAD);
420 ScopedAppGLStateRestore state_restore(ScopedAppGLStateRestore::MODE_DRAW);
421 gpu::InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread();
422 ScopedAllowGL allow_gl;
424 if (!attached_to_window_) {
425 TRACE_EVENT_INSTANT0(
426 "android_webview", "EarlyOut_NotAttached", TRACE_EVENT_SCOPE_THREAD);
430 if (draw_info->mode == AwDrawGLInfo::kModeProcess) {
431 TRACE_EVENT_INSTANT0(
432 "android_webview", "EarlyOut_ModeProcess", TRACE_EVENT_SCOPE_THREAD);
436 if (compositor_ && !hardware_initialized_) {
437 if (InitializeHwDraw()) {
438 last_egl_context_ = current_context;
440 TRACE_EVENT_INSTANT0(
441 "android_webview", "EarlyOut_HwInitFail", TRACE_EVENT_SCOPE_THREAD);
442 LOG(ERROR) << "WebView hardware initialization failed";
447 UpdateCachedGlobalVisibleRect();
448 if (cached_global_visible_rect_.IsEmpty()) {
449 TRACE_EVENT_INSTANT0("android_webview",
450 "EarlyOut_EmptyVisibleRect",
451 TRACE_EVENT_SCOPE_THREAD);
455 if (last_egl_context_ != current_context) {
456 // TODO(boliu): Handle context lost
457 TRACE_EVENT_INSTANT0(
458 "android_webview", "EGLContextChanged", TRACE_EVENT_SCOPE_THREAD);
462 TRACE_EVENT_INSTANT0(
463 "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD);
467 // DrawGL may be called without OnDraw, so cancel |fallback_tick_| here as
468 // well just to be safe.
469 fallback_tick_.Cancel();
471 // Update memory budget. This will no-op in compositor if the policy has not
472 // changed since last draw.
473 content::SynchronousCompositorMemoryPolicy policy;
474 policy.bytes_limit = g_memory_multiplier * kBytesPerPixel *
475 cached_global_visible_rect_.width() *
476 cached_global_visible_rect_.height();
477 // Round up to a multiple of kMemoryAllocationStep.
479 (policy.bytes_limit / kMemoryAllocationStep + 1) * kMemoryAllocationStep;
480 policy.num_resources_limit = g_num_gralloc_limit;
481 SetMemoryPolicy(policy);
484 gl_surface_->SetBackingFrameBufferObject(
485 state_restore.framebuffer_binding_ext());
487 gfx::Transform transform;
488 transform.matrix().setColMajorf(draw_info->transform);
489 transform.Translate(scroll_at_start_of_frame_.x(),
490 scroll_at_start_of_frame_.y());
491 gfx::Rect clip_rect(draw_info->clip_left,
493 draw_info->clip_right - draw_info->clip_left,
494 draw_info->clip_bottom - draw_info->clip_top);
496 // Assume we always draw the full visible rect if we are drawing into a layer.
497 bool drew_full_visible_rect = true;
499 gfx::Rect viewport_rect;
500 if (!draw_info->is_layer) {
501 viewport_rect = cached_global_visible_rect_;
502 clip_rect.Intersect(viewport_rect);
503 drew_full_visible_rect = clip_rect.Contains(viewport_rect);
505 viewport_rect = clip_rect;
508 block_invalidates_ = true;
509 // TODO(joth): Check return value.
510 compositor_->DemandDrawHw(gfx::Size(draw_info->width, draw_info->height),
514 state_restore.stencil_enabled());
515 block_invalidates_ = false;
516 gl_surface_->ResetBackingFrameBufferObject();
518 EnsureContinuousInvalidation(draw_info, !drew_full_visible_rect);
521 void InProcessViewRenderer::SetGlobalVisibleRect(
522 const gfx::Rect& visible_rect) {
523 cached_global_visible_rect_ = visible_rect;
526 bool InProcessViewRenderer::DrawSWInternal(jobject java_canvas,
527 const gfx::Rect& clip) {
528 if (clip.IsEmpty()) {
529 TRACE_EVENT_INSTANT0(
530 "android_webview", "EarlyOut_EmptyClip", TRACE_EVENT_SCOPE_THREAD);
535 TRACE_EVENT_INSTANT0(
536 "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD);
540 return RenderViaAuxilaryBitmapIfNeeded(
543 scroll_at_start_of_frame_,
545 base::Bind(&InProcessViewRenderer::CompositeSW,
546 base::Unretained(this)),
551 bool InProcessViewRenderer::RenderViaAuxilaryBitmapIfNeeded(
553 BrowserViewRenderer::JavaHelper* java_helper,
554 const gfx::Vector2d& scroll_correction,
555 const gfx::Rect& clip,
556 InProcessViewRenderer::RenderMethod render_source,
558 TRACE_EVENT0("android_webview",
559 "InProcessViewRenderer::RenderViaAuxilaryBitmapIfNeeded");
561 JNIEnv* env = AttachCurrentThread();
562 ScopedPixelAccess auto_release_pixels(env, java_canvas);
563 AwPixelInfo* pixels = auto_release_pixels.pixels();
564 if (pixels && pixels->state) {
565 skia::RefPtr<SkCanvas> canvas = skia::AdoptRef(
566 SkCanvasStateUtils::CreateFromCanvasState(pixels->state));
568 // Workarounds for http://crbug.com/271096: SW draw only supports
569 // translate & scale transforms, and a simple rectangular clip.
570 if (canvas && (!canvas->getTotalClip().isRect() ||
571 (canvas->getTotalMatrix().getType() &
572 ~(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)))) {
576 canvas->translate(scroll_correction.x(), scroll_correction.y());
577 return render_source.Run(canvas.get());
581 // Render into an auxiliary bitmap if pixel info is not available.
582 ScopedJavaLocalRef<jobject> jcanvas(env, java_canvas);
583 TRACE_EVENT0("android_webview", "RenderToAuxBitmap");
584 ScopedJavaLocalRef<jobject> jbitmap(java_helper->CreateBitmap(
585 env, clip.width(), clip.height(), jcanvas, owner_key));
586 if (!jbitmap.obj()) {
587 TRACE_EVENT_INSTANT0("android_webview",
588 "EarlyOut_BitmapAllocFail",
589 TRACE_EVENT_SCOPE_THREAD);
593 if (!RasterizeIntoBitmap(env, jbitmap,
594 clip.x() - scroll_correction.x(),
595 clip.y() - scroll_correction.y(),
597 TRACE_EVENT_INSTANT0("android_webview",
598 "EarlyOut_RasterizeFail",
599 TRACE_EVENT_SCOPE_THREAD);
603 java_helper->DrawBitmapIntoCanvas(env, jbitmap, jcanvas,
608 skia::RefPtr<SkPicture> InProcessViewRenderer::CapturePicture(int width,
610 TRACE_EVENT0("android_webview", "InProcessViewRenderer::CapturePicture");
612 // Return empty Picture objects for empty SkPictures.
613 skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture);
614 if (width <= 0 || height <= 0) {
618 // Reset scroll back to the origin, will go back to the old
619 // value when scroll_reset is out of scope.
620 base::AutoReset<gfx::Vector2dF> scroll_reset(&scroll_offset_dip_,
623 SkCanvas* rec_canvas = picture->beginRecording(width, height, 0);
625 CompositeSW(rec_canvas);
626 picture->endRecording();
630 void InProcessViewRenderer::EnableOnNewPicture(bool enabled) {
631 on_new_picture_enable_ = enabled;
632 EnsureContinuousInvalidation(NULL, false);
635 void InProcessViewRenderer::SetIsPaused(bool paused) {
636 TRACE_EVENT_INSTANT1("android_webview",
637 "InProcessViewRenderer::SetIsPaused",
638 TRACE_EVENT_SCOPE_THREAD,
642 EnsureContinuousInvalidation(NULL, false);
645 void InProcessViewRenderer::SetViewVisibility(bool view_visible) {
646 TRACE_EVENT_INSTANT1("android_webview",
647 "InProcessViewRenderer::SetViewVisibility",
648 TRACE_EVENT_SCOPE_THREAD,
651 view_visible_ = view_visible;
654 void InProcessViewRenderer::SetWindowVisibility(bool window_visible) {
655 TRACE_EVENT_INSTANT1("android_webview",
656 "InProcessViewRenderer::SetWindowVisibility",
657 TRACE_EVENT_SCOPE_THREAD,
660 window_visible_ = window_visible;
661 EnsureContinuousInvalidation(NULL, false);
664 void InProcessViewRenderer::OnSizeChanged(int width, int height) {
665 TRACE_EVENT_INSTANT2("android_webview",
666 "InProcessViewRenderer::OnSizeChanged",
667 TRACE_EVENT_SCOPE_THREAD,
676 void InProcessViewRenderer::OnAttachedToWindow(int width, int height) {
677 TRACE_EVENT2("android_webview",
678 "InProcessViewRenderer::OnAttachedToWindow",
683 attached_to_window_ = true;
688 void InProcessViewRenderer::OnDetachedFromWindow() {
689 TRACE_EVENT0("android_webview",
690 "InProcessViewRenderer::OnDetachedFromWindow");
692 NoLongerExpectsDrawGL();
693 if (hardware_initialized_) {
696 ScopedAppGLStateRestore state_restore(
697 ScopedAppGLStateRestore::MODE_RESOURCE_MANAGEMENT);
698 gpu::InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread();
699 ScopedAllowGL allow_gl;
700 compositor_->ReleaseHwDraw();
701 hardware_initialized_ = false;
705 attached_to_window_ = false;
708 bool InProcessViewRenderer::IsAttachedToWindow() {
709 return attached_to_window_;
712 bool InProcessViewRenderer::IsVisible() {
713 // Ignore |window_visible_| if |attached_to_window_| is false.
714 return view_visible_ && (!attached_to_window_ || window_visible_);
717 gfx::Rect InProcessViewRenderer::GetScreenRect() {
718 return gfx::Rect(client_->GetLocationOnScreen(), gfx::Size(width_, height_));
721 void InProcessViewRenderer::DidInitializeCompositor(
722 content::SynchronousCompositor* compositor) {
723 TRACE_EVENT0("android_webview",
724 "InProcessViewRenderer::DidInitializeCompositor");
725 DCHECK(compositor && compositor_ == NULL);
726 compositor_ = compositor;
727 hardware_initialized_ = false;
728 hardware_failed_ = false;
731 void InProcessViewRenderer::DidDestroyCompositor(
732 content::SynchronousCompositor* compositor) {
733 TRACE_EVENT0("android_webview",
734 "InProcessViewRenderer::DidDestroyCompositor");
735 DCHECK(compositor_ == compositor);
737 // This can fail if Apps call destroy while the webview is still attached
738 // to the view tree. This is an illegal operation that will lead to leaks.
739 // Log for now. Consider a proper fix if this becomes a problem.
740 LOG_IF(ERROR, hardware_initialized_)
741 << "Destroy called before OnDetachedFromWindow. May Leak GL resources";
745 void InProcessViewRenderer::SetContinuousInvalidate(bool invalidate) {
746 if (compositor_needs_continuous_invalidate_ == invalidate)
749 TRACE_EVENT_INSTANT1("android_webview",
750 "InProcessViewRenderer::SetContinuousInvalidate",
751 TRACE_EVENT_SCOPE_THREAD,
754 compositor_needs_continuous_invalidate_ = invalidate;
755 EnsureContinuousInvalidation(NULL, false);
758 void InProcessViewRenderer::SetDipScale(float dip_scale) {
759 dip_scale_ = dip_scale;
760 CHECK(dip_scale_ > 0);
763 gfx::Vector2d InProcessViewRenderer::max_scroll_offset() const {
764 DCHECK_GT(dip_scale_, 0);
765 return gfx::ToCeiledVector2d(gfx::ScaleVector2d(
766 max_scroll_offset_dip_, dip_scale_ * page_scale_factor_));
769 void InProcessViewRenderer::ScrollTo(gfx::Vector2d scroll_offset) {
770 gfx::Vector2d max_offset = max_scroll_offset();
771 gfx::Vector2dF scroll_offset_dip;
772 // To preserve the invariant that scrolling to the maximum physical pixel
773 // value also scrolls to the maximum dip pixel value we transform the physical
774 // offset into the dip offset by using a proportion (instead of dividing by
775 // dip_scale * page_scale_factor).
776 if (max_offset.x()) {
777 scroll_offset_dip.set_x((scroll_offset.x() * max_scroll_offset_dip_.x()) /
780 if (max_offset.y()) {
781 scroll_offset_dip.set_y((scroll_offset.y() * max_scroll_offset_dip_.y()) /
785 DCHECK_LE(0, scroll_offset_dip.x());
786 DCHECK_LE(0, scroll_offset_dip.y());
787 DCHECK_LE(scroll_offset_dip.x(), max_scroll_offset_dip_.x());
788 DCHECK_LE(scroll_offset_dip.y(), max_scroll_offset_dip_.y());
790 if (scroll_offset_dip_ == scroll_offset_dip)
793 scroll_offset_dip_ = scroll_offset_dip;
796 compositor_->DidChangeRootLayerScrollOffset();
799 void InProcessViewRenderer::DidUpdateContent() {
800 if (on_new_picture_enable_)
801 client_->OnNewPicture();
804 void InProcessViewRenderer::SetMaxRootLayerScrollOffset(
805 gfx::Vector2dF new_value_dip) {
806 DCHECK_GT(dip_scale_, 0);
808 max_scroll_offset_dip_ = new_value_dip;
809 DCHECK_LE(0, max_scroll_offset_dip_.x());
810 DCHECK_LE(0, max_scroll_offset_dip_.y());
812 client_->SetMaxContainerViewScrollOffset(max_scroll_offset());
815 void InProcessViewRenderer::SetTotalRootLayerScrollOffset(
816 gfx::Vector2dF scroll_offset_dip) {
817 // TOOD(mkosiba): Add a DCHECK to say that this does _not_ get called during
818 // DrawGl when http://crbug.com/249972 is fixed.
819 if (scroll_offset_dip_ == scroll_offset_dip)
822 scroll_offset_dip_ = scroll_offset_dip;
824 gfx::Vector2d max_offset = max_scroll_offset();
825 gfx::Vector2d scroll_offset;
826 // For an explanation as to why this is done this way see the comment in
827 // InProcessViewRenderer::ScrollTo.
828 if (max_scroll_offset_dip_.x()) {
829 scroll_offset.set_x((scroll_offset_dip.x() * max_offset.x()) /
830 max_scroll_offset_dip_.x());
833 if (max_scroll_offset_dip_.y()) {
834 scroll_offset.set_y((scroll_offset_dip.y() * max_offset.y()) /
835 max_scroll_offset_dip_.y());
838 DCHECK(0 <= scroll_offset.x());
839 DCHECK(0 <= scroll_offset.y());
840 DCHECK(scroll_offset.x() <= max_offset.x());
841 DCHECK(scroll_offset.y() <= max_offset.y());
843 client_->ScrollContainerViewTo(scroll_offset);
846 gfx::Vector2dF InProcessViewRenderer::GetTotalRootLayerScrollOffset() {
847 return scroll_offset_dip_;
850 bool InProcessViewRenderer::IsExternalFlingActive() const {
851 return client_->IsFlingActive();
854 void InProcessViewRenderer::SetRootLayerPageScaleFactor(
855 float page_scale_factor) {
856 page_scale_factor_ = page_scale_factor;
857 DCHECK_GT(page_scale_factor_, 0);
858 client_->SetPageScaleFactor(page_scale_factor);
861 void InProcessViewRenderer::SetRootLayerScrollableSize(
862 gfx::SizeF scrollable_size) {
863 client_->SetContentsSize(scrollable_size);
866 void InProcessViewRenderer::DidOverscroll(
867 gfx::Vector2dF accumulated_overscroll,
868 gfx::Vector2dF latest_overscroll_delta,
869 gfx::Vector2dF current_fling_velocity) {
870 DCHECK(current_fling_velocity.IsZero());
871 const float physical_pixel_scale = dip_scale_ * page_scale_factor_;
872 if (accumulated_overscroll == latest_overscroll_delta)
873 overscroll_rounding_error_ = gfx::Vector2dF();
874 gfx::Vector2dF scaled_overscroll_delta =
875 gfx::ScaleVector2d(latest_overscroll_delta, physical_pixel_scale);
876 gfx::Vector2d rounded_overscroll_delta = gfx::ToRoundedVector2d(
877 scaled_overscroll_delta + overscroll_rounding_error_);
878 overscroll_rounding_error_ =
879 scaled_overscroll_delta - rounded_overscroll_delta;
880 client_->DidOverscroll(rounded_overscroll_delta);
883 void InProcessViewRenderer::EnsureContinuousInvalidation(
884 AwDrawGLInfo* draw_info,
885 bool invalidate_ignore_compositor) {
886 // This method should be called again when any of these conditions change.
887 bool need_invalidate =
888 compositor_needs_continuous_invalidate_ || invalidate_ignore_compositor;
889 bool throttle = (is_paused_ && !on_new_picture_enable_) ||
890 (attached_to_window_ && !window_visible_);
891 if (!need_invalidate || block_invalidates_ || throttle)
895 draw_info->dirty_left = cached_global_visible_rect_.x();
896 draw_info->dirty_top = cached_global_visible_rect_.y();
897 draw_info->dirty_right = cached_global_visible_rect_.right();
898 draw_info->dirty_bottom = cached_global_visible_rect_.bottom();
899 draw_info->status_mask |= AwDrawGLInfo::kStatusMaskDraw;
901 client_->PostInvalidate();
904 block_invalidates_ = compositor_needs_continuous_invalidate_;
906 // Unretained here is safe because the callback is cancelled when
907 // |fallback_tick_| is destroyed.
908 fallback_tick_.Reset(base::Bind(&InProcessViewRenderer::FallbackTickFired,
909 base::Unretained(this)));
911 // No need to reschedule fallback tick if compositor does not need to be
912 // ticked. This can happen if this is reached because
913 // invalidate_ignore_compositor is true.
914 if (compositor_needs_continuous_invalidate_) {
915 BrowserThread::PostDelayedTask(
918 fallback_tick_.callback(),
919 base::TimeDelta::FromMilliseconds(
920 kFallbackTickTimeoutInMilliseconds));
924 void InProcessViewRenderer::FallbackTickFired() {
925 TRACE_EVENT1("android_webview",
926 "InProcessViewRenderer::FallbackTickFired",
927 "compositor_needs_continuous_invalidate_",
928 compositor_needs_continuous_invalidate_);
930 // This should only be called if OnDraw or DrawGL did not come in time, which
931 // means block_invalidates_ must still be true.
932 DCHECK(block_invalidates_);
933 if (compositor_needs_continuous_invalidate_ && compositor_)
934 ForceFakeCompositeSW();
937 void InProcessViewRenderer::ForceFakeCompositeSW() {
939 SkBitmapDevice device(SkBitmap::kARGB_8888_Config, 1, 1);
940 SkCanvas canvas(&device);
941 CompositeSW(&canvas);
944 bool InProcessViewRenderer::CompositeSW(SkCanvas* canvas) {
947 fallback_tick_.Cancel();
948 block_invalidates_ = true;
949 bool result = compositor_->DemandDrawSw(canvas);
950 block_invalidates_ = false;
951 EnsureContinuousInvalidation(NULL, false);
955 std::string InProcessViewRenderer::ToString(AwDrawGLInfo* draw_info) const {
957 base::StringAppendF(&str, "is_paused: %d ", is_paused_);
958 base::StringAppendF(&str, "view_visible: %d ", view_visible_);
959 base::StringAppendF(&str, "window_visible: %d ", window_visible_);
960 base::StringAppendF(&str, "dip_scale: %f ", dip_scale_);
961 base::StringAppendF(&str, "page_scale_factor: %f ", page_scale_factor_);
962 base::StringAppendF(&str,
963 "compositor_needs_continuous_invalidate: %d ",
964 compositor_needs_continuous_invalidate_);
965 base::StringAppendF(&str, "block_invalidates: %d ", block_invalidates_);
966 base::StringAppendF(&str, "view width height: [%d %d] ", width_, height_);
967 base::StringAppendF(&str, "attached_to_window: %d ", attached_to_window_);
968 base::StringAppendF(&str, "hardware_initialized: %d ", hardware_initialized_);
969 base::StringAppendF(&str, "hardware_failed: %d ", hardware_failed_);
970 base::StringAppendF(&str,
971 "global visible rect: %s ",
972 cached_global_visible_rect_.ToString().c_str());
973 base::StringAppendF(&str,
974 "scroll_at_start_of_frame: %s ",
975 scroll_at_start_of_frame_.ToString().c_str());
977 &str, "scroll_offset_dip: %s ", scroll_offset_dip_.ToString().c_str());
978 base::StringAppendF(&str,
979 "overscroll_rounding_error_: %s ",
980 overscroll_rounding_error_.ToString().c_str());
982 &str, "on_new_picture_enable: %d ", on_new_picture_enable_);
984 base::StringAppendF(&str,
985 "clip left top right bottom: [%d %d %d %d] ",
986 draw_info->clip_left,
988 draw_info->clip_right,
989 draw_info->clip_bottom);
990 base::StringAppendF(&str,
991 "surface width height: [%d %d] ",
994 base::StringAppendF(&str, "is_layer: %d ", draw_info->is_layer);
999 } // namespace android_webview