| 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 |