Hookup android_webview scroll offset delegation to Java side.
[chromium-blink-merge.git] / android_webview / browser / in_process_view_renderer.cc
blobacb6db8c2d60ee0b88cde771c676f8f90be1e1e5
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
37 #endif
39 #ifndef GL_TEXTURE_BINDING_EXTERNAL_OES
40 #define GL_TEXTURE_BINDING_EXTERNAL_OES 0x8D67
41 #endif
43 using base::android::AttachCurrentThread;
44 using base::android::JavaRef;
45 using base::android::ScopedJavaLocalRef;
46 using content::ContentViewCore;
48 namespace android_webview {
50 namespace {
52 class GLStateRestore {
53 public:
54 GLStateRestore() {
55 #if !defined(NDEBUG)
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) {
73 glGetVertexAttribiv(
74 i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &vertex_attrib_[i].enabled);
75 glGetVertexAttribiv(
76 i, GL_VERTEX_ATTRIB_ARRAY_SIZE, &vertex_attrib_[i].size);
77 glGetVertexAttribiv(
78 i, GL_VERTEX_ATTRIB_ARRAY_TYPE, &vertex_attrib_[i].type);
79 glGetVertexAttribiv(
80 i, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &vertex_attrib_[i].normalized);
81 glGetVertexAttribiv(
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, &current_program_);
102 ~GLStateRestore() {
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);
117 } else {
118 glDisableVertexAttribArray(i);
122 if (depth_test_) {
123 glEnable(GL_DEPTH_TEST);
124 } else {
125 glDisable(GL_DEPTH_TEST);
128 if (cull_face_) {
129 glEnable(GL_CULL_FACE);
130 } else {
131 glDisable(GL_CULL_FACE);
134 glColorMask(color_mask_[0], color_mask_[1], color_mask_[2], color_mask_[3]);
136 if (blend_enabled_) {
137 glEnable(GL_BLEND);
138 } else {
139 glDisable(GL_BLEND);
142 glBlendFuncSeparate(
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]);
148 if (scissor_test_) {
149 glEnable(GL_SCISSOR_TEST);
150 } else {
151 glDisable(GL_SCISSOR_TEST);
154 glScissor(
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);
163 private:
164 GLint texture_external_oes_binding_;
165 GLint pack_alignment_;
166 GLint unpack_alignment_;
168 struct {
169 GLint enabled;
170 GLint size;
171 GLint type;
172 GLint normalized;
173 GLint stride;
174 GLvoid* pointer;
175 } vertex_attrib_[3];
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_;
186 GLint viewport_[4];
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 {
195 public:
196 UserData(InProcessViewRenderer* ptr) : instance_(ptr) {}
197 virtual ~UserData() {
198 instance_->WebContentsGone();
201 static InProcessViewRenderer* GetInstance(content::WebContents* contents) {
202 if (!contents)
203 return NULL;
204 UserData* data = reinterpret_cast<UserData*>(
205 contents->GetUserData(kUserDataKey));
206 return data ? data->instance_ : NULL;
209 private:
210 InProcessViewRenderer* instance_;
213 typedef base::Callback<bool(SkCanvas*)> RenderMethod;
215 bool RasterizeIntoBitmap(JNIEnv* env,
216 const JavaRef<jobject>& jbitmap,
217 int scroll_x,
218 int scroll_y,
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.";
225 return false;
228 void* pixels = NULL;
229 if (AndroidBitmap_lockPixels(env, jbitmap.obj(), &pixels) < 0) {
230 LOG(ERROR) << "Error locking java bitmap pixels.";
231 return false;
234 bool succeeded;
236 SkBitmap bitmap;
237 bitmap.setConfig(SkBitmap::kARGB_8888_Config,
238 bitmap_info.width,
239 bitmap_info.height,
240 bitmap_info.stride);
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.";
251 return false;
254 return succeeded;
257 bool RenderPictureToCanvas(SkPicture* picture, SkCanvas* canvas) {
258 canvas->drawPicture(*picture);
259 return true;
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;
278 } // namespace
280 // static
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.";
290 // static
291 AwDrawSWFunctionTable* BrowserViewRenderer::GetAwDrawSWFunctionTable() {
292 return g_sw_draw_functions;
295 // static
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)
305 : client_(client),
306 java_helper_(java_helper),
307 web_contents_(web_contents),
308 compositor_(NULL),
309 view_visible_(false),
310 dip_scale_(0.0),
311 continuous_invalidate_(false),
312 block_invalidates_(false),
313 width_(0),
314 height_(0),
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.
333 // static
334 InProcessViewRenderer* InProcessViewRenderer::FromWebContents(
335 content::WebContents* contents) {
336 return UserData::GetInstance(contents);
339 void InProcessViewRenderer::WebContentsGone() {
340 web_contents_ = NULL;
341 compositor_ = 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.
352 return true;
354 // Perform a software draw
355 block_invalidates_ = true;
356 bool result = DrawSWInternal(java_canvas, clip);
357 block_invalidates_ = false;
358 EnsureContinuousInvalidation(NULL);
359 return result;
362 void InProcessViewRenderer::DrawGL(AwDrawGLInfo* draw_info) {
363 if (!HardwareEnabled())
364 return;
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);
375 return;
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_)
387 return;
390 if (draw_info->mode == AwDrawGLInfo::kModeProcess)
391 return;
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.
402 if (!compositor_) {
403 TRACE_EVENT_INSTANT0(
404 "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD);
405 return;
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),
417 transform,
418 gfx::Rect(draw_info->clip_left,
419 draw_info->clip_top,
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);
434 return true;
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);
451 return false;
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);
462 return false;
465 ScopedJavaLocalRef<jobject> jcanvas(env, java_canvas);
466 java_helper_->DrawBitmapIntoCanvas(env, jbitmap, jcanvas,
467 clip.x(), clip.y());
468 return true;
471 // Draw in a SkCanvas built over the pixel information.
472 bool succeeded = false;
474 SkBitmap bitmap;
475 bitmap.setConfig(static_cast<SkBitmap::Config>(pixels->config),
476 pixels->width,
477 pixels->height,
478 pixels->row_bytes);
479 bitmap.setPixels(pixels->pixels);
480 SkDevice device(bitmap);
481 SkCanvas canvas(&device);
482 SkMatrix matrix;
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);
492 } else {
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);
502 return succeeded;
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.
529 picture->ref();
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()));
541 if (!jbitmap.obj())
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,
561 "view_visible",
562 view_visible,
563 "window_visible",
564 window_visible);
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,
572 "width",
573 width,
574 "height",
575 height);
576 width_ = width;
577 height_ = height;
580 void InProcessViewRenderer::OnAttachedToWindow(int width, int height) {
581 TRACE_EVENT2("android_webview",
582 "InProcessViewRenderer::OnAttachedToWindow",
583 "width",
584 width,
585 "height",
586 height);
587 attached_to_window_ = true;
588 width_ = width;
589 height_ = height;
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);
631 compositor_ = NULL;
634 void InProcessViewRenderer::SetContinuousInvalidate(bool invalidate) {
635 if (continuous_invalidate_ == invalidate)
636 return;
638 TRACE_EVENT_INSTANT1("android_webview",
639 "InProcessViewRenderer::SetContinuousInvalidate",
640 TRACE_EVENT_SCOPE_THREAD,
641 "invalidate",
642 invalidate);
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
658 // offset1 again.
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;
668 if (compositor_)
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)
677 return;
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_) {
696 if (draw_info) {
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;
702 } else {
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