OLD | NEW |
| (Empty) |
1 // Copyright (c) 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. | |
4 | |
5 #include "android_webview/browser/in_process_renderer/in_process_view_renderer.h
" | |
6 | |
7 #include <android/bitmap.h> | |
8 | |
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/debug/trace_event.h" | |
13 #include "base/logging.h" | |
14 #include "content/public/browser/android/content_view_core.h" | |
15 #include "content/public/browser/render_view_host.h" | |
16 #include "content/public/browser/web_contents.h" | |
17 #include "content/public/renderer/android/synchronous_compositor.h" | |
18 #include "third_party/skia/include/core/SkBitmap.h" | |
19 #include "third_party/skia/include/core/SkCanvas.h" | |
20 #include "third_party/skia/include/core/SkDevice.h" | |
21 #include "third_party/skia/include/core/SkGraphics.h" | |
22 #include "third_party/skia/include/core/SkPicture.h" | |
23 #include "ui/gfx/size_conversions.h" | |
24 #include "ui/gfx/transform.h" | |
25 #include "ui/gfx/vector2d_f.h" | |
26 #include "ui/gl/gl_bindings.h" | |
27 | |
28 // TODO(leandrogracia): Borrowed from gl2ext.h. Cannot be included due to | |
29 // conflicts with gl_bindings.h and the EGL library methods | |
30 // (eglGetCurrentContext). | |
31 #ifndef GL_TEXTURE_EXTERNAL_OES | |
32 #define GL_TEXTURE_EXTERNAL_OES 0x8D65 | |
33 #endif | |
34 | |
35 #ifndef GL_TEXTURE_BINDING_EXTERNAL_OES | |
36 #define GL_TEXTURE_BINDING_EXTERNAL_OES 0x8D67 | |
37 #endif | |
38 | |
39 using base::android::AttachCurrentThread; | |
40 using base::android::JavaRef; | |
41 using base::android::ScopedJavaLocalRef; | |
42 using content::Compositor; | |
43 using content::ContentViewCore; | |
44 | |
45 namespace android_webview { | |
46 | |
47 namespace { | |
48 | |
49 class GLStateRestore { | |
50 public: | |
51 GLStateRestore() { | |
52 #if !defined(NDEBUG) | |
53 { | |
54 GLint vertex_array_buffer_binding; | |
55 glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &vertex_array_buffer_binding); | |
56 DCHECK_EQ(0, vertex_array_buffer_binding); | |
57 | |
58 GLint index_array_buffer_binding; | |
59 glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, | |
60 &index_array_buffer_binding); | |
61 DCHECK_EQ(0, index_array_buffer_binding); | |
62 } | |
63 #endif // !defined(NDEBUG) | |
64 glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, | |
65 &texture_external_oes_binding_); | |
66 glGetIntegerv(GL_PACK_ALIGNMENT, &pack_alignment_); | |
67 glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack_alignment_); | |
68 | |
69 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(vertex_attrib_); ++i) { | |
70 glGetVertexAttribiv( | |
71 i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &vertex_attrib_[i].enabled); | |
72 glGetVertexAttribiv( | |
73 i, GL_VERTEX_ATTRIB_ARRAY_SIZE, &vertex_attrib_[i].size); | |
74 glGetVertexAttribiv( | |
75 i, GL_VERTEX_ATTRIB_ARRAY_TYPE, &vertex_attrib_[i].type); | |
76 glGetVertexAttribiv( | |
77 i, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &vertex_attrib_[i].normalized); | |
78 glGetVertexAttribiv( | |
79 i, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &vertex_attrib_[i].stride); | |
80 glGetVertexAttribPointerv( | |
81 i, GL_VERTEX_ATTRIB_ARRAY_POINTER, &vertex_attrib_[i].pointer); | |
82 } | |
83 | |
84 glGetBooleanv(GL_DEPTH_TEST, &depth_test_); | |
85 glGetBooleanv(GL_CULL_FACE, &cull_face_); | |
86 glGetBooleanv(GL_COLOR_WRITEMASK, color_mask_); | |
87 glGetBooleanv(GL_BLEND, &blend_enabled_); | |
88 glGetIntegerv(GL_BLEND_SRC_RGB, &blend_src_rgb_); | |
89 glGetIntegerv(GL_BLEND_SRC_ALPHA, &blend_src_alpha_); | |
90 glGetIntegerv(GL_BLEND_DST_RGB, &blend_dest_rgb_); | |
91 glGetIntegerv(GL_BLEND_DST_ALPHA, &blend_dest_alpha_); | |
92 glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture_); | |
93 glGetIntegerv(GL_VIEWPORT, viewport_); | |
94 glGetBooleanv(GL_SCISSOR_TEST, &scissor_test_); | |
95 glGetIntegerv(GL_SCISSOR_BOX, scissor_box_); | |
96 glGetIntegerv(GL_CURRENT_PROGRAM, ¤t_program_); | |
97 } | |
98 | |
99 ~GLStateRestore() { | |
100 glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_external_oes_binding_); | |
101 glPixelStorei(GL_PACK_ALIGNMENT, pack_alignment_); | |
102 glPixelStorei(GL_UNPACK_ALIGNMENT, unpack_alignment_); | |
103 | |
104 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(vertex_attrib_); ++i) { | |
105 glVertexAttribPointer(i, | |
106 vertex_attrib_[i].size, | |
107 vertex_attrib_[i].type, | |
108 vertex_attrib_[i].normalized, | |
109 vertex_attrib_[i].stride, | |
110 vertex_attrib_[i].pointer); | |
111 | |
112 if (vertex_attrib_[i].enabled) { | |
113 glEnableVertexAttribArray(i); | |
114 } else { | |
115 glDisableVertexAttribArray(i); | |
116 } | |
117 } | |
118 | |
119 if (depth_test_) { | |
120 glEnable(GL_DEPTH_TEST); | |
121 } else { | |
122 glDisable(GL_DEPTH_TEST); | |
123 } | |
124 | |
125 if (cull_face_) { | |
126 glEnable(GL_CULL_FACE); | |
127 } else { | |
128 glDisable(GL_CULL_FACE); | |
129 } | |
130 | |
131 glColorMask(color_mask_[0], color_mask_[1], color_mask_[2], color_mask_[3]); | |
132 | |
133 if (blend_enabled_) { | |
134 glEnable(GL_BLEND); | |
135 } else { | |
136 glDisable(GL_BLEND); | |
137 } | |
138 | |
139 glBlendFuncSeparate( | |
140 blend_src_rgb_, blend_dest_rgb_, blend_src_alpha_, blend_dest_alpha_); | |
141 glActiveTexture(active_texture_); | |
142 | |
143 glViewport(viewport_[0], viewport_[1], viewport_[2], viewport_[3]); | |
144 | |
145 if (scissor_test_) { | |
146 glEnable(GL_SCISSOR_TEST); | |
147 } else { | |
148 glDisable(GL_SCISSOR_TEST); | |
149 } | |
150 | |
151 glScissor( | |
152 scissor_box_[0], scissor_box_[1], scissor_box_[2], scissor_box_[3]); | |
153 | |
154 glUseProgram(current_program_); | |
155 | |
156 glBindBuffer(GL_ARRAY_BUFFER, 0); | |
157 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); | |
158 } | |
159 | |
160 private: | |
161 GLint texture_external_oes_binding_; | |
162 GLint pack_alignment_; | |
163 GLint unpack_alignment_; | |
164 | |
165 struct { | |
166 GLint enabled; | |
167 GLint size; | |
168 GLint type; | |
169 GLint normalized; | |
170 GLint stride; | |
171 GLvoid* pointer; | |
172 } vertex_attrib_[3]; | |
173 | |
174 GLboolean depth_test_; | |
175 GLboolean cull_face_; | |
176 GLboolean color_mask_[4]; | |
177 GLboolean blend_enabled_; | |
178 GLint blend_src_rgb_; | |
179 GLint blend_src_alpha_; | |
180 GLint blend_dest_rgb_; | |
181 GLint blend_dest_alpha_; | |
182 GLint active_texture_; | |
183 GLint viewport_[4]; | |
184 GLboolean scissor_test_; | |
185 GLint scissor_box_[4]; | |
186 GLint current_program_; | |
187 }; | |
188 | |
189 const void* kUserDataKey = &kUserDataKey; | |
190 | |
191 class UserData : public content::WebContents::Data { | |
192 public: | |
193 UserData(InProcessViewRenderer* ptr) : instance_(ptr) {} | |
194 virtual ~UserData() { | |
195 instance_->WebContentsGone(); | |
196 } | |
197 | |
198 static InProcessViewRenderer* GetInstance(content::WebContents* contents) { | |
199 if (!contents) | |
200 return NULL; | |
201 UserData* data = reinterpret_cast<UserData*>( | |
202 contents->GetUserData(kUserDataKey)); | |
203 return data ? data->instance_ : NULL; | |
204 } | |
205 | |
206 private: | |
207 InProcessViewRenderer* instance_; | |
208 }; | |
209 | |
210 typedef base::Callback<bool(SkCanvas*)> RenderMethod; | |
211 | |
212 bool RasterizeIntoBitmap(JNIEnv* env, | |
213 const JavaRef<jobject>& jbitmap, | |
214 int scroll_x, | |
215 int scroll_y, | |
216 const RenderMethod& renderer) { | |
217 DCHECK(jbitmap.obj()); | |
218 | |
219 AndroidBitmapInfo bitmap_info; | |
220 if (AndroidBitmap_getInfo(env, jbitmap.obj(), &bitmap_info) < 0) { | |
221 LOG(ERROR) << "Error getting java bitmap info."; | |
222 return false; | |
223 } | |
224 | |
225 void* pixels = NULL; | |
226 if (AndroidBitmap_lockPixels(env, jbitmap.obj(), &pixels) < 0) { | |
227 LOG(ERROR) << "Error locking java bitmap pixels."; | |
228 return false; | |
229 } | |
230 | |
231 bool succeeded; | |
232 { | |
233 SkBitmap bitmap; | |
234 bitmap.setConfig(SkBitmap::kARGB_8888_Config, | |
235 bitmap_info.width, | |
236 bitmap_info.height, | |
237 bitmap_info.stride); | |
238 bitmap.setPixels(pixels); | |
239 | |
240 SkDevice device(bitmap); | |
241 SkCanvas canvas(&device); | |
242 canvas.translate(-scroll_x, -scroll_y); | |
243 succeeded = renderer.Run(&canvas); | |
244 } | |
245 | |
246 if (AndroidBitmap_unlockPixels(env, jbitmap.obj()) < 0) { | |
247 LOG(ERROR) << "Error unlocking java bitmap pixels."; | |
248 return false; | |
249 } | |
250 | |
251 return succeeded; | |
252 } | |
253 | |
254 bool RenderPictureToCanvas(SkPicture* picture, SkCanvas* canvas) { | |
255 canvas->drawPicture(*picture); | |
256 return true; | |
257 } | |
258 | |
259 } // namespace | |
260 | |
261 InProcessViewRenderer::InProcessViewRenderer( | |
262 BrowserViewRenderer::Client* client, | |
263 JavaHelper* java_helper) | |
264 : client_(client), | |
265 java_helper_(java_helper), | |
266 web_contents_(NULL), | |
267 compositor_(NULL), | |
268 view_visible_(false), | |
269 continuous_invalidate_(false), | |
270 continuous_invalidate_task_pending_(false), | |
271 width_(0), | |
272 height_(0), | |
273 attached_to_window_(false), | |
274 hardware_initialized_(false), | |
275 hardware_failed_(false), | |
276 egl_context_at_init_(NULL), | |
277 weak_factory_(this) { | |
278 } | |
279 | |
280 InProcessViewRenderer::~InProcessViewRenderer() { | |
281 if (compositor_) | |
282 compositor_->SetClient(NULL); | |
283 SetContents(NULL); | |
284 } | |
285 | |
286 // static | |
287 InProcessViewRenderer* InProcessViewRenderer::FromWebContents( | |
288 content::WebContents* contents) { | |
289 return UserData::GetInstance(contents); | |
290 } | |
291 | |
292 // static | |
293 InProcessViewRenderer* InProcessViewRenderer::FromId(int render_process_id, | |
294 int render_view_id) { | |
295 const content::RenderViewHost* rvh = | |
296 content::RenderViewHost::FromID(render_process_id, render_view_id); | |
297 if (!rvh) return NULL; | |
298 return InProcessViewRenderer::FromWebContents( | |
299 content::WebContents::FromRenderViewHost(rvh)); | |
300 } | |
301 | |
302 void InProcessViewRenderer::BindSynchronousCompositor( | |
303 content::SynchronousCompositor* compositor) { | |
304 DCHECK(compositor && compositor_ != compositor); | |
305 if (compositor_) | |
306 compositor_->SetClient(NULL); | |
307 compositor_ = compositor; | |
308 hardware_initialized_ = false; | |
309 hardware_failed_ = false; | |
310 compositor_->SetClient(this); | |
311 | |
312 if (attached_to_window_) | |
313 client_->RequestProcessMode(); | |
314 } | |
315 | |
316 void InProcessViewRenderer::SetContents( | |
317 content::ContentViewCore* content_view_core) { | |
318 // First remove association from the prior ContentViewCore / WebContents. | |
319 if (web_contents_) { | |
320 web_contents_->SetUserData(kUserDataKey, NULL); | |
321 DCHECK(!web_contents_); // WebContentsGone should have been called. | |
322 } | |
323 | |
324 if (!content_view_core) | |
325 return; | |
326 | |
327 web_contents_ = content_view_core->GetWebContents(); | |
328 web_contents_->SetUserData(kUserDataKey, new UserData(this)); | |
329 } | |
330 | |
331 void InProcessViewRenderer::WebContentsGone() { | |
332 web_contents_ = NULL; | |
333 } | |
334 | |
335 bool InProcessViewRenderer::PrepareDrawGL(int x, int y) { | |
336 // No harm in updating |hw_rendering_scroll_| even if we return false. | |
337 hw_rendering_scroll_ = gfx::Point(x, y); | |
338 return attached_to_window_ && compositor_ && compositor_->IsHwReady() && | |
339 !hardware_failed_; | |
340 } | |
341 | |
342 void InProcessViewRenderer::DrawGL(AwDrawGLInfo* draw_info) { | |
343 DCHECK(view_visible_); | |
344 | |
345 // We need to watch if the current Android context has changed and enforce | |
346 // a clean-up in the compositor. | |
347 EGLContext current_context = eglGetCurrentContext(); | |
348 if (!current_context) { | |
349 LOG(WARNING) << "No current context attached. Skipping composite."; | |
350 return; | |
351 } | |
352 | |
353 GLStateRestore state_restore; | |
354 | |
355 if (attached_to_window_ && compositor_ && !hardware_initialized_) { | |
356 // TODO(boliu): Actually initialize the compositor GL path. | |
357 hardware_initialized_ = true; | |
358 egl_context_at_init_ = current_context; | |
359 } | |
360 | |
361 if (draw_info->mode == AwDrawGLInfo::kModeProcess) | |
362 return; | |
363 | |
364 if (egl_context_at_init_ != current_context) { | |
365 // TODO(boliu): Handle context lost | |
366 } | |
367 | |
368 // TODO(boliu): Make sure this is not called before compositor is initialized | |
369 // and GL is ready. Then make this a DCHECK. | |
370 if (!compositor_) | |
371 return; | |
372 | |
373 gfx::Transform transform; | |
374 transform.matrix().setColMajorf(draw_info->transform); | |
375 transform.Translate(hw_rendering_scroll_.x(), hw_rendering_scroll_.y()); | |
376 // TODO(joth): Check return value. | |
377 compositor_->DemandDrawHw( | |
378 gfx::Size(draw_info->width, draw_info->height), | |
379 transform, | |
380 gfx::Rect(draw_info->clip_left, | |
381 draw_info->clip_top, | |
382 draw_info->clip_right - draw_info->clip_left, | |
383 draw_info->clip_bottom - draw_info->clip_top)); | |
384 | |
385 EnsureContinuousInvalidation(); | |
386 } | |
387 | |
388 bool InProcessViewRenderer::DrawSW(jobject java_canvas, | |
389 const gfx::Rect& clip) { | |
390 bool result = DrawSWInternal(java_canvas, clip); | |
391 EnsureContinuousInvalidation(); | |
392 return result; | |
393 } | |
394 | |
395 bool InProcessViewRenderer::DrawSWInternal(jobject java_canvas, | |
396 const gfx::Rect& clip) { | |
397 TRACE_EVENT0("android_webview", "InProcessViewRenderer::DrawSW"); | |
398 | |
399 if (clip.IsEmpty()) { | |
400 TRACE_EVENT_INSTANT0("android_webview", "Empty Clip", | |
401 TRACE_EVENT_SCOPE_THREAD); | |
402 return true; | |
403 } | |
404 | |
405 JNIEnv* env = AttachCurrentThread(); | |
406 | |
407 AwDrawSWFunctionTable* sw_functions = GetAwDrawSWFunctionTable(); | |
408 AwPixelInfo* pixels = sw_functions ? | |
409 sw_functions->access_pixels(env, java_canvas) : NULL; | |
410 // Render into an auxiliary bitmap if pixel info is not available. | |
411 if (pixels == NULL) { | |
412 TRACE_EVENT0("android_webview", "Render to Aux Bitmap"); | |
413 ScopedJavaLocalRef<jobject> jbitmap(java_helper_->CreateBitmap( | |
414 env, clip.width(), clip.height(), true)); | |
415 if (!jbitmap.obj()) { | |
416 TRACE_EVENT_INSTANT0("android_webview", "Bitmap Alloc Fail", | |
417 TRACE_EVENT_SCOPE_THREAD); | |
418 return false; | |
419 } | |
420 | |
421 if (!RasterizeIntoBitmap(env, jbitmap, clip.x(), clip.y(), | |
422 base::Bind(&InProcessViewRenderer::RenderSW, | |
423 base::Unretained(this)))) { | |
424 TRACE_EVENT_INSTANT0("android_webview", "Rasterize Fail", | |
425 TRACE_EVENT_SCOPE_THREAD); | |
426 return false; | |
427 } | |
428 | |
429 ScopedJavaLocalRef<jobject> jcanvas(env, java_canvas); | |
430 java_helper_->DrawBitmapIntoCanvas(env, jbitmap, jcanvas); | |
431 return true; | |
432 } | |
433 | |
434 // Draw in a SkCanvas built over the pixel information. | |
435 bool succeeded = false; | |
436 { | |
437 SkBitmap bitmap; | |
438 bitmap.setConfig(static_cast<SkBitmap::Config>(pixels->config), | |
439 pixels->width, | |
440 pixels->height, | |
441 pixels->row_bytes); | |
442 bitmap.setPixels(pixels->pixels); | |
443 SkDevice device(bitmap); | |
444 SkCanvas canvas(&device); | |
445 SkMatrix matrix; | |
446 for (int i = 0; i < 9; i++) | |
447 matrix.set(i, pixels->matrix[i]); | |
448 canvas.setMatrix(matrix); | |
449 | |
450 SkRegion clip; | |
451 if (pixels->clip_region_size) { | |
452 size_t bytes_read = clip.readFromMemory(pixels->clip_region); | |
453 DCHECK_EQ(pixels->clip_region_size, bytes_read); | |
454 canvas.setClipRegion(clip); | |
455 } else { | |
456 clip.setRect(SkIRect::MakeWH(pixels->width, pixels->height)); | |
457 } | |
458 | |
459 succeeded = RenderSW(&canvas); | |
460 } | |
461 | |
462 sw_functions->release_pixels(pixels); | |
463 return succeeded; | |
464 } | |
465 | |
466 base::android::ScopedJavaLocalRef<jobject> | |
467 InProcessViewRenderer::CapturePicture() { | |
468 if (!GetAwDrawSWFunctionTable()) | |
469 return ScopedJavaLocalRef<jobject>(); | |
470 | |
471 gfx::Size record_size(width_, height_); | |
472 | |
473 // Return empty Picture objects for empty SkPictures. | |
474 JNIEnv* env = AttachCurrentThread(); | |
475 if (record_size.width() <= 0 || record_size.height() <= 0) { | |
476 return java_helper_->RecordBitmapIntoPicture( | |
477 env, ScopedJavaLocalRef<jobject>()); | |
478 } | |
479 | |
480 skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture); | |
481 SkCanvas* rec_canvas = picture->beginRecording(record_size.width(), | |
482 record_size.height(), | |
483 0); | |
484 if (!CompositeSW(rec_canvas)) | |
485 return ScopedJavaLocalRef<jobject>(); | |
486 picture->endRecording(); | |
487 | |
488 if (IsSkiaVersionCompatible()) { | |
489 // Add a reference that the create_picture() will take ownership of. | |
490 picture->ref(); | |
491 return ScopedJavaLocalRef<jobject>(env, | |
492 GetAwDrawSWFunctionTable()->create_picture(env, picture.get())); | |
493 } | |
494 | |
495 // If Skia versions are not compatible, workaround it by rasterizing the | |
496 // picture into a bitmap and drawing it into a new Java picture. Pass false | |
497 // for |cache_result| as the picture we create will hold a shallow reference | |
498 // to the bitmap drawn, and we don't want subsequent draws to corrupt any | |
499 // previously returned pictures. | |
500 ScopedJavaLocalRef<jobject> jbitmap(java_helper_->CreateBitmap( | |
501 env, picture->width(), picture->height(), false)); | |
502 if (!jbitmap.obj()) | |
503 return ScopedJavaLocalRef<jobject>(); | |
504 | |
505 if (!RasterizeIntoBitmap(env, jbitmap, 0, 0, | |
506 base::Bind(&RenderPictureToCanvas, | |
507 base::Unretained(picture.get())))) { | |
508 return ScopedJavaLocalRef<jobject>(); | |
509 } | |
510 | |
511 return java_helper_->RecordBitmapIntoPicture(env, jbitmap); | |
512 } | |
513 | |
514 void InProcessViewRenderer::EnableOnNewPicture(bool enabled) { | |
515 } | |
516 | |
517 void InProcessViewRenderer::OnVisibilityChanged(bool view_visible, | |
518 bool window_visible) { | |
519 view_visible_ = window_visible && view_visible; | |
520 } | |
521 | |
522 void InProcessViewRenderer::OnSizeChanged(int width, int height) { | |
523 width_ = width; | |
524 height_ = height; | |
525 } | |
526 | |
527 void InProcessViewRenderer::OnAttachedToWindow(int width, int height) { | |
528 attached_to_window_ = true; | |
529 width_ = width; | |
530 height_ = height; | |
531 if (compositor_ && !hardware_initialized_) | |
532 client_->RequestProcessMode(); | |
533 } | |
534 | |
535 void InProcessViewRenderer::OnDetachedFromWindow() { | |
536 // TODO(joth): Release GL resources. crbug.com/231986. | |
537 attached_to_window_ = false; | |
538 } | |
539 | |
540 bool InProcessViewRenderer::IsAttachedToWindow() { | |
541 return attached_to_window_; | |
542 } | |
543 | |
544 bool InProcessViewRenderer::IsViewVisible() { | |
545 return view_visible_; | |
546 } | |
547 | |
548 gfx::Rect InProcessViewRenderer::GetScreenRect() { | |
549 return gfx::Rect(client_->GetLocationOnScreen(), gfx::Size(width_, height_)); | |
550 } | |
551 | |
552 void InProcessViewRenderer::DidDestroyCompositor( | |
553 content::SynchronousCompositor* compositor) { | |
554 // Allow for transient hand-over when two compositors may reference | |
555 // a single client. | |
556 if (compositor_ == compositor) | |
557 compositor_ = NULL; | |
558 } | |
559 | |
560 void InProcessViewRenderer::SetContinuousInvalidate(bool invalidate) { | |
561 if (continuous_invalidate_ == invalidate) | |
562 return; | |
563 | |
564 continuous_invalidate_ = invalidate; | |
565 // TODO(boliu): Handle if not attached to window case. | |
566 EnsureContinuousInvalidation(); | |
567 } | |
568 | |
569 void InProcessViewRenderer::Invalidate() { | |
570 continuous_invalidate_task_pending_ = false; | |
571 if (continuous_invalidate_) | |
572 client_->Invalidate(); | |
573 } | |
574 | |
575 void InProcessViewRenderer::EnsureContinuousInvalidation() { | |
576 if (continuous_invalidate_ && !continuous_invalidate_task_pending_) { | |
577 base::MessageLoop::current()->PostTask(FROM_HERE, | |
578 base::Bind(&InProcessViewRenderer::Invalidate, | |
579 weak_factory_.GetWeakPtr())); | |
580 continuous_invalidate_task_pending_ = true; | |
581 } | |
582 } | |
583 | |
584 bool InProcessViewRenderer::RenderSW(SkCanvas* canvas) { | |
585 // TODO(joth): BrowserViewRendererImpl had a bunch of logic for dpi and page | |
586 // scale here. Determine what if any needs bringing over to this class. | |
587 return CompositeSW(canvas); | |
588 } | |
589 | |
590 bool InProcessViewRenderer::CompositeSW(SkCanvas* canvas) { | |
591 return compositor_ && compositor_->DemandDrawSw(canvas); | |
592 } | |
593 | |
594 } // namespace android_webview | |
OLD | NEW |