OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "android_webview/browser/browser_view_renderer.h" | 5 #include "android_webview/browser/browser_view_renderer.h" |
6 | 6 |
7 #include "android_webview/browser/browser_view_renderer_client.h" | 7 #include "android_webview/browser/browser_view_renderer_client.h" |
8 #include "android_webview/browser/shared_renderer_state.h" | 8 #include "android_webview/browser/shared_renderer_state.h" |
9 #include "android_webview/common/aw_switches.h" | |
9 #include "android_webview/public/browser/draw_gl.h" | 10 #include "android_webview/public/browser/draw_gl.h" |
10 #include "base/android/jni_android.h" | 11 #include "base/android/jni_android.h" |
11 #include "base/auto_reset.h" | 12 #include "base/auto_reset.h" |
12 #include "base/command_line.h" | 13 #include "base/command_line.h" |
13 #include "base/debug/trace_event.h" | 14 #include "base/debug/trace_event.h" |
14 #include "base/json/json_writer.h" | 15 #include "base/json/json_writer.h" |
15 #include "base/logging.h" | 16 #include "base/logging.h" |
16 #include "base/strings/string_number_conversions.h" | 17 #include "base/strings/string_number_conversions.h" |
17 #include "base/strings/stringprintf.h" | 18 #include "base/strings/stringprintf.h" |
19 #include "cc/output/compositor_frame.h" | |
18 #include "content/public/browser/android/synchronous_compositor.h" | 20 #include "content/public/browser/android/synchronous_compositor.h" |
19 #include "content/public/browser/browser_thread.h" | 21 #include "content/public/browser/browser_thread.h" |
20 #include "content/public/browser/web_contents.h" | 22 #include "content/public/browser/web_contents.h" |
21 #include "content/public/common/content_switches.h" | 23 #include "content/public/common/content_switches.h" |
22 #include "third_party/skia/include/core/SkBitmap.h" | 24 #include "third_party/skia/include/core/SkBitmap.h" |
23 #include "third_party/skia/include/core/SkCanvas.h" | 25 #include "third_party/skia/include/core/SkCanvas.h" |
24 #include "third_party/skia/include/core/SkPicture.h" | 26 #include "third_party/skia/include/core/SkPicture.h" |
25 #include "third_party/skia/include/core/SkPictureRecorder.h" | 27 #include "third_party/skia/include/core/SkPictureRecorder.h" |
26 #include "ui/gfx/vector2d_conversions.h" | 28 #include "ui/gfx/vector2d_conversions.h" |
27 | 29 |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
122 shared_renderer_state_(shared_renderer_state), | 124 shared_renderer_state_(shared_renderer_state), |
123 web_contents_(web_contents), | 125 web_contents_(web_contents), |
124 weak_factory_on_ui_thread_(this), | 126 weak_factory_on_ui_thread_(this), |
125 ui_thread_weak_ptr_(weak_factory_on_ui_thread_.GetWeakPtr()), | 127 ui_thread_weak_ptr_(weak_factory_on_ui_thread_.GetWeakPtr()), |
126 ui_task_runner_(ui_task_runner), | 128 ui_task_runner_(ui_task_runner), |
127 has_compositor_(false), | 129 has_compositor_(false), |
128 is_paused_(false), | 130 is_paused_(false), |
129 view_visible_(false), | 131 view_visible_(false), |
130 window_visible_(false), | 132 window_visible_(false), |
131 attached_to_window_(false), | 133 attached_to_window_(false), |
134 hardware_enabled_(false), | |
132 dip_scale_(0.0), | 135 dip_scale_(0.0), |
133 page_scale_factor_(1.0), | 136 page_scale_factor_(1.0), |
134 on_new_picture_enable_(false), | 137 on_new_picture_enable_(false), |
135 clear_view_(false), | 138 clear_view_(false), |
136 compositor_needs_continuous_invalidate_(false), | 139 compositor_needs_continuous_invalidate_(false), |
137 block_invalidates_(false), | 140 block_invalidates_(false), |
138 width_(0), | 141 width_(0), |
139 height_(0), | 142 height_(0), |
140 num_tiles_(0u), | 143 num_tiles_(0u), |
141 num_bytes_(0u) { | 144 num_bytes_(0u) { |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
181 | 184 |
182 TRACE_EVENT0("android_webview", "BrowserViewRenderer::TrimMemory"); | 185 TRACE_EVENT0("android_webview", "BrowserViewRenderer::TrimMemory"); |
183 | 186 |
184 RequestMemoryPolicy(zero_policy); | 187 RequestMemoryPolicy(zero_policy); |
185 EnforceMemoryPolicyImmediately(zero_policy); | 188 EnforceMemoryPolicyImmediately(zero_policy); |
186 } | 189 } |
187 | 190 |
188 SynchronousCompositorMemoryPolicy | 191 SynchronousCompositorMemoryPolicy |
189 BrowserViewRenderer::CalculateDesiredMemoryPolicy() { | 192 BrowserViewRenderer::CalculateDesiredMemoryPolicy() { |
190 SynchronousCompositorMemoryPolicy policy; | 193 SynchronousCompositorMemoryPolicy policy; |
191 size_t width = draw_gl_input_.global_visible_rect.width(); | 194 size_t width = global_visible_rect_.width(); |
192 size_t height = draw_gl_input_.global_visible_rect.height(); | 195 size_t height = global_visible_rect_.height(); |
193 policy.bytes_limit = kMemoryMultiplier * kBytesPerPixel * width * height; | 196 policy.bytes_limit = kMemoryMultiplier * kBytesPerPixel * width * height; |
194 // Round up to a multiple of kMemoryAllocationStep. | 197 // Round up to a multiple of kMemoryAllocationStep. |
195 policy.bytes_limit = | 198 policy.bytes_limit = |
196 (policy.bytes_limit / kMemoryAllocationStep + 1) * kMemoryAllocationStep; | 199 (policy.bytes_limit / kMemoryAllocationStep + 1) * kMemoryAllocationStep; |
197 | 200 |
198 size_t tiles = width * height * kTileMultiplier / g_tile_area; | 201 size_t tiles = width * height * kTileMultiplier / g_tile_area; |
199 // Round up to a multiple of kTileAllocationStep. The minimum number of tiles | 202 // Round up to a multiple of kTileAllocationStep. The minimum number of tiles |
200 // is also kTileAllocationStep. | 203 // is also kTileAllocationStep. |
201 tiles = (tiles / kTileAllocationStep + 1) * kTileAllocationStep; | 204 tiles = (tiles / kTileAllocationStep + 1) * kTileAllocationStep; |
202 policy.num_resources_limit = tiles; | 205 policy.num_resources_limit = tiles; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
240 | 243 |
241 size_t BrowserViewRenderer::GetNumTiles() const { | 244 size_t BrowserViewRenderer::GetNumTiles() const { |
242 return shared_renderer_state_->GetMemoryPolicy().num_resources_limit; | 245 return shared_renderer_state_->GetMemoryPolicy().num_resources_limit; |
243 } | 246 } |
244 | 247 |
245 bool BrowserViewRenderer::OnDraw(jobject java_canvas, | 248 bool BrowserViewRenderer::OnDraw(jobject java_canvas, |
246 bool is_hardware_canvas, | 249 bool is_hardware_canvas, |
247 const gfx::Vector2d& scroll, | 250 const gfx::Vector2d& scroll, |
248 const gfx::Rect& global_visible_rect, | 251 const gfx::Rect& global_visible_rect, |
249 const gfx::Rect& clip) { | 252 const gfx::Rect& clip) { |
250 draw_gl_input_.frame_id++; | 253 scroll_offset_ = scroll; |
251 draw_gl_input_.scroll_offset = scroll; | 254 global_visible_rect_ = global_visible_rect; |
252 draw_gl_input_.global_visible_rect = global_visible_rect; | 255 |
253 draw_gl_input_.width = width_; | |
254 draw_gl_input_.height = height_; | |
255 if (clear_view_) | 256 if (clear_view_) |
256 return false; | 257 return false; |
258 | |
257 if (is_hardware_canvas && attached_to_window_) { | 259 if (is_hardware_canvas && attached_to_window_) { |
258 shared_renderer_state_->SetDrawGLInput(draw_gl_input_); | 260 if (switches::UbercompEnabled()) { |
259 | 261 return OnDrawHardware(java_canvas); |
260 SynchronousCompositorMemoryPolicy old_policy = | 262 } else { |
261 shared_renderer_state_->GetMemoryPolicy(); | 263 return OnDrawHardwareLegacy(java_canvas); |
262 SynchronousCompositorMemoryPolicy new_policy = | 264 } |
263 CalculateDesiredMemoryPolicy(); | |
264 RequestMemoryPolicy(new_policy); | |
265 // We should be performing a hardware draw here. If we don't have the | |
266 // compositor yet or if RequestDrawGL fails, it means we failed this draw | |
267 // and thus return false here to clear to background color for this draw. | |
268 bool did_draw_gl = | |
269 has_compositor_ && client_->RequestDrawGL(java_canvas, false); | |
270 if (did_draw_gl) | |
271 GlobalTileManager::GetInstance()->DidUse(tile_manager_key_); | |
272 else | |
273 RequestMemoryPolicy(old_policy); | |
274 | |
275 return did_draw_gl; | |
276 } | 265 } |
277 // Perform a software draw | 266 // Perform a software draw |
278 return DrawSWInternal(java_canvas, clip); | 267 return DrawSWInternal(java_canvas, clip); |
279 } | 268 } |
280 | 269 |
281 void BrowserViewRenderer::DidDrawGL(const DrawGLResult& result) { | 270 bool BrowserViewRenderer::OnDrawHardwareLegacy(jobject java_canvas) { |
282 DidComposite(!result.clip_contains_visible_rect); | 271 scoped_ptr<DrawGLInput> draw_gl_input(new DrawGLInput); |
272 draw_gl_input->scroll_offset = scroll_offset_; | |
273 draw_gl_input->global_visible_rect = global_visible_rect_; | |
274 draw_gl_input->width = width_; | |
275 draw_gl_input->height = height_; | |
276 | |
277 SynchronousCompositorMemoryPolicy old_policy = | |
278 shared_renderer_state_->GetMemoryPolicy(); | |
279 SynchronousCompositorMemoryPolicy new_policy = CalculateDesiredMemoryPolicy(); | |
280 RequestMemoryPolicy(new_policy); | |
281 // We should be performing a hardware draw here. If we don't have the | |
282 // compositor yet or if RequestDrawGL fails, it means we failed this draw | |
283 // and thus return false here to clear to background color for this draw. | |
284 bool did_draw_gl = | |
285 has_compositor_ && client_->RequestDrawGL(java_canvas, false); | |
286 if (did_draw_gl) { | |
287 GlobalTileManager::GetInstance()->DidUse(tile_manager_key_); | |
288 shared_renderer_state_->SetDrawGLInput(draw_gl_input.Pass()); | |
289 } else { | |
290 RequestMemoryPolicy(old_policy); | |
291 } | |
292 | |
293 return did_draw_gl; | |
294 } | |
295 | |
296 void BrowserViewRenderer::DidDrawGL(scoped_ptr<DrawGLResult> result) { | |
297 DidComposite(!result->clip_contains_visible_rect); | |
298 } | |
299 | |
300 bool BrowserViewRenderer::OnDrawHardware(jobject java_canvas) { | |
301 if (!has_compositor_) | |
302 return false; | |
303 | |
304 scoped_ptr<DrawGLInput> draw_gl_input(new DrawGLInput); | |
305 draw_gl_input->scroll_offset = scroll_offset_; | |
306 draw_gl_input->global_visible_rect = global_visible_rect_; | |
307 draw_gl_input->width = width_; | |
308 draw_gl_input->height = height_; | |
309 | |
310 DCHECK(attached_to_window_); | |
mkosiba (inactive)
2014/05/19 20:01:16
nit: I think the consensus is that either you DCHE
boliu
2014/05/19 23:13:01
Just checked that this can't actually happen. OnDr
| |
311 if (!hardware_enabled_ && attached_to_window_) { | |
312 hardware_enabled_ = | |
313 shared_renderer_state_->GetCompositor()->InitializeHwDraw(NULL); | |
314 if (hardware_enabled_) { | |
315 DCHECK(shared_renderer_state_->GetCompositor()->GetShareContext()); | |
mkosiba (inactive)
2014/05/19 20:01:16
maybe:
type share_context = shared_renderer_stat
boliu
2014/05/19 23:13:01
Done
| |
316 shared_renderer_state_->SetSharedContext( | |
317 shared_renderer_state_->GetCompositor()->GetShareContext()); | |
318 } | |
319 } | |
320 if (!hardware_enabled_) | |
321 return false; | |
322 | |
323 ReturnResources(); | |
mkosiba (inactive)
2014/05/19 20:01:16
is it possible for the renderer thread to try and
boliu
2014/05/19 23:13:01
ReturnResources only return the resources that the
| |
324 SynchronousCompositorMemoryPolicy new_policy = CalculateDesiredMemoryPolicy(); | |
325 RequestMemoryPolicy(new_policy); | |
326 shared_renderer_state_->GetCompositor()->SetMemoryPolicy( | |
327 shared_renderer_state_->GetMemoryPolicy()); | |
328 | |
329 gfx::Transform transform; | |
330 gfx::Size surface_size(width_, height_); | |
331 gfx::Rect viewport(surface_size); | |
332 gfx::Rect clip = viewport; // Should really be global_visible_rect_. | |
333 bool stencil_enabled = false; | |
334 bool drew_delegated = shared_renderer_state_->GetCompositor()->DemandDrawHw( | |
335 surface_size, | |
336 transform, | |
337 viewport, | |
338 clip, | |
339 stencil_enabled, | |
340 &draw_gl_input->frame); | |
341 if (!drew_delegated) | |
342 return false; | |
343 | |
344 GlobalTileManager::GetInstance()->DidUse(tile_manager_key_); | |
345 | |
346 scoped_ptr<DrawGLInput> old_input = shared_renderer_state_->PassDrawGLInput(); | |
347 if (old_input.get()) { | |
348 shared_renderer_state_->ReturnResources( | |
349 old_input->frame.delegated_frame_data->resource_list); | |
350 } | |
351 shared_renderer_state_->SetDrawGLInput(draw_gl_input.Pass()); | |
352 | |
353 DidComposite(false); | |
354 bool did_request = client_->RequestDrawGL(java_canvas, false); | |
355 if (did_request) | |
356 return true; | |
357 | |
358 ReturnResources(); | |
359 return false; | |
360 } | |
361 | |
362 void BrowserViewRenderer::DidDrawDelegated(scoped_ptr<DrawGLResult> result) { | |
363 if (!ui_task_runner_->BelongsToCurrentThread()) { | |
364 // TODO(boliu): This should be a cancelable callback. | |
365 ui_task_runner_->PostTask(FROM_HERE, | |
366 base::Bind(&BrowserViewRenderer::DidDrawDelegated, | |
367 ui_thread_weak_ptr_, | |
368 base::Passed(&result))); | |
369 return; | |
370 } | |
371 ReturnResources(); | |
372 } | |
373 | |
374 void BrowserViewRenderer::ReturnResources() { | |
375 cc::CompositorFrameAck frame_ack; | |
376 shared_renderer_state_->SwapReturnedResources(&frame_ack.resources); | |
mkosiba (inactive)
2014/05/19 20:01:16
It seems like this logic could just live in the sh
boliu
2014/05/19 23:13:01
Once legacy path is removed, SharedRendererState w
| |
377 if (!frame_ack.resources.empty()) { | |
378 shared_renderer_state_->GetCompositor()->ReturnResources(frame_ack); | |
379 } | |
283 } | 380 } |
284 | 381 |
285 bool BrowserViewRenderer::DrawSWInternal(jobject java_canvas, | 382 bool BrowserViewRenderer::DrawSWInternal(jobject java_canvas, |
286 const gfx::Rect& clip) { | 383 const gfx::Rect& clip) { |
287 if (clip.IsEmpty()) { | 384 if (clip.IsEmpty()) { |
288 TRACE_EVENT_INSTANT0( | 385 TRACE_EVENT_INSTANT0( |
289 "android_webview", "EarlyOut_EmptyClip", TRACE_EVENT_SCOPE_THREAD); | 386 "android_webview", "EarlyOut_EmptyClip", TRACE_EVENT_SCOPE_THREAD); |
290 return true; | 387 return true; |
291 } | 388 } |
292 | 389 |
293 if (!has_compositor_) { | 390 if (!has_compositor_) { |
294 TRACE_EVENT_INSTANT0( | 391 TRACE_EVENT_INSTANT0( |
295 "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD); | 392 "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD); |
296 return false; | 393 return false; |
297 } | 394 } |
298 | 395 |
299 return BrowserViewRendererJavaHelper::GetInstance() | 396 return BrowserViewRendererJavaHelper::GetInstance() |
300 ->RenderViaAuxilaryBitmapIfNeeded( | 397 ->RenderViaAuxilaryBitmapIfNeeded( |
301 java_canvas, | 398 java_canvas, |
302 draw_gl_input_.scroll_offset, | 399 scroll_offset_, |
303 clip, | 400 clip, |
304 base::Bind(&BrowserViewRenderer::CompositeSW, | 401 base::Bind(&BrowserViewRenderer::CompositeSW, |
305 base::Unretained(this))); | 402 base::Unretained(this))); |
306 } | 403 } |
307 | 404 |
308 skia::RefPtr<SkPicture> BrowserViewRenderer::CapturePicture(int width, | 405 skia::RefPtr<SkPicture> BrowserViewRenderer::CapturePicture(int width, |
309 int height) { | 406 int height) { |
310 TRACE_EVENT0("android_webview", "BrowserViewRenderer::CapturePicture"); | 407 TRACE_EVENT0("android_webview", "BrowserViewRenderer::CapturePicture"); |
311 | 408 |
312 // Return empty Picture objects for empty SkPictures. | 409 // Return empty Picture objects for empty SkPictures. |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
392 height); | 489 height); |
393 attached_to_window_ = true; | 490 attached_to_window_ = true; |
394 width_ = width; | 491 width_ = width; |
395 height_ = height; | 492 height_ = height; |
396 tile_manager_key_ = GlobalTileManager::GetInstance()->PushBack(this); | 493 tile_manager_key_ = GlobalTileManager::GetInstance()->PushBack(this); |
397 } | 494 } |
398 | 495 |
399 void BrowserViewRenderer::OnDetachedFromWindow() { | 496 void BrowserViewRenderer::OnDetachedFromWindow() { |
400 TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDetachedFromWindow"); | 497 TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDetachedFromWindow"); |
401 attached_to_window_ = false; | 498 attached_to_window_ = false; |
499 if (hardware_enabled_) { | |
500 scoped_ptr<DrawGLInput> input = shared_renderer_state_->PassDrawGLInput(); | |
501 if (input.get()) { | |
502 shared_renderer_state_->ReturnResources( | |
503 input->frame.delegated_frame_data->resource_list); | |
504 } | |
505 ReturnResources(); | |
506 DCHECK(shared_renderer_state_->ReturnedResourcesEmpty()); | |
507 | |
508 if (switches::UbercompEnabled()) | |
509 shared_renderer_state_->GetCompositor()->ReleaseHwDraw(); | |
510 shared_renderer_state_->SetSharedContext(NULL); | |
511 hardware_enabled_ = false; | |
512 } | |
402 SynchronousCompositorMemoryPolicy zero_policy; | 513 SynchronousCompositorMemoryPolicy zero_policy; |
403 RequestMemoryPolicy(zero_policy); | 514 RequestMemoryPolicy(zero_policy); |
404 GlobalTileManager::GetInstance()->Remove(tile_manager_key_); | 515 GlobalTileManager::GetInstance()->Remove(tile_manager_key_); |
405 // The hardware resources are released in the destructor of hardware renderer, | 516 // The hardware resources are released in the destructor of hardware renderer, |
406 // so we don't need to do it here. | 517 // so we don't need to do it here. |
407 // See AwContents::ReleaseHardwareDrawOnRenderThread(JNIEnv*, jobject). | 518 // See AwContents::ReleaseHardwareDrawOnRenderThread(JNIEnv*, jobject). |
408 } | 519 } |
409 | 520 |
410 bool BrowserViewRenderer::IsAttachedToWindow() const { | 521 bool BrowserViewRenderer::IsAttachedToWindow() const { |
411 return attached_to_window_; | 522 return attached_to_window_; |
(...skipping 361 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
773 base::StringAppendF(&str, "dip_scale: %f ", dip_scale_); | 884 base::StringAppendF(&str, "dip_scale: %f ", dip_scale_); |
774 base::StringAppendF(&str, "page_scale_factor: %f ", page_scale_factor_); | 885 base::StringAppendF(&str, "page_scale_factor: %f ", page_scale_factor_); |
775 base::StringAppendF(&str, | 886 base::StringAppendF(&str, |
776 "compositor_needs_continuous_invalidate: %d ", | 887 "compositor_needs_continuous_invalidate: %d ", |
777 compositor_needs_continuous_invalidate_); | 888 compositor_needs_continuous_invalidate_); |
778 base::StringAppendF(&str, "block_invalidates: %d ", block_invalidates_); | 889 base::StringAppendF(&str, "block_invalidates: %d ", block_invalidates_); |
779 base::StringAppendF(&str, "view width height: [%d %d] ", width_, height_); | 890 base::StringAppendF(&str, "view width height: [%d %d] ", width_, height_); |
780 base::StringAppendF(&str, "attached_to_window: %d ", attached_to_window_); | 891 base::StringAppendF(&str, "attached_to_window: %d ", attached_to_window_); |
781 base::StringAppendF(&str, | 892 base::StringAppendF(&str, |
782 "global visible rect: %s ", | 893 "global visible rect: %s ", |
783 draw_gl_input_.global_visible_rect.ToString().c_str()); | 894 global_visible_rect_.ToString().c_str()); |
784 base::StringAppendF( | 895 base::StringAppendF( |
785 &str, "scroll_offset_dip: %s ", scroll_offset_dip_.ToString().c_str()); | 896 &str, "scroll_offset_dip: %s ", scroll_offset_dip_.ToString().c_str()); |
786 base::StringAppendF(&str, | 897 base::StringAppendF(&str, |
787 "overscroll_rounding_error_: %s ", | 898 "overscroll_rounding_error_: %s ", |
788 overscroll_rounding_error_.ToString().c_str()); | 899 overscroll_rounding_error_.ToString().c_str()); |
789 base::StringAppendF( | 900 base::StringAppendF( |
790 &str, "on_new_picture_enable: %d ", on_new_picture_enable_); | 901 &str, "on_new_picture_enable: %d ", on_new_picture_enable_); |
791 base::StringAppendF(&str, "clear_view: %d ", clear_view_); | 902 base::StringAppendF(&str, "clear_view: %d ", clear_view_); |
792 if (draw_info) { | 903 if (draw_info) { |
793 base::StringAppendF(&str, | 904 base::StringAppendF(&str, |
794 "clip left top right bottom: [%d %d %d %d] ", | 905 "clip left top right bottom: [%d %d %d %d] ", |
795 draw_info->clip_left, | 906 draw_info->clip_left, |
796 draw_info->clip_top, | 907 draw_info->clip_top, |
797 draw_info->clip_right, | 908 draw_info->clip_right, |
798 draw_info->clip_bottom); | 909 draw_info->clip_bottom); |
799 base::StringAppendF(&str, | 910 base::StringAppendF(&str, |
800 "surface width height: [%d %d] ", | 911 "surface width height: [%d %d] ", |
801 draw_info->width, | 912 draw_info->width, |
802 draw_info->height); | 913 draw_info->height); |
803 base::StringAppendF(&str, "is_layer: %d ", draw_info->is_layer); | 914 base::StringAppendF(&str, "is_layer: %d ", draw_info->is_layer); |
804 } | 915 } |
805 return str; | 916 return str; |
806 } | 917 } |
807 | 918 |
808 } // namespace android_webview | 919 } // namespace android_webview |
OLD | NEW |