Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(91)

Side by Side Diff: android_webview/browser/browser_view_renderer_impl.cc

Issue 12041009: [Android WebView] Migrate the rendering code to a separate set of classes. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: updated and rebased. Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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/browser_view_renderer_impl.h"
6
7 #include <android/bitmap.h>
8 #include <sys/system_properties.h>
9
10 #include "android_webview/common/renderer_picture_map.h"
11 #include "android_webview/public/browser/draw_gl.h"
12 #include "android_webview/public/browser/draw_sw.h"
13 #include "base/android/jni_android.h"
14 #include "base/debug/trace_event.h"
15 #include "base/logging.h"
16 #include "cc/layer.h"
17 #include "content/public/browser/android/content_view_core.h"
18 #include "content/public/browser/render_process_host.h"
19 #include "content/public/browser/web_contents.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 "ui/gfx/size.h"
24 #include "ui/gfx/transform.h"
25 #include "ui/gl/gl_bindings.h"
26
27 // TODO(leandrogracia): remove when crbug.com/164140 is closed.
28 // Borrowed from gl2ext.h. Cannot be included due to conflicts with
29 // gl_bindings.h and the EGL library methods (eglGetCurrentContext).
30 #ifndef GL_TEXTURE_EXTERNAL_OES
31 #define GL_TEXTURE_EXTERNAL_OES 0x8D65
32 #endif
33
34 #ifndef GL_TEXTURE_BINDING_EXTERNAL_OES
35 #define GL_TEXTURE_BINDING_EXTERNAL_OES 0x8D67
36 #endif
37
38 using base::android::AttachCurrentThread;
39 using base::android::JavaRef;
40 using base::android::ScopedJavaLocalRef;
41 using content::Compositor;
42 using content::ContentViewCore;
43
44 namespace {
45
46 typedef base::Callback<bool(SkCanvas*)> RenderMethod;
47
48 static bool RasterizeIntoBitmap(JNIEnv* env,
49 const JavaRef<jobject>& jbitmap,
50 int scroll_x,
51 int scroll_y,
52 const RenderMethod& renderer) {
53 DCHECK(jbitmap.obj());
54
55 AndroidBitmapInfo bitmap_info;
56 if (AndroidBitmap_getInfo(env, jbitmap.obj(), &bitmap_info) < 0) {
57 LOG(ERROR) << "Error getting java bitmap info.";
58 return false;
59 }
60
61 void* pixels = NULL;
62 if (AndroidBitmap_lockPixels(env, jbitmap.obj(), &pixels) < 0) {
63 LOG(ERROR) << "Error locking java bitmap pixels.";
64 return false;
65 }
66
67 bool succeeded = false;
joth 2013/02/06 20:26:31 nit: you can remove = false here, as it's uncondit
Leandro Graciá Gil 2013/02/07 12:43:56 Done.
68 {
69 SkBitmap bitmap;
70 bitmap.setConfig(SkBitmap::kARGB_8888_Config,
71 bitmap_info.width,
72 bitmap_info.height,
73 bitmap_info.stride);
74 bitmap.setPixels(pixels);
75
76 SkDevice device(bitmap);
77 SkCanvas canvas(&device);
78 canvas.translate(-scroll_x, -scroll_y);
79 succeeded = renderer.Run(&canvas);
80 }
81
82 if (AndroidBitmap_unlockPixels(env, jbitmap.obj()) < 0) {
83 LOG(ERROR) << "Error unlocking java bitmap pixels.";
84 return false;
85 }
86
87 return succeeded;
88 }
89
90 } // namespace
91
92 namespace android_webview {
93
94 // static
95 BrowserViewRendererImpl* BrowserViewRendererImpl::Create(
96 BrowserViewRenderer::Client* client,
97 JavaHelper* java_helper) {
98 return new BrowserViewRendererImpl(client, java_helper);
99 }
100
101 BrowserViewRendererImpl::BrowserViewRendererImpl(
102 BrowserViewRenderer::Client* client,
103 JavaHelper* java_helper)
104 : BrowserViewRenderer(client, java_helper),
105 ALLOW_THIS_IN_INITIALIZER_LIST(compositor_(Compositor::Create(this))),
106 view_clip_layer_(cc::Layer::create()),
107 transform_layer_(cc::Layer::create()),
108 scissor_clip_layer_(cc::Layer::create()),
109 view_visible_(false),
110 compositor_visible_(false),
111 is_composite_pending_(false),
112 dpi_scale_(1.0f),
113 on_new_picture_mode_(kOnNewPictureDisabled),
114 last_frame_context_(NULL),
115 web_contents_(NULL) {
116 DCHECK(java_helper);
117
118 // Define the view hierarchy.
119 transform_layer_->addChild(view_clip_layer_);
120 scissor_clip_layer_->addChild(transform_layer_);
121 compositor_->SetRootLayer(scissor_clip_layer_);
122
123 RendererPictureMap::CreateInstance();
124 }
125
126 BrowserViewRendererImpl::~BrowserViewRendererImpl() {
127 }
128
129 void BrowserViewRendererImpl::SetContents(ContentViewCore* content_view_core) {
130 dpi_scale_ = content_view_core->GetDpiScale();
131 web_contents_ = content_view_core->GetWebContents();
132 if (!view_renderer_host_)
133 view_renderer_host_.reset(new ViewRendererHost(web_contents_, this));
134 else
135 view_renderer_host_->Observe(web_contents_);
136
137 view_clip_layer_->removeAllChildren();
138 view_clip_layer_->addChild(content_view_core->GetLayer());
139 Invalidate();
140 }
141
142 void BrowserViewRendererImpl::DrawGL(AwDrawGLInfo* draw_info) {
143 TRACE_EVENT0("android_webview", "BrowserViewRendererImpl::DrawGL");
144
145 if (view_size_.IsEmpty() || !scissor_clip_layer_ ||
146 draw_info->mode == AwDrawGLInfo::kModeProcess)
147 return;
148
149 DCHECK_EQ(draw_info->mode, AwDrawGLInfo::kModeDraw);
150
151 SetCompositorVisibility(view_visible_);
152 if (!compositor_visible_)
153 return;
154
155 // TODO(leandrogracia): remove when crbug.com/164140 is closed.
156 // ---------------------------------------------------------------------------
157 GLint texture_external_oes_binding;
158 glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &texture_external_oes_binding);
159
160 GLint vertex_array_buffer_binding;
161 glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &vertex_array_buffer_binding);
162
163 GLint index_array_buffer_binding;
164 glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &index_array_buffer_binding);
165
166 GLint pack_alignment;
167 glGetIntegerv(GL_PACK_ALIGNMENT, &pack_alignment);
168
169 GLint unpack_alignment;
170 glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack_alignment);
171
172 struct {
173 GLint enabled;
174 GLint size;
175 GLint type;
176 GLint normalized;
177 GLint stride;
178 GLvoid* pointer;
179 } vertex_attrib[3];
180
181 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(vertex_attrib); ++i) {
182 glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED,
183 &vertex_attrib[i].enabled);
184 glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_SIZE,
185 &vertex_attrib[i].size);
186 glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_TYPE,
187 &vertex_attrib[i].type);
188 glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED,
189 &vertex_attrib[i].normalized);
190 glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_STRIDE,
191 &vertex_attrib[i].stride);
192 glGetVertexAttribPointerv(i, GL_VERTEX_ATTRIB_ARRAY_POINTER,
193 &vertex_attrib[i].pointer);
194 }
195
196 GLboolean depth_test;
197 glGetBooleanv(GL_DEPTH_TEST, &depth_test);
198
199 GLboolean cull_face;
200 glGetBooleanv(GL_CULL_FACE, &cull_face);
201
202 GLboolean color_mask[4];
203 glGetBooleanv(GL_COLOR_WRITEMASK, color_mask);
204
205 GLboolean blend_enabled;
206 glGetBooleanv(GL_BLEND, &blend_enabled);
207
208 GLint blend_src_rgb;
209 glGetIntegerv(GL_BLEND_SRC_RGB, &blend_src_rgb);
210
211 GLint blend_src_alpha;
212 glGetIntegerv(GL_BLEND_SRC_ALPHA, &blend_src_alpha);
213
214 GLint blend_dest_rgb;
215 glGetIntegerv(GL_BLEND_DST_RGB, &blend_dest_rgb);
216
217 GLint blend_dest_alpha;
218 glGetIntegerv(GL_BLEND_DST_ALPHA, &blend_dest_alpha);
219
220 GLint active_texture;
221 glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);
222
223 GLint viewport[4];
224 glGetIntegerv(GL_VIEWPORT, viewport);
225
226 GLboolean scissor_test;
227 glGetBooleanv(GL_SCISSOR_TEST, &scissor_test);
228
229 GLint scissor_box[4];
230 glGetIntegerv(GL_SCISSOR_BOX, scissor_box);
231
232 GLint current_program;
233 glGetIntegerv(GL_CURRENT_PROGRAM, &current_program);
234 // ---------------------------------------------------------------------------
235
236 // We need to watch if the current Android context has changed and enforce
237 // a clean-up in the compositor.
238 EGLContext current_context = eglGetCurrentContext();
239 if (!current_context) {
240 LOG(WARNING) << "No current context attached. Skipping composite.";
241 return;
242 }
243
244 if (last_frame_context_ != current_context) {
245 if (last_frame_context_)
246 ResetCompositor();
247 last_frame_context_ = current_context;
248 }
249
250 compositor_->SetWindowBounds(gfx::Size(draw_info->width, draw_info->height));
251
252 if (draw_info->is_layer) {
253 // When rendering into a separate layer no view clipping, transform,
254 // scissoring or background transparency need to be handled.
255 // The Android framework will composite us afterwards.
256 compositor_->SetHasTransparentBackground(false);
257 view_clip_layer_->setMasksToBounds(false);
258 transform_layer_->setTransform(gfx::Transform());
259 scissor_clip_layer_->setMasksToBounds(false);
260 scissor_clip_layer_->setPosition(gfx::PointF());
261 scissor_clip_layer_->setBounds(gfx::Size());
262 scissor_clip_layer_->setSublayerTransform(gfx::Transform());
263
264 } else {
265 compositor_->SetHasTransparentBackground(true);
266
267 gfx::Rect clip_rect(draw_info->clip_left, draw_info->clip_top,
268 draw_info->clip_right - draw_info->clip_left,
269 draw_info->clip_bottom - draw_info->clip_top);
270
271 scissor_clip_layer_->setPosition(clip_rect.origin());
272 scissor_clip_layer_->setBounds(clip_rect.size());
273 scissor_clip_layer_->setMasksToBounds(true);
274
275 // The compositor clipping architecture enforces us to have the clip layer
276 // as an ancestor of the area we want to clip, but this makes the transform
277 // become relative to the clip area rather than the full surface. The clip
278 // position offset needs to be undone before applying the transform.
279 gfx::Transform undo_clip_position;
280 undo_clip_position.Translate(-clip_rect.x(), -clip_rect.y());
281 scissor_clip_layer_->setSublayerTransform(undo_clip_position);
282
283 gfx::Transform transform;
284 transform.matrix().setColMajorf(draw_info->transform);
285
286 // The scrolling values of the Android Framework affect the transformation
287 // matrix. This needs to be undone to let the compositor handle scrolling.
288 transform.Translate(hw_rendering_scroll_.x(), hw_rendering_scroll_.y());
mkosiba (inactive) 2013/02/07 10:10:29 like we discussed earlier - when we have syncrhono
Leandro Graciá Gil 2013/02/07 12:43:56 Good point. Done.
289 transform_layer_->setTransform(transform);
290
291 view_clip_layer_->setMasksToBounds(true);
292 }
293
294 compositor_->Composite();
295 is_composite_pending_ = false;
296
297 // TODO(leandrogracia): remove when crbug.com/164140 is closed.
298 // ---------------------------------------------------------------------------
299 char no_gl_restore_prop[PROP_VALUE_MAX];
300 __system_property_get("webview.chromium_no_gl_restore", no_gl_restore_prop);
301 if (!strcmp(no_gl_restore_prop, "true")) {
302 LOG(WARNING) << "Android GL functor not restoring the previous GL state.";
303 } else {
304 glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_external_oes_binding);
305 glBindBuffer(GL_ARRAY_BUFFER, vertex_array_buffer_binding);
306 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_array_buffer_binding);
307
308 glPixelStorei(GL_PACK_ALIGNMENT, pack_alignment);
309 glPixelStorei(GL_UNPACK_ALIGNMENT, unpack_alignment);
310
311 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(vertex_attrib); ++i) {
312 glVertexAttribPointer(i, vertex_attrib[i].size,
313 vertex_attrib[i].type, vertex_attrib[i].normalized,
314 vertex_attrib[i].stride, vertex_attrib[i].pointer);
315
316 if (vertex_attrib[i].enabled)
317 glEnableVertexAttribArray(i);
318 else
319 glDisableVertexAttribArray(i);
320 }
321
322 if (depth_test)
323 glEnable(GL_DEPTH_TEST);
324 else
325 glDisable(GL_DEPTH_TEST);
326
327 if (cull_face)
328 glEnable(GL_CULL_FACE);
329 else
330 glDisable(GL_CULL_FACE);
331
332 glColorMask(color_mask[0], color_mask[1], color_mask[2],
333 color_mask[3]);
mkosiba (inactive) 2013/02/07 10:10:29 nit: indent
Leandro Graciá Gil 2013/02/07 12:43:56 Done.
334
335 if (blend_enabled)
336 glEnable(GL_BLEND);
337 else
338 glDisable(GL_BLEND);
339
340 glBlendFuncSeparate(blend_src_rgb, blend_dest_rgb,
341 blend_src_alpha, blend_dest_alpha);
mkosiba (inactive) 2013/02/07 10:10:29 nit:indent
Leandro Graciá Gil 2013/02/07 12:43:56 Done.
342
343 glActiveTexture(active_texture);
344
345 glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
346
347 if (scissor_test)
348 glEnable(GL_SCISSOR_TEST);
349 else
350 glDisable(GL_SCISSOR_TEST);
351
352 glScissor(scissor_box[0], scissor_box[1], scissor_box[2],
353 scissor_box[3]);
mkosiba (inactive) 2013/02/07 10:10:29 nit: indent
Leandro Graciá Gil 2013/02/07 12:43:56 Done.
354
355 glUseProgram(current_program);
356 }
357 // ---------------------------------------------------------------------------
358 }
359
360 void BrowserViewRendererImpl::SetScrollForHWFrame(int x, int y) {
361 hw_rendering_scroll_ = gfx::Point(x, y);
362 }
363
364 bool BrowserViewRendererImpl::DrawSW(jobject java_canvas,
365 const gfx::Rect& clip) {
366 TRACE_EVENT0("android_webview", "BrowserViewRendererImpl::DrawSW");
367
368 if (clip.IsEmpty())
369 return true;
370
371 AwPixelInfo* pixels;
372 JNIEnv* env = AttachCurrentThread();
373
374 // Render into an auxiliary bitmap if pixel info is not available.
375 if (!SWDrawFunctions() ||
376 (pixels = SWDrawFunctions()->access_pixels(env, java_canvas)) == NULL) {
377 ScopedJavaLocalRef<jobject> jbitmap(java_helper()->CreateBitmap(
378 env, clip.width(), clip.height()));
379 if (!jbitmap.obj())
380 return false;
381
382 if (!RasterizeIntoBitmap(env, jbitmap, clip.x(), clip.y(),
383 base::Bind(&BrowserViewRendererImpl::RenderSW, base::Unretained(this))))
joth 2013/02/06 20:26:31 if (!RasterizeIntoBitmap(env, jbitmap, clip.x(), c
Leandro Graciá Gil 2013/02/07 12:43:56 Done.
384 return false;
385
386 ScopedJavaLocalRef<jobject> jcanvas(env, java_canvas);
387 java_helper()->DrawBitmapIntoCanvas(env, jbitmap, jcanvas);
388 return true;
389 }
390
391 // Draw in a SkCanvas built over the pixel information.
392 bool succeeded = false;
393 {
394 SkBitmap bitmap;
395 bitmap.setConfig(static_cast<SkBitmap::Config>(pixels->config),
396 pixels->width,
397 pixels->height,
398 pixels->row_bytes);
399 bitmap.setPixels(pixels->pixels);
400 SkDevice device(bitmap);
401 SkCanvas canvas(&device);
joth 2013/02/06 20:26:31 feels like there's some repetition here with Raste
Leandro Graciá Gil 2013/02/07 12:43:56 It's similar but not quite the same. RasterizeInto
402 SkMatrix matrix;
403 for (int i = 0; i < 9; i++)
404 matrix.set(i, pixels->matrix[i]);
405 canvas.setMatrix(matrix);
406
407 SkRegion clip;
408 if (pixels->clip_region_size) {
409 size_t bytes_read = clip.readFromMemory(pixels->clip_region);
410 DCHECK_EQ(pixels->clip_region_size, bytes_read);
411 canvas.setClipRegion(clip);
412 } else {
413 clip.setRect(SkIRect::MakeWH(pixels->width, pixels->height));
414 }
415
416 succeeded = RenderSW(&canvas);
417 }
418
419 SWDrawFunctions()->release_pixels(pixels);
420 return succeeded;
421 }
422
423 ScopedJavaLocalRef<jobject> BrowserViewRendererImpl::CapturePicture() {
424 skia::RefPtr<SkPicture> picture = GetLastCapturedPicture();
425 if (!picture || !SWDrawFunctions())
426 return ScopedJavaLocalRef<jobject>();
427
428 JNIEnv* env = AttachCurrentThread();
429 if (IsSkiaVersionCompatible()) {
430 return ScopedJavaLocalRef<jobject>(env,
431 SWDrawFunctions()->create_picture(env, picture->clone()));
432 }
433
434 // If Skia versions are not compatible, workaround it by rasterizing the
435 // picture into a bitmap and drawing it into a new Java picture.
436 ScopedJavaLocalRef<jobject> jbitmap(java_helper()->CreateBitmap(
437 env, picture->width(), picture->height()));
438 if (!jbitmap.obj())
439 return ScopedJavaLocalRef<jobject>();
440
441 if (!RasterizeIntoBitmap(env, jbitmap, 0, 0,
442 base::Bind(&BrowserViewRendererImpl::RenderPicture,
443 base::Unretained(this)))) {
444 return ScopedJavaLocalRef<jobject>();
445 }
446
447 return java_helper()->RecordBitmapIntoPicture(env, jbitmap);
448 }
449
450 void BrowserViewRendererImpl::EnableOnNewPicture(OnNewPictureMode mode) {
451 on_new_picture_mode_ = mode;
452
453 // TODO(leandrogracia): when SW rendering uses the compositor rather than
454 // picture rasterization, send update the renderer side with the correct
455 // listener state. (For now, we always leave render picture listener enabled).
456 // render_view_host_ext_->EnableCapturePictureCallback(enabled);
457 //DCHECK(view_renderer_host_);
458 //view_renderer_host_->EnableCapturePictureCallback(
459 // on_new_picture_mode_ == kOnNewPictureEnabled);
460 }
461
462 void BrowserViewRendererImpl::OnVisibilityChanged(bool view_visible,
463 bool window_visible) {
joth 2013/02/06 20:26:31 indent
Leandro Graciá Gil 2013/02/07 12:43:56 Done.
464 view_visible_ = window_visible && view_visible;
465 Invalidate();
466 }
467
468 void BrowserViewRendererImpl::OnSizeChanged(int width, int height) {
469 view_size_ = gfx::Size(width, height);
470 view_clip_layer_->setBounds(view_size_);
471 }
472
473 void BrowserViewRendererImpl::OnAttachedToWindow(int width, int height) {
474 view_size_ = gfx::Size(width, height);
475 view_clip_layer_->setBounds(view_size_);
476 }
477
478 void BrowserViewRendererImpl::OnDetachedFromWindow() {
479 view_visible_ = false;
480 SetCompositorVisibility(false);
481 }
482
483 void BrowserViewRendererImpl::ScheduleComposite() {
484 TRACE_EVENT0("android_webview", "BrowserViewRendererImpl::ScheduleComposite");
485
486 if (is_composite_pending_)
487 return;
488
489 is_composite_pending_ = true;
490 Invalidate();
491 }
492
493 skia::RefPtr<SkPicture> BrowserViewRendererImpl::GetLastCapturedPicture() {
494 // Use the latest available picture if the listener callback is enabled.
495 skia::RefPtr<SkPicture> picture;
496 if (on_new_picture_mode_ == kOnNewPictureEnabled)
497 picture = RendererPictureMap::GetInstance()->GetRendererPicture(
498 web_contents_->GetRoutingID());
499
500 // If not available or not in listener mode get it synchronously.
501 if (!picture) {
502 DCHECK(view_renderer_host_);
503 view_renderer_host_->CapturePictureSync();
504 picture = RendererPictureMap::GetInstance()->GetRendererPicture(
505 web_contents_->GetRoutingID());
506 }
507
508 return picture;
509 }
510
511 void BrowserViewRendererImpl::OnPictureUpdated(int process_id,
512 int render_view_id) {
513 CHECK_EQ(web_contents_->GetRenderProcessHost()->GetID(), process_id);
514 if (render_view_id != web_contents_->GetRoutingID())
515 return;
516
517 // TODO(leandrogracia): this can be made unconditional once software rendering
518 // uses Ubercompositor. Until then this path is required for SW invalidations.
519 if (on_new_picture_mode_ == kOnNewPictureEnabled)
520 client()->OnNewPicture(CapturePicture());
521
522 // TODO(leandrogracia): delete when sw rendering uses Ubercompositor.
523 // Invalidation should be provided by the compositor only.
524 Invalidate();
525 }
526
527 void BrowserViewRendererImpl::SetCompositorVisibility(bool visible) {
528 if (compositor_visible_ != visible) {
529 compositor_visible_ = visible;
530 compositor_->SetVisible(compositor_visible_);
531 }
532 }
533
534 void BrowserViewRendererImpl::ResetCompositor() {
535 compositor_.reset(content::Compositor::Create(this));
536 compositor_->SetRootLayer(scissor_clip_layer_);
537 }
538
539 void BrowserViewRendererImpl::Invalidate() {
540 if (view_visible_)
541 client()->Invalidate();
542
543 // When not in invalidation-only mode onNewPicture will be triggered
544 // from the OnPictureUpdated callback.
545 if (on_new_picture_mode_ == kOnNewPictureInvalidationOnly)
546 client()->OnNewPicture(ScopedJavaLocalRef<jobject>());
547 }
548
549 bool BrowserViewRendererImpl::RenderSW(SkCanvas* canvas) {
550 // TODO(leandrogracia): once Ubercompositor is ready and we support software
551 // rendering mode, we should avoid this as much as we can, ideally always.
552 // This includes finding a proper replacement for onDraw calls in hardware
553 // mode with software canvases. http://crbug.com/170086.
554 return RenderPicture(canvas);
555
556 //compositor_->Composite();
557 //is_composite_pending_ = false;
558 //return true;
559 }
560
561 bool BrowserViewRendererImpl::RenderPicture(SkCanvas* canvas) {
562 skia::RefPtr<SkPicture> picture = GetLastCapturedPicture();
563 if (!picture)
564 return false;
565
566 // Correct device scale.
567 canvas->scale(dpi_scale_, dpi_scale_);
568
569 picture->draw(canvas);
570 return true;
571 }
572
573 } // namespace android_webview
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698