Extended the iOS platform policy loader to load an additional key.
[chromium-blink-merge.git] / android_webview / browser / browser_view_renderer.cc
blob5bbc1ab2addfd0f27d94554c7b5e77351f16ba92
1 // Copyright 2014 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/browser_view_renderer.h"
7 #include "android_webview/browser/browser_view_renderer_client.h"
8 #include "android_webview/browser/shared_renderer_state.h"
9 #include "android_webview/public/browser/draw_gl.h"
10 #include "base/android/jni_android.h"
11 #include "base/auto_reset.h"
12 #include "base/debug/trace_event.h"
13 #include "base/logging.h"
14 #include "base/strings/stringprintf.h"
15 #include "content/public/browser/android/synchronous_compositor.h"
16 #include "content/public/browser/web_contents.h"
17 #include "third_party/skia/include/core/SkBitmap.h"
18 #include "third_party/skia/include/core/SkCanvas.h"
19 #include "third_party/skia/include/core/SkPicture.h"
20 #include "ui/gfx/vector2d_conversions.h"
22 using base::android::AttachCurrentThread;
23 using base::android::JavaRef;
24 using base::android::ScopedJavaLocalRef;
26 namespace android_webview {
28 namespace {
30 const int64 kFallbackTickTimeoutInMilliseconds = 20;
32 class AutoResetWithLock {
33 public:
34 AutoResetWithLock(gfx::Vector2dF* scoped_variable,
35 gfx::Vector2dF new_value,
36 base::Lock& lock)
37 : scoped_variable_(scoped_variable),
38 original_value_(*scoped_variable),
39 lock_(lock) {
40 base::AutoLock auto_lock(lock_);
41 *scoped_variable_ = new_value;
44 ~AutoResetWithLock() {
45 base::AutoLock auto_lock(lock_);
46 *scoped_variable_ = original_value_;
49 private:
50 gfx::Vector2dF* scoped_variable_;
51 gfx::Vector2dF original_value_;
52 base::Lock& lock_;
54 DISALLOW_COPY_AND_ASSIGN(AutoResetWithLock);
57 } // namespace
59 BrowserViewRenderer::BrowserViewRenderer(
60 BrowserViewRendererClient* client,
61 SharedRendererState* shared_renderer_state,
62 content::WebContents* web_contents,
63 const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner)
64 : client_(client),
65 shared_renderer_state_(shared_renderer_state),
66 web_contents_(web_contents),
67 weak_factory_on_ui_thread_(this),
68 ui_thread_weak_ptr_(weak_factory_on_ui_thread_.GetWeakPtr()),
69 ui_task_runner_(ui_task_runner),
70 has_compositor_(false),
71 is_paused_(false),
72 view_visible_(false),
73 window_visible_(false),
74 attached_to_window_(false),
75 dip_scale_(0.0),
76 page_scale_factor_(1.0),
77 on_new_picture_enable_(false),
78 clear_view_(false),
79 compositor_needs_continuous_invalidate_(false),
80 block_invalidates_(false),
81 width_(0),
82 height_(0) {
83 CHECK(web_contents_);
84 content::SynchronousCompositor::SetClientForWebContents(web_contents_, this);
86 // Currently the logic in this class relies on |has_compositor_| remaining
87 // false until the DidInitializeCompositor() call, hence it is not set here.
90 BrowserViewRenderer::~BrowserViewRenderer() {
91 content::SynchronousCompositor::SetClientForWebContents(web_contents_, NULL);
94 bool BrowserViewRenderer::OnDraw(jobject java_canvas,
95 bool is_hardware_canvas,
96 const gfx::Vector2d& scroll,
97 const gfx::Rect& global_visible_rect,
98 const gfx::Rect& clip) {
99 draw_gl_input_.frame_id++;
100 draw_gl_input_.scroll_offset = scroll;
101 draw_gl_input_.global_visible_rect = global_visible_rect;
102 if (clear_view_)
103 return false;
104 if (is_hardware_canvas && attached_to_window_) {
105 shared_renderer_state_->SetDrawGLInput(draw_gl_input_);
106 // We should be performing a hardware draw here. If we don't have the
107 // compositor yet or if RequestDrawGL fails, it means we failed this draw
108 // and thus return false here to clear to background color for this draw.
109 return has_compositor_ && client_->RequestDrawGL(java_canvas);
111 // Perform a software draw
112 return DrawSWInternal(java_canvas, clip);
115 void BrowserViewRenderer::DidDrawGL(const DrawGLResult& result) {
116 DidComposite(!result.clip_contains_visible_rect);
119 bool BrowserViewRenderer::DrawSWInternal(jobject java_canvas,
120 const gfx::Rect& clip) {
121 if (clip.IsEmpty()) {
122 TRACE_EVENT_INSTANT0(
123 "android_webview", "EarlyOut_EmptyClip", TRACE_EVENT_SCOPE_THREAD);
124 return true;
127 if (!has_compositor_) {
128 TRACE_EVENT_INSTANT0(
129 "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD);
130 return false;
133 return BrowserViewRendererJavaHelper::GetInstance()
134 ->RenderViaAuxilaryBitmapIfNeeded(
135 java_canvas,
136 draw_gl_input_.scroll_offset,
137 clip,
138 base::Bind(&BrowserViewRenderer::CompositeSW,
139 base::Unretained(this)));
142 skia::RefPtr<SkPicture> BrowserViewRenderer::CapturePicture(int width,
143 int height) {
144 TRACE_EVENT0("android_webview", "BrowserViewRenderer::CapturePicture");
146 // Return empty Picture objects for empty SkPictures.
147 skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture);
148 if (width <= 0 || height <= 0) {
149 return picture;
152 // Reset scroll back to the origin, will go back to the old
153 // value when scroll_reset is out of scope.
154 AutoResetWithLock scroll_reset(
155 &scroll_offset_dip_, gfx::Vector2dF(), scroll_offset_dip_lock_);
157 SkCanvas* rec_canvas = picture->beginRecording(width, height, 0);
158 if (has_compositor_)
159 CompositeSW(rec_canvas);
160 picture->endRecording();
161 return picture;
164 void BrowserViewRenderer::EnableOnNewPicture(bool enabled) {
165 on_new_picture_enable_ = enabled;
168 void BrowserViewRenderer::ClearView() {
169 TRACE_EVENT_INSTANT0("android_webview",
170 "BrowserViewRenderer::ClearView",
171 TRACE_EVENT_SCOPE_THREAD);
172 if (clear_view_)
173 return;
175 clear_view_ = true;
176 // Always invalidate ignoring the compositor to actually clear the webview.
177 EnsureContinuousInvalidation(true);
180 void BrowserViewRenderer::SetIsPaused(bool paused) {
181 TRACE_EVENT_INSTANT1("android_webview",
182 "BrowserViewRenderer::SetIsPaused",
183 TRACE_EVENT_SCOPE_THREAD,
184 "paused",
185 paused);
186 is_paused_ = paused;
187 EnsureContinuousInvalidation(false);
190 void BrowserViewRenderer::SetViewVisibility(bool view_visible) {
191 TRACE_EVENT_INSTANT1("android_webview",
192 "BrowserViewRenderer::SetViewVisibility",
193 TRACE_EVENT_SCOPE_THREAD,
194 "view_visible",
195 view_visible);
196 view_visible_ = view_visible;
199 void BrowserViewRenderer::SetWindowVisibility(bool window_visible) {
200 TRACE_EVENT_INSTANT1("android_webview",
201 "BrowserViewRenderer::SetWindowVisibility",
202 TRACE_EVENT_SCOPE_THREAD,
203 "window_visible",
204 window_visible);
205 window_visible_ = window_visible;
206 EnsureContinuousInvalidation(false);
209 void BrowserViewRenderer::OnSizeChanged(int width, int height) {
210 TRACE_EVENT_INSTANT2("android_webview",
211 "BrowserViewRenderer::OnSizeChanged",
212 TRACE_EVENT_SCOPE_THREAD,
213 "width",
214 width,
215 "height",
216 height);
217 width_ = width;
218 height_ = height;
221 void BrowserViewRenderer::OnAttachedToWindow(int width, int height) {
222 TRACE_EVENT2("android_webview",
223 "BrowserViewRenderer::OnAttachedToWindow",
224 "width",
225 width,
226 "height",
227 height);
228 attached_to_window_ = true;
229 width_ = width;
230 height_ = height;
233 void BrowserViewRenderer::OnDetachedFromWindow() {
234 TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDetachedFromWindow");
235 attached_to_window_ = false;
238 bool BrowserViewRenderer::IsAttachedToWindow() const {
239 return attached_to_window_;
242 bool BrowserViewRenderer::IsVisible() const {
243 // Ignore |window_visible_| if |attached_to_window_| is false.
244 return view_visible_ && (!attached_to_window_ || window_visible_);
247 gfx::Rect BrowserViewRenderer::GetScreenRect() const {
248 return gfx::Rect(client_->GetLocationOnScreen(), gfx::Size(width_, height_));
251 void BrowserViewRenderer::DidInitializeCompositor(
252 content::SynchronousCompositor* compositor) {
253 TRACE_EVENT0("android_webview",
254 "BrowserViewRenderer::DidInitializeCompositor");
255 DCHECK(compositor);
256 DCHECK(!has_compositor_);
257 DCHECK(ui_task_runner_->BelongsToCurrentThread());
258 has_compositor_ = true;
259 shared_renderer_state_->SetCompositorOnUiThread(compositor);
262 void BrowserViewRenderer::DidDestroyCompositor(
263 content::SynchronousCompositor* compositor) {
264 TRACE_EVENT0("android_webview", "BrowserViewRenderer::DidDestroyCompositor");
265 DCHECK(has_compositor_);
266 DCHECK(ui_task_runner_->BelongsToCurrentThread());
267 has_compositor_ = false;
268 shared_renderer_state_->SetCompositorOnUiThread(NULL);
271 void BrowserViewRenderer::SetContinuousInvalidate(bool invalidate) {
272 if (!ui_task_runner_->BelongsToCurrentThread()) {
273 ui_task_runner_->PostTask(
274 FROM_HERE,
275 base::Bind(&BrowserViewRenderer::SetContinuousInvalidate,
276 ui_thread_weak_ptr_,
277 invalidate));
278 return;
280 if (compositor_needs_continuous_invalidate_ == invalidate)
281 return;
283 TRACE_EVENT_INSTANT1("android_webview",
284 "BrowserViewRenderer::SetContinuousInvalidate",
285 TRACE_EVENT_SCOPE_THREAD,
286 "invalidate",
287 invalidate);
288 compositor_needs_continuous_invalidate_ = invalidate;
289 EnsureContinuousInvalidation(false);
292 void BrowserViewRenderer::SetDipScale(float dip_scale) {
293 dip_scale_ = dip_scale;
294 CHECK(dip_scale_ > 0);
297 gfx::Vector2d BrowserViewRenderer::max_scroll_offset() const {
298 DCHECK_GT(dip_scale_, 0);
299 return gfx::ToCeiledVector2d(gfx::ScaleVector2d(
300 max_scroll_offset_dip_, dip_scale_ * page_scale_factor_));
303 void BrowserViewRenderer::ScrollTo(gfx::Vector2d scroll_offset) {
304 gfx::Vector2d max_offset = max_scroll_offset();
305 gfx::Vector2dF scroll_offset_dip;
306 // To preserve the invariant that scrolling to the maximum physical pixel
307 // value also scrolls to the maximum dip pixel value we transform the physical
308 // offset into the dip offset by using a proportion (instead of dividing by
309 // dip_scale * page_scale_factor).
310 if (max_offset.x()) {
311 scroll_offset_dip.set_x((scroll_offset.x() * max_scroll_offset_dip_.x()) /
312 max_offset.x());
314 if (max_offset.y()) {
315 scroll_offset_dip.set_y((scroll_offset.y() * max_scroll_offset_dip_.y()) /
316 max_offset.y());
319 DCHECK_LE(0, scroll_offset_dip.x());
320 DCHECK_LE(0, scroll_offset_dip.y());
321 DCHECK_LE(scroll_offset_dip.x(), max_scroll_offset_dip_.x());
322 DCHECK_LE(scroll_offset_dip.y(), max_scroll_offset_dip_.y());
325 base::AutoLock lock(scroll_offset_dip_lock_);
326 if (scroll_offset_dip_ == scroll_offset_dip)
327 return;
329 scroll_offset_dip_ = scroll_offset_dip;
332 if (has_compositor_)
333 shared_renderer_state_->CompositorDidChangeRootLayerScrollOffset();
336 void BrowserViewRenderer::DidUpdateContent() {
337 if (!ui_task_runner_->BelongsToCurrentThread()) {
338 ui_task_runner_->PostTask(FROM_HERE,
339 base::Bind(&BrowserViewRenderer::DidUpdateContent,
340 ui_thread_weak_ptr_));
341 return;
343 TRACE_EVENT_INSTANT0("android_webview",
344 "BrowserViewRenderer::DidUpdateContent",
345 TRACE_EVENT_SCOPE_THREAD);
346 clear_view_ = false;
347 if (on_new_picture_enable_)
348 client_->OnNewPicture();
351 void BrowserViewRenderer::SetMaxRootLayerScrollOffset(
352 gfx::Vector2dF new_value_dip) {
353 if (!ui_task_runner_->BelongsToCurrentThread()) {
354 ui_task_runner_->PostTask(
355 FROM_HERE,
356 base::Bind(&BrowserViewRenderer::SetMaxRootLayerScrollOffset,
357 ui_thread_weak_ptr_,
358 new_value_dip));
359 return;
361 DCHECK_GT(dip_scale_, 0);
363 max_scroll_offset_dip_ = new_value_dip;
364 DCHECK_LE(0, max_scroll_offset_dip_.x());
365 DCHECK_LE(0, max_scroll_offset_dip_.y());
367 client_->SetMaxContainerViewScrollOffset(max_scroll_offset());
370 void BrowserViewRenderer::SetTotalRootLayerScrollOffset(
371 gfx::Vector2dF scroll_offset_dip) {
372 if (!ui_task_runner_->BelongsToCurrentThread()) {
373 ui_task_runner_->PostTask(
374 FROM_HERE,
375 base::Bind(&BrowserViewRenderer::SetTotalRootLayerScrollOffset,
376 ui_thread_weak_ptr_,
377 scroll_offset_dip));
378 return;
382 base::AutoLock lock(scroll_offset_dip_lock_);
383 // TOOD(mkosiba): Add a DCHECK to say that this does _not_ get called during
384 // DrawGl when http://crbug.com/249972 is fixed.
385 if (scroll_offset_dip_ == scroll_offset_dip)
386 return;
388 scroll_offset_dip_ = scroll_offset_dip;
391 gfx::Vector2d max_offset = max_scroll_offset();
392 gfx::Vector2d scroll_offset;
393 // For an explanation as to why this is done this way see the comment in
394 // BrowserViewRenderer::ScrollTo.
395 if (max_scroll_offset_dip_.x()) {
396 scroll_offset.set_x((scroll_offset_dip.x() * max_offset.x()) /
397 max_scroll_offset_dip_.x());
400 if (max_scroll_offset_dip_.y()) {
401 scroll_offset.set_y((scroll_offset_dip.y() * max_offset.y()) /
402 max_scroll_offset_dip_.y());
405 DCHECK(0 <= scroll_offset.x());
406 DCHECK(0 <= scroll_offset.y());
407 // Disabled because the conditions are being violated while running
408 // AwZoomTest.testMagnification, see http://crbug.com/340648
409 // DCHECK(scroll_offset.x() <= max_offset.x());
410 // DCHECK(scroll_offset.y() <= max_offset.y());
412 client_->ScrollContainerViewTo(scroll_offset);
415 gfx::Vector2dF BrowserViewRenderer::GetTotalRootLayerScrollOffset() {
416 base::AutoLock lock(scroll_offset_dip_lock_);
417 return scroll_offset_dip_;
420 bool BrowserViewRenderer::IsExternalFlingActive() const {
421 if (!ui_task_runner_->BelongsToCurrentThread()) {
422 // TODO(boliu): This is short term hack since we cannot call into
423 // view system on non-UI thread.
424 return false;
426 return client_->IsFlingActive();
429 void BrowserViewRenderer::SetRootLayerPageScaleFactorAndLimits(
430 float page_scale_factor,
431 float min_page_scale_factor,
432 float max_page_scale_factor) {
433 if (!ui_task_runner_->BelongsToCurrentThread()) {
434 ui_task_runner_->PostTask(
435 FROM_HERE,
436 base::Bind(&BrowserViewRenderer::SetRootLayerPageScaleFactorAndLimits,
437 ui_thread_weak_ptr_,
438 page_scale_factor,
439 min_page_scale_factor,
440 max_page_scale_factor));
441 return;
443 page_scale_factor_ = page_scale_factor;
444 DCHECK_GT(page_scale_factor_, 0);
445 client_->SetPageScaleFactorAndLimits(
446 page_scale_factor, min_page_scale_factor, max_page_scale_factor);
447 client_->SetMaxContainerViewScrollOffset(max_scroll_offset());
450 void BrowserViewRenderer::SetRootLayerScrollableSize(
451 gfx::SizeF scrollable_size) {
452 if (!ui_task_runner_->BelongsToCurrentThread()) {
453 ui_task_runner_->PostTask(
454 FROM_HERE,
455 base::Bind(&BrowserViewRenderer::SetRootLayerScrollableSize,
456 ui_thread_weak_ptr_,
457 scrollable_size));
458 return;
460 client_->SetContentsSize(scrollable_size);
463 void BrowserViewRenderer::DidOverscroll(gfx::Vector2dF accumulated_overscroll,
464 gfx::Vector2dF latest_overscroll_delta,
465 gfx::Vector2dF current_fling_velocity) {
466 if (!ui_task_runner_->BelongsToCurrentThread()) {
467 ui_task_runner_->PostTask(
468 FROM_HERE,
469 base::Bind(&BrowserViewRenderer::DidOverscroll,
470 ui_thread_weak_ptr_,
471 accumulated_overscroll,
472 latest_overscroll_delta,
473 current_fling_velocity));
474 return;
476 const float physical_pixel_scale = dip_scale_ * page_scale_factor_;
477 if (accumulated_overscroll == latest_overscroll_delta)
478 overscroll_rounding_error_ = gfx::Vector2dF();
479 gfx::Vector2dF scaled_overscroll_delta =
480 gfx::ScaleVector2d(latest_overscroll_delta, physical_pixel_scale);
481 gfx::Vector2d rounded_overscroll_delta = gfx::ToRoundedVector2d(
482 scaled_overscroll_delta + overscroll_rounding_error_);
483 overscroll_rounding_error_ =
484 scaled_overscroll_delta - rounded_overscroll_delta;
485 client_->DidOverscroll(rounded_overscroll_delta);
488 void BrowserViewRenderer::EnsureContinuousInvalidation(bool force_invalidate) {
489 // This method should be called again when any of these conditions change.
490 bool need_invalidate =
491 compositor_needs_continuous_invalidate_ || force_invalidate;
492 if (!need_invalidate || block_invalidates_)
493 return;
495 // Always call view invalidate. We rely the Android framework to ignore the
496 // invalidate when it's not needed such as when view is not visible.
497 client_->PostInvalidate();
499 // Stop fallback ticks when one of these is true.
500 // 1) Webview is paused. Also need to check we are not in clear view since
501 // paused, offscreen still expect clear view to recover.
502 // 2) If we are attached to window and the window is not visible (eg when
503 // app is in the background). We are sure in this case the webview is used
504 // "on-screen" but that updates are not needed when in the background.
505 bool throttle_fallback_tick =
506 (is_paused_ && !clear_view_) || (attached_to_window_ && !window_visible_);
507 if (throttle_fallback_tick)
508 return;
510 block_invalidates_ = compositor_needs_continuous_invalidate_;
512 // Unretained here is safe because the callback is cancelled when
513 // |fallback_tick_| is destroyed.
514 fallback_tick_.Reset(base::Bind(&BrowserViewRenderer::FallbackTickFired,
515 base::Unretained(this)));
517 // No need to reschedule fallback tick if compositor does not need to be
518 // ticked. This can happen if this is reached because force_invalidate is
519 // true.
520 if (compositor_needs_continuous_invalidate_) {
521 ui_task_runner_->PostDelayedTask(
522 FROM_HERE,
523 fallback_tick_.callback(),
524 base::TimeDelta::FromMilliseconds(kFallbackTickTimeoutInMilliseconds));
528 void BrowserViewRenderer::FallbackTickFired() {
529 TRACE_EVENT1("android_webview",
530 "BrowserViewRenderer::FallbackTickFired",
531 "compositor_needs_continuous_invalidate_",
532 compositor_needs_continuous_invalidate_);
534 // This should only be called if OnDraw or DrawGL did not come in time, which
535 // means block_invalidates_ must still be true.
536 DCHECK(block_invalidates_);
537 if (compositor_needs_continuous_invalidate_ && has_compositor_)
538 ForceFakeCompositeSW();
541 void BrowserViewRenderer::ForceFakeCompositeSW() {
542 DCHECK(has_compositor_);
543 SkBitmap bitmap;
544 bitmap.allocN32Pixels(1, 1);
545 bitmap.eraseColor(0);
546 SkCanvas canvas(bitmap);
547 CompositeSW(&canvas);
550 bool BrowserViewRenderer::CompositeSW(SkCanvas* canvas) {
551 DCHECK(has_compositor_);
552 bool result = shared_renderer_state_->CompositorDemandDrawSw(canvas);
553 DidComposite(false);
554 return result;
557 void BrowserViewRenderer::DidComposite(bool force_invalidate) {
558 fallback_tick_.Cancel();
559 block_invalidates_ = false;
560 EnsureContinuousInvalidation(force_invalidate);
563 std::string BrowserViewRenderer::ToString(AwDrawGLInfo* draw_info) const {
564 std::string str;
565 base::StringAppendF(&str, "is_paused: %d ", is_paused_);
566 base::StringAppendF(&str, "view_visible: %d ", view_visible_);
567 base::StringAppendF(&str, "window_visible: %d ", window_visible_);
568 base::StringAppendF(&str, "dip_scale: %f ", dip_scale_);
569 base::StringAppendF(&str, "page_scale_factor: %f ", page_scale_factor_);
570 base::StringAppendF(&str,
571 "compositor_needs_continuous_invalidate: %d ",
572 compositor_needs_continuous_invalidate_);
573 base::StringAppendF(&str, "block_invalidates: %d ", block_invalidates_);
574 base::StringAppendF(&str, "view width height: [%d %d] ", width_, height_);
575 base::StringAppendF(&str, "attached_to_window: %d ", attached_to_window_);
576 base::StringAppendF(&str,
577 "global visible rect: %s ",
578 draw_gl_input_.global_visible_rect.ToString().c_str());
579 base::StringAppendF(
580 &str, "scroll_offset_dip: %s ", scroll_offset_dip_.ToString().c_str());
581 base::StringAppendF(&str,
582 "overscroll_rounding_error_: %s ",
583 overscroll_rounding_error_.ToString().c_str());
584 base::StringAppendF(
585 &str, "on_new_picture_enable: %d ", on_new_picture_enable_);
586 base::StringAppendF(&str, "clear_view: %d ", clear_view_);
587 if (draw_info) {
588 base::StringAppendF(&str,
589 "clip left top right bottom: [%d %d %d %d] ",
590 draw_info->clip_left,
591 draw_info->clip_top,
592 draw_info->clip_right,
593 draw_info->clip_bottom);
594 base::StringAppendF(&str,
595 "surface width height: [%d %d] ",
596 draw_info->width,
597 draw_info->height);
598 base::StringAppendF(&str, "is_layer: %d ", draw_info->is_layer);
600 return str;
603 } // namespace android_webview