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/public/browser/draw_gl.h"
10 #include "android_webview/public/browser/draw_sw.h"
11 #include "base/android/jni_android.h"
12 #include "base/command_line.h"
13 #include "base/debug/trace_event.h"
14 #include "base/logging.h"
15 #include "content/public/browser/android/content_view_core.h"
16 #include "content/public/browser/android/synchronous_compositor.h"
17 #include "content/public/browser/render_view_host.h"
18 #include "content/public/browser/web_contents.h"
19 #include "skia/ext/refptr.h"
20 #include "third_party/skia/include/core/SkBitmap.h"
21 #include "third_party/skia/include/core/SkCanvas.h"
22 #include "third_party/skia/include/core/SkDevice.h"
23 #include "third_party/skia/include/core/SkGraphics.h"
24 #include "third_party/skia/include/core/SkPicture.h"
25 #include "ui/gfx/size_conversions.h"
26 #include "ui/gfx/skia_util.h"
27 #include "ui/gfx/transform.h"
28 #include "ui/gfx/vector2d_conversions.h"
29 #include "ui/gfx/vector2d_f.h"
30 #include "ui/gl/gl_bindings.h"
32 // TODO(leandrogracia): Borrowed from gl2ext.h. Cannot be included due to
33 // conflicts with gl_bindings.h and the EGL library methods
34 // (eglGetCurrentContext).
35 #ifndef GL_TEXTURE_EXTERNAL_OES
36 #define GL_TEXTURE_EXTERNAL_OES 0x8D65
39 #ifndef GL_TEXTURE_BINDING_EXTERNAL_OES
40 #define GL_TEXTURE_BINDING_EXTERNAL_OES 0x8D67
43 using base::android::AttachCurrentThread
;
44 using base::android::JavaRef
;
45 using base::android::ScopedJavaLocalRef
;
46 using content::ContentViewCore
;
48 namespace android_webview
{
52 class GLStateRestore
{
57 GLint vertex_array_buffer_binding
;
58 glGetIntegerv(GL_ARRAY_BUFFER_BINDING
, &vertex_array_buffer_binding
);
59 DCHECK_EQ(0, vertex_array_buffer_binding
);
61 GLint index_array_buffer_binding
;
62 glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING
,
63 &index_array_buffer_binding
);
64 DCHECK_EQ(0, index_array_buffer_binding
);
66 #endif // !defined(NDEBUG)
67 glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES
,
68 &texture_external_oes_binding_
);
69 glGetIntegerv(GL_PACK_ALIGNMENT
, &pack_alignment_
);
70 glGetIntegerv(GL_UNPACK_ALIGNMENT
, &unpack_alignment_
);
72 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(vertex_attrib_
); ++i
) {
74 i
, GL_VERTEX_ATTRIB_ARRAY_ENABLED
, &vertex_attrib_
[i
].enabled
);
76 i
, GL_VERTEX_ATTRIB_ARRAY_SIZE
, &vertex_attrib_
[i
].size
);
78 i
, GL_VERTEX_ATTRIB_ARRAY_TYPE
, &vertex_attrib_
[i
].type
);
80 i
, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED
, &vertex_attrib_
[i
].normalized
);
82 i
, GL_VERTEX_ATTRIB_ARRAY_STRIDE
, &vertex_attrib_
[i
].stride
);
83 glGetVertexAttribPointerv(
84 i
, GL_VERTEX_ATTRIB_ARRAY_POINTER
, &vertex_attrib_
[i
].pointer
);
87 glGetBooleanv(GL_DEPTH_TEST
, &depth_test_
);
88 glGetBooleanv(GL_CULL_FACE
, &cull_face_
);
89 glGetBooleanv(GL_COLOR_WRITEMASK
, color_mask_
);
90 glGetBooleanv(GL_BLEND
, &blend_enabled_
);
91 glGetIntegerv(GL_BLEND_SRC_RGB
, &blend_src_rgb_
);
92 glGetIntegerv(GL_BLEND_SRC_ALPHA
, &blend_src_alpha_
);
93 glGetIntegerv(GL_BLEND_DST_RGB
, &blend_dest_rgb_
);
94 glGetIntegerv(GL_BLEND_DST_ALPHA
, &blend_dest_alpha_
);
95 glGetIntegerv(GL_ACTIVE_TEXTURE
, &active_texture_
);
96 glGetIntegerv(GL_VIEWPORT
, viewport_
);
97 glGetBooleanv(GL_SCISSOR_TEST
, &scissor_test_
);
98 glGetIntegerv(GL_SCISSOR_BOX
, scissor_box_
);
99 glGetIntegerv(GL_CURRENT_PROGRAM
, ¤t_program_
);
103 glBindTexture(GL_TEXTURE_EXTERNAL_OES
, texture_external_oes_binding_
);
104 glPixelStorei(GL_PACK_ALIGNMENT
, pack_alignment_
);
105 glPixelStorei(GL_UNPACK_ALIGNMENT
, unpack_alignment_
);
107 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(vertex_attrib_
); ++i
) {
108 glVertexAttribPointer(i
,
109 vertex_attrib_
[i
].size
,
110 vertex_attrib_
[i
].type
,
111 vertex_attrib_
[i
].normalized
,
112 vertex_attrib_
[i
].stride
,
113 vertex_attrib_
[i
].pointer
);
115 if (vertex_attrib_
[i
].enabled
) {
116 glEnableVertexAttribArray(i
);
118 glDisableVertexAttribArray(i
);
123 glEnable(GL_DEPTH_TEST
);
125 glDisable(GL_DEPTH_TEST
);
129 glEnable(GL_CULL_FACE
);
131 glDisable(GL_CULL_FACE
);
134 glColorMask(color_mask_
[0], color_mask_
[1], color_mask_
[2], color_mask_
[3]);
136 if (blend_enabled_
) {
143 blend_src_rgb_
, blend_dest_rgb_
, blend_src_alpha_
, blend_dest_alpha_
);
144 glActiveTexture(active_texture_
);
146 glViewport(viewport_
[0], viewport_
[1], viewport_
[2], viewport_
[3]);
149 glEnable(GL_SCISSOR_TEST
);
151 glDisable(GL_SCISSOR_TEST
);
155 scissor_box_
[0], scissor_box_
[1], scissor_box_
[2], scissor_box_
[3]);
157 glUseProgram(current_program_
);
159 glBindBuffer(GL_ARRAY_BUFFER
, 0);
160 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER
, 0);
164 GLint texture_external_oes_binding_
;
165 GLint pack_alignment_
;
166 GLint unpack_alignment_
;
177 GLboolean depth_test_
;
178 GLboolean cull_face_
;
179 GLboolean color_mask_
[4];
180 GLboolean blend_enabled_
;
181 GLint blend_src_rgb_
;
182 GLint blend_src_alpha_
;
183 GLint blend_dest_rgb_
;
184 GLint blend_dest_alpha_
;
185 GLint active_texture_
;
187 GLboolean scissor_test_
;
188 GLint scissor_box_
[4];
189 GLint current_program_
;
192 const void* kUserDataKey
= &kUserDataKey
;
194 class UserData
: public content::WebContents::Data
{
196 UserData(InProcessViewRenderer
* ptr
) : instance_(ptr
) {}
197 virtual ~UserData() {
198 instance_
->WebContentsGone();
201 static InProcessViewRenderer
* GetInstance(content::WebContents
* contents
) {
204 UserData
* data
= reinterpret_cast<UserData
*>(
205 contents
->GetUserData(kUserDataKey
));
206 return data
? data
->instance_
: NULL
;
210 InProcessViewRenderer
* instance_
;
213 typedef base::Callback
<bool(SkCanvas
*)> RenderMethod
;
215 bool RasterizeIntoBitmap(JNIEnv
* env
,
216 const JavaRef
<jobject
>& jbitmap
,
219 const RenderMethod
& renderer
) {
220 DCHECK(jbitmap
.obj());
222 AndroidBitmapInfo bitmap_info
;
223 if (AndroidBitmap_getInfo(env
, jbitmap
.obj(), &bitmap_info
) < 0) {
224 LOG(ERROR
) << "Error getting java bitmap info.";
229 if (AndroidBitmap_lockPixels(env
, jbitmap
.obj(), &pixels
) < 0) {
230 LOG(ERROR
) << "Error locking java bitmap pixels.";
237 bitmap
.setConfig(SkBitmap::kARGB_8888_Config
,
241 bitmap
.setPixels(pixels
);
243 SkDevice
device(bitmap
);
244 SkCanvas
canvas(&device
);
245 canvas
.translate(-scroll_x
, -scroll_y
);
246 succeeded
= renderer
.Run(&canvas
);
249 if (AndroidBitmap_unlockPixels(env
, jbitmap
.obj()) < 0) {
250 LOG(ERROR
) << "Error unlocking java bitmap pixels.";
257 bool RenderPictureToCanvas(SkPicture
* picture
, SkCanvas
* canvas
) {
258 canvas
->drawPicture(*picture
);
262 // TODO(boliu): Remove this when hardware mode is ready.
263 bool HardwareEnabled() {
264 return CommandLine::ForCurrentProcess()->HasSwitch("testing-webview-gl-mode");
267 // Provides software rendering functions from the Android glue layer.
268 // Allows preventing extra copies of data when rendering.
269 AwDrawSWFunctionTable
* g_sw_draw_functions
= NULL
;
271 // Tells if the Skia library versions in Android and Chromium are compatible.
272 // If they are then it's possible to pass Skia objects like SkPictures to the
273 // Android glue layer via the SW rendering functions.
274 // If they are not, then additional copies and rasterizations are required
275 // as a fallback mechanism, which will have an important performance impact.
276 bool g_is_skia_version_compatible
= false;
281 void BrowserViewRenderer::SetAwDrawSWFunctionTable(
282 AwDrawSWFunctionTable
* table
) {
283 g_sw_draw_functions
= table
;
284 g_is_skia_version_compatible
=
285 g_sw_draw_functions
->is_skia_version_compatible(&SkGraphics::GetVersion
);
286 LOG_IF(WARNING
, !g_is_skia_version_compatible
)
287 << "Skia versions are not compatible, rendering performance will suffer.";
291 AwDrawSWFunctionTable
* BrowserViewRenderer::GetAwDrawSWFunctionTable() {
292 return g_sw_draw_functions
;
296 bool BrowserViewRenderer::IsSkiaVersionCompatible() {
297 DCHECK(g_sw_draw_functions
);
298 return g_is_skia_version_compatible
;
301 InProcessViewRenderer::InProcessViewRenderer(
302 BrowserViewRenderer::Client
* client
,
303 JavaHelper
* java_helper
,
304 content::WebContents
* web_contents
)
306 java_helper_(java_helper
),
307 web_contents_(web_contents
),
309 view_visible_(false),
311 continuous_invalidate_(false),
312 block_invalidates_(false),
315 attached_to_window_(false),
316 hardware_initialized_(false),
317 hardware_failed_(false),
318 last_egl_context_(NULL
) {
319 CHECK(web_contents_
);
320 web_contents_
->SetUserData(kUserDataKey
, new UserData(this));
321 content::SynchronousCompositor::SetClientForWebContents(web_contents_
, this);
322 // Currently the logic in this class relies on |compositor_| remaining NULL
323 // until the DidInitializeCompositor() call, hence it is not set here.
326 InProcessViewRenderer::~InProcessViewRenderer() {
327 CHECK(web_contents_
);
328 content::SynchronousCompositor::SetClientForWebContents(web_contents_
, NULL
);
329 web_contents_
->SetUserData(kUserDataKey
, NULL
);
330 DCHECK(web_contents_
== NULL
); // WebContentsGone should have been called.
334 InProcessViewRenderer
* InProcessViewRenderer::FromWebContents(
335 content::WebContents
* contents
) {
336 return UserData::GetInstance(contents
);
339 void InProcessViewRenderer::WebContentsGone() {
340 web_contents_
= NULL
;
344 bool InProcessViewRenderer::OnDraw(jobject java_canvas
,
345 bool is_hardware_canvas
,
346 const gfx::Vector2d
& scroll
,
347 const gfx::Rect
& clip
) {
348 scroll_at_start_of_frame_
= scroll
;
349 if (is_hardware_canvas
&& attached_to_window_
&& compositor_
&&
350 HardwareEnabled() && client_
->RequestDrawGL(java_canvas
)) {
351 // All set: we'll get a call on DrawGL when the time comes.
354 // Perform a software draw
355 block_invalidates_
= true;
356 bool result
= DrawSWInternal(java_canvas
, clip
);
357 block_invalidates_
= false;
358 EnsureContinuousInvalidation(NULL
);
362 void InProcessViewRenderer::DrawGL(AwDrawGLInfo
* draw_info
) {
363 if (!HardwareEnabled())
366 TRACE_EVENT0("android_webview", "InProcessViewRenderer::DrawGL");
367 DCHECK(view_visible_
);
369 // We need to watch if the current Android context has changed and enforce
370 // a clean-up in the compositor.
371 EGLContext current_context
= eglGetCurrentContext();
372 if (!current_context
) {
373 TRACE_EVENT_INSTANT0(
374 "android_webview", "EarlyOut_NullEGLContext", TRACE_EVENT_SCOPE_THREAD
);
378 GLStateRestore state_restore
;
380 if (attached_to_window_
&& compositor_
&& !hardware_initialized_
) {
381 TRACE_EVENT0("android_webview", "InitializeHwDraw");
382 hardware_failed_
= !compositor_
->InitializeHwDraw();
383 hardware_initialized_
= true;
384 last_egl_context_
= current_context
;
386 if (hardware_failed_
)
390 if (draw_info
->mode
== AwDrawGLInfo::kModeProcess
)
393 if (last_egl_context_
!= current_context
) {
394 // TODO(boliu): Handle context lost
395 TRACE_EVENT_INSTANT0(
396 "android_webview", "EGLContextChanged", TRACE_EVENT_SCOPE_THREAD
);
398 last_egl_context_
= current_context
;
400 // TODO(boliu): Make sure this is not called before compositor is initialized
401 // and GL is ready. Then make this a DCHECK.
403 TRACE_EVENT_INSTANT0(
404 "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD
);
409 gfx::Transform transform
;
410 transform
.matrix().setColMajorf(draw_info
->transform
);
411 transform
.Translate(scroll_at_start_of_frame_
.x(),
412 scroll_at_start_of_frame_
.y());
413 // TODO(joth): Check return value.
414 block_invalidates_
= true;
415 compositor_
->DemandDrawHw(
416 gfx::Size(draw_info
->width
, draw_info
->height
),
418 gfx::Rect(draw_info
->clip_left
,
420 draw_info
->clip_right
- draw_info
->clip_left
,
421 draw_info
->clip_bottom
- draw_info
->clip_top
));
422 block_invalidates_
= false;
424 EnsureContinuousInvalidation(draw_info
);
427 bool InProcessViewRenderer::DrawSWInternal(jobject java_canvas
,
428 const gfx::Rect
& clip
) {
429 TRACE_EVENT0("android_webview", "InProcessViewRenderer::DrawSW");
431 if (clip
.IsEmpty()) {
432 TRACE_EVENT_INSTANT0(
433 "android_webview", "EarlyOut_EmptyClip", TRACE_EVENT_SCOPE_THREAD
);
437 JNIEnv
* env
= AttachCurrentThread();
439 AwDrawSWFunctionTable
* sw_functions
= GetAwDrawSWFunctionTable();
440 AwPixelInfo
* pixels
= sw_functions
?
441 sw_functions
->access_pixels(env
, java_canvas
) : NULL
;
442 // Render into an auxiliary bitmap if pixel info is not available.
443 if (pixels
== NULL
) {
444 TRACE_EVENT0("android_webview", "RenderToAuxBitmap");
445 ScopedJavaLocalRef
<jobject
> jbitmap(java_helper_
->CreateBitmap(
446 env
, clip
.width(), clip
.height()));
447 if (!jbitmap
.obj()) {
448 TRACE_EVENT_INSTANT0("android_webview",
449 "EarlyOut_BitmapAllocFail",
450 TRACE_EVENT_SCOPE_THREAD
);
454 if (!RasterizeIntoBitmap(env
, jbitmap
,
455 clip
.x() - scroll_at_start_of_frame_
.x(),
456 clip
.y() - scroll_at_start_of_frame_
.y(),
457 base::Bind(&InProcessViewRenderer::RenderSW
,
458 base::Unretained(this)))) {
459 TRACE_EVENT_INSTANT0("android_webview",
460 "EarlyOut_RasterizeFail",
461 TRACE_EVENT_SCOPE_THREAD
);
465 ScopedJavaLocalRef
<jobject
> jcanvas(env
, java_canvas
);
466 java_helper_
->DrawBitmapIntoCanvas(env
, jbitmap
, jcanvas
,
471 // Draw in a SkCanvas built over the pixel information.
472 bool succeeded
= false;
475 bitmap
.setConfig(static_cast<SkBitmap::Config
>(pixels
->config
),
479 bitmap
.setPixels(pixels
->pixels
);
480 SkDevice
device(bitmap
);
481 SkCanvas
canvas(&device
);
483 for (int i
= 0; i
< 9; i
++)
484 matrix
.set(i
, pixels
->matrix
[i
]);
485 canvas
.setMatrix(matrix
);
487 if (pixels
->clip_region_size
) {
488 SkRegion clip_region
;
489 size_t bytes_read
= clip_region
.readFromMemory(pixels
->clip_region
);
490 DCHECK_EQ(pixels
->clip_region_size
, bytes_read
);
491 canvas
.setClipRegion(clip_region
);
493 canvas
.clipRect(gfx::RectToSkRect(clip
));
495 canvas
.translate(scroll_at_start_of_frame_
.x(),
496 scroll_at_start_of_frame_
.y());
498 succeeded
= RenderSW(&canvas
);
501 sw_functions
->release_pixels(pixels
);
505 base::android::ScopedJavaLocalRef
<jobject
>
506 InProcessViewRenderer::CapturePicture() {
507 if (!GetAwDrawSWFunctionTable())
508 return ScopedJavaLocalRef
<jobject
>();
510 gfx::Size
record_size(width_
, height_
);
512 // Return empty Picture objects for empty SkPictures.
513 JNIEnv
* env
= AttachCurrentThread();
514 if (record_size
.width() <= 0 || record_size
.height() <= 0) {
515 return java_helper_
->RecordBitmapIntoPicture(
516 env
, ScopedJavaLocalRef
<jobject
>());
519 skia::RefPtr
<SkPicture
> picture
= skia::AdoptRef(new SkPicture
);
520 SkCanvas
* rec_canvas
= picture
->beginRecording(record_size
.width(),
521 record_size
.height(),
523 if (!CompositeSW(rec_canvas
))
524 return ScopedJavaLocalRef
<jobject
>();
525 picture
->endRecording();
527 if (IsSkiaVersionCompatible()) {
528 // Add a reference that the create_picture() will take ownership of.
530 return ScopedJavaLocalRef
<jobject
>(env
,
531 GetAwDrawSWFunctionTable()->create_picture(env
, picture
.get()));
534 // If Skia versions are not compatible, workaround it by rasterizing the
535 // picture into a bitmap and drawing it into a new Java picture. Pass false
536 // for |cache_result| as the picture we create will hold a shallow reference
537 // to the bitmap drawn, and we don't want subsequent draws to corrupt any
538 // previously returned pictures.
539 ScopedJavaLocalRef
<jobject
> jbitmap(java_helper_
->CreateBitmap(
540 env
, picture
->width(), picture
->height()));
542 return ScopedJavaLocalRef
<jobject
>();
544 if (!RasterizeIntoBitmap(env
, jbitmap
, 0, 0,
545 base::Bind(&RenderPictureToCanvas
,
546 base::Unretained(picture
.get())))) {
547 return ScopedJavaLocalRef
<jobject
>();
550 return java_helper_
->RecordBitmapIntoPicture(env
, jbitmap
);
553 void InProcessViewRenderer::EnableOnNewPicture(bool enabled
) {
556 void InProcessViewRenderer::OnVisibilityChanged(bool view_visible
,
557 bool window_visible
) {
558 TRACE_EVENT_INSTANT2("android_webview",
559 "InProcessViewRenderer::OnVisibilityChanged",
560 TRACE_EVENT_SCOPE_THREAD
,
565 view_visible_
= window_visible
&& view_visible
;
568 void InProcessViewRenderer::OnSizeChanged(int width
, int height
) {
569 TRACE_EVENT_INSTANT2("android_webview",
570 "InProcessViewRenderer::OnSizeChanged",
571 TRACE_EVENT_SCOPE_THREAD
,
580 void InProcessViewRenderer::OnAttachedToWindow(int width
, int height
) {
581 TRACE_EVENT2("android_webview",
582 "InProcessViewRenderer::OnAttachedToWindow",
587 attached_to_window_
= true;
590 if (compositor_
&& !hardware_initialized_
)
591 client_
->RequestDrawGL(NULL
);
594 void InProcessViewRenderer::OnDetachedFromWindow() {
595 TRACE_EVENT0("android_webview",
596 "InProcessViewRenderer::OnDetachedFromWindow");
597 // TODO(joth): Release GL resources. crbug.com/231986.
598 attached_to_window_
= false;
601 bool InProcessViewRenderer::IsAttachedToWindow() {
602 return attached_to_window_
;
605 bool InProcessViewRenderer::IsViewVisible() {
606 return view_visible_
;
609 gfx::Rect
InProcessViewRenderer::GetScreenRect() {
610 return gfx::Rect(client_
->GetLocationOnScreen(), gfx::Size(width_
, height_
));
613 void InProcessViewRenderer::DidInitializeCompositor(
614 content::SynchronousCompositor
* compositor
) {
615 TRACE_EVENT0("android_webview",
616 "InProcessViewRenderer::DidInitializeCompositor");
617 DCHECK(compositor
&& compositor_
== NULL
);
618 compositor_
= compositor
;
619 hardware_initialized_
= false;
620 hardware_failed_
= false;
622 if (attached_to_window_
)
623 client_
->RequestDrawGL(NULL
);
626 void InProcessViewRenderer::DidDestroyCompositor(
627 content::SynchronousCompositor
* compositor
) {
628 TRACE_EVENT0("android_webview",
629 "InProcessViewRenderer::DidDestroyCompositor");
630 DCHECK(compositor_
== compositor
);
634 void InProcessViewRenderer::SetContinuousInvalidate(bool invalidate
) {
635 if (continuous_invalidate_
== invalidate
)
638 TRACE_EVENT_INSTANT1("android_webview",
639 "InProcessViewRenderer::SetContinuousInvalidate",
640 TRACE_EVENT_SCOPE_THREAD
,
643 continuous_invalidate_
= invalidate
;
644 // TODO(boliu): Handle if not attached to window case.
645 EnsureContinuousInvalidation(NULL
);
648 void InProcessViewRenderer::SetDipScale(float dip_scale
) {
649 dip_scale_
= dip_scale
;
650 CHECK(dip_scale_
> 0);
653 void InProcessViewRenderer::ScrollTo(gfx::Vector2d new_value
) {
654 DCHECK(dip_scale_
> 0);
655 // In general we don't guarantee that the scroll offset transforms are
656 // symmetrical. That is if scrolling from JS to offset1 results in a native
657 // offset2 then scrolling from UI to offset2 results in JS being scrolled to
659 // The reason we explicitly do rounding here is that it seems to yeld the
660 // most stabile transformation.
661 gfx::Vector2dF new_value_css
= gfx::ToRoundedVector2d(
662 gfx::ScaleVector2d(new_value
, 1.0f
/ dip_scale_
));
664 DCHECK(scroll_offset_css_
!= new_value_css
);
666 scroll_offset_css_
= new_value_css
;
669 compositor_
->DidChangeRootLayerScrollOffset();
672 void InProcessViewRenderer::SetTotalRootLayerScrollOffset(
673 gfx::Vector2dF new_value_css
) {
674 // TOOD(mkosiba): Add a DCHECK to say that this does _not_ get called during
675 // DrawGl when http://crbug.com/249972 is fixed.
676 if (scroll_offset_css_
== new_value_css
)
679 scroll_offset_css_
= new_value_css
;
681 DCHECK(dip_scale_
> 0);
683 gfx::Vector2d scroll_offset
=
684 gfx::ToRoundedVector2d(gfx::ScaleVector2d(new_value_css
, dip_scale_
));
686 client_
->ScrollContainerViewTo(scroll_offset
);
689 gfx::Vector2dF
InProcessViewRenderer::GetTotalRootLayerScrollOffset() {
690 return scroll_offset_css_
;
693 void InProcessViewRenderer::EnsureContinuousInvalidation(
694 AwDrawGLInfo
* draw_info
) {
695 if (continuous_invalidate_
&& !block_invalidates_
) {
697 draw_info
->dirty_left
= draw_info
->clip_left
;
698 draw_info
->dirty_top
= draw_info
->clip_top
;
699 draw_info
->dirty_right
= draw_info
->clip_right
;
700 draw_info
->dirty_bottom
= draw_info
->clip_bottom
;
701 draw_info
->status_mask
|= AwDrawGLInfo::kStatusMaskDraw
;
703 client_
->PostInvalidate();
705 block_invalidates_
= true;
709 bool InProcessViewRenderer::RenderSW(SkCanvas
* canvas
) {
710 // TODO(joth): BrowserViewRendererImpl had a bunch of logic for dpi and page
711 // scale here. Determine what if any needs bringing over to this class.
712 return CompositeSW(canvas
);
715 bool InProcessViewRenderer::CompositeSW(SkCanvas
* canvas
) {
716 return compositor_
&& compositor_
->DemandDrawSw(canvas
);
719 } // namespace android_webview