Dirty rects always contain full tiles with delegated rendering.
[chromium-blink-merge.git] / android_webview / browser / in_process_view_renderer.cc
blob4496f2b1b310adcc6809a69d31702044a6e8ebbc
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 {
44 namespace {
47 const void* kUserDataKey = &kUserDataKey;
49 class UserData : public content::WebContents::Data {
50 public:
51 UserData(InProcessViewRenderer* ptr) : instance_(ptr) {}
52 virtual ~UserData() {
53 instance_->WebContentsGone();
56 static InProcessViewRenderer* GetInstance(content::WebContents* contents) {
57 if (!contents)
58 return NULL;
59 UserData* data = reinterpret_cast<UserData*>(
60 contents->GetUserData(kUserDataKey));
61 return data ? data->instance_ : NULL;
64 private:
65 InProcessViewRenderer* instance_;
68 bool RasterizeIntoBitmap(JNIEnv* env,
69 const JavaRef<jobject>& jbitmap,
70 int scroll_x,
71 int scroll_y,
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.";
78 return false;
81 void* pixels = NULL;
82 if (AndroidBitmap_lockPixels(env, jbitmap.obj(), &pixels) < 0) {
83 LOG(ERROR) << "Error locking java bitmap pixels.";
84 return false;
87 bool succeeded;
89 SkBitmap bitmap;
90 bitmap.setConfig(SkBitmap::kARGB_8888_Config,
91 bitmap_info.width,
92 bitmap_info.height,
93 bitmap_info.stride);
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.";
104 return false;
107 return succeeded;
110 class ScopedPixelAccess {
111 public:
112 ScopedPixelAccess(JNIEnv* env, jobject java_canvas) {
113 AwDrawSWFunctionTable* sw_functions =
114 BrowserViewRenderer::GetAwDrawSWFunctionTable();
115 pixels_ = sw_functions ?
116 sw_functions->access_pixels(env, java_canvas) : NULL;
118 ~ScopedPixelAccess() {
119 if (pixels_)
120 BrowserViewRenderer::GetAwDrawSWFunctionTable()->release_pixels(pixels_);
122 AwPixelInfo* pixels() { return pixels_; }
124 private:
125 AwPixelInfo* pixels_;
127 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedPixelAccess);
130 bool HardwareEnabled() {
131 static bool g_hw_enabled = !CommandLine::ForCurrentProcess()->HasSwitch(
132 switches::kDisableWebViewGLMode);
133 return g_hw_enabled;
136 // Provides software rendering functions from the Android glue layer.
137 // Allows preventing extra copies of data when rendering.
138 AwDrawSWFunctionTable* g_sw_draw_functions = NULL;
140 const int64 kFallbackTickTimeoutInMilliseconds = 20;
143 // Used to calculate memory and resource allocation. Determined experimentally.
144 size_t g_memory_multiplier = 10;
145 size_t g_num_gralloc_limit = 150;
146 const size_t kBytesPerPixel = 4;
147 const size_t kMemoryAllocationStep = 5 * 1024 * 1024;
149 class ScopedAllowGL {
150 public:
151 ScopedAllowGL();
152 ~ScopedAllowGL();
154 static bool IsAllowed() {
155 return BrowserThread::CurrentlyOn(BrowserThread::UI) && allow_gl;
158 private:
159 static bool allow_gl;
161 DISALLOW_COPY_AND_ASSIGN(ScopedAllowGL);
164 ScopedAllowGL::ScopedAllowGL() {
165 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
166 DCHECK(!allow_gl);
167 allow_gl = true;
170 ScopedAllowGL::~ScopedAllowGL() {
171 allow_gl = false;
174 bool ScopedAllowGL::allow_gl = false;
176 base::LazyInstance<GLViewRendererManager>::Leaky g_view_renderer_manager;
178 void RequestProcessGLOnUIThread() {
179 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
180 BrowserThread::PostTask(
181 BrowserThread::UI, FROM_HERE, base::Bind(&RequestProcessGLOnUIThread));
182 return;
185 InProcessViewRenderer* renderer = static_cast<InProcessViewRenderer*>(
186 g_view_renderer_manager.Get().GetMostRecentlyDrawn());
187 if (!renderer || !renderer->RequestProcessGL()) {
188 LOG(ERROR) << "Failed to request GL process. Deadlock likely: "
189 << !!renderer;
193 } // namespace
195 // Called from different threads!
196 static void ScheduleGpuWork() {
197 if (ScopedAllowGL::IsAllowed()) {
198 gpu::InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread();
199 } else {
200 RequestProcessGLOnUIThread();
204 // static
205 void BrowserViewRenderer::SetAwDrawSWFunctionTable(
206 AwDrawSWFunctionTable* table) {
207 g_sw_draw_functions = table;
208 gpu::InProcessCommandBuffer::SetScheduleCallback(
209 base::Bind(&ScheduleGpuWork));
212 // static
213 AwDrawSWFunctionTable* BrowserViewRenderer::GetAwDrawSWFunctionTable() {
214 return g_sw_draw_functions;
217 InProcessViewRenderer::InProcessViewRenderer(
218 BrowserViewRenderer::Client* client,
219 JavaHelper* java_helper,
220 content::WebContents* web_contents)
221 : client_(client),
222 java_helper_(java_helper),
223 web_contents_(web_contents),
224 compositor_(NULL),
225 is_paused_(false),
226 view_visible_(false),
227 window_visible_(false),
228 attached_to_window_(false),
229 dip_scale_(0.0),
230 page_scale_factor_(1.0),
231 on_new_picture_enable_(false),
232 compositor_needs_continuous_invalidate_(false),
233 block_invalidates_(false),
234 width_(0),
235 height_(0),
236 hardware_initialized_(false),
237 hardware_failed_(false),
238 last_egl_context_(NULL),
239 manager_key_(g_view_renderer_manager.Get().NullKey()) {
240 CHECK(web_contents_);
241 web_contents_->SetUserData(kUserDataKey, new UserData(this));
242 content::SynchronousCompositor::SetClientForWebContents(web_contents_, this);
244 // Currently the logic in this class relies on |compositor_| remaining NULL
245 // until the DidInitializeCompositor() call, hence it is not set here.
248 InProcessViewRenderer::~InProcessViewRenderer() {
249 CHECK(web_contents_);
250 content::SynchronousCompositor::SetClientForWebContents(web_contents_, NULL);
251 web_contents_->SetUserData(kUserDataKey, NULL);
252 NoLongerExpectsDrawGL();
253 DCHECK(web_contents_ == NULL); // WebContentsGone should have been called.
256 void InProcessViewRenderer::NoLongerExpectsDrawGL() {
257 GLViewRendererManager& mru = g_view_renderer_manager.Get();
258 if (manager_key_ != mru.NullKey()) {
259 mru.NoLongerExpectsDrawGL(manager_key_);
260 manager_key_ = mru.NullKey();
264 // static
265 InProcessViewRenderer* InProcessViewRenderer::FromWebContents(
266 content::WebContents* contents) {
267 return UserData::GetInstance(contents);
270 void InProcessViewRenderer::WebContentsGone() {
271 web_contents_ = NULL;
272 compositor_ = NULL;
275 // static
276 void InProcessViewRenderer::CalculateTileMemoryPolicy() {
277 CommandLine* cl = CommandLine::ForCurrentProcess();
278 if (cl->HasSwitch(switches::kTileMemoryMultiplier)) {
279 std::string string_value =
280 cl->GetSwitchValueASCII(switches::kTileMemoryMultiplier);
281 int int_value = 0;
282 if (base::StringToInt(string_value, &int_value) &&
283 int_value >= 2 && int_value <= 50) {
284 g_memory_multiplier = int_value;
288 if (cl->HasSwitch(switches::kNumGrallocBuffersPerWebview)) {
289 std::string string_value =
290 cl->GetSwitchValueASCII(switches::kNumGrallocBuffersPerWebview);
291 int int_value = 0;
292 if (base::StringToInt(string_value, &int_value) &&
293 int_value >= 50 && int_value <= 500) {
294 g_num_gralloc_limit = int_value;
298 const char kDefaultTileSize[] = "384";
299 if (!cl->HasSwitch(switches::kDefaultTileWidth))
300 cl->AppendSwitchASCII(switches::kDefaultTileWidth, kDefaultTileSize);
302 if (!cl->HasSwitch(switches::kDefaultTileHeight))
303 cl->AppendSwitchASCII(switches::kDefaultTileHeight, kDefaultTileSize);
306 bool InProcessViewRenderer::RequestProcessGL() {
307 return client_->RequestDrawGL(NULL);
310 void InProcessViewRenderer::TrimMemory(int level) {
311 // Constants from Android ComponentCallbacks2.
312 enum {
313 TRIM_MEMORY_RUNNING_LOW = 10,
314 TRIM_MEMORY_UI_HIDDEN = 20,
315 TRIM_MEMORY_BACKGROUND = 40,
318 // Not urgent enough. TRIM_MEMORY_UI_HIDDEN is treated specially because
319 // it does not indicate memory pressure, but merely that the app is
320 // backgrounded.
321 if (level < TRIM_MEMORY_RUNNING_LOW || level == TRIM_MEMORY_UI_HIDDEN)
322 return;
324 // Nothing to drop.
325 if (!attached_to_window_ || !hardware_initialized_ || !compositor_)
326 return;
328 // Do not release resources on view we expect to get DrawGL soon.
329 if (level < TRIM_MEMORY_BACKGROUND) {
330 client_->UpdateGlobalVisibleRect();
331 if (view_visible_ && window_visible_ &&
332 !cached_global_visible_rect_.IsEmpty()) {
333 return;
337 if (!eglGetCurrentContext()) {
338 NOTREACHED();
339 return;
342 // Just set the memory limit to 0 and drop all tiles. This will be reset to
343 // normal levels in the next DrawGL call.
344 content::SynchronousCompositorMemoryPolicy policy;
345 policy.bytes_limit = 0;
346 policy.num_resources_limit = 0;
347 if (memory_policy_ == policy)
348 return;
350 TRACE_EVENT0("android_webview", "InProcessViewRenderer::TrimMemory");
351 ScopedAppGLStateRestore state_restore(
352 ScopedAppGLStateRestore::MODE_RESOURCE_MANAGEMENT);
353 gpu::InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread();
354 ScopedAllowGL allow_gl;
356 SetMemoryPolicy(policy);
357 ForceFakeCompositeSW();
360 void InProcessViewRenderer::SetMemoryPolicy(
361 content::SynchronousCompositorMemoryPolicy& new_policy) {
362 if (memory_policy_ == new_policy)
363 return;
365 memory_policy_ = new_policy;
366 compositor_->SetMemoryPolicy(memory_policy_);
369 void InProcessViewRenderer::UpdateCachedGlobalVisibleRect() {
370 client_->UpdateGlobalVisibleRect();
373 bool InProcessViewRenderer::OnDraw(jobject java_canvas,
374 bool is_hardware_canvas,
375 const gfx::Vector2d& scroll,
376 const gfx::Rect& clip) {
377 scroll_at_start_of_frame_ = scroll;
378 if (is_hardware_canvas && attached_to_window_ && HardwareEnabled()) {
379 // We should be performing a hardware draw here. If we don't have the
380 // comositor yet or if RequestDrawGL fails, it means we failed this draw and
381 // thus return false here to clear to background color for this draw.
382 return compositor_ && client_->RequestDrawGL(java_canvas);
384 // Perform a software draw
385 return DrawSWInternal(java_canvas, clip);
388 bool InProcessViewRenderer::InitializeHwDraw() {
389 TRACE_EVENT0("android_webview", "InitializeHwDraw");
390 DCHECK(!gl_surface_);
391 gl_surface_ = new AwGLSurface;
392 hardware_failed_ = !compositor_->InitializeHwDraw(gl_surface_);
393 hardware_initialized_ = true;
395 if (hardware_failed_)
396 gl_surface_ = NULL;
398 return !hardware_failed_;
401 void InProcessViewRenderer::DrawGL(AwDrawGLInfo* draw_info) {
402 TRACE_EVENT0("android_webview", "InProcessViewRenderer::DrawGL");
404 manager_key_ = g_view_renderer_manager.Get().DidDrawGL(manager_key_, this);
406 // We need to watch if the current Android context has changed and enforce
407 // a clean-up in the compositor.
408 EGLContext current_context = eglGetCurrentContext();
409 if (!current_context) {
410 TRACE_EVENT_INSTANT0(
411 "android_webview", "EarlyOut_NullEGLContext", TRACE_EVENT_SCOPE_THREAD);
412 return;
415 ScopedAppGLStateRestore state_restore(ScopedAppGLStateRestore::MODE_DRAW);
416 gpu::InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread();
417 ScopedAllowGL allow_gl;
419 if (!attached_to_window_) {
420 TRACE_EVENT_INSTANT0(
421 "android_webview", "EarlyOut_NotAttached", TRACE_EVENT_SCOPE_THREAD);
422 return;
425 if (draw_info->mode == AwDrawGLInfo::kModeProcess) {
426 TRACE_EVENT_INSTANT0(
427 "android_webview", "EarlyOut_ModeProcess", TRACE_EVENT_SCOPE_THREAD);
428 return;
431 if (compositor_ && !hardware_initialized_) {
432 if (InitializeHwDraw()) {
433 last_egl_context_ = current_context;
434 } else {
435 TRACE_EVENT_INSTANT0(
436 "android_webview", "EarlyOut_HwInitFail", TRACE_EVENT_SCOPE_THREAD);
437 LOG(ERROR) << "WebView hardware initialization failed";
438 return;
442 UpdateCachedGlobalVisibleRect();
443 if (cached_global_visible_rect_.IsEmpty()) {
444 TRACE_EVENT_INSTANT0("android_webview",
445 "EarlyOut_EmptyVisibleRect",
446 TRACE_EVENT_SCOPE_THREAD);
447 return;
450 if (last_egl_context_ != current_context) {
451 // TODO(boliu): Handle context lost
452 TRACE_EVENT_INSTANT0(
453 "android_webview", "EGLContextChanged", TRACE_EVENT_SCOPE_THREAD);
456 if (!compositor_) {
457 TRACE_EVENT_INSTANT0(
458 "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD);
459 return;
462 // DrawGL may be called without OnDraw, so cancel |fallback_tick_| here as
463 // well just to be safe.
464 fallback_tick_.Cancel();
466 // Update memory budget. This will no-op in compositor if the policy has not
467 // changed since last draw.
468 content::SynchronousCompositorMemoryPolicy policy;
469 policy.bytes_limit = g_memory_multiplier * kBytesPerPixel *
470 cached_global_visible_rect_.width() *
471 cached_global_visible_rect_.height();
472 // Round up to a multiple of kMemoryAllocationStep.
473 policy.bytes_limit =
474 (policy.bytes_limit / kMemoryAllocationStep + 1) * kMemoryAllocationStep;
475 policy.num_resources_limit = g_num_gralloc_limit;
476 SetMemoryPolicy(policy);
478 DCHECK(gl_surface_);
479 gl_surface_->SetBackingFrameBufferObject(
480 state_restore.framebuffer_binding_ext());
482 gfx::Transform transform;
483 transform.matrix().setColMajorf(draw_info->transform);
484 transform.Translate(scroll_at_start_of_frame_.x(),
485 scroll_at_start_of_frame_.y());
486 gfx::Rect clip_rect(draw_info->clip_left,
487 draw_info->clip_top,
488 draw_info->clip_right - draw_info->clip_left,
489 draw_info->clip_bottom - draw_info->clip_top);
491 // Assume we always draw the full visible rect if we are drawing into a layer.
492 bool drew_full_visible_rect = true;
494 gfx::Rect viewport_rect;
495 if (!draw_info->is_layer) {
496 viewport_rect = cached_global_visible_rect_;
497 clip_rect.Intersect(viewport_rect);
498 drew_full_visible_rect = clip_rect.Contains(viewport_rect);
499 } else {
500 viewport_rect = clip_rect;
503 block_invalidates_ = true;
504 // TODO(joth): Check return value.
505 compositor_->DemandDrawHw(gfx::Size(draw_info->width, draw_info->height),
506 transform,
507 viewport_rect,
508 clip_rect,
509 state_restore.stencil_enabled());
510 block_invalidates_ = false;
511 gl_surface_->ResetBackingFrameBufferObject();
513 EnsureContinuousInvalidation(draw_info, !drew_full_visible_rect);
516 void InProcessViewRenderer::SetGlobalVisibleRect(
517 const gfx::Rect& visible_rect) {
518 cached_global_visible_rect_ = visible_rect;
521 bool InProcessViewRenderer::DrawSWInternal(jobject java_canvas,
522 const gfx::Rect& clip) {
523 if (clip.IsEmpty()) {
524 TRACE_EVENT_INSTANT0(
525 "android_webview", "EarlyOut_EmptyClip", TRACE_EVENT_SCOPE_THREAD);
526 return true;
529 if (!compositor_) {
530 TRACE_EVENT_INSTANT0(
531 "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD);
532 return false;
535 return RenderViaAuxilaryBitmapIfNeeded(
536 java_canvas,
537 java_helper_,
538 scroll_at_start_of_frame_,
539 clip,
540 base::Bind(&InProcessViewRenderer::CompositeSW,
541 base::Unretained(this)),
542 web_contents_);
545 // static
546 bool InProcessViewRenderer::RenderViaAuxilaryBitmapIfNeeded(
547 jobject java_canvas,
548 BrowserViewRenderer::JavaHelper* java_helper,
549 const gfx::Vector2d& scroll_correction,
550 const gfx::Rect& clip,
551 InProcessViewRenderer::RenderMethod render_source,
552 void* owner_key) {
553 TRACE_EVENT0("android_webview",
554 "InProcessViewRenderer::RenderViaAuxilaryBitmapIfNeeded");
556 JNIEnv* env = AttachCurrentThread();
557 ScopedPixelAccess auto_release_pixels(env, java_canvas);
558 AwPixelInfo* pixels = auto_release_pixels.pixels();
559 if (pixels && pixels->state) {
560 skia::RefPtr<SkCanvas> canvas = skia::AdoptRef(
561 SkCanvasStateUtils::CreateFromCanvasState(pixels->state));
563 // Workarounds for http://crbug.com/271096: SW draw only supports
564 // translate & scale transforms, and a simple rectangular clip.
565 if (canvas && (!canvas->getTotalClip().isRect() ||
566 (canvas->getTotalMatrix().getType() &
567 ~(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)))) {
568 canvas.clear();
570 if (canvas) {
571 canvas->translate(scroll_correction.x(), scroll_correction.y());
572 return render_source.Run(canvas.get());
576 // Render into an auxiliary bitmap if pixel info is not available.
577 ScopedJavaLocalRef<jobject> jcanvas(env, java_canvas);
578 TRACE_EVENT0("android_webview", "RenderToAuxBitmap");
579 ScopedJavaLocalRef<jobject> jbitmap(java_helper->CreateBitmap(
580 env, clip.width(), clip.height(), jcanvas, owner_key));
581 if (!jbitmap.obj()) {
582 TRACE_EVENT_INSTANT0("android_webview",
583 "EarlyOut_BitmapAllocFail",
584 TRACE_EVENT_SCOPE_THREAD);
585 return false;
588 if (!RasterizeIntoBitmap(env, jbitmap,
589 clip.x() - scroll_correction.x(),
590 clip.y() - scroll_correction.y(),
591 render_source)) {
592 TRACE_EVENT_INSTANT0("android_webview",
593 "EarlyOut_RasterizeFail",
594 TRACE_EVENT_SCOPE_THREAD);
595 return false;
598 java_helper->DrawBitmapIntoCanvas(env, jbitmap, jcanvas,
599 clip.x(), clip.y());
600 return true;
603 skia::RefPtr<SkPicture> InProcessViewRenderer::CapturePicture(int width,
604 int height) {
605 TRACE_EVENT0("android_webview", "InProcessViewRenderer::CapturePicture");
607 // Return empty Picture objects for empty SkPictures.
608 skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture);
609 if (width <= 0 || height <= 0) {
610 return picture;
613 // Reset scroll back to the origin, will go back to the old
614 // value when scroll_reset is out of scope.
615 base::AutoReset<gfx::Vector2dF> scroll_reset(&scroll_offset_dip_,
616 gfx::Vector2d());
618 SkCanvas* rec_canvas = picture->beginRecording(width, height, 0);
619 if (compositor_)
620 CompositeSW(rec_canvas);
621 picture->endRecording();
622 return picture;
625 void InProcessViewRenderer::EnableOnNewPicture(bool enabled) {
626 on_new_picture_enable_ = enabled;
627 EnsureContinuousInvalidation(NULL, false);
630 void InProcessViewRenderer::SetIsPaused(bool paused) {
631 TRACE_EVENT_INSTANT1("android_webview",
632 "InProcessViewRenderer::SetIsPaused",
633 TRACE_EVENT_SCOPE_THREAD,
634 "paused",
635 paused);
636 is_paused_ = paused;
637 EnsureContinuousInvalidation(NULL, false);
640 void InProcessViewRenderer::SetViewVisibility(bool view_visible) {
641 TRACE_EVENT_INSTANT1("android_webview",
642 "InProcessViewRenderer::SetViewVisibility",
643 TRACE_EVENT_SCOPE_THREAD,
644 "view_visible",
645 view_visible);
646 view_visible_ = view_visible;
649 void InProcessViewRenderer::SetWindowVisibility(bool window_visible) {
650 TRACE_EVENT_INSTANT1("android_webview",
651 "InProcessViewRenderer::SetWindowVisibility",
652 TRACE_EVENT_SCOPE_THREAD,
653 "window_visible",
654 window_visible);
655 window_visible_ = window_visible;
656 EnsureContinuousInvalidation(NULL, false);
659 void InProcessViewRenderer::OnSizeChanged(int width, int height) {
660 TRACE_EVENT_INSTANT2("android_webview",
661 "InProcessViewRenderer::OnSizeChanged",
662 TRACE_EVENT_SCOPE_THREAD,
663 "width",
664 width,
665 "height",
666 height);
667 width_ = width;
668 height_ = height;
671 void InProcessViewRenderer::OnAttachedToWindow(int width, int height) {
672 TRACE_EVENT2("android_webview",
673 "InProcessViewRenderer::OnAttachedToWindow",
674 "width",
675 width,
676 "height",
677 height);
678 attached_to_window_ = true;
679 width_ = width;
680 height_ = height;
683 void InProcessViewRenderer::OnDetachedFromWindow() {
684 TRACE_EVENT0("android_webview",
685 "InProcessViewRenderer::OnDetachedFromWindow");
687 NoLongerExpectsDrawGL();
688 if (hardware_initialized_) {
689 DCHECK(compositor_);
691 ScopedAppGLStateRestore state_restore(
692 ScopedAppGLStateRestore::MODE_RESOURCE_MANAGEMENT);
693 gpu::InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread();
694 ScopedAllowGL allow_gl;
695 compositor_->ReleaseHwDraw();
696 hardware_initialized_ = false;
699 gl_surface_ = NULL;
700 attached_to_window_ = false;
703 bool InProcessViewRenderer::IsAttachedToWindow() {
704 return attached_to_window_;
707 bool InProcessViewRenderer::IsVisible() {
708 // Ignore |window_visible_| if |attached_to_window_| is false.
709 return view_visible_ && (!attached_to_window_ || window_visible_);
712 gfx::Rect InProcessViewRenderer::GetScreenRect() {
713 return gfx::Rect(client_->GetLocationOnScreen(), gfx::Size(width_, height_));
716 void InProcessViewRenderer::DidInitializeCompositor(
717 content::SynchronousCompositor* compositor) {
718 TRACE_EVENT0("android_webview",
719 "InProcessViewRenderer::DidInitializeCompositor");
720 DCHECK(compositor && compositor_ == NULL);
721 compositor_ = compositor;
722 hardware_initialized_ = false;
723 hardware_failed_ = false;
726 void InProcessViewRenderer::DidDestroyCompositor(
727 content::SynchronousCompositor* compositor) {
728 TRACE_EVENT0("android_webview",
729 "InProcessViewRenderer::DidDestroyCompositor");
730 DCHECK(compositor_ == compositor);
732 // This can fail if Apps call destroy while the webview is still attached
733 // to the view tree. This is an illegal operation that will lead to leaks.
734 // Log for now. Consider a proper fix if this becomes a problem.
735 LOG_IF(ERROR, hardware_initialized_)
736 << "Destroy called before OnDetachedFromWindow. May Leak GL resources";
737 compositor_ = NULL;
740 void InProcessViewRenderer::SetContinuousInvalidate(bool invalidate) {
741 if (compositor_needs_continuous_invalidate_ == invalidate)
742 return;
744 TRACE_EVENT_INSTANT1("android_webview",
745 "InProcessViewRenderer::SetContinuousInvalidate",
746 TRACE_EVENT_SCOPE_THREAD,
747 "invalidate",
748 invalidate);
749 compositor_needs_continuous_invalidate_ = invalidate;
750 EnsureContinuousInvalidation(NULL, false);
753 void InProcessViewRenderer::SetDipScale(float dip_scale) {
754 dip_scale_ = dip_scale;
755 CHECK(dip_scale_ > 0);
758 gfx::Vector2d InProcessViewRenderer::max_scroll_offset() const {
759 DCHECK_GT(dip_scale_, 0);
760 return gfx::ToCeiledVector2d(gfx::ScaleVector2d(
761 max_scroll_offset_dip_, dip_scale_ * page_scale_factor_));
764 void InProcessViewRenderer::ScrollTo(gfx::Vector2d scroll_offset) {
765 gfx::Vector2d max_offset = max_scroll_offset();
766 gfx::Vector2dF scroll_offset_dip;
767 // To preserve the invariant that scrolling to the maximum physical pixel
768 // value also scrolls to the maximum dip pixel value we transform the physical
769 // offset into the dip offset by using a proportion (instead of dividing by
770 // dip_scale * page_scale_factor).
771 if (max_offset.x()) {
772 scroll_offset_dip.set_x((scroll_offset.x() * max_scroll_offset_dip_.x()) /
773 max_offset.x());
775 if (max_offset.y()) {
776 scroll_offset_dip.set_y((scroll_offset.y() * max_scroll_offset_dip_.y()) /
777 max_offset.y());
780 DCHECK_LE(0, scroll_offset_dip.x());
781 DCHECK_LE(0, scroll_offset_dip.y());
782 DCHECK_LE(scroll_offset_dip.x(), max_scroll_offset_dip_.x());
783 DCHECK_LE(scroll_offset_dip.y(), max_scroll_offset_dip_.y());
785 if (scroll_offset_dip_ == scroll_offset_dip)
786 return;
788 scroll_offset_dip_ = scroll_offset_dip;
790 if (compositor_)
791 compositor_->DidChangeRootLayerScrollOffset();
794 void InProcessViewRenderer::DidUpdateContent() {
795 if (on_new_picture_enable_)
796 client_->OnNewPicture();
799 void InProcessViewRenderer::SetMaxRootLayerScrollOffset(
800 gfx::Vector2dF new_value_dip) {
801 DCHECK_GT(dip_scale_, 0);
803 max_scroll_offset_dip_ = new_value_dip;
804 DCHECK_LE(0, max_scroll_offset_dip_.x());
805 DCHECK_LE(0, max_scroll_offset_dip_.y());
807 client_->SetMaxContainerViewScrollOffset(max_scroll_offset());
810 void InProcessViewRenderer::SetTotalRootLayerScrollOffset(
811 gfx::Vector2dF scroll_offset_dip) {
812 // TOOD(mkosiba): Add a DCHECK to say that this does _not_ get called during
813 // DrawGl when http://crbug.com/249972 is fixed.
814 if (scroll_offset_dip_ == scroll_offset_dip)
815 return;
817 scroll_offset_dip_ = scroll_offset_dip;
819 gfx::Vector2d max_offset = max_scroll_offset();
820 gfx::Vector2d scroll_offset;
821 // For an explanation as to why this is done this way see the comment in
822 // InProcessViewRenderer::ScrollTo.
823 if (max_scroll_offset_dip_.x()) {
824 scroll_offset.set_x((scroll_offset_dip.x() * max_offset.x()) /
825 max_scroll_offset_dip_.x());
828 if (max_scroll_offset_dip_.y()) {
829 scroll_offset.set_y((scroll_offset_dip.y() * max_offset.y()) /
830 max_scroll_offset_dip_.y());
833 DCHECK(0 <= scroll_offset.x());
834 DCHECK(0 <= scroll_offset.y());
835 DCHECK(scroll_offset.x() <= max_offset.x());
836 DCHECK(scroll_offset.y() <= max_offset.y());
838 client_->ScrollContainerViewTo(scroll_offset);
841 gfx::Vector2dF InProcessViewRenderer::GetTotalRootLayerScrollOffset() {
842 return scroll_offset_dip_;
845 bool InProcessViewRenderer::IsExternalFlingActive() const {
846 return client_->IsFlingActive();
849 void InProcessViewRenderer::SetRootLayerPageScaleFactor(
850 float page_scale_factor) {
851 page_scale_factor_ = page_scale_factor;
852 DCHECK_GT(page_scale_factor_, 0);
853 client_->SetPageScaleFactor(page_scale_factor);
856 void InProcessViewRenderer::SetRootLayerScrollableSize(
857 gfx::SizeF scrollable_size) {
858 client_->SetContentsSize(scrollable_size);
861 void InProcessViewRenderer::DidOverscroll(
862 gfx::Vector2dF accumulated_overscroll,
863 gfx::Vector2dF latest_overscroll_delta,
864 gfx::Vector2dF current_fling_velocity) {
865 DCHECK(current_fling_velocity.IsZero());
866 const float physical_pixel_scale = dip_scale_ * page_scale_factor_;
867 if (accumulated_overscroll == latest_overscroll_delta)
868 overscroll_rounding_error_ = gfx::Vector2dF();
869 gfx::Vector2dF scaled_overscroll_delta =
870 gfx::ScaleVector2d(latest_overscroll_delta, physical_pixel_scale);
871 gfx::Vector2d rounded_overscroll_delta = gfx::ToRoundedVector2d(
872 scaled_overscroll_delta + overscroll_rounding_error_);
873 overscroll_rounding_error_ =
874 scaled_overscroll_delta - rounded_overscroll_delta;
875 client_->DidOverscroll(rounded_overscroll_delta);
878 void InProcessViewRenderer::EnsureContinuousInvalidation(
879 AwDrawGLInfo* draw_info,
880 bool invalidate_ignore_compositor) {
881 // This method should be called again when any of these conditions change.
882 bool need_invalidate =
883 compositor_needs_continuous_invalidate_ || invalidate_ignore_compositor;
884 if (!need_invalidate || block_invalidates_)
885 return;
887 if (draw_info) {
888 draw_info->dirty_left = cached_global_visible_rect_.x();
889 draw_info->dirty_top = cached_global_visible_rect_.y();
890 draw_info->dirty_right = cached_global_visible_rect_.right();
891 draw_info->dirty_bottom = cached_global_visible_rect_.bottom();
892 draw_info->status_mask |= AwDrawGLInfo::kStatusMaskDraw;
893 } else {
894 client_->PostInvalidate();
897 bool throttle_fallback_tick = (is_paused_ && !on_new_picture_enable_) ||
898 (attached_to_window_ && !window_visible_);
899 if (throttle_fallback_tick)
900 return;
902 block_invalidates_ = compositor_needs_continuous_invalidate_;
904 // Unretained here is safe because the callback is cancelled when
905 // |fallback_tick_| is destroyed.
906 fallback_tick_.Reset(base::Bind(&InProcessViewRenderer::FallbackTickFired,
907 base::Unretained(this)));
909 // No need to reschedule fallback tick if compositor does not need to be
910 // ticked. This can happen if this is reached because
911 // invalidate_ignore_compositor is true.
912 if (compositor_needs_continuous_invalidate_) {
913 BrowserThread::PostDelayedTask(
914 BrowserThread::UI,
915 FROM_HERE,
916 fallback_tick_.callback(),
917 base::TimeDelta::FromMilliseconds(
918 kFallbackTickTimeoutInMilliseconds));
922 void InProcessViewRenderer::FallbackTickFired() {
923 TRACE_EVENT1("android_webview",
924 "InProcessViewRenderer::FallbackTickFired",
925 "compositor_needs_continuous_invalidate_",
926 compositor_needs_continuous_invalidate_);
928 // This should only be called if OnDraw or DrawGL did not come in time, which
929 // means block_invalidates_ must still be true.
930 DCHECK(block_invalidates_);
931 if (compositor_needs_continuous_invalidate_ && compositor_)
932 ForceFakeCompositeSW();
935 void InProcessViewRenderer::ForceFakeCompositeSW() {
936 DCHECK(compositor_);
937 SkBitmapDevice device(SkBitmap::kARGB_8888_Config, 1, 1);
938 SkCanvas canvas(&device);
939 CompositeSW(&canvas);
942 bool InProcessViewRenderer::CompositeSW(SkCanvas* canvas) {
943 DCHECK(compositor_);
945 fallback_tick_.Cancel();
946 block_invalidates_ = true;
947 bool result = compositor_->DemandDrawSw(canvas);
948 block_invalidates_ = false;
949 EnsureContinuousInvalidation(NULL, false);
950 return result;
953 std::string InProcessViewRenderer::ToString(AwDrawGLInfo* draw_info) const {
954 std::string str;
955 base::StringAppendF(&str, "is_paused: %d ", is_paused_);
956 base::StringAppendF(&str, "view_visible: %d ", view_visible_);
957 base::StringAppendF(&str, "window_visible: %d ", window_visible_);
958 base::StringAppendF(&str, "dip_scale: %f ", dip_scale_);
959 base::StringAppendF(&str, "page_scale_factor: %f ", page_scale_factor_);
960 base::StringAppendF(&str,
961 "compositor_needs_continuous_invalidate: %d ",
962 compositor_needs_continuous_invalidate_);
963 base::StringAppendF(&str, "block_invalidates: %d ", block_invalidates_);
964 base::StringAppendF(&str, "view width height: [%d %d] ", width_, height_);
965 base::StringAppendF(&str, "attached_to_window: %d ", attached_to_window_);
966 base::StringAppendF(&str, "hardware_initialized: %d ", hardware_initialized_);
967 base::StringAppendF(&str, "hardware_failed: %d ", hardware_failed_);
968 base::StringAppendF(&str,
969 "global visible rect: %s ",
970 cached_global_visible_rect_.ToString().c_str());
971 base::StringAppendF(&str,
972 "scroll_at_start_of_frame: %s ",
973 scroll_at_start_of_frame_.ToString().c_str());
974 base::StringAppendF(
975 &str, "scroll_offset_dip: %s ", scroll_offset_dip_.ToString().c_str());
976 base::StringAppendF(&str,
977 "overscroll_rounding_error_: %s ",
978 overscroll_rounding_error_.ToString().c_str());
979 base::StringAppendF(
980 &str, "on_new_picture_enable: %d ", on_new_picture_enable_);
981 if (draw_info) {
982 base::StringAppendF(&str,
983 "clip left top right bottom: [%d %d %d %d] ",
984 draw_info->clip_left,
985 draw_info->clip_top,
986 draw_info->clip_right,
987 draw_info->clip_bottom);
988 base::StringAppendF(&str,
989 "surface width height: [%d %d] ",
990 draw_info->width,
991 draw_info->height);
992 base::StringAppendF(&str, "is_layer: %d ", draw_info->is_layer);
994 return str;
997 } // namespace android_webview